diff --git a/UI_REFACTOR_ADMIN.md b/UI_REFACTOR_ADMIN.md index bd4233d..3a77532 100644 --- a/UI_REFACTOR_ADMIN.md +++ b/UI_REFACTOR_ADMIN.md @@ -347,6 +347,8 @@ admin-frontend/ - 补齐移动端适配与细节视觉统一 - 保留旧版后台模板备份,便于回滚 +> 当前仓库版本已将以上阶段全部落地,并额外完成:路由按需加载(首屏更轻)、侧栏徽章(待审核/待处理反馈)、移动端细节优化与错误提示防刷屏。 + --- ## 6. 风险点与注意事项(提前说明) @@ -401,30 +403,24 @@ admin-frontend/ --- -## 8. 需要你确认的问题(确认后再开始开发) +## 8. 已确认的决策(用于后续维护) -已确认(来自你的回复): - -- 范围:先改后台(`/yuyx/admin`),并同步美化后台登录页(`/yuyx`),仅 UI 不改登录逻辑 -- 技术:Vue3 + Vite 构建产物部署到 `static/admin/`;部署时允许拉依赖并构建 +- 范围:只改后台(`/yuyx/admin`),并同步美化后台登录页(`/yuyx`),仅 UI 不改登录逻辑 +- 技术:Vue3 + Vite + Element Plus;构建产物部署到 `static/admin/`;接口保持 `/yuyx/api/...` 不变 - 布局:左侧导航 + 右侧内容(Admin Layout) -- 风格:简洁克制(浅色背景 + 卡片 + 少量主色点缀) -- 暗色模式:不需要 -- 适配:PC 优先;同时保证手机端不变形(必要时对表格做响应式处理/横向滚动) +- 风格:简洁克制(浅色背景 + 卡片 + 少量主色点缀),不做暗色模式 +- 适配:PC 优先;手机端不变形(表格允许横向滚动;表单在小屏做纵向布局) - 交互:允许把原生 `alert/confirm/prompt` 替换为 Element Plus 弹窗/对话框 -- 403 行为:保持现状(接口 403 时前端提示错误,不强制跳转登录页) -- `/yuyx/vip`:为历史废弃入口,VIP 已整合在后台,已删除该路由 +- 403 行为:接口 403 时前端仅提示错误,不强制跳转登录页(并已增加提示节流,避免统计页刷新导致刷屏) +- 部署:根路径部署(例如 `https://zsglpt.workyai.cn/`),域名本身无影响 +- `/yuyx/vip`:历史废弃入口(VIP 已整合在后台),已删除该路由 -仍需你确认(只剩 1 点,影响 Vite `base` 与反代配置): - -1) 部署路径/前缀: -- A. 你的站点是根路径部署(例如 `https://zsglpt.workyai.cn/` 直接访问就是本系统) -- B. 你的站点是二级目录部署(例如 `https://example.com/zsglpt/`,需要告诉我前缀 `/zsglpt`) - -> 说明:域名本身没有影响,关键在“是否挂在二级目录”。若是根路径部署,我们默认使用 `/static/admin/` 与 `/yuyx/api/...` 即可。 +> 备注:若未来需要二级目录部署(例如 `https://example.com/zsglpt/`),需要同步调整反代前缀/Flask 的 URL 生成,否则 `/static/...` 可能出现 404。 --- -## 9. 下一步 +## 9. 下一步(部署与验收) -你确认第 8 节后,我会按“分阶段交付”开始开发,并在每个阶段完成后给你可验收的版本点。 +- 部署:更新到最新 `master` 后重启服务即可(`static/admin/` 构建产物已提交到仓库) +- 如需重新构建前端:`cd admin-frontend && npm ci && npm run build` +- 验收:按第 7 节清单逐项点验;若发现任何“功能不一致/缺按钮/接口报错”,把具体页面与操作步骤发我即可快速修复 diff --git a/admin-frontend/src/api/client.js b/admin-frontend/src/api/client.js index 5e014b1..dc75579 100644 --- a/admin-frontend/src/api/client.js +++ b/admin-frontend/src/api/client.js @@ -1,6 +1,17 @@ import axios from 'axios' import { ElMessage } from 'element-plus' +let lastToastKey = '' +let lastToastAt = 0 + +function toastErrorOnce(key, message, minIntervalMs = 1500) { + const now = Date.now() + if (key === lastToastKey && now - lastToastAt < minIntervalMs) return + lastToastKey = key + lastToastAt = now + ElMessage.error(message) +} + export const api = axios.create({ baseURL: '/yuyx/api', timeout: 30_000, @@ -15,16 +26,15 @@ api.interceptors.response.use( const message = payload?.error || payload?.message || error?.message || '请求失败' if (status === 403) { - ElMessage.error(message || '需要管理员权限') + toastErrorOnce('403', message || '需要管理员权限', 5000) } else if (status) { - ElMessage.error(message) + toastErrorOnce(`http:${status}:${message}`, message) } else if (error?.code === 'ECONNABORTED') { - ElMessage.error('请求超时') + toastErrorOnce('timeout', '请求超时', 3000) } else { - ElMessage.error(message) + toastErrorOnce(`net:${message}`, message, 3000) } return Promise.reject(error) }, ) - diff --git a/admin-frontend/src/layouts/AdminLayout.vue b/admin-frontend/src/layouts/AdminLayout.vue index 8f50e56..e3e9934 100644 --- a/admin-frontend/src/layouts/AdminLayout.vue +++ b/admin-frontend/src/layouts/AdminLayout.vue @@ -318,6 +318,22 @@ async function go(path) { } @media (max-width: 768px) { + .layout-header { + flex-wrap: wrap; + height: auto; + padding-top: 10px; + padding-bottom: 10px; + } + + .header-right { + width: 100%; + justify-content: flex-end; + } + + .admin-name .app-muted { + display: none; + } + .layout-main { padding: 12px; } diff --git a/admin-frontend/src/pages/EmailPage.vue b/admin-frontend/src/pages/EmailPage.vue index e0965ca..261b724 100644 --- a/admin-frontend/src/pages/EmailPage.vue +++ b/admin-frontend/src/pages/EmailPage.vue @@ -1,5 +1,5 @@ - + +