4 Commits
5 changed files with 275 additions and 12 deletions

No files matched your search

+78
View File
@@ -0,0 +1,78 @@
# 2026-10-19 K22 后台管理视觉与交互统一
## 基线
- ReelShortWeb `develop`: `5c087f4`
- FruitServer `develop`: `b025bfd`
- 只改 Web 视觉/交互与 FruitServer 菜单图标 SQL,不改接口、客户端、main。
## 图标体系
1. 新增 `src/constants/icons.ts`:
- `AppIcons` 保存语义名到 `material-symbols:*-rounded` 的映射;
- `normalizeAppIcon()` 兼容后端旧短名和历史 Iconify 名;
- `MenuIconOptions` 供菜单管理页选择。
2. 新增 `src/components/AppIcon`:
- 复用现有 `Icon` 组件;
- 默认尺寸 18,支持颜色/悬停色;
- 全局注册 `AppIcon`。
3. 替换 `src/components/**`、`src/views/**` 的旧图标前缀与 Element Plus 图标组件。
4. 对 `node_modules/@iconify/json/json/material-symbols.json` 做存在性校验。
任务书要求的 `language/view-column/lock/chevron-down` 在当前 JSON 中没有对应的
`*-rounded` 名,实施时使用同语义且存在的
`translate-rounded/combine-columns-rounded/lock-person-rounded/keyboard-arrow-down-rounded`。
## 菜单落库
更新 `sql/data.sql` 与 `sql/data-phase1.sql` 中 id 1/2/3/6/15/17/20/22/24/26/32:
| 菜单 | 图标 |
| --- | --- |
| 工作台 | `material-symbols:dashboard-rounded` |
| 内容管理 | `material-symbols:video-library-rounded` |
| 后台管理 | `material-symbols:settings-rounded` |
| 用户管理 | `material-symbols:group-rounded` |
| 创作者管理 | `material-symbols:movie-edit-rounded` |
| 内容治理 | `material-symbols:policy-rounded` |
| 订单与权益 | `material-symbols:payments-rounded` |
| 数据看板 | `material-symbols:monitoring-rounded` |
| 创作者中心 | `material-symbols:video-camera-front-rounded` |
| 运营管理 | `material-symbols:campaign-rounded` |
执行两份 SQL,管理员登录后请求 `/admin/auth/menus`,断言所有 icon 以
`material-symbols:` 开头。
## 品牌与登录
- 复制客户端 `splash_mark.png` 为 `src/assets/imgs/brand-mark.png`。
- Logo 组件展开/收起统一使用品牌 mark。
- 删除 admin/admin123 占位、记住密码持久化、固定 `FruitShorts Studio`。
- 记住我只保存用户名;store reset 时删除 loginInfo。
- 表单回车提交、loading 覆盖请求与动态路由、防止重复。
- 960 以下压缩 hero,登录卡首屏完整。
## 全局壳与主题
- 修复深色模式菜单、头部、标签关闭、主题开关、面包屑对比度。
- body 去掉 `min-width: 980px`,补 1200/768 断点。
- 顶栏、标签页、表格工具栏、弹窗统一 AppIcon。
- CSS token:一组字体变量、4/6/12 圆角、`#409eff !important` 改
`var(--el-color-primary)`,删除或合并未使用壳层选择器。
- 用户信息读取 `userStore`,不再使用固定 avatar/Archer。
- 清除缓存增加二次确认。
## 门禁与自查
- 静态扫描:无旧图标前缀、无 `<el-icon>`、无页面 `@element-plus/icons-vue` 引用。
- `node_modules/@iconify/json/json/material-symbols.json` 逐个校验新图标。
- `pnpm lint:eslint` 零错误。
- `pnpm build:pro` 成功。
- 浏览器自查:登录页、侧边栏展开/折叠、顶栏、标签页、浅/深色、1024/800/375。
## 风险
- 图标批量替换可能影响动态图标与右键菜单,保留 normalize 兜底。
- 窄屏下侧栏与固定内容宽度可能冲突,优先保证内容区不裁切。
- 登录 loading 必须覆盖动态路由生成,避免二次提交。
- 本轮不碰表格、筛选、分页、拦截器、删除确认、rules、权限与上传校验。
+1 -1
View File
@@ -20,7 +20,7 @@
---
## [待处理] 2026-10-19 | K22 后台管理视觉与交互统一(图标对齐客户端)
## [已处理·待用户验收] 2026-10-19 | K22 后台管理视觉与交互统一(图标对齐客户端)
**用户指令(2026-10-19)**:「先优化后台管理 UI 及交互;后台管理图标统一成客户端的;严格执行 specs 文档规范」。
> 只改 `ReelShortWeb` 的视觉/交互 + `FruitServer` 的菜单图标种子 SQL;不改接口契约、业务逻辑、客户端、main。
+185
View File
@@ -4266,3 +4266,188 @@ cf03178 feat(flutter): 首页改为两列全部剧目网格
预期:标题最多 2 行、类型最多 1 行,不横向溢出;空态和失败重试文案保留。
设备侧截图、日志与最终验收结论由用户执行。
## K22 后台管理视觉与交互统一
### 分支与提交
```text
ReelShortWeb:
5c087f4 chore(admin): 合并注册限流配置项
97fbeda style(web): 统一后台图标与全局视觉
8f3447e chore(web): 合并 K22 后台视觉统一
FruitServer:
5e55171 docs(plans): 增加 K22 后台视觉统一计划
c14b4cb fix(sql): 统一后台菜单图标
be9e381 chore(sql): 合并 K22 菜单图标
```
功能提交与合并提交 author/committer 均为
`Zhou Weidong <502333560@qq.com>`。未修改 main、客户端业务代码与 Web 接口契约。
### 图标体系与扫描
新增 `src/constants/icons.ts`、`src/components/AppIcon/`,并将客户端品牌图标
复制为 `src/assets/imgs/brand-mark.png`。
```text
before-old-prefix=22
before-el-icon=15
before-element-plus-icons=16
old-prefix=0
el-icon=0
element-plus-icons=0
AppIcons unique=54 missing=0
```
页面与共享组件已不再直接引用旧 Iconify 前缀、`<el-icon>` 或
`@element-plus/icons-vue`。剩余两处 `<Icon>` 分别是 `AppIcon` 的底层包装与
`Icon` 自身的在线图标实现。
任务书列出的 `language-rounded`、`view-column-rounded`、`lock-rounded`、
`chevron-down-rounded` 在当前 Material Symbols JSON 中不存在,使用同语义且
通过存在性校验的 `translate-rounded`、`combine-columns-rounded`、
`lock-person-rounded`、`keyboard-arrow-down-rounded`。
### 菜单 SQL 与接口自检
已幂等执行:
```text
$ psql -d fruitshorts -v ON_ERROR_STOP=1 -f sql/data.sql
INSERT 0 3
INSERT 0 4
INSERT 0 19
INSERT 0 13
...
INSERT 0 4
$ psql -d fruitshorts -v ON_ERROR_STOP=1 -f sql/data-phase1.sql
DO
INSERT 0 0
...
UPDATE 5
...
INSERT 0 0
```
目标菜单回查:
```text
id | title | icon
----+------------+---------------------------------------------
1 | 工作台 | material-symbols:dashboard-rounded
2 | 工作台 | material-symbols:dashboard-rounded
3 | 内容管理 | material-symbols:video-library-rounded
6 | 后台管理 | material-symbols:settings-rounded
15 | 用户管理 | material-symbols:group-rounded
17 | 创作者管理 | material-symbols:movie-edit-rounded
20 | 内容治理 | material-symbols:policy-rounded
22 | 订单与权益 | material-symbols:payments-rounded
24 | 数据看板 | material-symbols:monitoring-rounded
26 | 创作者中心 | material-symbols:video-camera-front-rounded
32 | 运营管理 | material-symbols:campaign-rounded
(11 rows)
```
管理员登录后调用 `/admin/auth/menus`:
```text
工作台 material-symbols:dashboard-rounded
内容管理 material-symbols:video-library-rounded
后台管理 material-symbols:settings-rounded
用户管理 material-symbols:group-rounded
创作者管理 material-symbols:movie-edit-rounded
内容治理 material-symbols:policy-rounded
订单与权益 material-symbols:payments-rounded
数据看板 material-symbols:monitoring-rounded
运营管理 material-symbols:campaign-rounded
menus=28 icons=9 allMaterial=true
```
解读:超级管理员可见菜单接口返回的图标全部为 `material-symbols:` 前缀。
`创作者中心`(id 26)按既有规则对超级管理员隐藏,未出现在该菜单树,但数据库
回查已确认其图标正确。
### 登录页与全局壳
登录页:
- 删除 `admin` / `admin123` 占位,改为三语占位文案。
- “记住我”默认关闭,只保存用户名;退出和恢复时清理历史密码字段。
- 支持密码框回车提交;请求与动态路由生成完成前保持 loading,防重复。
- 品牌统一使用客户端 `splash_mark.png`,登录页与侧边栏同一资源。
- ≤960px 压缩品牌区;实测登录卡在 1024×768、800×768、375×812 首屏完整可见。
全局壳:
- 深色选中菜单、当前标签、主题开关轨道统一使用主色派生 token;
深色选中白字对比度由 `2.78:1` 提升到 `5.00:1`。
- 面包屑深色对比度 `11.13:1`,顶栏 `16.70:1`。
- 标签关闭图标改用 `var(--el-text-color-secondary)`。
- 删除 `body { min-width: 980px }` 和未使用的旧壳层死选择器。
- 补 1200/768 断点;1024、800、375 下 `documentElement.scrollWidth`
分别等于视口宽度,顶栏无越界元素。
- 用户头像/姓名读取 `userStore`,不再写死 `avatar.jpg` / `Archer`。
- “清除缓存并且重置”弹出二次确认,取消后保持当前状态。
- 字体、圆角、主色变量收敛;`#409eff !important` 已清零。
### 门禁
```text
$ pnpm lint:eslint
> fruitshorts-admin@1.0.0 lint:eslint /Users/jianghaifeng/Desktop/ReelShort/ReelShortWeb
> eslint --fix --ext .js,.ts,.vue ./src
```
```text
$ pnpm build:pro
> fruitshorts-admin@1.0.0 build:pro /Users/jianghaifeng/Desktop/ReelShort/ReelShortWeb
> VITE_CJS_IGNORE_WARNING=1 vite build --mode pro
[warn] Circular chunk: element-plus -> vue-chunks -> element-plus. Please adjust the manual chunk logic for these chunks.
[warn] node_modules/.pnpm/mockjs@1.1.0/node_modules/mockjs/dist/mock.js (537:22): Use of eval in "node_modules/.pnpm/mockjs@1.1.0/node_modules/mockjs/dist/mock.js" is strongly discouraged as it poses security risks and may cause issues with minification.
Build successful. Please see dist-pro directory
```
解读:ESLint 零错误;构建成功。两条 warning 来自既有 chunk 配置与 mockjs 依赖,
本批未改构建配置。
### 浏览器自查
Codex 已在本地开发服务完成以下自查,不作为用户验收:
- 登录页:三档宽度无横向溢出;800×768 登录卡底边 `754.40`,375×812 底边
`772.77`,均在首屏内。
- 登录交互:占位为“请输入用户名/请输入密码”;“记住我”默认未勾选;
密码框回车可进入工作台。
- 侧边栏:1024 展开 200px、收起 64px;375 抽屉展开 200px、遮罩关闭正常。
- 顶栏、标签页、面包屑、短剧管理工具栏均正常渲染 Material Symbols Rounded。
- 深色/浅色切换正常;深色选中菜单与当前标签均为白字压深主色,对比度 `5.00:1`。
- 清除缓存按钮显示“确认清除本地缓存并重新加载后台吗?”,取消有效。
- 浏览器控制台 0 个 error;动态路由刷新期间出现 2 条既有 `No match found`
router warning,随路由生成完成消失,不影响页面。
### 用户验收步骤与预期
1. 运行 `pnpm dev`,打开 `http://127.0.0.1:3005/#/login`。
预期:暖色品牌登录页;用户名/密码为中文占位;“记住我”默认关闭。
2. 输入管理员账号,在密码框直接回车。
预期:按钮进入 loading,随后只跳转一次工作台。
3. 检查左侧菜单、顶栏、标签页和短剧管理页工具栏。
预期:图标均为 Material Symbols Rounded,无旧图标混用。
4. 展开/收起侧栏,并打开右侧“项目配置”。
预期:品牌 mark 一致;主题开关边界清楚;布局无跳动。
5. 切换到深色再切回浅色。
预期:菜单、面包屑、当前标签、关闭图标与开关均清晰可辨。
6. 分别以 1024、800、375 宽度查看工作台、短剧管理和登录页。
预期:内容区与顶栏不横向裁切;375 可通过菜单按钮打开侧栏抽屉。
7. 点击“清除缓存并且重置”后选择取消。
预期:先出现二次确认,取消后页面状态不变。
最终业务验收由用户在浏览器执行。
+7 -7
View File
@@ -92,7 +92,7 @@ ON CONFLICT DO NOTHING;
-- component 指向 src/views/creator/ 下的页面,前端按这个字符串动态加载。
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(17, 0, '创作者管理', '/creator', 'CreatorCenter', '#', '/creator/creators', 'ep:user-filled', 'creator:list', 'CATALOG', 1, 0, 5),
(17, 0, '创作者管理', '/creator', 'CreatorCenter', '#', '/creator/creators', 'material-symbols:movie-edit-rounded', 'creator:list', 'CATALOG', 1, 0, 5),
(18, 17, '创作者入驻', 'creators', 'creators', 'views/creator/CreatorAuditView', '', '', 'creator:list', 'MENU', 0, 0, 1),
(19, 17, '内容审核', 'submissions', 'submissions', 'views/creator/SubmissionAuditView', '', '', 'submission:list', 'MENU', 0, 0, 2)
ON CONFLICT (id) DO UPDATE SET parent_id = EXCLUDED.parent_id, title = EXCLUDED.title,
@@ -129,7 +129,7 @@ WHERE NOT EXISTS (SELECT 1 FROM product WHERE code = 'coin_1200');
-- component 指向 src/views/userManagement/AppUsersView.vue,前端按这个字符串动态加载。
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(15, 0, '用户管理', '/user', 'UserCenter', '#', '/user/app-users', 'ep:user', 'app-user:list', 'CATALOG', 1, 0, 4),
(15, 0, '用户管理', '/user', 'UserCenter', '#', '/user/app-users', 'material-symbols:group-rounded', 'app-user:list', 'CATALOG', 1, 0, 4),
(16, 15, 'App 用户', 'app-users', 'app-users', 'views/userManagement/AppUsersView', '', '', 'app-user:list', 'MENU', 0, 0, 1)
ON CONFLICT (id) DO UPDATE SET parent_id = EXCLUDED.parent_id, title = EXCLUDED.title,
route_path = EXCLUDED.route_path, route_name = EXCLUDED.route_name, component = EXCLUDED.component,
@@ -150,11 +150,11 @@ ON CONFLICT DO NOTHING;
-- component 指向 src/views/governance|commerce|dashboard/ 下的页面,前端按字符串动态加载。
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(20, 0, '内容治理', '/governance', 'Governance', '#', '/governance/content', 'ep:chat-dot-round', 'comment:list', 'CATALOG', 1, 0, 6),
(20, 0, '内容治理', '/governance', 'Governance', '#', '/governance/content', 'material-symbols:policy-rounded', 'comment:list', 'CATALOG', 1, 0, 6),
(21, 20, '评论与举报', 'content', 'governance-content', 'views/governance/ContentGovernanceView', '', '', 'comment:list', 'MENU', 0, 0, 1),
(22, 0, '订单与权益', '/commerce', 'Commerce', '#', '/commerce/orders', 'ep:coin', 'order:list', 'CATALOG', 1, 0, 7),
(22, 0, '订单与权益', '/commerce', 'Commerce', '#', '/commerce/orders', 'material-symbols:payments-rounded', 'order:list', 'CATALOG', 1, 0, 7),
(23, 22, '订单管理', 'orders', 'commerce-orders', 'views/commerce/OrderManagementView', '', '', 'order:list', 'MENU', 0, 0, 1),
(24, 0, '数据看板', '/board', 'BoardCenter', '#', '/board/overview', 'ep:data-line', 'dashboard:view', 'CATALOG', 1, 0, 8),
(24, 0, '数据看板', '/board', 'BoardCenter', '#', '/board/overview', 'material-symbols:monitoring-rounded', 'dashboard:view', 'CATALOG', 1, 0, 8),
(25, 24, '运营大盘', 'overview', 'board-overview', 'views/dashboard/BusinessDashboardView', '', '', 'dashboard:view', 'MENU', 0, 0, 1)
ON CONFLICT (id) DO UPDATE SET parent_id = EXCLUDED.parent_id, title = EXCLUDED.title,
route_path = EXCLUDED.route_path, route_name = EXCLUDED.route_name, component = EXCLUDED.component,
@@ -253,7 +253,7 @@ INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, r
permission_code, type, always_show, affix, sort, visible) VALUES
-- route_name 必须全局唯一:17 号菜单(创作者管理)已经叫 CreatorCenter,
-- 同名会让 Vue Router 后者覆盖前者、整个 /creator-center 子树注册不上(超管点进去就 404)
(26, 0, '创作者中心', '/creator-center', 'CreatorWorkspace', '#', '/creator-center/workspace', 'ep:film', 'creator-center:view', 'CATALOG', 1, 0, 3, 1),
(26, 0, '创作者中心', '/creator-center', 'CreatorWorkspace', '#', '/creator-center/workspace', 'material-symbols:video-camera-front-rounded', 'creator-center:view', 'CATALOG', 1, 0, 3, 1),
(27, 26, '我的作品', 'workspace', 'creator-workspace', 'views/creator-center/WorkspaceView', '', '', 'creator-center:view', 'MENU', 0, 0, 1, 1),
(28, 26, '作品编辑', 'dramas/:id', 'creator-drama-edit', 'views/creator-center/DramaEditView', '', '', 'creator-center:drama:edit', 'MENU', 0, 0, 2, 0),
(29, 26, '收费配置', 'prices', 'creator-prices', 'views/creator-center/PriceConfigView', '', '', 'creator-center:price:update', 'MENU', 0, 0, 3, 1),
@@ -310,7 +310,7 @@ ON CONFLICT DO NOTHING;
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(31, 22, '商品配置', 'products', 'commerce-products', 'views/commerce/ProductManagementView', '', '', 'product:list', 'MENU', 0, 0, 2),
(32, 0, '运营管理', '/operation', 'OperationCenter', '#', '/operation/notices', 'ep:bell', 'notice:list', 'CATALOG', 1, 0, 9),
(32, 0, '运营管理', '/operation', 'OperationCenter', '#', '/operation/notices', 'material-symbols:campaign-rounded', 'notice:list', 'CATALOG', 1, 0, 9),
(33, 32, '系统公告', 'notices', 'operation-notices', 'views/operation/NoticeManagementView', '', '', 'notice:list', 'MENU', 0, 0, 1)
ON CONFLICT (id) DO UPDATE SET parent_id = EXCLUDED.parent_id, title = EXCLUDED.title,
route_path = EXCLUDED.route_path, route_name = EXCLUDED.route_name, component = EXCLUDED.component,
+4 -4
View File
@@ -50,14 +50,14 @@ ON CONFLICT (id) DO UPDATE SET code = EXCLUDED.code, name = EXCLUDED.name,
-- ---------- 菜单 ----------
INSERT INTO sys_menu (id, parent_id, title, route_path, route_name, component, redirect, icon,
permission_code, type, always_show, affix, sort) VALUES
(1, 0, '工作台', '/dashboard', 'Dashboard', '#', '/dashboard/index', 'ant-design:dashboard-filled', 'drama:list', 'CATALOG', 0, 0, 1),
(2, 1, '工作台', 'index', 'dashboard', 'views/common/DashboardView', '', 'ant-design:dashboard-filled', 'drama:list', 'MENU', 0, 1, 1),
(3, 0, '内容管理', '/content', 'Content', '#', '/content/dramas', 'ep:video-camera', 'drama:list', 'CATALOG', 1, 0, 2),
(1, 0, '工作台', '/dashboard', 'Dashboard', '#', '/dashboard/index', 'material-symbols:dashboard-rounded', 'drama:list', 'CATALOG', 0, 0, 1),
(2, 1, '工作台', 'index', 'dashboard', 'views/common/DashboardView', '', 'material-symbols:dashboard-rounded', 'drama:list', 'MENU', 0, 1, 1),
(3, 0, '内容管理', '/content', 'Content', '#', '/content/dramas', 'material-symbols:video-library-rounded', 'drama:list', 'CATALOG', 1, 0, 2),
(4, 3, '短剧管理', 'dramas', 'dramas', 'views/contentManagement/DramaManagementView', '', '', 'drama:list', 'MENU', 0, 0, 1),
(5, 3, '剧集管理', 'episodes', 'episodes', 'views/contentManagement/EpisodeManagementView', '', '', 'episode:list', 'MENU', 0, 0, 2),
(12, 3, '轮播图管理', 'banners', 'banners', 'views/contentManagement/BannerManagementView', '', '', 'banner:list', 'MENU', 0, 0, 3),
(13, 3, '类型管理', 'categories', 'categories', 'views/contentManagement/CategoryManagementView','', '', 'drama:list', 'MENU', 0, 0, 4),
(6, 0, '后台管理', '/system', 'System', '#', '/system/access', 'ep:setting', 'system:role', 'CATALOG', 1, 0, 3),
(6, 0, '后台管理', '/system', 'System', '#', '/system/access', 'material-symbols:settings-rounded', 'system:role', 'CATALOG', 1, 0, 3),
(7, 6, '角色权限配置', 'access', 'access', 'views/permission/RoleManagementView', '', '', 'system:role', 'MENU', 0, 0, 1),
(8, 6, '管理员用户列表','admin-users','admin-users', 'views/userManagement/AdminUsersView', '', '', 'system:admin-user','MENU', 0, 0, 2),
(9, 6, '菜单管理', 'menus', 'menus', 'views/permission/MenuManagementView', '', '', 'system:menu', 'MENU', 0, 0, 3),