/**
* 转账功能模块
* 支持用户发转账、AI发转账、收款/退还、钱包余额管理
*/
import { getSettings } from './config.js';
import { requestSave } from './save-manager.js';
import { showToast } from './toast.js';
import { escapeHtml, sleep } from './utils.js';
import { refreshChatList } from './ui.js';
import { callAI } from './ai.js';
import { deductFromWallet, addToWallet, getWalletBalance, updateWalletDisplay } from './red-packet.js';
// 当前转账相关状态
let currentTransferAmount = '';
let currentTransferDescription = '';
let pendingReceiveTransfer = null; // 待收款的转账信息
let pendingReceiveContact = null; // 待收款转账的联系人
// ===== 发转账页面 =====
/**
* 显示发转账页面
*/
export function showTransferPage() {
currentTransferAmount = '';
currentTransferDescription = '';
const page = document.getElementById('wechat-transfer-page');
if (page) {
page.classList.remove('hidden');
updateTransferAmountDisplay();
const descInput = document.getElementById('wechat-transfer-description');
if (descInput) {
descInput.value = '';
}
const amountInput = document.getElementById('wechat-transfer-amount-input');
if (amountInput) {
amountInput.value = '';
}
}
}
/**
* 隐藏发转账页面
*/
export function hideTransferPage() {
const page = document.getElementById('wechat-transfer-page');
if (page) {
page.classList.add('hidden');
}
}
/**
* 更新金额显示
*/
function updateTransferAmountDisplay() {
const amountDisplay = document.getElementById('wechat-transfer-amount-display');
const amountInput = document.getElementById('wechat-transfer-amount-input');
const amount = amountInput ? parseFloat(amountInput.value) || 0 : parseFloat(currentTransferAmount) || 0;
if (amountDisplay) {
amountDisplay.textContent = '¥ ' + (amount > 0 ? amount.toFixed(2) : '0.00');
}
}
/**
* 显示密码输入弹窗
*/
export function showTransferPasswordModal() {
const amountInput = document.getElementById('wechat-transfer-amount-input');
const amount = amountInput ? parseFloat(amountInput.value) || 0 : 0;
if (amount <= 0) {
showToast('请输入金额');
return;
}
if (amount > getWalletBalance()) {
showToast('余额不足');
return;
}
currentTransferAmount = amount.toString();
// 获取转账说明
const descInput = document.getElementById('wechat-transfer-description');
if (descInput && descInput.value.trim()) {
currentTransferDescription = descInput.value.trim();
}
const modal = document.getElementById('wechat-transfer-password-modal');
if (modal) {
modal.classList.remove('hidden');
const passwordInput = document.getElementById('wechat-transfer-password-input');
if (passwordInput) {
passwordInput.value = '';
passwordInput.focus();
}
}
}
/**
* 隐藏密码输入弹窗
*/
export function hideTransferPasswordModal() {
const modal = document.getElementById('wechat-transfer-password-modal');
if (modal) {
modal.classList.add('hidden');
}
}
/**
* 验证密码并发送转账
*/
function verifyTransferPasswordAndSend() {
const passwordInput = document.getElementById('wechat-transfer-password-input');
const password = passwordInput?.value || '';
if (password.length !== 6) {
showToast('请输入6位密码');
return;
}
const settings = getSettings();
const correctPassword = settings.paymentPassword || '666666';
if (password === correctPassword) {
hideTransferPasswordModal();
sendTransfer();
} else {
showToast('密码错误');
if (passwordInput) passwordInput.value = '';
}
}
/**
* 发送转账
*/
async function sendTransfer() {
const amount = parseFloat(currentTransferAmount) || 0;
const description = currentTransferDescription;
// 扣款(转账无上限,但需要检查余额)
const current = getWalletBalance();
if (amount > current) {
showToast('余额不足', 'info');
return;
}
// 扣款
const settings = getSettings();
settings.walletAmount = (current - amount).toFixed(2);
requestSave();
updateWalletDisplay();
// 关闭发转账页面
hideTransferPage();
// 触发发送转账事件
const event = new CustomEvent('transfer-send', {
detail: {
amount: amount,
description: description
}
});
document.dispatchEvent(event);
}
// ===== 收款页面 =====
/**
* 显示收款页面(AI发的转账)
*/
export function showReceiveTransferPage(transferInfo, contact) {
pendingReceiveTransfer = transferInfo;
pendingReceiveContact = contact;
const page = document.getElementById('wechat-receive-transfer-page');
if (!page) return;
// 更新显示内容
const senderAvatar = document.getElementById('wechat-transfer-receive-avatar');
const senderName = document.getElementById('wechat-transfer-receive-name');
const amountEl = document.getElementById('wechat-transfer-receive-amount');
const descEl = document.getElementById('wechat-transfer-receive-desc');
if (senderAvatar) {
if (contact?.avatar) {
senderAvatar.innerHTML = `
`;
} else {
senderAvatar.innerHTML = contact?.name?.charAt(0) || '?';
}
}
if (senderName) {
senderName.textContent = contact?.name || 'AI';
}
if (amountEl) {
amountEl.textContent = '¥' + transferInfo.amount.toFixed(2);
}
if (descEl) {
descEl.textContent = transferInfo.description || '转账给你';
}
page.classList.remove('hidden');
}
/**
* 隐藏收款页面
*/
export function hideReceiveTransferPage() {
const page = document.getElementById('wechat-receive-transfer-page');
if (page) {
page.classList.add('hidden');
}
pendingReceiveTransfer = null;
pendingReceiveContact = null;
}
/**
* 确认收款
*/
export async function confirmReceiveTransfer() {
if (!pendingReceiveTransfer || !pendingReceiveContact) return;
const transferInfo = pendingReceiveTransfer;
const contact = pendingReceiveContact;
// 存入钱包
addToWallet(transferInfo.amount);
// 更新转账状态
transferInfo.status = 'received';
transferInfo.receivedAt = Date.now();
// 保存
requestSave();
// 隐藏收款页面
hideReceiveTransferPage();
// 更新聊天中的转账气泡状态
updateTransferBubbleStatus(transferInfo.id, 'received');
// 显示收款成功提示
showToast('已收款 ¥' + transferInfo.amount.toFixed(2), 'success');
pendingReceiveTransfer = null;
pendingReceiveContact = null;
}
/**
* 显示退还确认框
*/
export function showRefundConfirmModal() {
if (!pendingReceiveContact) return;
const modal = document.getElementById('wechat-transfer-refund-confirm');
if (!modal) return;
const titleEl = modal.querySelector('.wechat-transfer-confirm-title');
if (titleEl) {
titleEl.textContent = `退还 ${pendingReceiveContact.name} 的转账?`;
}
modal.classList.remove('hidden');
}
/**
* 隐藏退还确认框
*/
export function hideRefundConfirmModal() {
const modal = document.getElementById('wechat-transfer-refund-confirm');
if (modal) {
modal.classList.add('hidden');
}
}
/**
* 确认退还转账
*/
export async function confirmRefundTransfer() {
if (!pendingReceiveTransfer || !pendingReceiveContact) return;
const transferInfo = pendingReceiveTransfer;
// 更新转账状态
transferInfo.status = 'refunded';
transferInfo.refundedAt = Date.now();
// 保存
requestSave();
// 隐藏弹窗和收款页面
hideRefundConfirmModal();
hideReceiveTransferPage();
// 更新聊天中的转账气泡状态
updateTransferBubbleStatus(transferInfo.id, 'refunded');
// 显示退还提示
showToast('已退还转账', 'refund');
pendingReceiveTransfer = null;
pendingReceiveContact = null;
}
/**
* 更新转账气泡状态
*/
function updateTransferBubbleStatus(transferId, status) {
const bubble = document.querySelector(`.wechat-transfer-bubble[data-tf-id="${transferId}"]`);
if (!bubble) return;
bubble.classList.remove('pending', 'received', 'refunded');
bubble.classList.add(status);
const statusIcon = bubble.querySelector('.wechat-tf-bubble-status-icon');
const statusText = bubble.querySelector('.wechat-tf-bubble-status-text');
if (statusIcon && statusText) {
if (status === 'received') {
statusIcon.innerHTML = ``;
statusText.textContent = '已收款';
} else if (status === 'refunded') {
statusIcon.innerHTML = ``;
// 判断是发送方还是接收方
const role = bubble.dataset.role;
statusText.textContent = role === 'user' ? '已被退还' : '已退还';
}
}
}
// ===== 生成转账ID =====
export function generateTransferId() {
return 'tf_' + Math.random().toString(36).substring(2, 10) + '_' + Date.now();
}
// ===== 初始化事件监听 =====
export function initTransferEvents() {
// 发转账页面返回按钮
document.getElementById('wechat-transfer-back')?.addEventListener('click', hideTransferPage);
// 金额输入框变化时更新显示
document.getElementById('wechat-transfer-amount-input')?.addEventListener('input', updateTransferAmountDisplay);
// 转账按钮
document.getElementById('wechat-transfer-submit')?.addEventListener('click', showTransferPasswordModal);
// 密码弹窗关闭
document.getElementById('wechat-transfer-password-close')?.addEventListener('click', hideTransferPasswordModal);
// 密码确认按钮
document.getElementById('wechat-transfer-password-confirm')?.addEventListener('click', verifyTransferPasswordAndSend);
// 收款页面返回按钮
document.getElementById('wechat-transfer-receive-back')?.addEventListener('click', hideReceiveTransferPage);
// 收款按钮
document.getElementById('wechat-transfer-receive-btn')?.addEventListener('click', confirmReceiveTransfer);
// 退还按钮(显示确认框)
document.getElementById('wechat-transfer-refund-btn')?.addEventListener('click', showRefundConfirmModal);
// 退还确认框按钮
document.getElementById('wechat-transfer-refund-cancel')?.addEventListener('click', hideRefundConfirmModal);
document.getElementById('wechat-transfer-refund-confirm')?.addEventListener('click', confirmRefundTransfer);
// 监听转账发送事件(用户发转账后,AI 收款)
document.addEventListener('transfer-send', handleUserSendTransfer);
}
/**
* 处理用户发送转账
*/
async function handleUserSendTransfer(event) {
const { amount, description } = event.detail;
const settings = getSettings();
// 动态导入 chat.js 中的函数,避免循环依赖
const chatModule = await import('./chat.js');
const { currentChatIndex, appendTransferMessage, showTypingIndicator, hideTypingIndicator, appendMessage } = chatModule;
if (currentChatIndex < 0) return;
const contact = settings.contacts[currentChatIndex];
if (!contact) return;
const now = new Date();
const timeStr = now.toLocaleString('zh-CN', {
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false
}).replace(/\//g, '-');
// 创建转账信息
const tfInfo = {
id: generateTransferId(),
amount: amount,
description: description || '',
senderName: settings.userName || 'User',
status: 'pending',
receivedAt: null,
refundedAt: null,
expireAt: Date.now() + 24 * 60 * 60 * 1000
};
// 保存转账消息到聊天记录
if (!contact.chatHistory) contact.chatHistory = [];
contact.chatHistory.push({
role: 'user',
content: `[转账] ¥${amount.toFixed(2)}`,
time: timeStr,
timestamp: Date.now(),
isTransfer: true,
transferInfo: tfInfo
});
// 显示转账消息
appendTransferMessage('user', tfInfo, contact);
requestSave();
refreshChatList();
// AI 收款(延迟 2-5 秒)
const receiveDelay = 2000 + Math.random() * 3000;
await sleep(receiveDelay);
// 更新转账状态
tfInfo.status = 'received';
tfInfo.receivedAt = Date.now();
// 更新聊天中的转账气泡状态
updateTransferBubbleStatus(tfInfo.id, 'received');
requestSave();
// AI 发送感谢消息(带上下文)
await sleep(1000);
// 显示打字指示器
showTypingIndicator(contact);
try {
// 构建提示,让 AI 根据上下文自然回复
const thankPrompt = description
? `用户给你转账了${amount}元,备注是"${description}",请自然地表示感谢,不要使用任何特殊格式标签。`
: `用户给你转账了${amount}元,请自然地表示感谢,不要使用任何特殊格式标签。`;
const aiResponse = await callAI(contact, thankPrompt);
hideTypingIndicator();
if (aiResponse && aiResponse.trim()) {
// 取第一条回复
let thankMsg = aiResponse.split('|||')[0].trim();
// 移除可能的格式标签
thankMsg = thankMsg.replace(/^\[.*?\]\s*/, '');
if (thankMsg) {
contact.chatHistory.push({
role: 'assistant',
content: thankMsg,
time: new Date().toLocaleString('zh-CN', {
year: 'numeric', month: '2-digit', day: '2-digit',
hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false
}).replace(/\//g, '-'),
timestamp: Date.now()
});
appendMessage('assistant', thankMsg, contact);
requestSave();
refreshChatList();
}
}
} catch (e) {
console.error('[可乐] AI感谢转账失败:', e);
hideTypingIndicator();
}
}