From b09cd98e97c5952188ed4e4d4bf182c0aadc6190 Mon Sep 17 00:00:00 2001 From: zhinianboke <115088296+zhinianboke@users.noreply.github.com> Date: Mon, 4 Aug 2025 10:40:27 +0800 Subject: [PATCH] =?UTF-8?q?Revert=20"=E4=BC=98=E5=8C=96=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E7=BB=93=E6=9E=84"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 61d8f6eabf6f236eeb29fa6bed064b707a6fe7d9. --- static/js/app-modular.js | 77 ---- static/js/modules/account-list.js | 132 ------- static/js/modules/all-other-features.js | 197 ---------- static/js/modules/cookies.js | 347 ------------------ static/js/modules/dashboard.js | 141 -------- static/js/modules/example-usage.html | 102 ------ static/js/modules/globals.js | 15 - static/js/modules/init.js | 171 --------- static/js/modules/keyword-cache.js | 42 --- static/js/modules/keywords.js | 463 ------------------------ static/js/modules/main-features.js | 189 ---------- static/js/modules/navigation.js | 86 ----- static/js/modules/utils.js | 85 ----- 13 files changed, 2047 deletions(-) delete mode 100644 static/js/app-modular.js delete mode 100644 static/js/modules/account-list.js delete mode 100644 static/js/modules/all-other-features.js delete mode 100644 static/js/modules/cookies.js delete mode 100644 static/js/modules/dashboard.js delete mode 100644 static/js/modules/example-usage.html delete mode 100644 static/js/modules/globals.js delete mode 100644 static/js/modules/init.js delete mode 100644 static/js/modules/keyword-cache.js delete mode 100644 static/js/modules/keywords.js delete mode 100644 static/js/modules/main-features.js delete mode 100644 static/js/modules/navigation.js delete mode 100644 static/js/modules/utils.js diff --git a/static/js/app-modular.js b/static/js/app-modular.js deleted file mode 100644 index 3234da5..0000000 --- a/static/js/app-modular.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * 闲鱼自动回复系统 - 模块化主入口文件 - * - * 此文件负责引入所有功能模块,替代原来的单一app.js文件 - * - * 模块结构: - * - globals.js: 全局变量 - * - utils.js: 通用工具函数 - * - navigation.js: 页面导航功能 - * - dashboard.js: 仪表盘管理 - * - keyword-cache.js: 关键词缓存管理 - * - account-list.js: 账号列表管理 - * - keywords.js: 关键词管理 - * - cookies.js: Cookie管理 - * - main-features.js: 主要功能 - * - all-other-features.js: 所有其他功能 - * - init.js: 应用初始化 - */ - -// 注意:在HTML中需要按以下顺序引入所有模块文件: -/* - - - - - - - - - - - -*/ - -// 模块加载完成后的初始化检查 -document.addEventListener('DOMContentLoaded', function() { - console.log('闲鱼自动回复系统 - 模块化版本已加载'); - - // 检查关键函数是否存在 - const requiredFunctions = [ - 'showSection', - 'loadDashboard', - 'loadCookies', - 'refreshAccountList', - 'loadAccountKeywords', - 'showToast', - 'toggleLoading' - ]; - - const missingFunctions = requiredFunctions.filter(func => typeof window[func] !== 'function'); - - if (missingFunctions.length > 0) { - console.error('缺少必要的函数:', missingFunctions); - console.error('请检查模块文件是否正确加载'); - } else { - console.log('所有必要的函数已加载完成'); - } -}); - -// 导出模块信息(用于调试) -window.moduleInfo = { - version: '1.0.0', - modules: [ - 'globals', - 'utils', - 'navigation', - 'dashboard', - 'keyword-cache', - 'account-list', - 'keywords', - 'cookies', - 'main-features', - 'all-other-features', - 'init' - ], - loadedAt: new Date().toISOString() -}; diff --git a/static/js/modules/account-list.js b/static/js/modules/account-list.js deleted file mode 100644 index 2888fbf..0000000 --- a/static/js/modules/account-list.js +++ /dev/null @@ -1,132 +0,0 @@ -// ==================== 账号列表管理 ==================== - -// 刷新账号列表(用于自动回复页面) -async function refreshAccountList() { - try { - toggleLoading(true); - - // 获取账号列表 - const response = await fetch(`${apiBase}/cookies/details`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (response.ok) { - const accounts = await response.json(); - const select = document.getElementById('accountSelect'); - select.innerHTML = ''; - - // 为每个账号获取关键词数量 - const accountsWithKeywords = await Promise.all( - accounts.map(async (account) => { - try { - const keywordsResponse = await fetch(`${apiBase}/keywords/${account.id}`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (keywordsResponse.ok) { - const keywordsData = await keywordsResponse.json(); - return { - ...account, - keywords: keywordsData, - keywordCount: keywordsData.length - }; - } else { - return { - ...account, - keywordCount: 0 - }; - } - } catch (error) { - console.error(`获取账号 ${account.id} 关键词失败:`, error); - return { - ...account, - keywordCount: 0 - }; - } - }) - ); - - // 渲染账号选项(显示所有账号,但标识禁用状态) - if (accountsWithKeywords.length === 0) { - select.innerHTML = ''; - return; - } - - // 分组显示:先显示启用的账号,再显示禁用的账号 - const enabledAccounts = accountsWithKeywords.filter(account => { - const enabled = account.enabled === undefined ? true : account.enabled; - console.log(`账号 ${account.id} 过滤状态: enabled=${account.enabled}, 判断为启用=${enabled}`); - return enabled; - }); - const disabledAccounts = accountsWithKeywords.filter(account => { - const enabled = account.enabled === undefined ? true : account.enabled; - return !enabled; - }); - - // 渲染启用的账号 - enabledAccounts.forEach(account => { - const option = document.createElement('option'); - option.value = account.id; - - // 根据关键词数量显示不同的图标和样式 - let icon = '📝'; - let status = ''; - if (account.keywordCount === 0) { - icon = '⚪'; - status = ' (未配置)'; - } else if (account.keywordCount >= 5) { - icon = '🟢'; - status = ` (${account.keywordCount} 个关键词)`; - } else { - icon = '🟡'; - status = ` (${account.keywordCount} 个关键词)`; - } - - option.textContent = `${icon} ${account.id}${status}`; - select.appendChild(option); - }); - - // 如果有禁用的账号,添加分隔线和禁用账号 - if (disabledAccounts.length > 0) { - // 添加分隔线 - const separatorOption = document.createElement('option'); - separatorOption.disabled = true; - separatorOption.textContent = `--- 禁用账号 (${disabledAccounts.length} 个) ---`; - select.appendChild(separatorOption); - - // 渲染禁用的账号 - disabledAccounts.forEach(account => { - const option = document.createElement('option'); - option.value = account.id; - - // 禁用账号使用特殊图标和样式 - let icon = '🔴'; - let status = ''; - if (account.keywordCount === 0) { - status = ' (未配置) [已禁用]'; - } else { - status = ` (${account.keywordCount} 个关键词) [已禁用]`; - } - - option.textContent = `${icon} ${account.id}${status}`; - option.style.color = '#6b7280'; - option.style.fontStyle = 'italic'; - select.appendChild(option); - }); - } - - console.log('账号列表刷新完成,关键词统计:', accountsWithKeywords.map(a => ({ id: a.id, keywords: a.keywordCount }))); - } else { - showToast('获取账号列表失败', 'danger'); - } - } catch (error) { - console.error('刷新账号列表失败:', error); - showToast('刷新账号列表失败', 'danger'); - } finally { - toggleLoading(false); - } -} diff --git a/static/js/modules/all-other-features.js b/static/js/modules/all-other-features.js deleted file mode 100644 index e0be265..0000000 --- a/static/js/modules/all-other-features.js +++ /dev/null @@ -1,197 +0,0 @@ -// ==================== 所有其他功能模块 ==================== -// 此文件包含原app.js中除已拆分模块外的所有其他功能 - -// ==================== 默认回复管理功能 ==================== - -// 打开默认回复管理器 -async function openDefaultReplyManager() { - try { - await loadDefaultReplies(); - const modal = new bootstrap.Modal(document.getElementById('defaultReplyModal')); - modal.show(); - } catch (error) { - console.error('打开默认回复管理器失败:', error); - showToast('打开默认回复管理器失败', 'danger'); - } -} - -// 加载默认回复列表 -async function loadDefaultReplies() { - try { - // 获取所有账号 - const accountsResponse = await fetch(`${apiBase}/cookies`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (!accountsResponse.ok) { - throw new Error('获取账号列表失败'); - } - - const accounts = await accountsResponse.json(); - - // 获取所有默认回复设置 - const repliesResponse = await fetch(`${apiBase}/default-replies`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - let defaultReplies = {}; - if (repliesResponse.ok) { - defaultReplies = await repliesResponse.json(); - } - - renderDefaultRepliesList(accounts, defaultReplies); - } catch (error) { - console.error('加载默认回复列表失败:', error); - showToast('加载默认回复列表失败', 'danger'); - } -} - -// 渲染默认回复列表 -function renderDefaultRepliesList(accounts, defaultReplies) { - const tbody = document.getElementById('defaultReplyTableBody'); - tbody.innerHTML = ''; - - if (accounts.length === 0) { - tbody.innerHTML = ` - - - -
暂无账号数据
-

