/** * 转账功能模块 * 支持用户发转账、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(); } }