docs: 补充规格文档(specs 01-15)
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
# 00 总览:后台管理系统 Vue 化与 Flask 移除
|
||||
|
||||
## 1. 文档目的
|
||||
|
||||
本目录是后台管理系统 Vue 化、Java 收敛和 Flask 管理能力移除的唯一设计输入,供后续 step-2 按功能点拆分任务。
|
||||
|
||||
本次范围不是客户端前端重构。客户端工程 `frontend-vue/` 及其 `new_web_source/` 不属于本项目的后台前端产物。
|
||||
|
||||
## 2. 已确认决策
|
||||
|
||||
| 主题 | 决策 |
|
||||
|---|---|
|
||||
| 前端工程 | 独立 `admin-frontend-vue/` |
|
||||
| UI | Vue 3 + TypeScript + Element Plus |
|
||||
| 状态 | Pinia 只保存用户、菜单和全局应用状态;页面数据局部管理 |
|
||||
| 路由 | Vue Router History;生产基准路径 `/admin-vue/` |
|
||||
| 菜单 | Java 后端返回树形菜单;前端不写死菜单分组 |
|
||||
| 权限粒度 | 仅菜单/页面级;不做按钮级权限 |
|
||||
| 权限存储 | 继续复用 `columns` 和 `user_column_permission` |
|
||||
| 权限 key 与 URL | 分离;`column_key` 是稳定权限标识,`route_path` 是 Vue 页面路径 |
|
||||
| API | 保持 `/api/admin/*`;不新建 v2 API |
|
||||
| 认证 | 复用现有同源 Cookie/Session;不引入 JWT |
|
||||
| 后端 | Java 成为后台管理唯一后端;Flask 管理能力完全移除 |
|
||||
| 版本接口 | Java 提供 `/api/version`、`/api/version/latest`,路径和字段不变 |
|
||||
| 静态资源 | Nginx 独立目录托管,不打进 Java JAR |
|
||||
| 入口 | `/admin` 重定向 `/admin-vue/` |
|
||||
| 旧链接 | 不兼容旧 `#tab=xxx` 和旧后台路径 |
|
||||
| 菜单迁移 | 通过 Flyway 正式迁移 |
|
||||
| 首批 | 后台壳层、用户、菜单、数据权限分组 |
|
||||
| 视觉 | 深色侧边栏 + 浅色内容区 |
|
||||
|
||||
## 3. 当前实现基线
|
||||
|
||||
### 3.1 旧后台前端
|
||||
|
||||
- 页面:`backend/web_source/admin.html`,包含 17 个面板、26 个弹窗和全部页面样式。
|
||||
- 业务脚本:`backend/static/admin.js`,将请求、状态、DOM 渲染、权限和轮询集中在单个 IIFE。
|
||||
- 横切交互:`backend/static/admin-interactions.js`,负责 loading、toast、confirm、键盘和按钮增强。
|
||||
- Java 静态副本:`backend-java/src/main/resources/static/admin.html` 及 `static/admin.js`。
|
||||
|
||||
### 3.2 现有后台 API
|
||||
|
||||
- Flask 管理蓝图:`backend/blueprints/admin_api.py`。
|
||||
- Java 管理控制器:`backend-java/src/main/java/com/nanri/aiimage/modules/admin/controller/AdminUserController.java`、`AdminConsoleController.java`。
|
||||
- Java 权限控制器:`backend-java/src/main/java/com/nanri/aiimage/modules/permission/controller/PermissionMenuController.java`。
|
||||
- 版本管理:`backend-java/src/main/java/com/nanri/aiimage/modules/softwareversion/controller/SoftwareVersionAdminController.java`。
|
||||
|
||||
### 3.3 已有权限数据模型
|
||||
|
||||
- `columns`:菜单、分组和页面节点。
|
||||
- `user_column_permission`:用户到菜单节点的直接授权。
|
||||
- `PermissionMenuService`:负责有效权限展开、父子菜单和授权边界。
|
||||
|
||||
## 4. 目标架构
|
||||
|
||||
```text
|
||||
Browser
|
||||
│
|
||||
├── /admin
|
||||
│ └── 302 → /admin-vue/
|
||||
│
|
||||
└── /admin-vue/*
|
||||
│
|
||||
▼
|
||||
Nginx/OpenResty
|
||||
├── /admin-vue/assets/* → 独立静态资源
|
||||
├── /admin-vue/<route> → History fallback 到 index.html
|
||||
└── /api/* → Java
|
||||
│
|
||||
├── Session/Auth
|
||||
├── Admin APIs
|
||||
├── Menu Tree API
|
||||
├── Version Admin API
|
||||
└── Public Version API
|
||||
```
|
||||
|
||||
```text
|
||||
admin-frontend-vue/
|
||||
├── src/layout/ # AdminLayout、侧边栏、顶栏
|
||||
├── src/router/ # History 路由和菜单守卫
|
||||
├── src/stores/ # Pinia 用户/菜单状态
|
||||
├── src/api/ # 后台 API 适配
|
||||
├── src/pages/account/ # 首批账号权限模块
|
||||
├── src/pages/asin/ # ASIN 数据中心
|
||||
├── src/pages/shop/ # 店铺中心
|
||||
├── src/pages/tasks/ # 任务和重复分析
|
||||
├── src/pages/records/ # 历史、版本
|
||||
└── dist/ # Nginx 发布目录
|
||||
```
|
||||
|
||||
## 5. 精确依赖图:现状符号到目标符号
|
||||
|
||||
| 当前文件与符号 | 当前依赖 | 目标替代/消费者 |
|
||||
|---|---|---|
|
||||
| `backend/blueprints/main.py:admin_page` | `blueprints.admin_api._load_current_backend_menu_items`、`utils.render.render_html`、`web_source/admin.html` | 删除 Flask 页面职责;`AdminConsoleController.adminPage` 重定向 `/admin-vue/` |
|
||||
| `backend/blueprints/main.py:serve_static` | `backend/static/*` | 删除后台静态托管职责;Nginx 托管 `admin-frontend-vue/dist` |
|
||||
| `backend/blueprints/admin_api.py:get_admin_current_user` | Flask Session、当前用户查询 | `AdminConsoleController.currentUser` |
|
||||
| `backend/blueprints/admin_api.py:get_admin_current_user_menus` | `_load_current_backend_menu_items`、Java 权限代理 | `AdminConsoleController.currentUserMenus` + `PermissionMenuService.getUserColumnPermissions` + 树构造器 |
|
||||
| `backend/blueprints/admin_api.py:list_users` | Flask DB/Java 代理、`_ensure_backend_menu_access` | `AdminUserController.listUsers` + `AdminUserService.listUsers` |
|
||||
| `backend/blueprints/admin_api.py:create_user/update_user/delete_user` | Flask 管理用户逻辑 | `AdminUserController.createUser/updateUser/deleteUser` |
|
||||
| `backend/blueprints/admin_api.py` 的菜单 CRUD 路由 | Flask 权限代理 | `PermissionMenuController.listMenus/createMenu/updateMenu/deleteMenu/reorderColumns` |
|
||||
| `backend/blueprints/version.py:api_version` | `APP_VERSION`、`APP_UPDATE_URL` | `PublicVersionController.currentVersion` |
|
||||
| `backend/blueprints/version.py:api_version_latest` | `utils.db.get_db`、`web_config` | `PublicVersionController.latestVersion` + `SoftwareVersionService.latestSoftwareVersion` |
|
||||
| `backend/web_source/admin.html` 的 `panel-users` | `admin.js:loadUsers`、DOM ID 约定 | `pages/account/UsersPage.vue` |
|
||||
| `backend/web_source/admin.html` 的 `panel-columns` | `admin.js:loadColumns`、拖拽排序 | `pages/account/MenusPage.vue` + 菜单 API |
|
||||
| `backend/web_source/admin.html` 的 `panel-group-manage` | `admin.js:loadShopManageGroups`、分组弹窗 | `pages/account/GroupsPage.vue` |
|
||||
| `backend/static/admin.js:loadAdminCurrentUser` | `/api/admin/current-user` | `api/session.ts:fetchCurrentUser` + `stores/admin-session.ts:initialize` |
|
||||
| `backend/static/admin.js:loadAdminMenus` | `/api/admin/current-user/menus`、`renderAdminTabs` | `api/session.ts:fetchAdminMenuTree` + `AdminLayout.vue` |
|
||||
| `backend/static/admin.js:activateAdminTab` | `hideAllAdminPanels`、`runTabLoader` | `router/index.ts` + 路由级异步页面组件 |
|
||||
| `backend/static/admin-interactions.js:showToast` | `adminToastRegion` | Element Plus `ElMessage` |
|
||||
| `backend/static/admin-interactions.js:openConfirm` | `adminConfirmModal` | Element Plus `ElMessageBox` |
|
||||
| `backend-java/.../AdminConsoleController.currentUser` | `AdminAuthSupport.requireAdminOrInternal` | 保留,作为 Vue Session 初始化接口 |
|
||||
| `backend-java/.../AdminConsoleController.currentUserMenus` | `PermissionMenuService.getUserColumnPermissions` | 保留调用,增加树形组装;输出 `key/name/route/children` |
|
||||
| `backend-java/.../PermissionMenuService.getUserColumnPermissions` | `columns`、`user_column_permission`、父子展开 | 保留为菜单权限唯一来源 |
|
||||
| `backend-java/.../AdminUserController.listUsers` | `AdminUserService.listUsers` | Vue `UsersPage` API 适配层 |
|
||||
| `backend-java/.../PermissionMenuController.listMenus` | `PermissionMenuService.list` | Vue `MenusPage` API 适配层 |
|
||||
| `backend-java/.../SoftwareVersionAdminController` | `SoftwareVersionService`、`web_config` | Vue Records/Version 页面 |
|
||||
| `frontend-vue/*` | 客户端 Vite 多页面工程 | 不依赖、不修改、不作为后台工程入口 |
|
||||
|
||||
## 6. 目标菜单数据契约
|
||||
|
||||
接口:`GET /api/admin/current-user/menus`。
|
||||
|
||||
目标响应的 `items` 是树形数组。页面节点至少包含:
|
||||
|
||||
| 字段 | 来源 | 语义 |
|
||||
|---|---|---|
|
||||
| `key` | `columns.column_key` | 稳定菜单权限标识 |
|
||||
| `name` | `columns.name` | 展示名称 |
|
||||
| `route` | `columns.route_path` | Vue Router 页面路径,不包含 `/admin-vue` 基准前缀 |
|
||||
| `children` | `columns.parent_id` | 子菜单;叶子页面可省略或为空数组 |
|
||||
| `sort` | `columns.sort_order` | 仅用于后端排序,是否输出由最终 DTO 决定 |
|
||||
|
||||
不输出按钮级 `actions`,不新增操作权限表。
|
||||
|
||||
## 7. 实现顺序
|
||||
|
||||
1. 固化 Java 版本接口契约和菜单树 DTO。
|
||||
2. 完成 Flyway 后台 route_path 迁移。
|
||||
3. 完成后台前端壳层、Session、菜单守卫。
|
||||
4. 完成账号与权限首批页面。
|
||||
5. 完成版本/历史和低风险数据页面。
|
||||
6. 完成 ASIN、店铺、任务、重复检查页面。
|
||||
7. 做 Java API 对照、权限回归、客户端版本更新回归。
|
||||
8. Nginx 发布 `/admin-vue/`,将 `/admin` 重定向到 Vue。
|
||||
9. 删除 Flask 管理蓝图、旧 admin 模板和旧管理脚本。
|
||||
10. 删除旧菜单响应、旧静态资源和迁移期间兼容代码。
|
||||
|
||||
## 8. 迁移边界
|
||||
|
||||
本次必须保留:
|
||||
|
||||
- `/api/version`。
|
||||
- `/api/version/latest`。
|
||||
- `/api/admin/*` 的业务 API 路径和业务响应语义。
|
||||
- Cookie/Session 登录态。
|
||||
- `columns`、`user_column_permission` 的数据库模型。
|
||||
|
||||
本次最终删除:
|
||||
|
||||
- Flask 管理页面路由。
|
||||
- Flask 管理 API 蓝图。
|
||||
- Flask 管理后台静态资源。
|
||||
- 旧 `admin.html`、`admin.js`、`admin-interactions.js`。
|
||||
- 客户端请求不到的 Flask 版本蓝图(版本能力已迁移 Java)。
|
||||
|
||||
## 10. 模块职责
|
||||
|
||||
本总览模块负责定义后台前端、Java API、权限存储、公开版本接口、静态部署和 Flask 删除之间的边界;不直接实现业务页面。
|
||||
|
||||
## 11. 依赖关系
|
||||
|
||||
所有模块依赖 `00-overview.md` 的技术选型和发布边界;页面模块依赖壳层与 Session 菜单模块;Java 菜单、版本和部署模块是最终切换的后端前置条件。
|
||||
|
||||
## 12. 核心接口
|
||||
|
||||
核心外部接口包括 `/admin`、`/admin-vue/`、`/api/admin/current-user`、`/api/admin/current-user/menus`、`/api/version`、`/api/version/latest`;各接口的原实现到目标实现映射见第 5 节和对应独立 spec。
|
||||
|
||||
## 13. 内部结构
|
||||
|
||||
总体系由独立后台前端、Java 管理 API、权限数据库、公开版本服务和 Nginx 发布层组成,结构图见第 4 节。
|
||||
|
||||
## 14. 类型映射
|
||||
|
||||
总体系的关键类型映射为:`column_key → menu key`、`route_path → Vue route`、`PermissionMenuItemVo[] → AdminMenuNode[]`、`web_config version/file_url → PublicVersionResponse`。
|
||||
|
||||
## 15. 迁移/实现注意事项
|
||||
|
||||
本总览约束所有子 spec 不得引入客户端前端依赖、按钮级权限、JWT、旧 hash 兼容或 Flask 管理长期兼容分支;未在本总览批准的跨模块变更必须先更新决策和对应 spec。
|
||||
## 9. 主要风险与验收标准
|
||||
|
||||
### P0:客户端更新接口中断
|
||||
|
||||
证据:Flask `version.py` 当前提供 `/api/version/latest`,客户端已有固定调用。
|
||||
|
||||
验收:Java 接口在 Flask 停止后仍返回同路径、同字段、同空数据语义;至少完成真实 HTTP 回归。
|
||||
|
||||
### P0:菜单权限树错误导致后台不可用或越权展示
|
||||
|
||||
证据:当前权限展开依赖 `PermissionMenuService` 和 `user_column_permission`。
|
||||
|
||||
验收:超级管理员、管理员、普通账号、无菜单权限账号分别验证菜单树和路由守卫;页面 API 仍由后端鉴权。
|
||||
|
||||
### P1:History 刷新 404
|
||||
|
||||
证据:Vue Router 使用 History,生产由 Nginx fallback。
|
||||
|
||||
验收:直接访问并刷新 `/admin-vue/account/users`、`/admin-vue/account/menus`;不存在的静态资源必须返回 404 而不是 HTML。
|
||||
|
||||
### P1:路由迁移破坏权限关系
|
||||
|
||||
证据:现有后端大量使用旧 `column_key`,而新版 URL 需要重组。
|
||||
|
||||
验收:Flyway 只改变 `route_path`,旧 `column_key` 授权关系保持可解析;菜单 key 与 route 独立测试。
|
||||
|
||||
### P2:前端首屏包过大
|
||||
|
||||
证据:Element Plus 和后台所有模块会产生较大 bundle。
|
||||
|
||||
验收:页面组件按路由异步加载;首批页面不得把所有业务模块静态导入首屏。
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# 01 后台前端壳层与路由
|
||||
|
||||
## 模块职责
|
||||
|
||||
提供所有后台页面共用的应用外壳,不承载业务列表和业务请求。负责侧边栏、顶栏、内容区、页面标题、全局错误展示、退出登录入口,以及 Vue Router 的页面容器。
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:`02-session-menu-permission.md` 提供用户和菜单状态;`10-static-deployment-and-nginx.md` 提供 `/admin-vue/` 基准路径和 History fallback。
|
||||
|
||||
下游:所有业务页面挂载到 `AdminLayout` 的 `RouterView`;Pinia Session Store 提供菜单树和用户信息。
|
||||
|
||||
现有依赖:
|
||||
|
||||
- `backend/web_source/admin.html` 的 `.admin-layout`、`.admin-sidebar`、`.admin-topbar`、`.admin-content`。
|
||||
- `backend/static/admin-interactions.js` 的 loading、toast、confirm 横切行为。
|
||||
- 当前独立工程的 `admin-frontend-vue/src/layout/AdminLayout.vue`、`src/router/index.ts`、`src/styles/main.css`。
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 原实现 | 目标实现 |
|
||||
|---|---|
|
||||
| `admin.html` 内嵌完整布局 | `AdminLayout.vue` + 子组件 |
|
||||
| `admin.js:activateAdminTab` 通过 DOM 隐藏/显示面板 | Vue Router 路由切换 |
|
||||
| `admin.js:syncTabHash` 使用 `#tab` | History URL,如 `/admin-vue/account/users` |
|
||||
| `admin-interactions.js:showToast` | Element Plus `ElMessage` |
|
||||
| `admin-interactions.js:openConfirm` | Element Plus `ElMessageBox` |
|
||||
| 页面标题写死并由 DOM 更新 | 路由 `meta.title` 驱动 |
|
||||
|
||||
## 内部结构
|
||||
|
||||
```text
|
||||
AdminLayout
|
||||
├── AdminSidebar
|
||||
│ ├── 菜单分组
|
||||
│ └── 菜单页面项
|
||||
├── AdminTopbar
|
||||
│ ├── 当前页面标题
|
||||
│ ├── 当前用户名/角色
|
||||
│ └── 退出登录
|
||||
├── AdminContent
|
||||
│ ├── 全局错误提示
|
||||
│ └── RouterView
|
||||
└── 全局 Element Plus 消息/确认能力
|
||||
```
|
||||
|
||||
路由结构按业务域组织:
|
||||
|
||||
- `account/*`
|
||||
- `asin-center/*`
|
||||
- `shop-center/*`
|
||||
- `tasks/*`
|
||||
- `records/*`
|
||||
|
||||
路由 path 不承担权限标识,权限判断使用路由元数据中的 `menuKey` 与后端菜单节点 `key` 对比。
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 旧概念 | 目标类型 |
|
||||
|---|---|
|
||||
| `data-tab` | Vue route path |
|
||||
| `route_path` | 后端菜单 `route` |
|
||||
| `adminPageTitle` | `RouteMeta.title` |
|
||||
| `adminMenu` DOM | `AdminMenuNode[]` |
|
||||
| `adminCurrentUsername` | `AdminUser.username` |
|
||||
| `adminCurrentUserRole` | `AdminUser.role` |
|
||||
|
||||
`AdminMenuNode` 至少包含 `key`、`name`、可选 `route`、可选 `children`。
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. `createWebHistory('/admin-vue/')` 的基准路径必须和 Vite `base`、Nginx location 完全一致。
|
||||
2. 不实现旧 `#tab=xxx` 兼容;旧地址不属于目标契约。
|
||||
3. 不能把所有业务页面静态 import 到壳层;页面必须按路由异步加载。
|
||||
4. 侧边栏只渲染后端返回的菜单树,不根据角色在前端硬编码一份权限菜单。
|
||||
5. 页面级无权限时跳转到当前用户第一个可见页面;没有任何页面时展示无菜单状态。
|
||||
6. 视觉保持深色侧边栏、浅色内容区,但不得把旧 CSS 2.5 万行整体搬运进新工程。
|
||||
7. 全局 loading 只用于请求生命周期提示;业务页面仍需拥有自己的表格 loading 和空状态。
|
||||
@@ -0,0 +1,81 @@
|
||||
# 02 登录态、菜单树与菜单级权限
|
||||
|
||||
## 模块职责
|
||||
|
||||
负责后台 Vue 启动时的当前用户加载、菜单树加载、Cookie/Session 复用、路由级菜单权限判断、退出登录和未登录处理。本模块只处理菜单/页面级权限,不处理按钮级权限。
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:Java `AdminAuthSupport`、`AdminConsoleController.currentUser`、`AdminConsoleController.currentUserMenus`、`PermissionMenuService.getUserColumnPermissions`。
|
||||
|
||||
下游:`AdminLayout`、Vue Router 守卫、所有页面权限元数据。
|
||||
|
||||
数据表:`columns`、`user_column_permission`、`users`。
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 接口/符号 | 原实现 | 目标实现 |
|
||||
|---|---|---|
|
||||
| 当前用户 | Flask `get_admin_current_user` 或 Java `AdminConsoleController.currentUser` | Java `GET /api/admin/current-user`,维持 `{item}` 语义 |
|
||||
| 菜单 | Flask `get_admin_current_user_menus` 返回扁平项;Java同样返回扁平项 | Java `GET /api/admin/current-user/menus` 返回树形 `items` |
|
||||
| 登出 | `admin.js` 直接 fetch `/api/admin/logout` | `api/session.ts:logout`,由 Pinia action 调用 |
|
||||
| 权限展开 | Flask `_effective_permission_sets` 或 Java `PermissionMenuService` | 统一由 Java `PermissionMenuService` 完成 |
|
||||
| 前端权限 | `hasAdminTabAccess`、`applyTabAccess` | Router guard 比较 `route.meta.menuKey` 和菜单树 `key` |
|
||||
|
||||
## 目标菜单契约
|
||||
|
||||
菜单节点:
|
||||
|
||||
- `key`:稳定的 `columns.column_key`。
|
||||
- `name`:展示名称。
|
||||
- `route`:相对于 `/admin-vue/` 的页面路径,例如 `account/users`。
|
||||
- `children`:分组节点和页面节点的层级。
|
||||
- `sort`:后端排序字段;前端按后端顺序展示,不二次重排。
|
||||
|
||||
分组节点可以没有 `route`;页面节点必须有 `route` 才能进入页面。
|
||||
|
||||
## 内部结构
|
||||
|
||||
```text
|
||||
admin-session store
|
||||
├── user
|
||||
├── menuTree
|
||||
├── initialized
|
||||
├── loading
|
||||
└── error
|
||||
|
||||
初始化顺序
|
||||
1. GET /api/admin/current-user
|
||||
2. GET /api/admin/current-user/menus
|
||||
3. 保存用户和菜单树
|
||||
4. Router guard 校验目标页面
|
||||
5. 无目标路径时进入第一个可见页面
|
||||
```
|
||||
|
||||
Cookie 规则:
|
||||
|
||||
- 请求使用同源 Cookie/Session。
|
||||
- 前端不保存密码、JWT 或长期敏感凭证。
|
||||
- Axios `withCredentials` 必须开启。
|
||||
- 401 统一跳转 `/login`,并携带当前目标路径作为 redirect 信息;是否实际接受 redirect 参数由登录模块决定。
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 原字段 | 目标字段 |
|
||||
|---|---|
|
||||
| `route_path` | `route` |
|
||||
| `column_key` | `key` |
|
||||
| `parent_id` | `children` 关系 |
|
||||
| `adminCurrentUsername` | `AdminUser.username` |
|
||||
| `currentUserRole` | `AdminUser.role` |
|
||||
| `adminTabs` | `AdminMenuNode[]` |
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. 后端必须先过滤当前用户的有效菜单,再组装树,不能把全量菜单发给前端后让前端过滤。
|
||||
2. 超级管理员可以获得全部 admin 菜单,但仍应通过同一树形 DTO 返回。
|
||||
3. 页面权限只控制菜单可见性和路由进入;具体 API 继续由 Java 后端鉴权。
|
||||
4. 不新增按钮级 `actions` 字段,不新增 action 权限表。
|
||||
5. 不保留 `X-Admin-Menu-Format` 双格式,不根据 User-Agent、查询参数或调用方返回不同菜单结构。
|
||||
6. `column_key` 继续作为稳定权限 key,Flyway 只迁移 `route_path`,避免现有 Java 业务权限常量失效。
|
||||
7. 菜单树为空时必须区分“权限为空”和“接口失败”,不能把接口失败误显示为无权限。
|
||||
@@ -0,0 +1,86 @@
|
||||
# 03 账号与权限页面
|
||||
|
||||
## 模块职责
|
||||
|
||||
覆盖首批账号与权限页面:用户管理、菜单管理、数据权限分组。负责列表、筛选、分页、编辑/新增入口、菜单树展示和分组管理入口,但权限粒度仍只到页面菜单。
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:`02-session-menu-permission.md` 的用户和菜单状态;Java `AdminUserController`、`PermissionMenuController`、分组相关管理接口。
|
||||
|
||||
下游:`AdminLayout` 路由;后续业务页面使用用户选择器、分组数据。
|
||||
|
||||
旧页面来源:
|
||||
|
||||
- `admin.html#panel-users`
|
||||
- `admin.html#panel-columns`
|
||||
- `admin.html#panel-group-manage`
|
||||
- `admin.js:loadUsers`、`bindUserActions`
|
||||
- `admin.js:loadColumns`、`bindColumnActions`
|
||||
- `admin.js:loadShopManageGroups`、`initShopManageGroupPanel`
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 功能 | 原实现 | 目标实现 |
|
||||
|---|---|---|
|
||||
| 用户列表 | Flask `list_users` / Java `AdminUserController.listUsers` | `UsersPage.vue` 调用 `GET /api/admin/users` |
|
||||
| 新建用户 | `create_user` / `AdminUserController.createUser` | `UsersPage` 的 Element Plus Dialog + `POST /api/admin/user` |
|
||||
| 编辑用户 | `update_user` / `AdminUserController.updateUser` | Dialog 表单 + `PUT /api/admin/user/{uid}` |
|
||||
| 删除用户 | `delete_user` / `AdminUserController.deleteUser` | `ElMessageBox` 确认 + `DELETE /api/admin/user/{uid}` |
|
||||
| 菜单列表 | `admin.js:loadColumns` | `MenusPage.vue` + `GET /api/admin/permission-menus?menuType=admin` |
|
||||
| 菜单新增/编辑/删除 | Flask/Java 菜单 CRUD | Element Plus Dialog/Tree + 对应 `permission-menus` API |
|
||||
| 菜单排序 | `bindColumnDragSort`、`persistColumnOrder` | 菜单树同级排序组件 + `POST /api/admin/column/reorder` |
|
||||
| 用户菜单授权 | 旧用户编辑中的权限树 | 用户编辑时调用 `GET/PUT /api/admin/permission-users/{uid}/column-permissions` |
|
||||
| 分组列表 | `loadShopManageGroups` | `GroupsPage.vue` + `/api/admin/shop-manage-groups` |
|
||||
|
||||
## 内部结构
|
||||
|
||||
```text
|
||||
AccountPageGroup
|
||||
├── UsersPage
|
||||
│ ├── UserFilterBar
|
||||
│ ├── UserTable
|
||||
│ ├── UserEditorDialog
|
||||
│ └── UserPermissionTree
|
||||
├── MenusPage
|
||||
│ ├── MenuTreeTable
|
||||
│ ├── MenuEditorDialog
|
||||
│ └── SameLevelSortInteraction
|
||||
└── GroupsPage
|
||||
├── GroupFilter/summary
|
||||
├── GroupTable
|
||||
└── GroupEditorDialog
|
||||
```
|
||||
|
||||
页面级状态必须局部化:
|
||||
|
||||
- 当前页数据。
|
||||
- 筛选条件。
|
||||
- 分页。
|
||||
- Dialog/Drawer 可见状态。
|
||||
- 表单草稿。
|
||||
- 保存中的 loading。
|
||||
|
||||
Pinia 不保存这些业务表格状态。
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 原字段/概念 | 目标类型 |
|
||||
|---|---|
|
||||
| `userListBody` | `AdminUser[]` |
|
||||
| `userPagination` | `PaginationState` |
|
||||
| `columnTree` | `AdminMenuNode[]` / `PermissionMenuItem[]` |
|
||||
| `column_id` | `number` |
|
||||
| `created_by_id` | `number | null` |
|
||||
| `role` | 联合字面量或后端枚举映射 |
|
||||
| `grant_menu_routes` | `number[]` 的菜单 ID 授权请求 |
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. 用户接口分页字段要按 Java 实际 VO 归一化,不能直接假设 Flask 字段命名。
|
||||
2. 删除、创建、编辑继续保留后端权限校验;前端不添加按钮级权限体系。
|
||||
3. 菜单管理必须区分 admin 菜单和 app 菜单,默认只操作 `menuType=admin`。
|
||||
4. 菜单分组节点不应被当作可进入页面;叶子页面才产生 Router route。
|
||||
5. 用户授权更新必须提交菜单 ID,而不是前端路由字符串,除非后端 API 明确支持 route。
|
||||
6. 菜单迁移后 `column_key` 保持稳定,页面 URL 通过 `route_path` 变化。
|
||||
7. 数据权限分组的业务 API 若仍以旧字段返回,必须在 `api/groups.ts` 适配为稳定的前端 DTO,禁止把兼容逻辑散落在表格模板中。
|
||||
@@ -0,0 +1,94 @@
|
||||
# 04 ASIN 数据中心
|
||||
|
||||
## 模块职责
|
||||
|
||||
将旧后台中与 ASIN、品牌库、最低价和商品类目相关的页面重组为 ASIN 数据中心,保持现有 API 语义,改善筛选、导入、导出、详情抽屉和批量操作流程。
|
||||
|
||||
覆盖页面:
|
||||
|
||||
- 去重数据汇总:`dedupe-total-data`
|
||||
- 品牌数据库/无效 ASIN:`invalid-asin-data`
|
||||
- 查询 ASIN:`query-asin`
|
||||
- 最低价 ASIN:`skip-price-asin`
|
||||
- 商品类目:`product-categories`
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:账号菜单权限、用户和数据权限分组;Java 对应控制器和服务;统一下载/上传/进度适配器。
|
||||
|
||||
旧实现文件:
|
||||
|
||||
- `backend/web_source/admin.html` 的 `panel-dedupe-total-data`、`panel-invalid-asin-data`、`panel-query-asin`、`panel-skip-price-asin`、`panel-product-categories`。
|
||||
- `backend/static/admin.js:loadDedupeTotalData`、`loadInvalidAsinData`、`loadQueryAsin`、`loadSkipPriceAsin`、`loadProductCategories`。
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 领域 | 原接口族 | 目标前端模块 |
|
||||
|---|---|---|
|
||||
| 去重汇总 | `/api/admin/dedupe-total-data`、`/export`、`/import`、`/delete-import`、进度查询 | `pages/asin/DedupeRegistryPage.vue` |
|
||||
| 品牌数据库 | `/api/admin/invalid-asin-data` | `pages/asin/InvalidAsinPage.vue` |
|
||||
| 查询 ASIN | `/api/admin/query-asins`、`/query-asin`、`/export`、`/import`、`/delete-import` | `pages/asin/QueryAsinPage.vue` |
|
||||
| 最低价 ASIN | `/api/admin/skip-price-asins`、`/skip-price-asin`、导入/删除导入/导出 | `pages/asin/SkipPricePage.vue` |
|
||||
| 商品类目 | `/api/admin/product-categories/*`、`/product-category` | `pages/asin/ProductCategoriesPage.vue` |
|
||||
|
||||
API 路径保持 `/api/admin/*`,本模块只改变请求编排和页面表现,不改变后端业务规则。
|
||||
|
||||
## 内部结构
|
||||
|
||||
```text
|
||||
AsinCenter
|
||||
├── Registry
|
||||
│ ├── FilterBar
|
||||
│ ├── Import/ExportToolbar
|
||||
│ ├── PaginatedTable
|
||||
│ └── ImportProgressDialog
|
||||
├── InvalidAsin
|
||||
│ ├── FilterBar
|
||||
│ ├── PaginatedTable
|
||||
│ └── EditorDialog
|
||||
├── QueryAsin
|
||||
│ ├── FilterBar
|
||||
│ ├── Import/ExportToolbar
|
||||
│ ├── PaginatedTable
|
||||
│ └── DetailDrawer
|
||||
├── SkipPrice
|
||||
│ ├── FilterBar
|
||||
│ ├── Import/ExportToolbar
|
||||
│ ├── PaginatedTable
|
||||
│ └── DetailDrawer
|
||||
└── ProductCategories
|
||||
├── SearchBar
|
||||
├── CategoryTreeTable
|
||||
└── EditorDialog
|
||||
```
|
||||
|
||||
共用 composable:
|
||||
|
||||
- 分页和查询参数序列化。
|
||||
- 文件导入任务轮询。
|
||||
- 下载响应头文件名解析。
|
||||
- ASIN/国家/店铺选择器。
|
||||
- 删除确认。
|
||||
- 空结果和错误提示。
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 原字段 | 目标类型/规则 |
|
||||
|---|---|
|
||||
| `page`、`page_size` | `PaginationQuery` |
|
||||
| `items`、`total`、`total_pages` | `PaginatedResult<T>` |
|
||||
| `import_id` | `ImportJobId`,字符串化处理,禁止丢失大整数精度 |
|
||||
| `country`/`country_codes` | 国家代码联合类型;展示名称由共享字典转换 |
|
||||
| `file_url`、`download_url` | `DownloadDescriptor`,统一空白值判定 |
|
||||
| 抽屉详情字段 | `Record<string, unknown>` 经页面 schema 归一化,不直接在模板遍历原始 JSON |
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. 不把五个页面继续合成一个巨型组件;每个页面独立管理局部筛选、分页和弹窗。
|
||||
2. 导入流程必须保留“上传—解析—确认—入队—轮询—终态”的状态语义,不能只根据 HTTP 200 判断成功。
|
||||
3. 导出必须通过统一下载适配器处理文件名、空响应、错误响应和大文件等待。
|
||||
4. ASIN 详情抽屉只读展示时要做字段白名单和敏感字段脱敏,不能直接 `JSON.stringify` 全量输出。
|
||||
5. 查询条件切换时取消或失效旧请求,避免后返回的旧查询覆盖新结果。
|
||||
6. 所有删除操作保留二次确认;后端仍是最终鉴权边界。
|
||||
7. 商品类目树的展开状态属于页面局部状态,不放进 Pinia。
|
||||
8. 本模块不引入新的后端 v2 API;若 Flask 与 Java 字段存在差异,在 Admin API adapter 中完成归一化。
|
||||
@@ -0,0 +1,79 @@
|
||||
# 05 店铺中心
|
||||
|
||||
## 模块职责
|
||||
|
||||
将店铺密钥、店铺账号、最低价配置和店铺相关基础操作组织为店铺中心。最低价 ASIN 的复杂数据操作在 `04-asin-data-center.md` 定义,本文件只描述店铺侧入口和基础店铺管理边界。
|
||||
|
||||
覆盖页面:
|
||||
|
||||
- 店铺密钥:`shop-keys`
|
||||
- 店铺管理:`shop-manage`
|
||||
- 店铺分组选择器和店铺账号编辑
|
||||
- 店铺凭证展示、遮罩和安全操作
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:菜单树和用户权限;Java 店铺控制器;分组/用户选择器;下载和 confirm 基础组件。
|
||||
|
||||
旧实现:
|
||||
|
||||
- `admin.html` 的 `panel-shop-keys`、`panel-shop-manage`。
|
||||
- `admin.js:loadShopKeys`、`loadShopManage`、`loadShopManageGroups`、`renderShopPasswordCell`、`bindShopKeyActions`、`bindShopManageActions`。
|
||||
|
||||
Java API 主要来源:
|
||||
|
||||
- `ShopKeyController`:`/api/admin/shop-keys`、`/api/admin/shop-key`。
|
||||
- `ShopManageController`:`/api/admin/shop-manages`、`/api/admin/shop-manage`、凭证和分组接口。
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 功能 | 原实现 | 目标实现 |
|
||||
|---|---|---|
|
||||
| 店铺密钥列表 | `admin.js:loadShopKeys` | `ShopKeysPage.vue` + `/api/admin/shop-keys` |
|
||||
| 新增/编辑密钥 | 原生 modal + DOM 表单 | Element Plus Dialog + `/api/admin/shop-key` |
|
||||
| 店铺列表 | `admin.js:loadShopManage` | `ShopManagePage.vue` + `/api/admin/shop-manages` |
|
||||
| 店铺新增/编辑/删除 | DOM modal、手写确认 | Dialog/Drawer + `/api/admin/shop-manage` |
|
||||
| 店铺凭证 | `renderShopPasswordCell` | 显式遮罩组件,按需显示 |
|
||||
| 店铺分组 | 旧多处 select 和自定义下拉 | 可复用 `ShopGroupSelect`,数据来源统一 |
|
||||
|
||||
## 内部结构
|
||||
|
||||
```text
|
||||
ShopCenter
|
||||
├── ShopKeysPage
|
||||
│ ├── FilterBar
|
||||
│ ├── KeysTable
|
||||
│ └── KeyEditorDialog
|
||||
└── ShopManagePage
|
||||
├── FilterBar
|
||||
├── ShopsTable
|
||||
├── ShopEditorDrawer
|
||||
├── ShopGroupSelect
|
||||
└── CredentialReveal
|
||||
```
|
||||
|
||||
敏感字段生命周期:
|
||||
|
||||
1. 默认以遮罩或掩码展示。
|
||||
2. 用户主动点击后才显示短时内容。
|
||||
3. 不写入 Pinia、localStorage、URL 或日志。
|
||||
4. API 返回失败或离开页面时清理临时明文。
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 原字段 | 目标类型/规则 |
|
||||
|---|---|
|
||||
| `shop_name`、`mall_name` | `ShopSummary` |
|
||||
| `zn_username`、账号、密码 | `ShopCredential`,敏感字段分离 |
|
||||
| `group_id` | `number | null`,统一转成表单值 |
|
||||
| 紫鸟令牌/密钥 | `SensitiveString`,禁止进入通用日志 |
|
||||
| 店铺分页响应 | `PaginatedResult<ShopSummary>` |
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. 页面级权限只决定是否显示和进入店铺中心,不新增“查看密码”“编辑店铺”等按钮权限模型。
|
||||
2. 后端现有角色和数据权限校验必须保持;前端隐藏按钮不是安全措施。
|
||||
3. 编辑店铺和店铺密钥的表单不能共用一个无类型的大对象,避免提交多余字段。
|
||||
4. 删除、重置密钥、覆盖账号等不可逆操作必须使用明确的确认文案。
|
||||
5. 分组数据加载应有缓存但必须有失效机制;页面切换不应重复创建无限轮询或请求。
|
||||
6. 店铺凭证不能出现在错误消息、网络日志、埋点和前端异常上报中。
|
||||
@@ -0,0 +1,94 @@
|
||||
# 06 任务与重复分析中心
|
||||
|
||||
## 模块职责
|
||||
|
||||
覆盖高复杂度的任务记录、批量下载、权限配置和店铺数据重复检查,拆分旧 `admin.js` 中长函数和多种视图状态,保证任务轮询、下载和分析视图互不污染。
|
||||
|
||||
覆盖页面:
|
||||
|
||||
- 视频任务记录:`image-video-tasks`
|
||||
- 店铺数据记录:`shop-data-crawl-tasks`
|
||||
- 店铺数据重复检查:`shop-data-duplicate-check`
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:菜单级页面权限、统一任务状态类型、下载 URL/文件下载适配器、用户和店铺分组选择器。
|
||||
|
||||
旧实现:
|
||||
|
||||
- `admin.js:loadImageVideoTasks`
|
||||
- `admin.js:loadShopDataCrawlTasks`
|
||||
- `admin.js:loadShopDataDuplicateCheckOverview`
|
||||
- `admin.js:loadShopDataDuplicateCheckItems`
|
||||
- `admin.js:loadShopDataDuplicateDetail`
|
||||
- `admin.js:saveImageVideoPermissions`
|
||||
- `admin.js:saveShopDataTaskPermissions`
|
||||
|
||||
Java API 来源:
|
||||
|
||||
- `AdminImageVideoTaskController`
|
||||
- `AdminShopDataCrawlTasksController`
|
||||
- `AdminShopDataDuplicateCheckController`
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 功能 | 原实现 | 目标实现 |
|
||||
|---|---|---|
|
||||
| 视频任务列表 | DOM 卡片、批量下载 | `ImageVideoTasksPage.vue` + 状态化任务卡片/表格 |
|
||||
| 视频任务权限配置 | 旧权限 modal | 页面内 Permission Dialog,仍是用户/数据范围配置,不是按钮权限 |
|
||||
| 店铺数据任务 | 店铺分组卡片、分页 | `ShopDataTasksPage.vue` + 独立筛选和任务列表状态 |
|
||||
| 店铺数据批量下载 | 旧脚本直接组装 ZIP 请求 | `BatchDownloadController` composable + 下载状态面板 |
|
||||
| 重复检查总览 | `loadShopDataDuplicateCheckOverview` | `DuplicateCheckPage.vue` 的 Overview 区域 |
|
||||
| 重复检查明细 | `loadShopDataDuplicateCheckItems/detail` | Overview、Items、Detail 三个明确的数据源和视图状态 |
|
||||
| 重复检查导出/导入 | 旧按钮和 modal | 明确的任务状态 Dialog;不阻塞列表刷新 |
|
||||
|
||||
## 内部结构
|
||||
|
||||
```text
|
||||
TaskCenter
|
||||
├── ImageVideoTasksPage
|
||||
│ ├── TaskFilter
|
||||
│ ├── PermissionScopeDialog
|
||||
│ ├── TaskCardGrid
|
||||
│ └── BatchDownloadPanel
|
||||
├── ShopDataTasksPage
|
||||
│ ├── FilterBar
|
||||
│ ├── ShopTaskTable/CardView
|
||||
│ ├── PermissionScopeDialog
|
||||
│ └── BatchDownloadPanel
|
||||
└── DuplicateCheckPage
|
||||
├── FilterBar
|
||||
├── MetricsCards
|
||||
├── DistributionView
|
||||
├── DuplicateItemsTable
|
||||
└── DetailDrawer
|
||||
```
|
||||
|
||||
状态隔离:
|
||||
|
||||
- 每个页面维护自己的 filter key、page、loading 和 error。
|
||||
- 重复检查的总览、列表、详情使用独立请求 key。
|
||||
- 批量下载使用独立 job 状态,不能复用普通列表 loading。
|
||||
- 页面卸载时取消轮询、清理计时器和 AbortController。
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 原字段/概念 | 目标类型 |
|
||||
|---|---|
|
||||
| 任务状态字符串/数字 | `TaskStatus` 归一化枚举 |
|
||||
| `task_id`、`result_id` | `TaskId`、`ResultId`,保持字符串兼容 |
|
||||
| 结果文件 | `ResultFileDescriptor` |
|
||||
| 批量下载 | `BatchDownloadJob` |
|
||||
| 重复总览 | `DuplicateOverview` |
|
||||
| 重复明细 | `DuplicateItem`、`DuplicateDetail` |
|
||||
| 权限范围用户 | `PermissionUserItem[]` |
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. 任务列表刷新不能停止正在运行的下载或导出任务。
|
||||
2. 轮询必须有终态、失败退避、可见性降频和卸载清理,不能在组件每次更新时创建新计时器。
|
||||
3. 批量下载必须处理部分失败、响应头文件名、空文件和服务端错误摘要。
|
||||
4. 重复检查的 Overview、Items、Detail 不得使用一个全局 `currentData`,避免抽屉打开时覆盖主列表。
|
||||
5. 权限配置仍然是现有后端数据范围权限接口,不扩展为按钮 action 权限。
|
||||
6. 大数据导出必须展示等待状态,不得把完整数据加载到浏览器内存后再导出。
|
||||
7. 复杂视图可以保留专用 CSS,但公共表格、Dialog、Drawer、Pagination 使用 Element Plus。
|
||||
@@ -0,0 +1,77 @@
|
||||
# 07 记录与版本中心
|
||||
|
||||
## 模块职责
|
||||
|
||||
覆盖历史生成记录、客户端软件版本和数字人版本。该模块必须区分“后台管理版本页面”和“客户端公开更新接口”,前者可重构,后者必须保持兼容。
|
||||
|
||||
覆盖页面:
|
||||
|
||||
- 历史记录:`history`
|
||||
- 软件版本:`version`
|
||||
- 数字人版本:`digital-human-version`
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:菜单树、当前用户、分页/下载适配器。
|
||||
|
||||
后端:
|
||||
|
||||
- Java `ImageHistoryController`。
|
||||
- Java `SoftwareVersionAdminController`、`SoftwareVersionService`。
|
||||
- 数字人版本控制器和 `digitalhuman` 模块。
|
||||
|
||||
公开版本接口的详细契约见 `09-public-version-compatibility.md`。
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 功能 | 原实现 | 目标实现 |
|
||||
|---|---|---|
|
||||
| 历史记录 | `admin.js:loadHistory` + `panel-history` | `HistoryPage.vue` + 原 `/api/admin/history` |
|
||||
| 软件版本列表 | `admin.js:loadSoftwareVersions` + `/api/admin/versions` | `SoftwareVersionsPage.vue` |
|
||||
| 软件版本上传 | `admin.js` 上传 modal + `/api/admin/version` | Element Plus Upload/Dialog + 原接口 |
|
||||
| 数字人版本列表 | `admin.js:loadDigitalHumanVersions` | `DigitalHumanVersionsPage.vue` |
|
||||
| 数字人版本上传/发布 | 旧版本 modal 和按钮 | 页面局部表单,保持原数字人版本 API |
|
||||
| 客户端检查更新 | Flask `/api/version`、`/api/version/latest` | Java `PublicVersionController`,URL/字段完全不变 |
|
||||
|
||||
## 内部结构
|
||||
|
||||
```text
|
||||
RecordsCenter
|
||||
├── HistoryPage
|
||||
│ ├── HistoryFilterBar
|
||||
│ ├── HistoryTable
|
||||
│ └── ResultPreviewDrawer
|
||||
├── SoftwareVersionsPage
|
||||
│ ├── VersionTable
|
||||
│ └── SoftwareVersionUploadDialog
|
||||
└── DigitalHumanVersionsPage
|
||||
├── VersionTable
|
||||
├── UploadDialog
|
||||
└── Release/Latest actions
|
||||
```
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 原字段 | 目标类型 |
|
||||
|---|---|
|
||||
| `type` | `HistoryRecordType` |
|
||||
| `result_preview` | `PreviewDescriptor`,限制长度和字段 |
|
||||
| `version` | `VersionString` |
|
||||
| `file_url` | `PublicDownloadUrl` |
|
||||
| `created_at` | `DisplayDateTime`,后端格式化或前端统一解析 |
|
||||
| 数字人状态 | `DigitalHumanVersionStatus` |
|
||||
|
||||
公开接口映射:
|
||||
|
||||
- `/api/version`:`version`、`desc`、`url`。
|
||||
- `/api/version/latest`:`version`、`file_url`。
|
||||
- 不把 `/api/admin/version` 的上传响应当成客户端公开版本响应。
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. 软件版本管理页面调用 `/api/admin/versions` 和 `/api/admin/version`,客户端更新调用 `/api/version/latest`;二者不可混用。
|
||||
2. 最新版本判断沿用 `web_config.created_at DESC`,若同一时间并列,使用 id 倒序作为稳定次序。
|
||||
3. 上传成功后页面刷新列表,但不得改变公开接口的空值语义。
|
||||
4. 版本下载链接是公开客户端资源,页面展示时需要处理超长 URL,不把 URL 写入不必要的日志。
|
||||
5. 数字人版本与客户端软件版本是不同业务表和 API,不得合并 DTO。
|
||||
6. 历史记录预览要限制内容大小,避免大 JSON 直接阻塞页面。
|
||||
@@ -0,0 +1,83 @@
|
||||
# 08 Java 菜单树与 Flyway 权限迁移
|
||||
|
||||
## 模块职责
|
||||
|
||||
将 Java 权限模型作为后台菜单唯一来源,继续使用 `columns` 和 `user_column_permission`,把现有扁平有效菜单转换为后端维护的树形菜单,并通过 Flyway 把旧 route_path 迁移到新版 History 路由。
|
||||
|
||||
本模块不引入按钮级权限,不新增 action 表。
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:现有数据库 `columns`、`user_column_permission`、`users`;`PermissionMenuService`。
|
||||
|
||||
下游:`AdminConsoleController.currentUserMenus`、Vue `fetchAdminMenuTree`、`MenusPage`。
|
||||
|
||||
相关文件和符号:
|
||||
|
||||
- `backend-java/.../permission/service/PermissionMenuService.java:getUserColumnPermissions`
|
||||
- `backend-java/.../permission/controller/PermissionMenuController.java:listMenus/createMenu/updateMenu/deleteMenu/reorderColumns`
|
||||
- `backend-java/.../permission/model/entity/PermissionMenuEntity.java`
|
||||
- `backend-java/.../permission/model/entity/UserColumnPermissionEntity.java`
|
||||
- `backend-java/.../admin/controller/AdminConsoleController.java:currentUserMenus`
|
||||
- `backend-java/src/main/resources/db/V100__admin_menu_frontend_routes.sql`(目标迁移文件)
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 内容 | 原实现 | 目标实现 |
|
||||
|---|---|---|
|
||||
| 当前用户菜单 | `List<PermissionMenuItemVo>` 扁平列表 | 树形 `items`,页面节点含 `key/name/route` |
|
||||
| 有效权限展开 | `PermissionMenuService.getUserColumnPermissions` | 保留,作为树输入;不在 Controller 重新实现授权规则 |
|
||||
| 菜单存储 | `columns.column_key` + `route_path` | `column_key` 保持稳定;`route_path` 改为 Vue path |
|
||||
| 用户授权 | `user_column_permission` | 保持不变 |
|
||||
| 菜单迁移 | 运行时 initializer 的默认菜单补齐 | Flyway 正式更新既有 admin route_path |
|
||||
| 权限菜单 CRUD | 旧 API 字段 | API 路径保持;页面使用树/表格适配器 |
|
||||
|
||||
## 内部结构\n\n`PermissionMenuService` 负责有效权限集合,`AdminConsoleController` 负责 DTO 树组装,Flyway 负责 route_path 数据迁移,`PermissionMenuController` 负责菜单管理 CRUD。\n\n## 目标树组装规则
|
||||
|
||||
1. 先由 `PermissionMenuService` 得到当前用户有效菜单集合。
|
||||
2. 以 `id` 建立节点索引。
|
||||
3. 用 `parent_id` 将子节点挂到父节点。
|
||||
4. 按 `sort_order`、再按稳定 key 排序。
|
||||
5. 分组节点可以无 route;页面节点带 route。
|
||||
6. 只返回当前用户有效节点,禁止返回全量菜单后由前端过滤。
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 数据库/旧 DTO | 目标菜单 DTO |
|
||||
|---|---|
|
||||
| `column_key` | `key` |
|
||||
| `name` | `name` |
|
||||
| `route_path` | `route` |
|
||||
| `parent_id` | `children` 关系 |
|
||||
| `sort_order` | 后端排序值 |
|
||||
| `menu_type=admin` | 后台菜单域 |
|
||||
|
||||
## Flyway 迁移内容
|
||||
|
||||
目标迁移按 `column_key` 更新 `route_path`,示例:
|
||||
|
||||
- `admin_users` → `account/users`
|
||||
- `admin_columns` → `account/menus`
|
||||
- `admin_group_manage` → `account/groups`
|
||||
- `admin_dedupe_total_data` → `asin-center/registry`
|
||||
- `admin_shop_manage` → `shop-center/shops`
|
||||
- `admin_history` → `records/history`
|
||||
- `admin_version` → `records/software-version`
|
||||
|
||||
迁移必须:
|
||||
|
||||
- 可重复执行或由 Flyway 保证版本只执行一次。
|
||||
- 不删除 `user_column_permission`。
|
||||
- 不修改既有 `column_key`,避免 Java 业务鉴权常量失效。
|
||||
- 迁移前后对比每个用户的有效菜单 key 集合。
|
||||
- 检查 `(menu_type, route_path)` 唯一约束。
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. `PermissionMenuSchemaInitializer` 仍可负责缺失基础表/默认数据兜底,但不能取代一次性数据迁移。
|
||||
2. Controller 不得根据当前请求头、User-Agent 或查询参数返回不同菜单结构。
|
||||
3. 树构造不能把同一个节点挂到多个父节点;发现脏数据应记录错误并阻止上线。
|
||||
4. 菜单分组虚拟 route 不能被当作页面路由。
|
||||
5. 新版前端不再兼容旧 route/hash,但权限 key 保持稳定,这两件事必须区分。
|
||||
6. 菜单 CRUD 新增页面时必须同时提供稳定 `column_key` 和 Vue `route_path`。
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# 09 客户端公开版本接口兼容
|
||||
|
||||
## 模块职责
|
||||
|
||||
把 Flask 版本蓝图中的公开客户端版本查询能力迁移到 Java,确保已发布客户端无需升级即可继续检查更新和下载新版本。
|
||||
|
||||
本模块只覆盖公开版本查询,不覆盖后台软件版本管理页面;后台页面见 `07-records-and-version.md`。
|
||||
|
||||
## 依赖关系
|
||||
|
||||
原实现:
|
||||
|
||||
- `backend/blueprints/version.py:api_version`
|
||||
- `backend/blueprints/version.py:api_version_latest`
|
||||
- `backend/utils/db.py` 中 `web_config` 表初始化/访问
|
||||
|
||||
目标实现:
|
||||
|
||||
- `backend-java/.../softwareversion/controller/PublicVersionController.java:currentVersion`
|
||||
- `backend-java/.../softwareversion/controller/PublicVersionController.java:latestVersion`
|
||||
- `backend-java/.../softwareversion/service/SoftwareVersionService.java:latestSoftwareVersion`
|
||||
- `SoftwareVersionMapper`、`SoftwareVersionEntity`
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
### GET `/api/version`
|
||||
|
||||
原响应:
|
||||
|
||||
- `version`:当前服务版本,默认值与旧服务一致。
|
||||
- `desc`:当前为空字符串。
|
||||
- `url`:旧环境配置的更新 URL,当前保持空字符串/配置值语义。
|
||||
|
||||
目标:Java 直接提供同路径和同字段,不包装成通用 `ApiResponse`,避免改变客户端解析。
|
||||
|
||||
### GET `/api/version/latest`
|
||||
|
||||
原逻辑:
|
||||
|
||||
- 从 `web_config` 读取 `version`、`file_url`。
|
||||
- 按 `created_at DESC` 取第一条。
|
||||
- 无记录返回 `version=null,file_url=null`。
|
||||
|
||||
目标逻辑:Java `SoftwareVersionService.latestSoftwareVersion` 使用同一张表和同一次序规则。
|
||||
|
||||
## 内部结构
|
||||
|
||||
```text
|
||||
PublicVersionController
|
||||
├── currentVersion()
|
||||
│ └── 应用版本配置
|
||||
└── latestVersion()
|
||||
└── SoftwareVersionService.latestSoftwareVersion()
|
||||
└── SoftwareVersionMapper → web_config
|
||||
```
|
||||
|
||||
## 类型映射
|
||||
|
||||
| 旧字段 | 目标字段 | 约束 |
|
||||
|---|---|---|
|
||||
| `version` | `version` | 字符串,不自动转数字 |
|
||||
| `desc` | `desc` | 保留字段,即使为空 |
|
||||
| `url` | `url` | 保留字段,即使为空 |
|
||||
| `file_url` | `file_url` | 不改名为 `download_url` |
|
||||
| 空记录 | `null` | 不改成空对象或 `success=false` |
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. Flask 停止前必须完成 Java 接口真实 HTTP 验证。
|
||||
2. 不要将公开接口放到 `/api/admin/version`;客户端接口和后台上传接口职责不同。
|
||||
3. Java 服务启动失败或数据库不可用时,要记录明确错误;不要返回伪造的最新版本。
|
||||
4. 版本记录写入仍由后台版本管理 API 完成,公开查询只读。
|
||||
5. 上线验收至少使用一个有版本记录和一个空表/无记录夹具对比旧服务响应。
|
||||
6. 必须验证旧客户端的请求地址、字段读取和下载 URL 不需要修改。
|
||||
@@ -0,0 +1,79 @@
|
||||
# 10 静态资源部署与 Nginx History 托管
|
||||
|
||||
## 模块职责
|
||||
|
||||
定义后台 Vue 构建产物、Nginx 静态目录、History fallback、Java API 代理和 `/admin` 入口重定向的发布契约。
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:`admin-frontend-vue/vite.config.ts` 的 `base=/admin-vue/`、`dist` 输出;Java API。
|
||||
|
||||
下游:浏览器访问后台、Vue Router 刷新、客户端 `/api/version/latest` 请求。
|
||||
|
||||
参考文件:
|
||||
|
||||
- `admin-frontend-vue/vite.config.ts`
|
||||
- `admin-frontend-vue/deploy/nginx-admin-vue.conf.example`
|
||||
- Java `AdminConsoleController.root/adminPage`
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 原实现 | 目标实现 |
|
||||
|---|---|
|
||||
| Java 重定向 `/admin.html` | Java 重定向 `/admin-vue/` |
|
||||
| Java classpath `admin.html` | Nginx 独立静态目录 `/var/www/admin-vue/` |
|
||||
| `admin.html` 内嵌 CSS/模板 | `dist/index.html` + hashed assets |
|
||||
| Flask `serve_static` | Nginx 静态资源 location |
|
||||
| 旧页面 hash 面板 | History route + fallback |
|
||||
|
||||
## 目录契约
|
||||
|
||||
```text
|
||||
/var/www/admin-vue/
|
||||
├── index.html
|
||||
├── assets/
|
||||
│ ├── index-<hash>.js
|
||||
│ ├── index-<hash>.css
|
||||
│ └── page-<hash>.js
|
||||
└── assets/logo.jpg
|
||||
```
|
||||
|
||||
浏览器路径:
|
||||
|
||||
- `/admin` → 302 `/admin-vue/`。
|
||||
- `/admin-vue/` → `index.html`。
|
||||
- `/admin-vue/account/users` → fallback `index.html`。
|
||||
- `/admin-vue/assets/<file>` → 真实文件。
|
||||
- `/api/*` → Java upstream。
|
||||
|
||||
## 内部结构
|
||||
|
||||
发布过程:
|
||||
|
||||
1. 在 `admin-frontend-vue` 执行依赖安装、类型检查和生产构建。
|
||||
2. 对 `dist/index.html`、assets 清单和入口引用做一致性校验。
|
||||
3. 上传到带版本号的临时发布目录。
|
||||
4. 校验完整后原子切换 Nginx 当前目录。
|
||||
5. 保留上一个版本目录用于快速回滚。
|
||||
|
||||
## 类型/路径映射
|
||||
|
||||
| 配置 | 目标值 |
|
||||
|---|---|
|
||||
| Vite `base` | `/admin-vue/` |
|
||||
| Vite `outDir` | `dist` |
|
||||
| Router history base | `/admin-vue/` |
|
||||
| Nginx 静态前缀 | `/admin-vue/` |
|
||||
| Java API upstream | `/api/` |
|
||||
| 登录跳转 | `/login` |
|
||||
|
||||
## 类型映射\n\n`dist/index.html` 映射为 `/admin-vue/` 入口;`dist/assets/*` 映射为 `/admin-vue/assets/*`;Vue Router 相对 route 映射为 `/admin-vue/<route>`;`/api/*` 不进入静态资源目录。\n\n## 迁移/实现注意事项
|
||||
|
||||
1. Nginx 对 `/admin-vue/assets/` 必须优先匹配真实文件,不能被 fallback 到 HTML。
|
||||
2. 不存在的 JS/CSS/图片必须返回 404,避免浏览器收到 HTML 后产生难以诊断的 MIME 错误。
|
||||
3. `try_files` 的 fallback 只针对 `/admin-vue/` 页面路径。
|
||||
4. hashed assets 可配置长期缓存;`index.html` 必须 no-cache 或短缓存。
|
||||
5. 发布不能把 `dist` 复制到客户端 `frontend-vue/new_web_source`。
|
||||
6. 静态资源不打进 Java JAR;Java 只承担 API 和入口重定向。
|
||||
7. 生产切换前必须验证 Nginx upstream 的 Cookie、Host、X-Forwarded-* 和 HTTPS 行为。
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# 11 Flask 管理能力移除与入口切换
|
||||
|
||||
> **状态(task-283 已执行阶段 5/6)**:Flask 管理蓝图(admin_api/auth/main)、`web_source/`、`backend/static/admin.*`、Java classpath 旧 admin.html/login.html 副本均已删除;`backend/app.py` 现仅保留版本公开 API 蓝图。Java 侧 `/`、`/admin`、`/admin.html` → `/admin-vue/`,`/login`、`/login.html` → `/admin-vue/login`(SPA 登录页)。Flask 进程(15124)仍保留 `/api/version*`,桌面客户端 `app_client` 的更新检查仍以它为 base_url,切换至 Java 前勿下线。工作区 `scripts/deploy.py` 的 pyfiles 动作已同步清理主机上的旧后台文件。
|
||||
|
||||
## 模块职责
|
||||
|
||||
定义从 Flask 管理后台到 Java + Vue 的最终切换、删除清单、回滚边界和依赖清理。版本公开接口不属于删除范围,因为已经迁移到 Java 后由客户端继续使用。
|
||||
|
||||
## 依赖关系
|
||||
|
||||
前置:
|
||||
|
||||
- 所有后台页面完成 Vue 迁移。
|
||||
- Java `/api/admin/*` API 回归通过。
|
||||
- Java `/api/version`、`/api/version/latest` 回归通过。
|
||||
- Nginx `/admin-vue/` 正常服务。
|
||||
- Flyway 菜单 route_path 迁移完成。
|
||||
|
||||
被删除的 Flask 文件/符号:
|
||||
|
||||
- `backend/blueprints/main.py:admin_page`。
|
||||
- `backend/blueprints/admin_api.py` 的管理 API 路由和权限代理辅助函数。
|
||||
- `backend/web_source/admin.html`。
|
||||
- `backend/static/admin.js`。
|
||||
- `backend/static/admin-interactions.js`。
|
||||
- Java classpath 中同步旧后台的 `admin.html`、旧管理脚本副本。
|
||||
|
||||
保留并迁移后的能力:
|
||||
|
||||
- Flask `version.py:api_version` → Java `PublicVersionController.currentVersion`。
|
||||
- Flask `version.py:api_version_latest` → Java `PublicVersionController.latestVersion`。
|
||||
|
||||
## 核心接口:原实现 → 目标实现
|
||||
|
||||
| 迁移项 | 原实现 | 目标实现 |
|
||||
|---|---|---|
|
||||
| `/admin` | Flask/Java 旧 `admin.html` | Java/Nginx → `/admin-vue/` |
|
||||
| 管理页面 | Jinja + DOM | Nginx + Vue |
|
||||
| 管理 API | Flask `admin_api` 或 Java 兼容 API | Java 唯一实现 |
|
||||
| 公开版本检查 | Flask `version.py` | Java公开版本控制器 |
|
||||
| 管理权限 | Flask 代理/本地判断 + Java | Java `PermissionMenuService` |
|
||||
| 静态资源 | Flask/Java 双份 | Nginx 单份 dist |
|
||||
|
||||
## 内部结构
|
||||
|
||||
切换阶段:
|
||||
|
||||
```text
|
||||
阶段 1:Java API + Vue /admin-vue 并行开发
|
||||
阶段 2:Nginx 先发布 /admin-vue,不立即删除旧源文件
|
||||
阶段 3:/admin → /admin-vue/,开始真实用户回归
|
||||
阶段 4:确认版本接口和全部后台页面稳定
|
||||
阶段 5:删除 Flask 管理蓝图和旧后台资源
|
||||
阶段 6:清理旧权限响应、旧复制脚本、旧文档和部署配置
|
||||
```
|
||||
|
||||
## 类型映射\n\nFlask `admin_page` 映射为 Java `/admin` redirect;Flask `admin_api` 管理路由映射为 Java `/api/admin/*`;Flask `version.py` 映射为 Java `/api/version*`;旧 `admin.html` 映射为 Nginx `/admin-vue/index.html`。\n\n## 删除/保留清单
|
||||
|
||||
### 必须删除
|
||||
|
||||
- Flask 管理页面入口和管理 API。
|
||||
- 旧 admin HTML/JS/CSS 中只服务后台的代码。
|
||||
- Java static 中旧 admin 页面副本。
|
||||
- `admin.js` 依赖的旧 DOM ID 和旧 toast/confirm 容器。
|
||||
- 旧菜单扁平响应适配分支。
|
||||
|
||||
### 必须保留
|
||||
|
||||
- Java `/api/admin/*` 业务 API。
|
||||
- Java 登录态和后台鉴权。
|
||||
- `web_config` 版本表。
|
||||
- Java `/api/version`、`/api/version/latest`。
|
||||
- 客户端所需公开下载 URL。
|
||||
|
||||
## 迁移/实现注意事项
|
||||
|
||||
1. 删除 Flask 前必须确认生产 Nginx/API 流量不再指向 Python 管理接口。
|
||||
2. 删除旧页面前先保存一次前后端 API/权限快照,用于回归对比。
|
||||
3. 不因为后台删除而删除 `web_config` 或版本上传逻辑。
|
||||
4. Flask 进程如果还承担其他非管理插件能力,必须按部署文档单独确认;本 spec 只要求移除 Flask 的后台管理职责和版本查询职责,不能误删其他客户端插件 API。
|
||||
5. 若 Flask 进程承载不可迁移的其他 API,最终部署可以分离进程,但后台请求不得再依赖它;是否完全停止 Python 进程需以其他服务清单为前置验收。
|
||||
6. 切换失败时回滚的是 Nginx current 目录和 Java `/admin` 重定向,不回滚数据库已执行的 Flyway 版本;数据库迁移必须设计前向兼容。
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
# 12 测试、回归与验收
|
||||
|
||||
## 模块职责
|
||||
|
||||
定义后台 Vue 化的测试层次、跨后端契约回归、版本接口保护和最终删除验收。该 spec 不实现测试代码,只规定后续任务必须覆盖的行为。
|
||||
|
||||
## 依赖关系
|
||||
|
||||
上游:所有模块 spec;现有 `backend-java` Maven 测试体系;新 `admin-frontend-vue` 构建和测试命令。
|
||||
|
||||
相关现有测试/工具:
|
||||
|
||||
- `backend-java/src/test/java` 下的权限、控制器和契约测试。
|
||||
- `frontend-vue/tests` 仅作为客户端工程参考,不得把后台测试混入客户端测试目录。
|
||||
- 新后台测试放在 `admin-frontend-vue/tests`,Java 契约测试放在 `backend-java/src/test/java`。
|
||||
|
||||
## 核心接口\n\n测试对象包括菜单树、用户/权限 API、业务 API、公开版本接口、Nginx History 路由和 Flask 删除后的流量边界。\n\n## 内部结构\n\n验收分为前端静态检查、前端契约测试、Java API 契约测试、数据库迁移测试、真实 HTTP 验收和最终删除验收六层。\n\n## 类型映射\n\n测试夹具需要覆盖 `AdminMenuNode`、`AdminUser`、分页结果、任务状态、版本公开响应和空值响应。\n\n## 迁移/实现注意事项\n\n先冻结旧快照,再执行迁移和新实现回归;任何客户端版本接口差异都阻断 Flask 删除和 `/admin` 正式切换。\n\n## 测试层次
|
||||
|
||||
### 前端静态和类型检查
|
||||
|
||||
- Vue/TypeScript 类型检查零错误。
|
||||
- Vite 构建成功,产出 `dist/index.html` 和所有 assets。
|
||||
- 构建产物中的 base 路径全部为 `/admin-vue/`。
|
||||
- 页面模块按路由拆 chunk。
|
||||
- 工程不引用客户端 `frontend-vue/new_web_source`。
|
||||
|
||||
### 前端单元/契约测试
|
||||
|
||||
至少覆盖:
|
||||
|
||||
- 菜单树扁平节点组装为树。
|
||||
- 分组节点无 route 时不可作为页面进入。
|
||||
- 当前用户无菜单时展示空状态。
|
||||
- 非超级管理员访问无权限 route 时跳到第一个有权限页面。
|
||||
- 超级管理员可访问有效 admin 菜单。
|
||||
- 401 跳转登录。
|
||||
- API `{data}`、`{item}`、`{items}` 归一化。
|
||||
- 分页字段边界、空列表、请求失败。
|
||||
- 退出登录清理 Pinia 状态。
|
||||
- 上传/导入/下载终态和重复点击保护。
|
||||
|
||||
### Java API 契约测试
|
||||
|
||||
至少覆盖:
|
||||
|
||||
- `/api/admin/current-user` 返回当前用户的 `item`。
|
||||
- `/api/admin/current-user/menus` 只返回有效 admin 菜单树。
|
||||
- 树节点 `key`、`route`、`name` 和 parent-child 关系正确。
|
||||
- 普通用户、管理员、超级管理员菜单不同且不越权。
|
||||
- `/api/version` 字段为 `version/desc/url`。
|
||||
- `/api/version/latest` 字段为 `version/file_url`。
|
||||
- `web_config` 无记录返回两个 null。
|
||||
- 多条版本记录按创建时间和 id 稳定取最新。
|
||||
- 不带登录态访问需鉴权的 admin API 被拒绝。
|
||||
|
||||
### Flyway/数据库测试
|
||||
|
||||
- 迁移后所有 admin 菜单 route_path 唯一。
|
||||
- `column_key` 不被改写。
|
||||
- 用户直接授权记录数量不减少。
|
||||
- 父菜单授权的有效子菜单展开语义保持一致。
|
||||
- 重复执行迁移不会产生重复菜单或重复授权。
|
||||
|
||||
### Nginx/真实 HTTP 验收
|
||||
|
||||
- `/admin` 返回 302 到 `/admin-vue/`。
|
||||
- `/admin-vue/` 返回 HTML。
|
||||
- `/admin-vue/account/users` 刷新仍返回 HTML。
|
||||
- assets 正常返回正确 MIME。
|
||||
- 不存在 assets 返回 404。
|
||||
- `/api/admin/current-user` Cookie 能透传到 Java。
|
||||
- `/api/version/latest` 在 Flask 停止后仍可访问。
|
||||
|
||||
## 迁移前后对比
|
||||
|
||||
必须保存以下快照:
|
||||
|
||||
- 旧后台每个角色可见菜单 key。
|
||||
- 新菜单树每个角色可见菜单 key。
|
||||
- 版本公开接口响应。
|
||||
- 每个业务面板主要列表字段和分页语义。
|
||||
- 关键导入/导出/下载错误场景。
|
||||
|
||||
允许变化:
|
||||
|
||||
- 菜单显示分组。
|
||||
- Vue route path。
|
||||
- 页面布局和交互流程。
|
||||
- 前端组件实现。
|
||||
|
||||
不允许变化:
|
||||
|
||||
- 客户端版本接口路径和字段。
|
||||
- 后端业务 API 路径,除非另有独立迁移决策。
|
||||
- 用户菜单权限的实际范围。
|
||||
- 数据删除、导入、导出和任务终态语义。
|
||||
|
||||
## 最终验收清单
|
||||
|
||||
1. `admin-frontend-vue` 构建和测试通过。
|
||||
2. Java 编译、单测、契约测试通过。
|
||||
3. Flyway 在测试库执行成功。
|
||||
4. 17 个后台业务页面均有 Vue 对应页面或明确的验收记录。
|
||||
5. `/admin` 已稳定重定向 `/admin-vue/`。
|
||||
6. Nginx History 刷新和 assets 404 语义正确。
|
||||
7. `/api/version/latest` 已完成真实客户端兼容验证。
|
||||
8. Flask 管理页面和管理 API 已无生产流量。
|
||||
9. 旧 `admin.html`、`admin.js`、`admin-interactions.js` 已删除。
|
||||
10. 客户端 `frontend-vue` 和 `new_web_source` 未被后台工程污染。
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# 13 AdminHtml 观感与交互对齐(蓝白浅色)Spec
|
||||
|
||||
> **状态(task-283)**:对齐工作已全部完成,本 spec 所引用的基线文件(`backend/web_source/admin.html`、`backend/static/admin.js`、`admin-interactions.js` 及 Java 侧 static 副本)已按 spec 11 阶段 5 删除;历史内容保留于 git 中(`git log -- backend/web_source/admin.html` 可查),本 spec 作为过程记录不再可逐行对照。
|
||||
|
||||
## 模块职责
|
||||
|
||||
让 `admin-frontend-vue`(Vue3 + Element Plus 后台 SPA)的**壳层与 15 个业务页面**在观感与交互上对齐旧 Flask 后台 `backend/web_source/admin.html` 的**现行「蓝白浅色」皮肤**与 `backend/static/admin.js` / `admin-interactions.js` 的交互文案,实现从旧后台切换到新后台时用户无感。**DuplicateCheckPage(店铺撞款监控,menuKey `admin_shop_data_duplicate_check`)为例外页:保留其自身设计,本次不比对、不修改。**
|
||||
|
||||
## 依赖关系
|
||||
|
||||
- **上游(冻结参照,禁止改动)**:
|
||||
- `backend/web_source/admin.html` —— 面板 markup + CSS(4 代主题纵向堆叠,**最终生效 = 末层 L4477-4830「蓝白色调」亮色皮肤**)
|
||||
- `backend/static/admin.js`(7206 行)—— 各面板交互与用户可见文案
|
||||
- `backend/static/admin-interactions.js`(333 行)—— 全局确认框/Toast/按钮 title 语义
|
||||
- Java 侧镜像副本 `backend-java/src/main/resources/static/admin.html` + `static/static/admin.*`
|
||||
- **下游**:`admin-frontend-vue`(src/layout、src/styles、src/pages/*、src/components/*、src/api 适配、tests/task-NNN.test.ts、e2e/)。
|
||||
- **例外页**:`src/pages/tasks/DuplicateCheckPage.vue` 不改。
|
||||
|
||||
## 基线:admin.html 蓝白浅色皮肤(对齐目标值)
|
||||
|
||||
最终生效 token(admin.html L4478 :root):
|
||||
- 主色 `#4f78a5`,主色强 `#2f5d8b`,主色浅 `#e7f0f8`,按钮渐变 `#5f85ad→#4f78a5`
|
||||
- 内容底 `#f4f7fb`(body 叠加两团淡蓝 radial 晕染),卡片白、卡片抬升 `#f9fbfd`
|
||||
- **浅色侧栏** `#f8fbfe→#edf3f9`(渐变),侧栏文字 `#536a81`
|
||||
- 边框 `#d8e3ee`(强 `#b7c9db`)、文字 `#24384d` / 次 `#5b6f83` / 弱 `#8293a5`
|
||||
- danger `#b35f6a`(渐变 `#c06d77→#b35f6a`)、success `#4e806d`、warning `#a8793e`
|
||||
- radius 14px(卡片/按钮),9px(控件);卡片阴影 `0 1px 2px rgba(39,67,94,.04),0 14px 30px -24px rgba(39,67,94,.28)`
|
||||
|
||||
壳层密度:侧栏 252px(折叠 64px)、顶栏 76px(sticky 半透明白 blur8)、菜单项 min-height 42px、品牌 mark 36px、内容 padding `30px 32px 56px`、kicker 10px/700 + 面包屑 + 页题 18px/650、角色胶囊(#2f5d8b/#e6f0f8/#bfd1e2)。
|
||||
|
||||
组件观感基线(详见 plan/任务 241-248 展开):
|
||||
- 按钮 `.btn`(渐变蓝、min-height42、shadow)、`.btn-secondary`、`.btn-danger`、`.btn-sm`(行内 36px)
|
||||
- 表单 `.form-group label` 上置、控件 min-height42、focus 蓝 ring `0 0 0 3px rgba(95,133,173,.16)`
|
||||
- 表格 `.table-scroll`:外框 1px `#dbe5ee` radius10、th `#edf4fa` 12.5px/600、td 13.5px、hover `#f1f7fb`、无斑马
|
||||
- 分页:非数字页码「共 N 条 · 上一页 · 第 x / y 页 · 下一页 · 跳至[ ] 跳转」
|
||||
- 弹窗 `.modal`(radius14、width min(920px,…))、右侧 `.drawer`(min(460px,…))三段式;撞款锚点抽屉除外
|
||||
- Toast 右上角(成功绿/错误红/信息蓝前徽);二次确认(遮罩 blur + 橙底感叹图标 + [取消][确认删除]);顶部 3px 进度条 + 右上「请求处理中...」
|
||||
- 空态 `.empty-tip`、行内 `暂无 X`;面板头统一「h3 与操作按钮同行」
|
||||
|
||||
## 面板 ↔ Vue 页面映射(权威,以 Vue menuKey 为准)
|
||||
|
||||
| admin.html panel | admin 菜单名 | Vue menuKey | Vue 页面文件 | 业务命名差异/备注 |
|
||||
|---|---|---|---|---|
|
||||
| panel-users | 用户管理 | admin_users | account/UsersPage.vue | — |
|
||||
| panel-columns | 菜单权限配置 | admin_columns | account/MenusPage.vue | 列/交互以 admin 为准 |
|
||||
| panel-group-manage | 分组管理 | admin_group_manage | account/GroupsPage.vue | 需补编辑器+选人 |
|
||||
| panel-dedupe-total-data | 去重数据汇总 | admin_dedupe_total_data | asin/DedupeRegistryPage.vue | 需补导入/导出/筛选 |
|
||||
| panel-invalid-asin-data | 品牌数据库 | admin_invalid_asin_data | asin/AsinInvalidPage.vue | 同一 API /invalid-asin-data;Vue 用业务名「不符合ASIN数据」,保留 |
|
||||
| panel-query-asin | 查询ASIN | admin_query_asin | asin/QueryAsinPage.vue | 需补配置抽屉/导入 |
|
||||
| panel-product-categories | 商品类目 | admin_product_categories | asin/ProductCategoryPage.vue | 需补懒加载/导出/删除 |
|
||||
| panel-skip-price-asin | 最低价ASIN设置 | admin_skip_price_asin | asin/SkipPricePage.vue | 需补配置抽屉/导入 |
|
||||
| panel-shop-keys | 店铺密钥管理 | admin_shop_keys | shop/ShopKeysPage.vue | 白名单药丸/令牌语义 |
|
||||
| panel-shop-manage | 店铺管理 | admin_shop_manage | shop/ShopManagePage.vue | 凭证明文/眼睛实时读 |
|
||||
| panel-image-video-tasks | 视频任务记录 | admin_image_video_tasks | tasks/ImageVideoTasksPage.vue | 需改卡片网格+播放 |
|
||||
| panel-shop-data-crawl-tasks | 店铺数据记录 | admin_shop_data_crawl_tasks | tasks/ShopDataTasksPage.vue | 需改每店卡片网格 |
|
||||
| panel-shop-data-duplicate-check | 店铺数据重复检查 | admin_shop_data_duplicate_check | tasks/DuplicateCheckPage.vue | **例外页,不动** |
|
||||
| panel-history | 生成记录 | admin_history | records/RecordsHistoryPage.vue | 缩略图预览布局 |
|
||||
| panel-version | 软件版本管理 | admin_version | records/RecordsSoftwareVersionPage.vue | — |
|
||||
| panel-digital-human-version | 数字人版本管理 | digital_human_version | records/RecordsDigitalHumanVersionPage.vue | 状态色/操作矩阵 |
|
||||
|
||||
## 对齐契约类别(每个任务按此过一遍)
|
||||
|
||||
1. **观感**:色板/尺寸/圆角/阴影 = 上节基线;页面结构 = 「面板头(h3+按钮同行) + 筛选条 + 表格/卡片 + 分页脚」。
|
||||
2. **交互逻辑**:筛选字段与提交方式、行内操作按钮集、弹窗/抽屉表单字段与校验、导入/导出/轮询/等待态、空/错/loading 态 —— 与 admin.js 对应段一致。
|
||||
3. **用户可见文案**:页头描述、按钮名、确认框文案(删除“X”…)、成功/错误提示 —— 对齐 admin。
|
||||
4. **复用优先**:优先接线已存在但未进 UI 的孤儿 TS 模块(如 user-create/user-edit/user-menu-auth、dedupe-total-export/import、query-asin-*/skip-price-*、product-category-export、history-*/version-*/digitalhuman-*、shop-*、image-video-*/shop-data-*),再补缺口,避免重复造。
|
||||
5. **已知容忍项**:业务命名差异(品牌数据库→不符合ASIN数据)、admin 分页无页码为历史不一致(Vue 保留跳页但观感统一)、登录页独立设计不纳入。
|
||||
|
||||
## 实现顺序
|
||||
|
||||
1. A 换皮与共享基线(241-249)——先做,供后续页面直接受益。
|
||||
2. B account(250-253)→ C asin(254-258)→ D records(259-261)→ E shop(262-263)→ F tasks(264-267)。
|
||||
3. G 收尾(268-272)。
|
||||
|
||||
## 迁移边界
|
||||
|
||||
- **改**:admin-frontend-vue 内样式/布局/页面/共享组件/测试/e2e;主题单测随 token 翻转更新。
|
||||
- **不改**:`backend/web_source/admin.html`、`backend/static/admin.js`、`admin-interactions.js`、Java 侧 static 副本;DuplicateCheckPage;Java 后端 API 契约(如遇后端缺口另开 Java 任务,不夹带)。
|
||||
- 每任务仅 stage 本任务改动文件;不覆盖工作树他人未提交改动。
|
||||
|
||||
## 风险与验收标准
|
||||
|
||||
| 级别 | 验收点 | 证据 |
|
||||
|---|---|---|
|
||||
| P0 | 壳层与 15 页为蓝白浅色;颜色/尺寸对齐基线 | 截图对照 admin.html;tests 断言 token 与 CSS 变量 |
|
||||
| P0 | 页面交互与文案对齐(含补齐缺失交互);无误导/死按钮 | 每页测试 + 真实交互 |
|
||||
| P1 | 换皮不引入对比度/无障碍回归(WCAG AA) | theme 不变量测试 |
|
||||
| P1 | 响应式/折叠/空错态/loading 语义一致 | e2e + 清单 |
|
||||
| P2 | DuplicateCheckPage 与其余回归不受影响;全部旧提交不破坏 | git diff 校验例外页不变;全量 test+build |
|
||||
| P2 | check_progress 闭合、总任务数 272 | check_progress.py 退出 0 |
|
||||
@@ -0,0 +1,61 @@
|
||||
# 14 Round2 像素复刻收尾 · 筛选契约修复 · 撞款数据范围(迭代分析 Spec)
|
||||
|
||||
> 场景:现有项目迭代(step-1 场景 3)。目标 = ①剩余 13 菜单页按样办(生成记录/去重汇总)模式像素复刻旧版(撞款页除外)②全站筛选失效修复 ③撞款数据范围需求(超管全部分组店铺、管理员仅本组店铺)。
|
||||
|
||||
## 模块 A:剩余 13 页像素复刻(对齐旧版 admin.html 对应 panel)
|
||||
|
||||
**延续样办模式**:模板自绘旧版 markup(form-box/panel-box/table-scroll/旧式分页/原生控件),CSS 沿用旧版蓝白末层 token 与类名(.btn 渐变 42px/.btn-sm 36px/`.form-group{label 上置}`/`.table-scroll{th #edf4fa}`),script 逻辑复用现有 Vue 实现;每页差异点以 `docs/plans/admin-front-vue/round2-align-checklist.md` 为准。
|
||||
|
||||
**页面清单与要点**(13 页,撞款页例外不动):
|
||||
|
||||
| # | 菜单 | 路由 | 旧版 panel 要点 |
|
||||
|---|---|---|---|
|
||||
| 1 | 用户管理 | account/users | panel-users:筛选(用户名+所属管理员[仅超管])、列 ID/用户名/角色中文/所属管理员/创建时间、行 编辑/删除(删除确认"确定删除用户 “x” 吗?")、头部说明文案;创建/编辑弹窗沿用现有逻辑(菜单权限树) |
|
||||
| 2 | 菜单权限配置 | account/menus | panel-columns:拖拽手柄提示、树形表(└缩进)、列 拖拽/ID/名称/类型(后台/软件)/上级/创建时间、行 编辑/删除(确认"确定删除菜单“xx”吗?");弹窗沿用现有逻辑 |
|
||||
| 3 | 分组管理 | account/groups | panel-group-manage:顶部摘要 chips(超管"全部分组·N 个"/成员组 chips+另 N 个/未加入分组)、列 序号/名称/组长/组员数/chips/创建/修改、行 编辑/删除(仅组长/超管);编辑器沿用现有逻辑 |
|
||||
| 4 | 品牌数据库(不符合ASIN) | asin-center/invalid | panel-invalid-asin-data:筛选 ASIN/品牌/分组、列 ID/ASIN/品牌/分组/来源(手动新增/自动导入)/创建时间、行 btn-sm 编辑/删除(确认"确定删除"xx"吗?");来源 AUTO 编辑隐藏分组 |
|
||||
| 5 | 查询ASIN | asin-center/query | panel-query-asin:页头 新增 ASIN/导入添加/导入删除、筛选 分组/店铺名/国家/ASIN、列 序号/分组/店铺/ASIN(可复制)/国家/操作(配置 btn-sm)、rowspan 店铺合并;新增弹窗级联(分组→店铺);配置抽屉沿用现有逻辑 |
|
||||
| 6 | 商品类目 | asin-center/categories | panel-product-categories:搜索条+搜索/清空/导出/新增类目、树形表(缩进 24px/级+[+/−]折叠+加粗+来源 tag 内置/自定义)、列 名称/层级路径/排序/来源/备注/操作、懒加载"加载更多 已加载 a/b"、行 btn-sm 编辑/删除(有子禁用)、编辑态标题"编辑商品类目"+保存类目+取消编辑;**编辑时父级只读** |
|
||||
| 7 | 最低价ASIN | asin-center/skip-price | panel-skip-price-asin:页头 新增 ASIN/导入文件新增/导入文件删除、筛选 分组/店铺名/国家/ASIN/最低价≥≤、列 序号/分组/店铺/ASIN/国家/最低价/操作(配置);新增弹窗级联+最低价(选填) |
|
||||
| 8 | 店铺密钥管理 | shop-center/keys | panel-shop-keys:无筛选、列 序号/备注名/紫鸟账号名称/令牌(掩码)/白名单状态(正常/未加白名单/未检测+title 检测详情)/创建/修改、行 btn-sm 编辑/删除(确认"确定删除店铺密钥“xx”吗?");编辑留空令牌=不改 |
|
||||
| 9 | 店铺管理 | shop-center/shops | panel-shop-manage:筛选 分组/店铺名、列 序号/分组/店铺名/商城名/自动化账号/账号/密码(******+眼睛→读取中...→显示密码/隐藏密码)/创建/修改、行 编辑/删除(确认"确定删除店铺“xx”吗?")、长文本省略 title;分组锁定非超管 |
|
||||
| 10 | 软件版本管理 | records/software-version | panel-version:页头 上传新版本、列 版本号/下载链接/创建时间/操作(下载)、全量无分页;上传弹窗(版本号+ZIP)提交"上传软件版本",成功"发布成功。版本:{v},链接:{url}" |
|
||||
| 11 | 数字人版本管理 | records/digital-human-version | panel-digital-human-version:页头 上传新版本、列 版本号/状态(草稿#999/已发布#52c41a/已废弃#ff4d4f)/最新★/文件大小(MB)/MD5(截12)/更新日志(截50)/发布时间/操作(发布/设为最新/下载/删除 按状态矩阵,确认文案见 admin.js)、数字页码分页 |
|
||||
| 12 | 视频任务记录 | records/image-video-tasks | panel-image-video-tasks:form-box 筛选(用户名/提交开始/提交结束 datetime-local)、panel-box toolbar 全选当前页+批量下载(N)+权限配置(仅超管)+汇总"共 N 个任务·本页 N 个视频"、任务卡片网格(video controls+状态徽章+用户名/分组/模式/生成时间/调试链接复制+下载)、空态"暂无符合条件的视频任务"、批量进度文案 |
|
||||
| 13 | 店铺数据记录 | shop-center/data-tasks | panel-shop-data-crawl-tasks:form-box 筛选(店铺/分组/国家/创建起止)、toolbar 全选可下载+批量下载(N)+权限配置+汇总"共 N 家店铺·本页 M 个结果文件"、每店卡片网格(店名/勾选+任务号+状态/分组/最新/国家/文件+下载文件/删除)、删除确认"确认删除店铺“x”的任务 {id} 及结果文件?"、批量 zip 进度;**保留 9 卡/页宫格与旧版无的删除结果文件(用户已确认逐项评估保留)** |
|
||||
|
||||
**已有基础**:round2-align-checklist.md(页面特异差异)、13-panel-checklist.md(面板×页面映射)、旧版基准 reference/old-admin/、样办 CSS 可复用(form-box/panel-box/btn/table-scroll/pagination/modal 已在两页实现,推广时抽公共 CSS 到共享模块或逐页内联,按现有惯例片段复用)。
|
||||
|
||||
## 模块 B:全站筛选不生效修复(P0 Bug)
|
||||
|
||||
**根因(已实测/代码证实)**:前端 `toAsinPageQuery`(asin-filter.ts)输出 **snake_case**(page_size/group_id/start_date/end_date/keyword/username/country);下列 Java 控制器为**裸 camel 变量名** @RequestParam(Spring Boot parent 默认 -parameters 开启 → 参数名=变量名 camel)→ 前端 snake 参数**全部匹配失败** → 后端落默认值(page=1 pageSize=15 等)→ 列表分页/筛选均不生效:
|
||||
|
||||
- `DedupeTotalDataController`(去重汇总列表/导出):page/pageSize/keyword/username/startDate/endDate/groupId/country
|
||||
- `InvalidAsinDataController`(品牌库列表):page/pageSize/keyword/dataValue/brand/groupId
|
||||
- `QueryAsinController`(查询ASIN 列表/导出/导入):page/pageSize/groupId/shopName/asin/country
|
||||
|
||||
已正确 snake 的对照(勿动):SkipPriceAsinController、AdminShopDataCrawlTasksController、AdminImageVideoTaskController、AdminUserController、AdminShopDataDuplicateCheckController、ProductCategoryController(task-284 已改)。
|
||||
|
||||
**修复**:Java 三控制器 @RequestParam 加显式 `name="page"/"page_size"/"group_id"/"data_value"/"shop_name"/"start_date"/"end_date"` 等 snake 名(与前端契约一致),并同步 service/mapper 无改动(仅参数绑定名)。导出/导入端点的同名参数一并改。**需重打包后端 jar 并重启本地栈**。
|
||||
**前端补充核查**:SkipPricePage 最低价区间(minimum_price_from/to)是否已随 toSkipPriceQuery 下发(skip-price-filter 有 minimumPriceFrom/To,确认序列化含 snake 参数);menuCols 等其它域筛选是否已有 snake(验收时逐页操作核验)。
|
||||
|
||||
## 模块 C:撞款数据范围(DuplicateCheckPage 例外页功能需求)
|
||||
|
||||
**需求**:超管可查询全部店铺(含全部组);管理员仅本组店铺(自己创建或指派给自己的分组)。
|
||||
**现状**:后端 `resolveVisibleShopKeys(operatorId, superAdmin)`:superAdmin→null(全量);否则 selectManagedShopNames = `group.created_by_id=me OR group.user_id=me` 下店铺 → 与前端 407fc78e 角色收口配套。
|
||||
**待验证/修复项**:
|
||||
1. 超管"没展示全":本地栈以超管实测撞款接口(含分组筛选)返回店铺覆盖数 vs `biz_shop_manage` 全量;若快照数据源有限则确认"扫描基线"是否全量(超管触发扫描应覆盖全部,管理员扫描仅其可管集→快照范围受限,此为数据模型固有,需向用户说明或按需扩大扫描范围)。
|
||||
2. 管理员范围:非超管验证仅返回本组店铺(多账号对比)。
|
||||
3. operator.superAdmin() 来源核验(AdminAuthSupport 角色判定仅 super_admin 为真)。
|
||||
|
||||
## 依赖与顺序
|
||||
|
||||
1. 模块 B 先行(修复筛选,需 Java 重打包 + 本地栈重启)——验收基准确认。
|
||||
2. 模块 A 按域分页推进(account 3 页 → asin 4 页[invalid/query/categories/skip] → shop 2 页 → records 2 页 → tasks 2 页),每批对齐+测试+commit,沿用样办断言模式对齐。
|
||||
3. 模块 C 与 B 并行验证;超管全量如涉扫描基线/数据源则出方案与用户确认。
|
||||
|
||||
## 验收
|
||||
|
||||
- 每页:旧版观感目检 + 该页 align-* 断言(自绘结构)+ `npm test` 全绿 + `npm run build` + 本地栈截图。
|
||||
- 筛选:逐页输入条件→查询→结果正确过滤(请求参数 snake 命中后端)。
|
||||
- 撞款:超管/管理员两账号各验一次范围。
|
||||
@@ -0,0 +1,72 @@
|
||||
# 15 亚马逊工具台 · PySide6 v2.0.4 视觉对齐与去线(迭代分析 Spec)
|
||||
|
||||
> 场景:现有项目迭代(step-1 场景 3,技术栈已固定为 Vue3 + Element Plus)。参考实现 = `reference/数富AI工具台_PySide6版_v2.0.4/源代码/shufuai_console_app_qt.py`(下称**参考**)。
|
||||
>
|
||||
> 用户已确认决策:①范围 = **逐项视觉对齐 + 去线**(现有真实业务表单不动)②去线目标 = **卡片悬浮边框线、页头竖分隔线、顶栏 tab 下划线**(时间线步骤连接线**保留**)③工具详情页:**中间旧表单区 + 右侧任务进度区保留现状,仅顶部/底部用参考界面**(即 Shell 头按参考改:去竖线、source 页加 Aliprice 按钮;底部 FooterBar 已与参考一致)
|
||||
|
||||
## 背景结论
|
||||
|
||||
前端 `amazon-console` 已复刻参考的功能层:首页(Hero/时间线/卡片墙)、顶栏、页脚、工具页壳(`AmazonToolPageShell`,17 个工具页已接入)、密钥设置(`BrandApiSecretSettingsButton` 已含三大密钥+保留时长+代理)、立即下载(已接 pywebview `save_workbench_zip`)。采集工作台(参考 `page_work`)已由 `collect-data` 真实功能页覆盖。
|
||||
|
||||
本次只处理**视觉差异**与**去线**,共 4 个模块。参考中的"演示表单/运行摘要侧栏"(`_render_params`、`summary_rows`)与密钥弹窗均**不重复实现**。
|
||||
|
||||
## 模块 A:首页 AmazonConsolePage.vue
|
||||
|
||||
| # | 前端现状(文件:行) | 参考实现(shufuai_console_app_qt.py:行) | 目标 |
|
||||
|---|---|---|---|
|
||||
| A1 | hero-pill 圆角胶囊 `.hero-pill{border-radius:999px;padding:5px 12px}`(294-303) | `pill` 直角:`padding:4px 12px`,无 border-radius(585-586) | 去掉圆角(border-radius:0)、padding 改 4px 12px |
|
||||
| A2 | 工作流编号块 `.step-circle{width:36px;height:26px}`(537-546) | `circ` 36×38(778-781,QLabel 36×38) | 高度 26 → 38 |
|
||||
| A3 | 步骤连接线 `.step-line{flex:1 1 auto;min-width:12px;margin:13px 2px 0;align-self:flex-start}`(563-569),模板 86 行 | `ln.setFixedSize(14,2)`(811-812),间距 6(802)+ 侧边 2(809) | 线改固定宽 14px(flex:none),垂直位置对齐参考;步骤间距约 6px 侧边 2px。**此线保留**(用户未勾选去掉) |
|
||||
| A4 | 卡片悬浮 `.tool-card:hover{border-color:var(--gc)}`(603-606) | `_build_card` hover:边框 2px 变分类色(929-930) | **去线**:hover 时边框**不变色**(保持 #2A3344),只保留背景变亮 #323D52 + "打开工具→"变分类色加粗 + tag 实底白字。默认 2px #2A3344 静态边框保留 |
|
||||
| A5 | 卡片 tag `.tool-tag{border-radius:3px}`(614-620) | `tag` border-radius:4px(903) | 圆角 3px → 4px |
|
||||
| A6 | 重复 hover 规则:522-530(带 disabled 版)与 571-579(无 disabled 版)重复 | — | 合并清理为一条规则(保留 disabled 除外判定) |
|
||||
|
||||
其余确认已对齐、不再改动:hero 卡(340 宽、dots+42px 短线、下载按钮 base64+hover 变亮)、时间线面板(PANEL 底 + LINE 边框)、标题/badge/hint、卡片网格 4 列 gap 12、统计行、toast。参考固定宽 1162px / 固定高 174px / 卡片墙固定行高 187px 为 Qt 布局产物,前端响应式自适应**不强制对齐**。
|
||||
|
||||
## 模块 B:顶栏 AmazonTopBar.vue
|
||||
|
||||
| # | 前端现状 | 参考实现 | 目标 |
|
||||
|---|---|---|---|
|
||||
| B1 | tab hover 背景 `.cat-tab:hover{background:#232a3b}`(165-168) | `_tab_qss` 非激活 hover:`background:CARD3`(#3D4A63,392-395) | hover 背景 #232A3B → #3D4A63 |
|
||||
| B2 | 激活 tab 下划线 `.cat-underline`(模板 22 行、样式 207-219) | tab 底部 3px 线(352-355),激活=分类色 | **去线**:模板与样式整块删除;激活态仅保留 CARD3 背景 + 白字 + badge 实色(现状即如此,无其它受影响的选中指示) |
|
||||
|
||||
其余已对齐:品牌(38×38 富)、tab 尺寸 140×38 圆角 10、badge 24×20(非激活 CARD2/#343F55、激活分类色白字)、右侧密钥按钮/帮助/AD admin、权限过滤逻辑(保留)。
|
||||
|
||||
## 模块 C:工具页壳 AmazonToolPageShell.vue
|
||||
|
||||
| # | 前端现状 | 参考实现 | 目标 |
|
||||
|---|---|---|---|
|
||||
| C1 | 页头竖分隔线 `.tool-head__sep`(模板 7 行、样式 85-90) | 参考无此分隔线(1113-1126 head 仅 back_btn+title+desc) | **去线**:模板与样式整块删除 |
|
||||
| C2 | 头部无"Aliprice点击注册"按钮 | `tool_extra_link`:仅 `source`(货源查询)工具显示,TEAL 渐变按钮,点击打开 `https://www.aiprice.com/?ext_id=10100&channel=chrome_offline&platform=1688&version=4.0.5&browser=chrome&mv=3`(1137-1149、1228-1229) | 在壳头部标题描述下方新增该按钮:toolId === 'source' 时显示(对应 /new_web_source/similar-asin.html 页,即 BrandSimilarAsinTab 所在页),样式对齐参考(TEAL 渐变、白字、hover 变亮) |
|
||||
| C3 | 头部 gap 18px(62-68) | back_btn 后间距约 10px(按钮自身 padding 6px 10px,无额外 spacing) | 可选微调为 10px |
|
||||
|
||||
其余已对齐:back 文案(返回分组列表+锚点)、标题 22px、desc 12px/700px、note 卡(#2E2414 底 #F8D8A8 字 #3A2A16 边框)。
|
||||
|
||||
## 模块 D:明确不动项
|
||||
|
||||
- 17 个工具页真实业务表单与右侧任务面板(真实接口,不作演示表单替换)
|
||||
- 采集工作台功能(collect-data 已覆盖,参考 `page_work` 不新增页面)
|
||||
- 密钥设置(`BrandApiSecretSettingsButton` 已覆盖参考弹窗全部字段)
|
||||
- 立即下载(已接 `save_workbench_zip`,含 v2.0.4 的修复行为:搜索常见位置→未找到时手动选择→记住路径)
|
||||
- 权限过滤(`filterGroupsByPermission`/`filterWorkflowByPermission`、置灰卡片)与页面 hash 锚点
|
||||
- icons/ToolIcon(渐变底+白色图形已按参考像素级复刻)
|
||||
|
||||
## 实现顺序与依赖
|
||||
|
||||
1. 模块 D 无改动;先做模块 B(TopBar,独立、影响面小)→ 模块 C(Shell,影响 17 个页面统一外观)→ 模块 A(首页,差异最多)
|
||||
2. 全部改动落在 `frontend-vue/src/pages/amazon/` 三个文件 + `tool-catalog.ts`(如需补充 source 相关标记则加);无新增依赖、无接口变更
|
||||
|
||||
## 验证与客户端同步(必须)
|
||||
|
||||
1. `cd crawler-plugin/frontend-vue && npm run build`(vue-tsc 类型检查 + vite build)
|
||||
2. 把 `new_web_source/` 下页面 HTML 拷贝到 `app_client/new_web_source/`,`new_web_source/assets/` 整体拷贝到 `app_client/assets/`(文件名带 hash,两边必须同步)
|
||||
3. 桌面端 `python main.py` 打开工具台核对:A1-A6、B1-B2、C1-C2 逐项对照参考截图/运行效果;重点验证 hover 无彩色边框线、页头无竖线、tab 无下划线
|
||||
4. 回归:17 个工具页壳头(无 sep、source 页有 Aliprice 按钮)、时间线连接线仍在、下载与密钥入口可用
|
||||
5. 视用户需要再执行 `build_shufuai.bat` 打包 exe
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 卡片 hover 去线后,`--gc` 变量仍被 `.tool-card:hover .tool-card-go` 与 tag 使用,**只删 border-color 规则,勿删 `--gc` 注入**(cardStyle 173-175)
|
||||
- `.workflow-step:hover` 与 `.workflow-step:not(.workflow-step--disabled):hover` 重复规则清理时,保留 `--disabled` 例外(置灰步骤不响应 hover 填色)
|
||||
- `AmazonTopBar` 的 `cat-underline` 删除后,`badgeStyle`/`createApp` 等不受影响;确认无其它页面单独使用该样式类
|
||||
- 若后续用户接受"卡片完全无边框",仅需再删默认 border 一行,spec 已按"保留静态边框、去悬浮变色"执行
|
||||
Reference in New Issue
Block a user