请先添加账号

- - - `; - return; - } - - accounts.forEach(accountId => { - const replySettings = defaultReplies[accountId] || { enabled: false, reply_content: '' }; - const tr = document.createElement('tr'); - - // 状态标签 - const statusBadge = replySettings.enabled ? - '启用' : - '禁用'; - - // 回复内容预览 - let contentPreview = replySettings.reply_content || '未设置'; - if (contentPreview.length > 50) { - contentPreview = contentPreview.substring(0, 50) + '...'; - } - - tr.innerHTML = ` - - ${accountId} - - ${statusBadge} - -
- ${contentPreview} -
- - -
- - -
- - `; - - tbody.appendChild(tr); - }); -} - -// 编辑默认回复 -async function editDefaultReply(accountId) { - try { - // 获取当前设置 - const response = await fetch(`${apiBase}/default-replies/${accountId}`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - let settings = { enabled: false, reply_content: '' }; - if (response.ok) { - settings = await response.json(); - } - - // 填充编辑表单 - document.getElementById('editAccountId').value = accountId; - document.getElementById('editAccountIdDisplay').value = accountId; - document.getElementById('editDefaultReplyEnabled').checked = settings.enabled; - document.getElementById('editReplyContent').value = settings.reply_content || ''; - - // 根据启用状态显示/隐藏内容输入框 - toggleReplyContentVisibility(); - - // 显示编辑模态框 - const modal = new bootstrap.Modal(document.getElementById('editDefaultReplyModal')); - modal.show(); - } catch (error) { - console.error('获取默认回复设置失败:', error); - showToast('获取默认回复设置失败', 'danger'); - } -} - -// 切换回复内容输入框的显示/隐藏 -function toggleReplyContentVisibility() { - const enabled = document.getElementById('editDefaultReplyEnabled').checked; - const contentGroup = document.getElementById('editReplyContentGroup'); - contentGroup.style.display = enabled ? 'block' : 'none'; -} - -// 保存默认回复设置 -async function saveDefaultReply() { - try { - const accountId = document.getElementById('editAccountId').value; - const enabled = document.getElementById('editDefaultReplyEnabled').checked; - const replyContent = document.getElementById('editReplyContent').value; - - if (enabled && !replyContent.trim()) { - showToast('启用默认回复时必须设置回复内容', 'warning'); - return; - } - - const data = { - enabled: enabled, - reply_content: enabled ? replyContent : null - }; - - const response = await fetch(`${apiBase}/default-replies/${accountId}`, { - method: 'PUT', - headers: { - 'Authorization': `Bearer ${authToken}`, - 'Content-Type': 'application/json' - }, - body: JSON.stringify(data) - }); - - if (response.ok) { - showToast('默认回复设置保存成功', 'success'); - bootstrap.Modal.getInstance(document.getElementById('editDefaultReplyModal')).hide(); - loadDefaultReplies(); // 刷新列表 - loadCookies(); // 刷新账号列表以更新默认回复状态显示 - } else { - const error = await response.text(); - showToast(`保存失败: ${error}`, 'danger'); - } - } catch (error) { - console.error('保存默认回复设置失败:', error); - showToast('保存默认回复设置失败', 'danger'); - } -} - -// 测试默认回复 -function testDefaultReply(accountId) { - console.log('测试默认回复功能,账号ID:', accountId); - showToast('测试功能开发中...', 'info'); -} diff --git a/static/js/modules/cookies.js b/static/js/modules/cookies.js deleted file mode 100644 index 60920fb..0000000 --- a/static/js/modules/cookies.js +++ /dev/null @@ -1,347 +0,0 @@ -// ==================== Cookie管理 ==================== - -// 加载Cookie列表 -async function loadCookies() { - try { - toggleLoading(true); - const tbody = document.querySelector('#cookieTable tbody'); - tbody.innerHTML = ''; - - const cookieDetails = await fetchJSON(apiBase + '/cookies/details'); - - if (cookieDetails.length === 0) { - tbody.innerHTML = ` - - - -
暂无账号
-

请添加新的闲鱼账号开始使用

