// 我的界面逻辑 (function() { let currentUsername = null; let currentUserInfo = null; // 超时配置(与后端保持一致) const TASK_TIMEOUT = 5 * 60 * 1000; // 5分钟超时 // 下载弹窗相关 let downloadConfirmOverlay = null; let downloadConfirmClose = null; let downloadOptions = null; let pendingDownloadUrl = null; let pendingDownloadFilename = null; let exportViewFrame = null; function init() { // 初始化下载弹窗元素 downloadConfirmOverlay = document.getElementById('downloadConfirmOverlay'); downloadConfirmClose = document.getElementById('downloadConfirmClose'); downloadOptions = document.querySelectorAll('.download-option'); exportViewFrame = document.getElementById('exportViewFrame'); // 加载VIP抠图价格 loadVIPMattingPrice(); // 初始化下载确认弹窗事件 initDownloadConfirmEvents(); bindEvents(); // 延迟加载,确保DOM完全渲染 setTimeout(() => { loadUserInfo(); loadPoints(); loadAIHistory(); loadPurchaseHistory(); }, 200); } /** * 加载VIP抠图价格 */ async function loadVIPMattingPrice() { try { const response = await fetch('/api/product-pricing'); if (response.ok) { const result = await response.json(); if (result.success && result.products) { const vipMattingProduct = result.products.find(p => p.id === 'vip-matting'); const priceEl = document.getElementById('vipMattingPrice'); if (vipMattingProduct && priceEl) { const price = vipMattingProduct.price || 0; if (price > 0) { priceEl.textContent = `${price} Ani币`; } else { priceEl.textContent = '免费'; } } } } } catch (error) { console.error('[ExportView] 加载VIP抠图价格失败:', error); const priceEl = document.getElementById('vipMattingPrice'); if (priceEl) { priceEl.textContent = '-'; } } } function bindEvents() { // 返回按钮 const backBtn = document.getElementById('backBtn'); if (backBtn) { backBtn.addEventListener('click', () => { // 如果在 iframe 中,通过 postMessage 通知父窗口切换页面 if (window.parent && window.parent !== window) { window.parent.postMessage({ type: 'navigation', page: 'store' }, '*'); } else { // 独立页面,直接跳转到主页面 window.location.href = '../../index.html'; } }); } // 头像上传功能已移除 // 充值按钮 const rechargeBtn = document.getElementById('rechargeBtn'); if (rechargeBtn) { rechargeBtn.addEventListener('click', () => { // 打开充值界面(通过postMessage通知父窗口,如果是独立页面则直接打开) if (window.parent && window.parent !== window) { window.parent.postMessage({ type: 'open-recharge-view' }, '*'); } else { // 独立页面,需要创建充值iframe openRechargeView(); } }); } // 退出登录按钮 const logoutBtn = document.getElementById('logoutBtn'); if (logoutBtn) { logoutBtn.addEventListener('click', handleLogout); } // 监听消息 window.addEventListener('message', (event) => { if (event.data && event.data.type === 'recharge-success') { loadPoints(); // 刷新点数 closeRechargeView(); // 关闭充值界面 } else if (event.data && event.data.type === 'close-recharge-view') { closeRechargeView(); } else if (event.data && event.data.type === 'open-recharge-view') { // 如果充值iframe发送消息,也打开充值界面 openRechargeView(); } else if (event.data && event.data.type === 'refresh-points') { // 刷新点数(购买成功后触发) loadPoints(); loadPurchaseHistory(); // 同时刷新购买记录 } else if (event.data && event.data.type === 'refresh-ai-history') { // 刷新AI历史(生图请求成功后触发) loadAIHistory(); } else if (event.data && (event.data.type === 'close-export-view' || event.data.type === 'export-confirmed')) { hideExportViewFrame(); } else if (event.data && event.data.type === 'export-view-ready') { // 内容准备好后显示 iframe showExportViewFrame(); } }); } // 打开充值界面 function openRechargeView() { const rechargeFrame = document.getElementById('rechargeViewFrame'); if (rechargeFrame) { rechargeFrame.style.display = 'block'; rechargeFrame.style.pointerEvents = 'auto'; rechargeFrame.style.visibility = 'visible'; // 发送消息给充值iframe const sendRechargeData = () => { if (rechargeFrame.contentWindow) { rechargeFrame.contentWindow.postMessage({ type: 'open-recharge-view' }, '*'); } else { setTimeout(sendRechargeData, 100); } }; sendRechargeData(); const handleLoad = () => { setTimeout(() => { sendRechargeData(); }, 50); }; if (rechargeFrame.contentDocument && rechargeFrame.contentDocument.readyState === 'complete') { handleLoad(); } else { rechargeFrame.addEventListener('load', handleLoad, { once: true }); } } } // 关闭充值界面 function closeRechargeView() { const rechargeFrame = document.getElementById('rechargeViewFrame'); if (rechargeFrame) { rechargeFrame.style.display = 'none'; rechargeFrame.style.pointerEvents = 'none'; rechargeFrame.style.visibility = 'hidden'; } } // 显示导出视图 iframe function showExportViewFrame() { if (!exportViewFrame) return; exportViewFrame.style.display = 'block'; exportViewFrame.style.pointerEvents = 'auto'; exportViewFrame.style.visibility = 'visible'; } // 隐藏导出视图 iframe function hideExportViewFrame() { if (!exportViewFrame) return; exportViewFrame.style.display = 'none'; exportViewFrame.style.pointerEvents = 'none'; exportViewFrame.style.visibility = 'hidden'; } // 显示下载确认弹窗 function showDownloadConfirm(imageUrl, fileName) { pendingDownloadUrl = imageUrl; pendingDownloadFilename = fileName || 'ai-image'; if (downloadConfirmOverlay) { downloadConfirmOverlay.style.display = 'flex'; } } // 隐藏下载确认弹窗 function hideDownloadConfirm() { if (downloadConfirmOverlay) { downloadConfirmOverlay.style.display = 'none'; } pendingDownloadUrl = null; pendingDownloadFilename = null; } // 初始化下载弹窗事件 function initDownloadConfirmEvents() { // 关闭按钮 if (downloadConfirmClose) { downloadConfirmClose.addEventListener('click', hideDownloadConfirm); } // 点击遮罩关闭 if (downloadConfirmOverlay) { downloadConfirmOverlay.addEventListener('click', (e) => { if (e.target === downloadConfirmOverlay) { hideDownloadConfirm(); } }); } // 下载选项点击 if (downloadOptions) { downloadOptions.forEach(option => { option.addEventListener('click', () => { const downloadType = option.getAttribute('data-option'); handleDownloadOption(downloadType); }); }); } } // 处理下载选项 async function handleDownloadOption(downloadType) { if (!pendingDownloadUrl) { console.error('[Profile] 没有待下载的图片'); return; } hideDownloadConfirm(); // 根据下载类型处理 if (downloadType === 'original') { // 直接下载原始图片 downloadImage(pendingDownloadUrl, pendingDownloadFilename); } else { // 普通抠图或VIP抠图,使用 iframe 处理 // iframe 会在准备好后发送 'export-view-ready' 消息,此时再显示 if (exportViewFrame) { const sendData = () => { try { exportViewFrame.contentWindow.postMessage({ type: 'show-export-preview', imageUrl: pendingDownloadUrl, fileName: pendingDownloadFilename, skipPreviewUI: true, directDownloadType: downloadType // 传递下载类型 }, '*'); // iframe 会在准备好后发送 'export-view-ready' 消息 } catch (error) { console.error('[Profile] 发送导出数据失败:', error); hideExportViewFrame(); downloadImage(pendingDownloadUrl, pendingDownloadFilename); } }; if (exportViewFrame.contentDocument && exportViewFrame.contentDocument.readyState === 'complete') { setTimeout(sendData, 50); } else { exportViewFrame.addEventListener('load', () => setTimeout(sendData, 50), { once: true }); let baseSrc = exportViewFrame.getAttribute('data-base-src'); if (!baseSrc) { baseSrc = exportViewFrame.src.split('?')[0]; exportViewFrame.setAttribute('data-base-src', baseSrc); } exportViewFrame.src = `${baseSrc}?t=${Date.now()}`; } } else { downloadImage(pendingDownloadUrl, pendingDownloadFilename); } } } // 打开导出视图并传递图片数据 function openExportView(imageUrl, fileName, options = {}) { if (!imageUrl) { return; } // 如果是跳过预览UI(直接下载),显示下载选择弹窗 if (options.skipPreviewUI) { showDownloadConfirm(imageUrl, fileName); return; } if (!exportViewFrame) { downloadImage(imageUrl, fileName || 'ai-image'); return; } showExportViewFrame(); const sendPreviewData = () => { try { exportViewFrame.contentWindow.postMessage({ type: 'show-export-preview', imageUrl: imageUrl, fileName: fileName || 'ai-image', skipPreviewUI: false }, '*'); } catch (error) { console.error('[Profile] 发送导出预览数据失败:', error); hideExportViewFrame(); downloadImage(imageUrl, fileName || 'ai-image'); } }; const handleLoad = () => { setTimeout(sendPreviewData, 50); }; if (exportViewFrame.contentDocument && exportViewFrame.contentDocument.readyState === 'complete') { handleLoad(); } else { exportViewFrame.addEventListener('load', handleLoad, { once: true }); let baseSrc = exportViewFrame.getAttribute('data-base-src'); if (!baseSrc) { baseSrc = exportViewFrame.src.split('?')[0]; exportViewFrame.setAttribute('data-base-src', baseSrc); } exportViewFrame.src = `${baseSrc}?t=${Date.now()}`; } } // 加载用户信息 async function loadUserInfo() { const username = getCurrentUsername(); if (!username) { // 未登录,跳转到登录页 window.location.href = '../../index.html'; return; } currentUsername = username; // 先从localStorage读取用户信息作为备用 try { const loginDataStr = localStorage.getItem('loginData'); if (loginDataStr) { const loginData = JSON.parse(loginDataStr); if (loginData.user) { // 先显示localStorage中的用户信息 displayUserInfo(loginData.user); } } } catch (error) { console.error('[Profile] 从localStorage读取用户信息失败:', error); } // 然后从API获取最新信息 try { const response = await fetch(`/api/user/info?username=${encodeURIComponent(username)}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (result.success && result.user) { currentUserInfo = result.user; displayUserInfo(result.user); } else { console.error('[Profile] API返回数据格式错误:', result); } } catch (error) { console.error('[Profile] 加载用户信息失败:', error); // 如果API调用失败,至少显示localStorage中的信息 if (window.parent && window.parent.HintView) { window.parent.HintView.error('加载用户信息失败,显示缓存信息', 2000); } } } // 手机号脱敏处理 function maskPhone(phone) { if (!phone || phone.length < 7) { return phone; } // 保留前3位和后4位,中间用*代替 const start = phone.substring(0, 3); const end = phone.substring(phone.length - 4); const middle = '*'.repeat(phone.length - 7); return start + middle + end; } // 显示用户信息 function displayUserInfo(user) { if (!user) { console.error('[Profile] 用户信息为空'); return; } // 使用函数来确保元素存在 const setUserInfo = () => { const avatarImage = document.getElementById('avatarImage'); const usernameInput = document.getElementById('usernameInput'); const phoneInput = document.getElementById('phoneInput'); if (avatarImage) { let avatarUrl = user.avatar; if (avatarUrl && !avatarUrl.startsWith('http') && !avatarUrl.startsWith('data:')) { avatarUrl = 'http://localhost:3000' + (avatarUrl.startsWith('/') ? avatarUrl : '/' + avatarUrl); } avatarImage.src = avatarUrl || '../../static/default-avatar.png'; avatarImage.onerror = function() { this.src = '../../static/default-avatar.png'; }; } if (usernameInput) { usernameInput.value = user.username || ''; } if (phoneInput) { const phone = user.phone || ''; phoneInput.value = maskPhone(phone); } }; // 如果元素还没准备好,等待一下再试 if (!document.getElementById('usernameInput') || !document.getElementById('phoneInput')) { setTimeout(setUserInfo, 100); } else { setUserInfo(); } } // 加载点数 async function loadPoints() { const username = getCurrentUsername(); if (!username) return; try { const response = await fetch(`/api/user/points?username=${encodeURIComponent(username)}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (result.success) { const pointsValue = document.getElementById('pointsValue'); if (pointsValue) { const points = parseFloat(result.points || 0); pointsValue.textContent = points.toFixed(2); } } } catch (error) { console.error('[Profile] 加载点数失败:', error); } } // 处理退出登录 function handleLogout() { if (confirm('确定要退出登录吗?')) { // 清除localStorage localStorage.removeItem('loginData'); // 通知父窗口(如果是在iframe中) if (window.parent && window.parent !== window) { window.parent.postMessage({ type: 'logout' }, '*'); } // 跳转到登录页 window.location.href = '../../index.html'; } } // 加载AI生图历史 async function loadAIHistory() { const username = getCurrentUsername(); if (!username) return; const historyLoading = document.getElementById('historyLoading'); const historyEmpty = document.getElementById('historyEmpty'); const historyGrid = document.getElementById('historyGrid'); if (historyLoading) { historyLoading.style.display = 'block'; } if (historyEmpty) { historyEmpty.style.display = 'none'; } if (historyGrid) { historyGrid.innerHTML = ''; } try { const response = await fetch(`/api/ai/history?username=${encodeURIComponent(username)}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (historyLoading) { historyLoading.style.display = 'none'; } if (result.success && result.history && result.history.length > 0) { if (historyGrid) { result.history.forEach(item => { const historyItem = createHistoryItem(item); historyGrid.appendChild(historyItem); }); } } else { if (historyEmpty) { historyEmpty.style.display = 'block'; } } // 如果有正在处理的任务,定期刷新 if (result.success && result.history) { const hasProcessing = result.history.some(item => item.status === 'rendering' || item.status === 'queued'); if (hasProcessing) { setTimeout(loadAIHistory, 3000); // 3秒后刷新 } } } catch (error) { console.error('[Profile] 加载AI历史失败:', error); if (historyLoading) { historyLoading.style.display = 'none'; } if (historyEmpty) { historyEmpty.style.display = 'block'; } } } // 创建历史记录项 function createHistoryItem(item) { const div = document.createElement('div'); div.className = 'history-item'; div.dataset.taskId = item.id; // 格式化时间 - 显示具体年月日时分秒 const formatTime = (dateString) => { if (!dateString) return ''; const date = new Date(dateString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; }; const timeText = formatTime(item.createdAt); // 预览图URL(模糊显示) const previewUrl = item.previewUrl || ''; // 计算已等待时间 const calculateElapsedTime = () => { const startTime = item.renderStartTime || new Date(item.createdAt).getTime(); const elapsed = Date.now() - startTime; const mins = Math.floor(elapsed / 60000); const secs = Math.floor((elapsed % 60000) / 1000); return `已等待 ${mins}:${String(secs).padStart(2, '0')}`; }; if (item.status === 'rendering' || item.status === 'queued') { div.classList.add(item.status); const statusText = item.status === 'rendering' ? '正在生成' : '等待中'; const elapsedText = (item.status === 'rendering' || item.status === 'queued') ? calculateElapsedTime() : ''; div.innerHTML = ` ${previewUrl ? `预览图` : ''}
${statusText}
${elapsedText ? `
${elapsedText}
` : ''}
${timeText}
`; } else if (item.status === 'completed' && item.imageUrl) { div.classList.add('completed'); div.innerHTML = ` AI生成图
${timeText}
`; const openPreview = (e) => { e.stopPropagation(); showImagePreviewModal(item.imageUrl, item.id || 'ai-image'); }; const imageEl = div.querySelector('.history-item-image'); if (imageEl) { imageEl.addEventListener('click', openPreview); } div.addEventListener('click', openPreview); } else if (item.status === 'failed') { div.classList.add('failed'); // 显示具体错误信息 const errorText = item.error || '生成失败'; const isTimeout = errorText.includes('超时'); div.innerHTML = `
${isTimeout ? '⏱️' : '❌'}
${errorText}
${timeText}
`; // 绑定删除按钮事件 const deleteBtn = div.querySelector('.delete-btn'); if (deleteBtn) { deleteBtn.addEventListener('click', async (e) => { e.stopPropagation(); await deleteFailedTask(item.id); }); } } return div; } // 删除失败的任务 async function deleteFailedTask(taskId) { const username = getCurrentUsername(); if (!username) { alert('请先登录'); return; } try { const response = await fetch('/api/ai/retry', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ taskId: taskId, username: username }) }); const result = await response.json(); if (result.success) { // 刷新历史列表 loadAIHistory(); } else { alert('删除失败: ' + (result.error || '未知错误')); } } catch (error) { console.error('[Profile] 删除失败:', error); alert('删除失败: ' + error.message); } } // 下载图片(直接下载PNG) function downloadImage(url, filename) { const a = document.createElement('a'); a.href = url; a.download = `${filename}.png`; document.body.appendChild(a); a.click(); document.body.removeChild(a); } // 显示图片预览弹窗 function showImagePreviewModal(imageUrl, filename) { const modal = document.createElement('div'); modal.className = 'image-preview-modal'; modal.innerHTML = `
预览图
`; document.body.appendChild(modal); requestAnimationFrame(() => { modal.classList.add('show'); }); const closeModal = () => { modal.classList.remove('show'); setTimeout(() => { if (modal.parentNode) modal.parentNode.removeChild(modal); }, 300); }; modal.querySelector('.image-preview-backdrop').onclick = closeModal; modal.querySelector('.image-preview-close').onclick = closeModal; modal.querySelector('.image-preview-download-btn').onclick = (e) => { e.stopPropagation(); closeModal(); openExportView(imageUrl, filename, { skipPreviewUI: true }); }; document.addEventListener('keydown', function escHandler(e) { if (e.key === 'Escape') { closeModal(); document.removeEventListener('keydown', escHandler); } }); } // 加载购买记录 async function loadPurchaseHistory() { const username = getCurrentUsername(); if (!username) return; const purchaseLoading = document.getElementById('purchaseLoading'); const purchaseEmpty = document.getElementById('purchaseEmpty'); const purchaseGrid = document.getElementById('purchaseGrid'); if (purchaseLoading) { purchaseLoading.style.display = 'block'; } if (purchaseEmpty) { purchaseEmpty.style.display = 'none'; } if (purchaseGrid) { purchaseGrid.innerHTML = ''; } try { const response = await fetch(`/api/pay/purchase-history?username=${encodeURIComponent(username)}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const result = await response.json(); if (purchaseLoading) { purchaseLoading.style.display = 'none'; } if (result.success && result.history && result.history.length > 0) { if (purchaseGrid) { result.history.forEach(item => { const purchaseItem = createPurchaseItem(item); purchaseGrid.appendChild(purchaseItem); }); } } else { if (purchaseEmpty) { purchaseEmpty.style.display = 'block'; } } } catch (error) { console.error('[Profile] 加载购买记录失败:', error); if (purchaseLoading) { purchaseLoading.style.display = 'none'; } if (purchaseEmpty) { purchaseEmpty.style.display = 'block'; } } } // 创建购买记录项 function createPurchaseItem(item) { const div = document.createElement('div'); div.className = 'purchase-item'; if (item.deleted) { div.classList.add('deleted'); } const previewHtml = item.previewUrl ? `${item.name}` : `
`; const deletedBadge = item.deleted ? '
已删除
' : ''; const priceText = item.points > 0 ? `
${item.points} Ani币
` : ''; // 格式化时间(购买记录暂时没有时间,可以添加) const formatTime = (dateString) => { if (!dateString) return ''; const date = new Date(dateString); const now = new Date(); const diff = now - date; const minutes = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); if (minutes < 1) return '刚刚'; if (minutes < 60) return `${minutes}分钟前`; if (hours < 24) return `${hours}小时前`; if (days < 7) return `${days}天前`; return date.toLocaleDateString('zh-CN', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); }; const timeText = item.purchasedAt ? formatTime(item.purchasedAt) : ''; div.innerHTML = ` ${previewHtml}
${item.name}
${item.category}
${priceText}
${timeText ? `
${timeText}
` : ''} ${deletedBadge} `; // 绑定添加按钮事件 const addBtn = div.querySelector('.purchase-item-add-btn'); if (addBtn) { addBtn.addEventListener('click', async (e) => { e.stopPropagation(); const resourcePath = addBtn.dataset.path; const categoryDir = addBtn.dataset.category; const itemName = addBtn.dataset.name; await handleAddToDisk(resourcePath, categoryDir, itemName, addBtn); }); } return div; } // 处理添加到网盘 async function handleAddToDisk(resourcePath, categoryDir, itemName, buttonEl) { const username = getCurrentUsername(); if (!username) { if (window.parent && window.parent.HintView) { window.parent.HintView.error('请先登录', 2000); } return; } // 禁用按钮 if (buttonEl) { buttonEl.disabled = true; buttonEl.textContent = '添加中...'; } try { const response = await fetch('/api/pay/purchase', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: username, resourcePath: resourcePath, categoryDir: categoryDir, itemName: itemName, points: 0 // 已购买,不需要扣除点数 }) }); const result = await response.json(); if (result.success) { if (window.parent && window.parent.HintView) { window.parent.HintView.success('添加成功!文件已添加到网盘', 2000); } // 通知父窗口刷新网盘 if (window.parent && window.parent.postMessage) { window.parent.postMessage({ type: 'refresh-disk' }, '*'); } } else { throw new Error(result.message || '添加失败'); } } catch (error) { console.error('[Profile] 添加到网盘失败:', error); if (window.parent && window.parent.HintView) { window.parent.HintView.error(error.message || '添加失败,请稍后重试', 2000); } } finally { // 恢复按钮状态 if (buttonEl) { buttonEl.disabled = false; buttonEl.innerHTML = ` 添加 `; } } } // 获取当前登录用户名 function getCurrentUsername() { try { const loginDataStr = localStorage.getItem('loginData'); if (!loginDataStr) { return null; } const loginData = JSON.parse(loginDataStr); const now = Date.now(); if (now >= loginData.expireTime) { localStorage.removeItem('loginData'); return null; } return loginData.user ? loginData.user.username : null; } catch (error) { console.error('[Profile] 获取用户名失败:', error); return null; } } // 初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();