- - - `; - return; - } - - // 为每个账号获取关键词数量和默认回复设置并渲染 - const accountsWithKeywords = await Promise.all( - cookieDetails.map(async (cookie) => { - try { - // 获取关键词数量 - const keywordsResponse = await fetch(`${apiBase}/keywords/${cookie.id}`, { - headers: { 'Authorization': `Bearer ${authToken}` } - }); - - let keywordCount = 0; - if (keywordsResponse.ok) { - const keywordsData = await keywordsResponse.json(); - keywordCount = keywordsData.length; - } - - // 获取默认回复设置 - const defaultReplyResponse = await fetch(`${apiBase}/default-replies/${cookie.id}`, { - headers: { 'Authorization': `Bearer ${authToken}` } - }); - - let defaultReply = { enabled: false, reply_content: '' }; - if (defaultReplyResponse.ok) { - defaultReply = await defaultReplyResponse.json(); - } - - // 获取AI回复设置 - const aiReplyResponse = await fetch(`${apiBase}/ai-reply-settings/${cookie.id}`, { - headers: { 'Authorization': `Bearer ${authToken}` } - }); - - let aiReply = { ai_enabled: false, model_name: 'qwen-plus' }; - if (aiReplyResponse.ok) { - aiReply = await aiReplyResponse.json(); - } - - return { - ...cookie, - keywordCount: keywordCount, - defaultReply: defaultReply, - aiReply: aiReply - }; - } catch (error) { - return { - ...cookie, - keywordCount: 0, - defaultReply: { enabled: false, reply_content: '' }, - aiReply: { ai_enabled: false, model_name: 'qwen-plus' } - }; - } - }) - ); - - accountsWithKeywords.forEach(cookie => { - // 使用数据库中的实际状态,默认为启用 - const isEnabled = cookie.enabled === undefined ? true : cookie.enabled; - - console.log(`账号 ${cookie.id} 状态: enabled=${cookie.enabled}, isEnabled=${isEnabled}`); // 调试信息 - - const tr = document.createElement('tr'); - tr.className = `account-row ${isEnabled ? 'enabled' : 'disabled'}`; - // 默认回复状态标签 - const defaultReplyBadge = cookie.defaultReply.enabled ? - '启用' : - '禁用'; - - // AI回复状态标签 - const aiReplyBadge = cookie.aiReply.ai_enabled ? - 'AI启用' : - 'AI禁用'; - - // 自动确认发货状态(默认开启) - const autoConfirm = cookie.auto_confirm === undefined ? true : cookie.auto_confirm; - - tr.innerHTML = ` - - - - - - - - - ${cookie.keywordCount} 个关键词 - - - -
- - - - -
- - - ${defaultReplyBadge} - - - ${aiReplyBadge} - - -
- - - - -
- - -
- - - - - -
- - `; - tbody.appendChild(tr); - }); - - // 为Cookie值添加点击复制功能 - document.querySelectorAll('.cookie-value').forEach(element => { - element.style.cursor = 'pointer'; - element.addEventListener('click', function() { - const cookieValue = this.textContent; - if (cookieValue && cookieValue !== '未设置') { - navigator.clipboard.writeText(cookieValue).then(() => { - showToast('Cookie已复制到剪贴板', 'success'); - }).catch(() => { - showToast('复制失败,请手动复制', 'error'); - }); - } - }); - }); - - } catch (err) { - // 错误已在fetchJSON中处理 - } finally { - toggleLoading(false); - } -} - -// 复制Cookie -function copyCookie(id, value) { - if (!value || value === '未设置') { - showToast('该账号暂无Cookie值', 'warning'); - return; - } - - navigator.clipboard.writeText(value).then(() => { - showToast(`账号 "${id}" 的Cookie已复制到剪贴板`, 'success'); - }).catch(() => { - // 降级方案:创建临时文本框 - const textArea = document.createElement('textarea'); - textArea.value = value; - document.body.appendChild(textArea); - textArea.select(); - try { - document.execCommand('copy'); - showToast(`账号 "${id}" 的Cookie已复制到剪贴板`, 'success'); - } catch (err) { - showToast('复制失败,请手动复制', 'error'); - } - document.body.removeChild(textArea); - }); -} - -// 删除Cookie -async function delCookie(id) { - if (!confirm(`确定要删除账号 "${id}" 吗?此操作不可恢复。`)) return; - - try { - await fetchJSON(apiBase + `/cookies/${id}`, { method: 'DELETE' }); - showToast(`账号 "${id}" 已删除`, 'success'); - loadCookies(); - } catch (err) { - // 错误已在fetchJSON中处理 - } -} - -// 内联编辑Cookie -function editCookieInline(id, currentValue) { - const row = event.target.closest('tr'); - const cookieValueCell = row.querySelector('.cookie-value'); - const originalContent = cookieValueCell.innerHTML; - - // 存储原始数据到全局变量,避免HTML注入问题 - window.editingCookieData = { - id: id, - originalContent: originalContent, - originalValue: currentValue || '' - }; - - // 创建编辑界面容器 - const editContainer = document.createElement('div'); - editContainer.className = 'd-flex gap-2'; - - // 创建输入框 - const input = document.createElement('input'); - input.type = 'text'; - input.className = 'form-control form-control-sm'; - input.id = `edit-${id}`; - input.value = currentValue || ''; - input.placeholder = '输入新的Cookie值'; - - // 创建保存按钮 - const saveBtn = document.createElement('button'); - saveBtn.className = 'btn btn-sm btn-success'; - saveBtn.title = '保存'; - saveBtn.innerHTML = ''; - saveBtn.onclick = () => saveCookieInline(id); - - // 创建取消按钮 - const cancelBtn = document.createElement('button'); - cancelBtn.className = 'btn btn-sm btn-secondary'; - cancelBtn.title = '取消'; - cancelBtn.innerHTML = ''; - cancelBtn.onclick = () => cancelCookieEdit(id); - - // 组装编辑界面 - editContainer.appendChild(input); - editContainer.appendChild(saveBtn); - editContainer.appendChild(cancelBtn); - - // 替换原内容 - cookieValueCell.innerHTML = ''; - cookieValueCell.appendChild(editContainer); - - // 聚焦输入框 - input.focus(); - input.select(); - - // 添加键盘事件监听 - input.addEventListener('keydown', function (e) { - if (e.key === 'Enter') { - e.preventDefault(); - saveCookieInline(id); - } else if (e.key === 'Escape') { - e.preventDefault(); - cancelCookieEdit(id); - } - }); - - // 禁用该行的其他按钮 - const actionButtons = row.querySelectorAll('.btn-group button'); - actionButtons.forEach(btn => btn.disabled = true); -} - -// 保存内联编辑的Cookie -async function saveCookieInline(id) { - const input = document.getElementById(`edit-${id}`); - const newValue = input.value.trim(); - - if (!newValue) { - showToast('Cookie值不能为空', 'warning'); - return; - } - - try { - toggleLoading(true); - - await fetchJSON(apiBase + `/cookies/${id}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - id: id, - value: newValue - }) - }); - - showToast(`账号 "${id}" Cookie已更新`, 'success'); - loadCookies(); // 重新加载列表 - - } catch (err) { - console.error('Cookie更新失败:', err); - showToast(`Cookie更新失败: ${err.message || '未知错误'}`, 'danger'); - // 恢复原内容 - cancelCookieEdit(id); - } finally { - toggleLoading(false); - } -} - -// 取消Cookie编辑 -function cancelCookieEdit(id) { - if (!window.editingCookieData || window.editingCookieData.id !== id) { - console.error('编辑数据不存在'); - return; - } - - const row = document.querySelector(`#edit-${id}`).closest('tr'); - const cookieValueCell = row.querySelector('.cookie-value'); - - // 恢复原内容 - cookieValueCell.innerHTML = window.editingCookieData.originalContent; - - // 恢复按钮状态 - const actionButtons = row.querySelectorAll('.btn-group button'); - actionButtons.forEach(btn => btn.disabled = false); - - // 清理全局数据 - delete window.editingCookieData; -} diff --git a/static/js/modules/dashboard.js b/static/js/modules/dashboard.js deleted file mode 100644 index e163fae..0000000 --- a/static/js/modules/dashboard.js +++ /dev/null @@ -1,141 +0,0 @@ -// ==================== 仪表盘管理 ==================== - -// 加载仪表盘数据 -async function loadDashboard() { - try { - toggleLoading(true); - - // 获取账号列表 - const cookiesResponse = await fetch(`${apiBase}/cookies/details`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (cookiesResponse.ok) { - const cookiesData = await cookiesResponse.json(); - - // 为每个账号获取关键词信息 - const accountsWithKeywords = await Promise.all( - cookiesData.map(async (account) => { - try { - const keywordsResponse = await fetch(`${apiBase}/keywords/${account.id}`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (keywordsResponse.ok) { - const keywordsData = await keywordsResponse.json(); - return { - ...account, - keywords: keywordsData, - keywordCount: keywordsData.length - }; - } else { - return { - ...account, - keywords: [], - keywordCount: 0 - }; - } - } catch (error) { - console.error(`获取账号 ${account.id} 关键词失败:`, error); - return { - ...account, - keywords: [], - keywordCount: 0 - }; - } - }) - ); - - dashboardData.accounts = accountsWithKeywords; - - // 计算统计数据 - let totalKeywords = 0; - let activeAccounts = 0; - let enabledAccounts = 0; - - accountsWithKeywords.forEach(account => { - const keywordCount = account.keywordCount || 0; - const isEnabled = account.enabled === undefined ? true : account.enabled; - - if (isEnabled) { - enabledAccounts++; - totalKeywords += keywordCount; - if (keywordCount > 0) { - activeAccounts++; - } - } - }); - - dashboardData.totalKeywords = totalKeywords; - - // 更新仪表盘显示 - updateDashboardStats(accountsWithKeywords.length, totalKeywords, enabledAccounts); - updateDashboardAccountsList(accountsWithKeywords); - } - } catch (error) { - console.error('加载仪表盘数据失败:', error); - showToast('加载仪表盘数据失败', 'danger'); - } finally { - toggleLoading(false); - } -} - -// 更新仪表盘统计数据 -function updateDashboardStats(totalAccounts, totalKeywords, enabledAccounts) { - document.getElementById('totalAccounts').textContent = totalAccounts; - document.getElementById('totalKeywords').textContent = totalKeywords; - document.getElementById('activeAccounts').textContent = enabledAccounts; -} - -// 更新仪表盘账号列表 -function updateDashboardAccountsList(accounts) { - const tbody = document.getElementById('dashboardAccountsList'); - tbody.innerHTML = ''; - - if (accounts.length === 0) { - tbody.innerHTML = ` - - - - 暂无账号数据 - - - `; - return; - } - - accounts.forEach(account => { - const keywordCount = account.keywordCount || 0; - const isEnabled = account.enabled === undefined ? true : account.enabled; - - let status = ''; - if (!isEnabled) { - status = '已禁用'; - } else if (keywordCount > 0) { - status = '活跃'; - } else { - status = '未配置'; - } - - const row = document.createElement('tr'); - row.className = isEnabled ? '' : 'table-secondary'; - row.innerHTML = ` - - ${account.id} - ${!isEnabled ? '' : ''} - - - ${keywordCount} 个关键词 - - ${status} - - ${new Date().toLocaleString()} - - `; - tbody.appendChild(row); - }); -} diff --git a/static/js/modules/example-usage.html b/static/js/modules/example-usage.html deleted file mode 100644 index e951e24..0000000 --- a/static/js/modules/example-usage.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - 闲鱼自动回复系统 - 模块化版本 - - - - - - - - - - -
- -
-
- Loading... -
-
- - -
- - -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/static/js/modules/globals.js b/static/js/modules/globals.js deleted file mode 100644 index 9eecdc0..0000000 --- a/static/js/modules/globals.js +++ /dev/null @@ -1,15 +0,0 @@ -// ==================== 全局变量 ==================== -const apiBase = location.origin; -let keywordsData = {}; -let currentCookieId = ''; -let editCookieId = ''; -let authToken = localStorage.getItem('auth_token'); -let dashboardData = { - accounts: [], - totalKeywords: 0 -}; - -// 账号关键词缓存 -let accountKeywordCache = {}; -let cacheTimestamp = 0; -const CACHE_DURATION = 30000; // 30秒缓存 diff --git a/static/js/modules/init.js b/static/js/modules/init.js deleted file mode 100644 index 629e38c..0000000 --- a/static/js/modules/init.js +++ /dev/null @@ -1,171 +0,0 @@ -// ==================== 应用初始化 ==================== - -// 登出功能 -async function logout() { - try { - if (authToken) { - await fetch('/logout', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - } - localStorage.removeItem('auth_token'); - window.location.href = '/'; - } catch (err) { - console.error('登出失败:', err); - localStorage.removeItem('auth_token'); - window.location.href = '/'; - } -} - -// 检查认证状态 -async function checkAuth() { - if (!authToken) { - window.location.href = '/'; - return false; - } - - try { - const response = await fetch('/verify', { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - const result = await response.json(); - - if (!result.authenticated) { - localStorage.removeItem('auth_token'); - window.location.href = '/'; - return false; - } - - // 检查是否为管理员,显示管理员菜单和功能 - if (result.username === 'admin') { - const adminMenuSection = document.getElementById('adminMenuSection'); - if (adminMenuSection) { - adminMenuSection.style.display = 'block'; - } - - // 显示备份管理功能 - const backupManagement = document.getElementById('backup-management'); - if (backupManagement) { - backupManagement.style.display = 'block'; - } - } - - return true; - } catch (err) { - localStorage.removeItem('auth_token'); - window.location.href = '/'; - return false; - } -} - -// 初始化事件监听 -document.addEventListener('DOMContentLoaded', async () => { - // 首先检查认证状态 - const isAuthenticated = await checkAuth(); - if (!isAuthenticated) return; - - // 添加Cookie表单提交 - document.getElementById('addForm').addEventListener('submit', async (e) => { - e.preventDefault(); - const id = document.getElementById('cookieId').value.trim(); - const value = document.getElementById('cookieValue').value.trim(); - - if (!id || !value) return; - - try { - await fetchJSON(apiBase + '/cookies', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ id, value }) - }); - - document.getElementById('cookieId').value = ''; - document.getElementById('cookieValue').value = ''; - showToast(`账号 "${id}" 添加成功`); - loadCookies(); - } catch (err) { - // 错误已在fetchJSON中处理 - } - }); - - // 增强的键盘快捷键和用户体验 - document.getElementById('newKeyword')?.addEventListener('keypress', function (e) { - if (e.key === 'Enter') { - e.preventDefault(); - document.getElementById('newReply').focus(); - } - }); - - document.getElementById('newReply')?.addEventListener('keypress', function (e) { - if (e.key === 'Enter') { - e.preventDefault(); - addKeyword(); - } - }); - - // ESC键取消编辑 - document.addEventListener('keydown', function (e) { - if (e.key === 'Escape' && typeof window.editingIndex !== 'undefined') { - e.preventDefault(); - cancelEdit(); - } - }); - - // 输入框实时验证和提示 - document.getElementById('newKeyword')?.addEventListener('input', function (e) { - const value = e.target.value.trim(); - const addBtn = document.querySelector('.add-btn'); - const replyInput = document.getElementById('newReply'); - - if (value.length > 0) { - e.target.style.borderColor = '#10b981'; - if (replyInput.value.trim().length > 0) { - addBtn.style.opacity = '1'; - addBtn.style.transform = 'scale(1)'; - } - } else { - e.target.style.borderColor = '#e5e7eb'; - addBtn.style.opacity = '0.7'; - addBtn.style.transform = 'scale(0.95)'; - } - }); - - document.getElementById('newReply')?.addEventListener('input', function (e) { - const value = e.target.value.trim(); - const addBtn = document.querySelector('.add-btn'); - const keywordInput = document.getElementById('newKeyword'); - - if (value.length > 0) { - e.target.style.borderColor = '#10b981'; - if (keywordInput.value.trim().length > 0) { - addBtn.style.opacity = '1'; - addBtn.style.transform = 'scale(1)'; - } - } else { - e.target.style.borderColor = '#e5e7eb'; - addBtn.style.opacity = '0.7'; - addBtn.style.transform = 'scale(0.95)'; - } - }); - - // 初始加载仪表盘 - loadDashboard(); - - // 点击侧边栏外部关闭移动端菜单 - document.addEventListener('click', function (e) { - const sidebar = document.getElementById('sidebar'); - const toggle = document.querySelector('.mobile-toggle'); - - if (window.innerWidth <= 768 && - !sidebar.contains(e.target) && - !toggle.contains(e.target) && - sidebar.classList.contains('show')) { - sidebar.classList.remove('show'); - } - }); -}); diff --git a/static/js/modules/keyword-cache.js b/static/js/modules/keyword-cache.js deleted file mode 100644 index 685c04b..0000000 --- a/static/js/modules/keyword-cache.js +++ /dev/null @@ -1,42 +0,0 @@ -// ==================== 关键词缓存管理 ==================== - -// 获取账号关键词数量(带缓存)- 包含普通关键词和商品关键词 -async function getAccountKeywordCount(accountId) { - const now = Date.now(); - - // 检查缓存 - if (accountKeywordCache[accountId] && (now - cacheTimestamp) < CACHE_DURATION) { - return accountKeywordCache[accountId]; - } - - try { - const response = await fetch(`${apiBase}/keywords/${accountId}`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (response.ok) { - const keywordsData = await response.json(); - // 现在API返回的是包含普通关键词和商品关键词的完整列表 - const count = keywordsData.length; - - // 更新缓存 - accountKeywordCache[accountId] = count; - cacheTimestamp = now; - - return count; - } else { - return 0; - } - } catch (error) { - console.error(`获取账号 ${accountId} 关键词失败:`, error); - return 0; - } -} - -// 清除关键词缓存 -function clearKeywordCache() { - accountKeywordCache = {}; - cacheTimestamp = 0; -} diff --git a/static/js/modules/keywords.js b/static/js/modules/keywords.js deleted file mode 100644 index ea06808..0000000 --- a/static/js/modules/keywords.js +++ /dev/null @@ -1,463 +0,0 @@ -// ==================== 关键词管理 ==================== - -// 加载账号关键词 -async function loadAccountKeywords() { - const accountId = document.getElementById('accountSelect').value; - const keywordManagement = document.getElementById('keywordManagement'); - - if (!accountId) { - keywordManagement.style.display = 'none'; - return; - } - - try { - toggleLoading(true); - currentCookieId = accountId; - - // 获取账号详情以检查状态 - const accountResponse = await fetch(`${apiBase}/cookies/details`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - let accountStatus = true; // 默认启用 - if (accountResponse.ok) { - const accounts = await accountResponse.json(); - const currentAccount = accounts.find(acc => acc.id === accountId); - accountStatus = currentAccount ? (currentAccount.enabled === undefined ? true : currentAccount.enabled) : true; - console.log(`加载关键词时账号 ${accountId} 状态: enabled=${currentAccount?.enabled}, accountStatus=${accountStatus}`); // 调试信息 - } - - const response = await fetch(`${apiBase}/keywords-with-item-id/${accountId}`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (response.ok) { - const data = await response.json(); - console.log('从服务器获取的关键词数据:', data); // 调试信息 - - // 后端返回的是 [{keyword, reply, item_id}, ...] 格式,直接使用 - const formattedData = data; - - console.log('格式化后的关键词数据:', formattedData); // 调试信息 - keywordsData[accountId] = formattedData; - renderKeywordsList(formattedData); - - // 加载商品列表 - await loadItemsList(accountId); - - // 更新账号徽章显示 - updateAccountBadge(accountId, accountStatus); - - keywordManagement.style.display = 'block'; - } else { - showToast('加载关键词失败', 'danger'); - } - } catch (error) { - console.error('加载关键词失败:', error); - showToast('加载关键词失败', 'danger'); - } finally { - toggleLoading(false); - } -} - -// 更新账号徽章显示 -function updateAccountBadge(accountId, isEnabled) { - const badge = document.getElementById('currentAccountBadge'); - if (!badge) return; - - const statusIcon = isEnabled ? '🟢' : '🔴'; - const statusText = isEnabled ? '启用' : '禁用'; - const statusClass = isEnabled ? 'bg-success' : 'bg-warning'; - - badge.innerHTML = ` - - ${statusIcon} ${accountId} - - - 状态: ${statusText} - ${!isEnabled ? ' (配置的关键词不会参与自动回复)' : ''} - - `; -} - -// 显示添加关键词表单 -function showAddKeywordForm() { - const form = document.getElementById('addKeywordForm'); - form.style.display = form.style.display === 'none' ? 'block' : 'none'; - - if (form.style.display === 'block') { - document.getElementById('newKeyword').focus(); - } -} - -// 加载商品列表 -async function loadItemsList(accountId) { - try { - const response = await fetch(`${apiBase}/items/${accountId}`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (response.ok) { - const data = await response.json(); - const items = data.items || []; - - // 更新商品选择下拉框 - const selectElement = document.getElementById('newItemIdSelect'); - if (selectElement) { - // 清空现有选项(保留第一个默认选项) - selectElement.innerHTML = ''; - - // 添加商品选项 - items.forEach(item => { - const option = document.createElement('option'); - option.value = item.item_id; - option.textContent = `${item.item_id} - ${item.item_title}`; - selectElement.appendChild(option); - }); - } - - console.log(`加载了 ${items.length} 个商品到选择列表`); - } else { - console.warn('加载商品列表失败:', response.status); - } - } catch (error) { - console.error('加载商品列表时发生错误:', error); - } -} - -// 添加或更新关键词 -async function addKeyword() { - const keyword = document.getElementById('newKeyword').value.trim(); - const reply = document.getElementById('newReply').value.trim(); - const itemId = document.getElementById('newItemIdSelect').value.trim(); - - if (!keyword || !reply) { - showToast('请填写关键词和回复内容', 'warning'); - return; - } - - if (!currentCookieId) { - showToast('请先选择账号', 'warning'); - return; - } - - // 检查是否为编辑模式 - const isEditMode = typeof window.editingIndex !== 'undefined'; - const actionText = isEditMode ? '更新' : '添加'; - - try { - toggleLoading(true); - - // 获取当前关键词列表 - let currentKeywords = [...(keywordsData[currentCookieId] || [])]; - - // 如果是编辑模式,先移除原关键词 - if (isEditMode) { - currentKeywords.splice(window.editingIndex, 1); - } - - // 准备要保存的关键词列表 - let keywordsToSave = [...currentKeywords]; - - // 如果是编辑模式,先移除原关键词 - if (isEditMode && typeof window.editingIndex !== 'undefined') { - keywordsToSave.splice(window.editingIndex, 1); - } - - // 检查关键词是否已存在(考虑商品ID) - const existingKeyword = keywordsToSave.find(item => - item.keyword === keyword && - (item.item_id || '') === (itemId || '') - ); - if (existingKeyword) { - const itemIdText = itemId ? `(商品ID: ${itemId})` : '(通用关键词)'; - showToast(`关键词 "${keyword}" ${itemIdText} 已存在,请使用其他关键词或商品ID`, 'warning'); - toggleLoading(false); - return; - } - - // 添加新关键词或更新的关键词 - const newKeyword = { - keyword: keyword, - reply: reply, - item_id: itemId || '' - }; - keywordsToSave.push(newKeyword); - - const response = await fetch(`${apiBase}/keywords-with-item-id/${currentCookieId}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${authToken}` - }, - body: JSON.stringify({ - keywords: keywordsToSave - }) - }); - - if (response.ok) { - showToast(`✨ 关键词 "${keyword}" ${actionText}成功!`, 'success'); - - // 清空输入框并重置样式 - const keywordInput = document.getElementById('newKeyword'); - const replyInput = document.getElementById('newReply'); - const selectElement = document.getElementById('newItemIdSelect'); - const addBtn = document.querySelector('.add-btn'); - - keywordInput.value = ''; - replyInput.value = ''; - if (selectElement) { - selectElement.value = ''; - } - keywordInput.style.borderColor = '#e5e7eb'; - replyInput.style.borderColor = '#e5e7eb'; - addBtn.style.opacity = '0.7'; - addBtn.style.transform = 'scale(0.95)'; - - // 如果是编辑模式,重置编辑状态 - if (isEditMode) { - delete window.editingIndex; - delete window.originalKeyword; - - // 恢复添加按钮 - addBtn.innerHTML = '添加'; - addBtn.style.background = 'linear-gradient(135deg, #10b981 0%, #059669 100%)'; - - // 移除取消按钮 - const cancelBtn = document.getElementById('cancelEditBtn'); - if (cancelBtn) { - cancelBtn.remove(); - } - } - - // 聚焦到关键词输入框,方便连续添加 - setTimeout(() => { - keywordInput.focus(); - }, 100); - - loadAccountKeywords(); // 重新加载关键词列表 - clearKeywordCache(); // 清除缓存 - } else { - const errorText = await response.text(); - console.error('关键词添加失败:', errorText); - showToast('关键词添加失败', 'danger'); - } - } catch (error) { - console.error('添加关键词失败:', error); - showToast('添加关键词失败', 'danger'); - } finally { - toggleLoading(false); - } -} - -// 渲染现代化关键词列表 -function renderKeywordsList(keywords) { - console.log('渲染关键词列表:', keywords); // 调试信息 - const container = document.getElementById('keywordsList'); - - if (!container) { - console.error('找不到关键词列表容器元素'); - return; - } - - container.innerHTML = ''; - - if (!keywords || keywords.length === 0) { - console.log('关键词列表为空,显示空状态'); - container.innerHTML = ` -
- -

还没有关键词

-

添加第一个关键词,让您的闲鱼店铺自动回复客户消息

- -
- `; - return; - } - - console.log(`开始渲染 ${keywords.length} 个关键词`); - - keywords.forEach((item, index) => { - console.log(`渲染关键词 ${index + 1}:`, item); // 调试信息 - - const keywordItem = document.createElement('div'); - keywordItem.className = 'keyword-item'; - // 商品ID显示 - const itemIdDisplay = item.item_id ? - ` 商品ID: ${item.item_id}` : - ' 通用关键词'; - - keywordItem.innerHTML = ` -
-
- - ${item.keyword} - ${itemIdDisplay} -
-
- - -
-
-
-

${item.reply}

-
- `; - container.appendChild(keywordItem); - }); - - console.log('关键词列表渲染完成'); -} - -// 聚焦到关键词输入框 -function focusKeywordInput() { - document.getElementById('newKeyword').focus(); -} - -// 编辑关键词 - 改进版本 -function editKeyword(index) { - const keywords = keywordsData[currentCookieId] || []; - const keyword = keywords[index]; - - if (!keyword) { - showToast('关键词不存在', 'warning'); - return; - } - - // 将关键词信息填入输入框 - document.getElementById('newKeyword').value = keyword.keyword; - document.getElementById('newReply').value = keyword.reply; - - // 设置商品ID选择框 - const selectElement = document.getElementById('newItemIdSelect'); - if (selectElement) { - selectElement.value = keyword.item_id || ''; - } - - // 设置编辑模式标识 - window.editingIndex = index; - window.originalKeyword = keyword.keyword; - window.originalItemId = keyword.item_id || ''; - - // 更新按钮文本和样式 - const addBtn = document.querySelector('.add-btn'); - addBtn.innerHTML = '更新'; - addBtn.style.background = 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)'; - - // 显示取消按钮 - showCancelEditButton(); - - // 聚焦到关键词输入框并选中文本 - setTimeout(() => { - const keywordInput = document.getElementById('newKeyword'); - keywordInput.focus(); - keywordInput.select(); - }, 100); - - showToast('📝 编辑模式:修改后点击"更新"按钮保存', 'info'); -} - -// 显示取消编辑按钮 -function showCancelEditButton() { - // 检查是否已存在取消按钮 - if (document.getElementById('cancelEditBtn')) { - return; - } - - const addBtn = document.querySelector('.add-btn'); - const cancelBtn = document.createElement('button'); - cancelBtn.id = 'cancelEditBtn'; - cancelBtn.className = 'btn btn-outline-secondary'; - cancelBtn.style.marginLeft = '0.5rem'; - cancelBtn.innerHTML = '取消'; - cancelBtn.onclick = cancelEdit; - - addBtn.parentNode.appendChild(cancelBtn); -} - -// 取消编辑 -function cancelEdit() { - // 清空输入框 - document.getElementById('newKeyword').value = ''; - document.getElementById('newReply').value = ''; - - // 清空商品ID选择框 - const selectElement = document.getElementById('newItemIdSelect'); - if (selectElement) { - selectElement.value = ''; - } - - // 重置编辑状态 - delete window.editingIndex; - delete window.originalKeyword; - delete window.originalItemId; - - // 恢复添加按钮 - const addBtn = document.querySelector('.add-btn'); - addBtn.innerHTML = '添加'; - addBtn.style.background = 'linear-gradient(135deg, #10b981 0%, #059669 100%)'; - - // 移除取消按钮 - const cancelBtn = document.getElementById('cancelEditBtn'); - if (cancelBtn) { - cancelBtn.remove(); - } - - showToast('已取消编辑', 'info'); -} - -// 删除关键词 -async function deleteKeyword(cookieId, index) { - if (!confirm('确定要删除这个关键词吗?')) { - return; - } - - try { - toggleLoading(true); - - // 获取当前关键词列表 - const currentKeywords = keywordsData[cookieId] || []; - // 移除指定索引的关键词 - currentKeywords.splice(index, 1); - - // 更新服务器 - const response = await fetch(`${apiBase}/keywords-with-item-id/${cookieId}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${authToken}` - }, - body: JSON.stringify({ - keywords: currentKeywords - }) - }); - - if (response.ok) { - showToast('关键词删除成功', 'success'); - keywordsData[cookieId] = currentKeywords; - renderKeywordsList(currentKeywords); - clearKeywordCache(); // 清除缓存 - } else { - const errorText = await response.text(); - console.error('关键词删除失败:', errorText); - showToast('关键词删除失败', 'danger'); - } - } catch (error) { - console.error('删除关键词失败:', error); - showToast('删除关键词删除失败', 'danger'); - } finally { - toggleLoading(false); - } -} diff --git a/static/js/modules/main-features.js b/static/js/modules/main-features.js deleted file mode 100644 index c2d6879..0000000 --- a/static/js/modules/main-features.js +++ /dev/null @@ -1,189 +0,0 @@ -// ==================== 主要功能模块 ==================== - -// 切换账号启用/禁用状态 -async function toggleAccountStatus(accountId, enabled) { - try { - toggleLoading(true); - - // 这里需要调用后端API来更新账号状态 - // 由于当前后端可能没有enabled字段,我们先在前端模拟 - // 实际项目中需要后端支持 - - const response = await fetch(`${apiBase}/cookies/${accountId}/status`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${authToken}` - }, - body: JSON.stringify({ enabled: enabled }) - }); - - if (response.ok) { - showToast(`账号 "${accountId}" 已${enabled ? '启用' : '禁用'}`, 'success'); - - // 清除相关缓存,确保数据一致性 - clearKeywordCache(); - - // 更新界面显示 - updateAccountRowStatus(accountId, enabled); - - // 刷新自动回复页面的账号列表 - refreshAccountList(); - - // 如果禁用的账号在自动回复页面被选中,更新显示 - const accountSelect = document.getElementById('accountSelect'); - if (accountSelect && accountSelect.value === accountId) { - if (!enabled) { - // 更新徽章显示禁用状态 - updateAccountBadge(accountId, false); - showToast('账号已禁用,配置的关键词不会参与自动回复', 'warning'); - } else { - // 更新徽章显示启用状态 - updateAccountBadge(accountId, true); - showToast('账号已启用,配置的关键词将参与自动回复', 'success'); - } - } - - } else { - // 如果后端不支持,先在前端模拟 - console.warn('后端暂不支持账号状态切换,使用前端模拟'); - showToast(`账号 "${accountId}" 已${enabled ? '启用' : '禁用'} (前端模拟)`, enabled ? 'success' : 'warning'); - updateAccountRowStatus(accountId, enabled); - } - - } catch (error) { - console.error('切换账号状态失败:', error); - - // 后端不支持时的降级处理 - showToast(`账号 "${accountId}" 已${enabled ? '启用' : '禁用'} (本地模拟)`, enabled ? 'success' : 'warning'); - updateAccountRowStatus(accountId, enabled); - - // 恢复切换按钮状态 - const toggle = document.querySelector(`input[onchange*="${accountId}"]`); - if (toggle) { - toggle.checked = enabled; - } - } finally { - toggleLoading(false); - } -} - -// 更新账号行的状态显示 -function updateAccountRowStatus(accountId, enabled) { - const toggle = document.querySelector(`input[onchange*="${accountId}"]`); - if (!toggle) return; - - const row = toggle.closest('tr'); - const statusBadge = row.querySelector('.status-badge'); - const actionButtons = row.querySelectorAll('.btn-group .btn:not(.btn-outline-info):not(.btn-outline-danger)'); - - // 更新行样式 - row.className = `account-row ${enabled ? 'enabled' : 'disabled'}`; - - // 更新状态徽章 - statusBadge.className = `status-badge ${enabled ? 'enabled' : 'disabled'}`; - statusBadge.title = enabled ? '账号已启用' : '账号已禁用'; - statusBadge.innerHTML = ` - - `; - - // 更新按钮状态(只禁用编辑Cookie按钮,其他按钮保持可用) - actionButtons.forEach(btn => { - if (btn.onclick && btn.onclick.toString().includes('editCookieInline')) { - btn.disabled = !enabled; - } - // 设置自动回复按钮始终可用,但更新提示文本 - if (btn.onclick && btn.onclick.toString().includes('goToAutoReply')) { - btn.title = enabled ? '设置自动回复' : '配置关键词 (账号已禁用)'; - } - }); - - // 更新切换按钮的提示 - const label = toggle.closest('.status-toggle'); - label.title = enabled ? '点击禁用' : '点击启用'; -} - -// 切换自动确认发货状态 -async function toggleAutoConfirm(accountId, enabled) { - try { - toggleLoading(true); - - const response = await fetch(`${apiBase}/cookies/${accountId}/auto-confirm`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${authToken}` - }, - body: JSON.stringify({ auto_confirm: enabled }) - }); - - if (response.ok) { - const result = await response.json(); - showToast(result.message, 'success'); - - // 更新界面显示 - updateAutoConfirmRowStatus(accountId, enabled); - } else { - const error = await response.json(); - showToast(error.detail || '更新自动确认发货设置失败', 'error'); - - // 恢复切换按钮状态 - const toggle = document.querySelector(`input[onchange*="toggleAutoConfirm('${accountId}'"]`); - if (toggle) { - toggle.checked = !enabled; - } - } - - } catch (error) { - console.error('切换自动确认发货状态失败:', error); - showToast('网络错误,请稍后重试', 'error'); - - // 恢复切换按钮状态 - const toggle = document.querySelector(`input[onchange*="toggleAutoConfirm('${accountId}'"]`); - if (toggle) { - toggle.checked = !enabled; - } - } finally { - toggleLoading(false); - } -} - -// 更新自动确认发货行状态 -function updateAutoConfirmRowStatus(accountId, enabled) { - const row = document.querySelector(`tr:has(input[onchange*="toggleAutoConfirm('${accountId}'"])`); - if (!row) return; - - const statusBadge = row.querySelector('.status-badge:has(i.bi-truck, i.bi-truck-flatbed)'); - const toggle = row.querySelector(`input[onchange*="toggleAutoConfirm('${accountId}'"]`); - - if (statusBadge && toggle) { - // 更新状态徽章 - statusBadge.className = `status-badge ${enabled ? 'enabled' : 'disabled'}`; - statusBadge.title = enabled ? '自动确认发货已开启' : '自动确认发货已关闭'; - statusBadge.innerHTML = ` - - `; - - // 更新切换按钮的提示 - const label = toggle.closest('.status-toggle'); - label.title = enabled ? '点击关闭自动确认发货' : '点击开启自动确认发货'; - } -} - -// 跳转到自动回复页面并选择指定账号 -function goToAutoReply(accountId) { - // 切换到自动回复页面 - showSection('auto-reply'); - - // 设置账号选择器的值 - setTimeout(() => { - const accountSelect = document.getElementById('accountSelect'); - if (accountSelect) { - accountSelect.value = accountId; - // 触发change事件来加载关键词 - loadAccountKeywords(); - } - }, 100); - - showToast(`已切换到自动回复页面,账号 "${accountId}" 已选中`, 'info'); -} diff --git a/static/js/modules/navigation.js b/static/js/modules/navigation.js deleted file mode 100644 index 63ac0cc..0000000 --- a/static/js/modules/navigation.js +++ /dev/null @@ -1,86 +0,0 @@ -// ==================== 页面导航功能 ==================== - -// 菜单切换功能 -function showSection(sectionName) { - console.log('切换到页面:', sectionName); // 调试信息 - - // 隐藏所有内容区域 - document.querySelectorAll('.content-section').forEach(section => { - section.classList.remove('active'); - }); - - // 移除所有菜单项的active状态 - document.querySelectorAll('.nav-link').forEach(link => { - link.classList.remove('active'); - }); - - // 显示选中的内容区域 - const targetSection = document.getElementById(sectionName + '-section'); - if (targetSection) { - targetSection.classList.add('active'); - console.log('页面已激活:', sectionName + '-section'); // 调试信息 - } else { - console.error('找不到页面元素:', sectionName + '-section'); // 调试信息 - } - - // 设置对应菜单项为active(修复event.target问题) - const menuLinks = document.querySelectorAll('.nav-link'); - menuLinks.forEach(link => { - if (link.onclick && link.onclick.toString().includes(`showSection('${sectionName}')`)) { - link.classList.add('active'); - } - }); - - // 根据不同section加载对应数据 - switch (sectionName) { - case 'dashboard': - loadDashboard(); - break; - case 'accounts': - loadCookies(); - break; - case 'items': - loadItems(); - break; - case 'auto-reply': - refreshAccountList(); - break; - case 'cards': - loadCards(); - break; - case 'auto-delivery': - loadDeliveryRules(); - break; - case 'notification-channels': - loadNotificationChannels(); - break; - case 'message-notifications': - loadMessageNotifications(); - break; - case 'logs': - // 如果没有日志数据,则加载 - setTimeout(() => { - if (!window.allLogs || window.allLogs.length === 0) { - refreshLogs(); - } - }, 100); - break; - } - - // 如果切换到非日志页面,停止自动刷新 - if (sectionName !== 'logs' && window.autoRefreshInterval) { - clearInterval(window.autoRefreshInterval); - window.autoRefreshInterval = null; - const button = document.querySelector('#autoRefreshText'); - const icon = button?.previousElementSibling; - if (button) { - button.textContent = '开启自动刷新'; - if (icon) icon.className = 'bi bi-play-circle me-1'; - } - } -} - -// 移动端侧边栏切换 -function toggleSidebar() { - document.getElementById('sidebar').classList.toggle('show'); -} diff --git a/static/js/modules/utils.js b/static/js/modules/utils.js deleted file mode 100644 index 9ac3988..0000000 --- a/static/js/modules/utils.js +++ /dev/null @@ -1,85 +0,0 @@ -// ==================== 通用工具函数 ==================== - -// 显示/隐藏加载动画 -function toggleLoading(show) { - document.getElementById('loading').classList.toggle('d-none', !show); -} - -// 显示提示消息 -function showToast(message, type = 'success') { - const toastContainer = document.querySelector('.toast-container'); - const toast = document.createElement('div'); - toast.className = `toast align-items-center text-white bg-${type} border-0`; - toast.setAttribute('role', 'alert'); - toast.setAttribute('aria-live', 'assertive'); - toast.setAttribute('aria-atomic', 'true'); - - toast.innerHTML = ` -
-
- ${message} -
- -
- `; - - toastContainer.appendChild(toast); - const bsToast = new bootstrap.Toast(toast, { delay: 3000 }); - bsToast.show(); - - // 自动移除 - toast.addEventListener('hidden.bs.toast', () => { - toast.remove(); - }); -} - -// 错误处理 -async function handleApiError(err) { - console.error(err); - showToast(err.message || '操作失败', 'danger'); - toggleLoading(false); -} - -// API请求包装 -async function fetchJSON(url, opts = {}) { - toggleLoading(true); - try { - // 添加认证头 - if (authToken) { - opts.headers = opts.headers || {}; - opts.headers['Authorization'] = `Bearer ${authToken}`; - } - - const res = await fetch(url, opts); - if (res.status === 401) { - // 未授权,跳转到登录页面 - localStorage.removeItem('auth_token'); - window.location.href = '/'; - return; - } - if (!res.ok) { - let errorMessage = `HTTP ${res.status}`; - try { - const errorText = await res.text(); - if (errorText) { - // 尝试解析JSON错误信息 - try { - const errorJson = JSON.parse(errorText); - errorMessage = errorJson.detail || errorJson.message || errorText; - } catch { - errorMessage = errorText; - } - } - } catch { - errorMessage = `HTTP ${res.status} ${res.statusText}`; - } - throw new Error(errorMessage); - } - const data = await res.json(); - toggleLoading(false); - return data; - } catch (err) { - handleApiError(err); - throw err; - } -}