2026-04-23 09:41:54 +08:00
|
|
|
|
## Work Log - 日记管理按 quiz 表与逻辑重构(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“用老工程表,参考老工程逻辑改造当前工程日记管理功能”要求,将 `fquiz` 的 `/admin/diary` 从系统日志复用页切换为独立 Diary 模块。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 后端模型与接口落地(对齐 quiz 口径):
|
|
|
|
|
|
- `api/app/models/diary.py`
|
|
|
|
|
|
- 新增主表 `diary`,字段:
|
|
|
|
|
|
- `id/title/content/diary_date/mood/weather/archived/create_date/create_user/update_date/update_user`
|
|
|
|
|
|
- 索引:`idx_diary_create_user/idx_diary_diary_date/idx_diary_mood/idx_diary_archived`。
|
|
|
|
|
|
- `api/app/schemas/diary.py`
|
|
|
|
|
|
- 新增 `DiaryMood` 枚举:`HAPPY/CALM/SAD/ANGRY/TIRED/EXCITED`。
|
|
|
|
|
|
- 新增 `DiaryQueryRequest/DiaryCreateRequest/DiaryUpdateRequest/DiarySummary/DiaryPageResponse`。
|
|
|
|
|
|
- `api/app/services/diary_service.py`
|
|
|
|
|
|
- 新增 create/search/get/update/delete/archive 逻辑。
|
|
|
|
|
|
- 查询逻辑对齐 quiz:按 `create_user` 隔离数据,支持 `title/mood/diary_date_start/diary_date_end/archived` 过滤,排序 `diary_date DESC, create_date DESC`。
|
|
|
|
|
|
- 归档逻辑对齐 quiz:`archive` 仅修改 `archived` 状态,保留原记录。
|
|
|
|
|
|
- `api/app/api/v1/diary.py`
|
|
|
|
|
|
- 新增接口:
|
|
|
|
|
|
- `POST /api/v1/diary/search`
|
|
|
|
|
|
- `GET /api/v1/diary/get/{id}`
|
|
|
|
|
|
- `POST /api/v1/diary/create`
|
|
|
|
|
|
- `PUT /api/v1/diary/update`
|
|
|
|
|
|
- `DELETE /api/v1/diary/delete/{id}`
|
|
|
|
|
|
- `POST /api/v1/diary/{id}/archive?archived=...`
|
|
|
|
|
|
- 权限口径:
|
|
|
|
|
|
- 读:`menu.read | menu.manage`
|
|
|
|
|
|
- 写:`menu.manage`
|
|
|
|
|
|
- 路由与建表注册:
|
|
|
|
|
|
- `api/app/api/router.py` 挂载 `diary` 路由。
|
|
|
|
|
|
- `api/app/models/__init__.py`、`api/app/core/database.py` 注册 `diary` 模型,确保 `create_all` 生效。
|
|
|
|
|
|
|
|
|
|
|
|
- 前端页面改造(替换 syslog 复用):
|
|
|
|
|
|
- `web/src/app/admin/diary/page.tsx`
|
|
|
|
|
|
- 改为独立 Diary 页面:
|
|
|
|
|
|
- 列表分页
|
|
|
|
|
|
- 条件查询(标题、心情、日期范围、归档状态)
|
|
|
|
|
|
- 新增 / 编辑 / 删除
|
|
|
|
|
|
- 归档 / 取消归档
|
|
|
|
|
|
- 详情弹窗
|
|
|
|
|
|
- API 调整到新后端接口 `/api/v1/diary/*`。
|
|
|
|
|
|
- `web/src/types/auth.ts`
|
|
|
|
|
|
- 新增 `DiaryMood/DiarySummary/DiaryListResponse` 类型。
|
|
|
|
|
|
- `web/src/app/admin/page.tsx`
|
|
|
|
|
|
- 首页卡片文案从“上帝视角”调整为“日记管理”。
|
|
|
|
|
|
- `api/app/services/seed_service.py`
|
|
|
|
|
|
- 菜单 `admin.diary` 名称更新为“日记管理”(路径保持 `/admin/diary`)。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `python3 -m py_compile api/app/models/diary.py api/app/schemas/diary.py api/app/services/diary_service.py api/app/api/v1/diary.py api/app/api/router.py api/app/models/__init__.py api/app/core/database.py api/app/services/seed_service.py` -> 通过。
|
|
|
|
|
|
- `python3 -m compileall api/app` -> 通过。
|
|
|
|
|
|
- 前端 ESLint 未完成(环境依赖缺失):
|
|
|
|
|
|
- `npm run lint` 提示 `eslint: not found`;
|
|
|
|
|
|
- 直接执行 eslint 后提示缺少 `typescript` 依赖(`Cannot find module 'typescript'`)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- `admin.diary` 保留 `menu.read/menu.manage` 权限体系(未引入独立 `diary.read/diary.manage`),属于兼容方案;后续若需要更细权限边界,可单独拆分权限码。
|
|
|
|
|
|
- 本次仅对齐了老工程 diary 主链路,不包含分组/tag 维度扩展(老工程该模块本身也未强依赖)。
|
2026-04-24 15:50:52 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 登录链路切换为 quiz 老表与老逻辑兼容(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“改用老工程 `/root/.openclaw/workspace/quiz` 中的表,参照老工程登录逻辑改造”要求,当前轮以“登录可用 + 会话鉴权可用 + 菜单可拉取”为最小闭环。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 登录请求契约切换:
|
|
|
|
|
|
- `api/app/schemas/auth.py`
|
|
|
|
|
|
- `LoginRequest` 从 `email + password` 改为 `user_id + password`(密码最小长度放宽为 1,兼容老库短密码)。
|
|
|
|
|
|
- `web/src/components/auth-provider.tsx`
|
|
|
|
|
|
- `login(...)` 传参改为 `user_id + password`,请求体同步改为 `{ user_id, password }`。
|
|
|
|
|
|
- `web/src/app/page.tsx`
|
|
|
|
|
|
- 登录表单输入从 `Email` 改为 `User ID`,记住密码缓存字段同步改为 `userId`。
|
|
|
|
|
|
|
|
|
|
|
|
- 密码与状态兼容:
|
|
|
|
|
|
- `api/app/core/security.py`
|
|
|
|
|
|
- `verify_password` 增加 `BCrypt` 兼容分支(老工程口令),保留现有 `Argon2` 支持。
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`(新增)
|
|
|
|
|
|
- 新增用户状态归一:`ENABLED/ACTIVE/1/TRUE -> active`,`DISABLED/... -> disabled`。
|
|
|
|
|
|
- `api/app/models/user.py`
|
|
|
|
|
|
- 用户默认状态改为 `ENABLED`;默认主键改为 `uuid4().hex`(32 位,兼容老表长度习惯)。
|
|
|
|
|
|
|
|
|
|
|
|
- 旧表角色/权限装配兼容层(核心):
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`(新增)
|
|
|
|
|
|
- 从老表链路读取授权信息:
|
|
|
|
|
|
- `user_role_rela -> user_role` 计算 `role_codes`
|
|
|
|
|
|
- `role_menu_rela -> menu` 映射 `permission_codes`
|
|
|
|
|
|
- 管理员识别兼容:`admin/sys_mgr/administrator` 或角色名含“管理员”,统一附加 `admin` 角色别名。
|
|
|
|
|
|
- 提供 `build_legacy_menu_tree(...)`,按老 `menu` 表生成 `/admin/me/menus` 所需菜单树。
|
|
|
|
|
|
|
|
|
|
|
|
- 后端鉴权链路接入兼容层:
|
|
|
|
|
|
- `api/app/services/auth_service.py`
|
|
|
|
|
|
- 登录改为按 `user_id` 查询。
|
|
|
|
|
|
- Access Token 的 `role_codes/permission_codes` 改为通过兼容层计算(不再依赖新 RBAC 表)。
|
|
|
|
|
|
- `api/app/core/dependencies.py`
|
|
|
|
|
|
- `get_current_user` 改为用户基础信息 + 兼容层授权计算。
|
|
|
|
|
|
- `api/app/api/v1/ws.py`
|
|
|
|
|
|
- WS 鉴权改为复用兼容层 `role_codes/permission_codes`。
|
|
|
|
|
|
- `api/app/services/jwt_generator_service.py`
|
|
|
|
|
|
- JWT 生成与用户列表角色展示改为兼容层口径,状态过滤兼容 `ENABLED`。
|
|
|
|
|
|
- `api/app/services/user_service.py`
|
|
|
|
|
|
- `serialize_user/queue_user_auth_refresh` 改为兼容层计算授权信息。
|
|
|
|
|
|
- 用户状态写入统一落库存储值 `ENABLED/DISABLED`。
|
|
|
|
|
|
- 用户角色更新改为直连老表 `user_role_rela` 写入(`rela_id + user_id + role_id`)。
|
|
|
|
|
|
- `api/app/services/admin_service.py`
|
|
|
|
|
|
- `build_menu_tree` 优先走老表菜单树构建,失败时回退现有实现。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 后端编译:
|
|
|
|
|
|
- `python3 -m py_compile api/app/services/legacy_authz_service.py api/app/core/security.py api/app/schemas/auth.py api/app/schemas/user.py api/app/services/auth_service.py api/app/core/dependencies.py api/app/services/user_service.py api/app/api/v1/ws.py api/app/services/jwt_generator_service.py api/app/services/admin_service.py api/app/models/user.py` -> 通过。
|
|
|
|
|
|
- `python3 -m compileall api/app` -> 通过。
|
|
|
|
|
|
- 前端构建:
|
|
|
|
|
|
- `npm run build:web` -> 失败(既有类型问题,非本轮新增):
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx:155`,`Card` 组件 `children` 类型不匹配(`ui-antd` 兼容层类型定义问题)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本轮优先闭环“登录 + 鉴权 + 菜单树”,未对 `admin/roles`、`admin/menus` 全量 CRUD 全面切换到老表语义;这些接口仍存在新旧口径混用风险。
|
|
|
|
|
|
- 旧表无独立 `permissions` 表,当前 `permission_codes` 为“角色菜单到权限码”的兼容映射;若老库菜单编码与映射不一致,可能出现权限显隐偏差。
|
|
|
|
|
|
- 注册接口当前保留并做了缺省兜底,但老库角色初始化策略(如默认 `user` 角色)依赖目标库实际数据,需联调确认。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第二轮:角色/菜单管理切换 quiz 老表口径(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“继续做第二轮”要求,将后台角色/菜单管理从现有 RBAC ORM 表切换为 quiz 老表链路,并同步前后端 ID 类型契约。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 后端接口与服务切换:
|
|
|
|
|
|
- `api/app/services/legacy_admin_rbac_service.py`
|
|
|
|
|
|
- 完成并启用老表 CRUD:
|
|
|
|
|
|
- 角色:`user_role`、`user_role_rela`、`role_menu_rela`
|
|
|
|
|
|
- 菜单:`menu`、`role_menu_rela`
|
|
|
|
|
|
- 支持:`list/get/create/update/delete role`、`list/get/create/update/delete menu`、`list/replace role menus`、`list permissions`。
|
|
|
|
|
|
- 保护项兼容:保留受保护角色与菜单编码删除拦截。
|
|
|
|
|
|
- 修复更新边界:`menu.parent_id` 支持显式清空;角色/菜单名称做 `strip` 空值校验。
|
|
|
|
|
|
- `api/app/api/v1/admin.py`
|
|
|
|
|
|
- 角色/菜单相关路由改为调用 `legacy_admin_rbac_service`。
|
|
|
|
|
|
- 角色/菜单 path 参数改为字符串:`role_id: str`、`menu_id: str`。
|
|
|
|
|
|
- `GET /admin/roles/{role_id}/menus` 返回改为 `list[str]`。
|
|
|
|
|
|
- `api/app/schemas/admin.py`
|
|
|
|
|
|
- 角色/菜单契约改为字符串 ID:
|
|
|
|
|
|
- `RolePublic.id`、`RolePublic.menu_ids`
|
|
|
|
|
|
- `RoleCreateRequest.menu_ids`、`RoleUpdateRequest.menu_ids`
|
|
|
|
|
|
- `MenuPublic.id`、`MenuPublic.parent_id`
|
|
|
|
|
|
- `MenuCreateRequest.parent_id`、`MenuUpdateRequest.parent_id`
|
|
|
|
|
|
- `RoleMenuUpdateRequest.menu_ids`
|
|
|
|
|
|
|
|
|
|
|
|
- 鉴权菜单树 ID 口径对齐:
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`
|
|
|
|
|
|
- `build_legacy_menu_tree` 改为直接使用老表 `menu.menu_id/parent_id` 作为菜单树 ID,不再生成临时递增 ID。
|
|
|
|
|
|
|
|
|
|
|
|
- 前端类型与页面对齐:
|
|
|
|
|
|
- `web/src/types/auth.ts`
|
|
|
|
|
|
- `RoleItem.id/menu_ids`、`MenuItem.id/parent_id` 改为字符串类型。
|
|
|
|
|
|
- `web/src/app/admin/roles/page.tsx`
|
|
|
|
|
|
- 角色编辑状态与 `menu_ids` 改为字符串口径。
|
|
|
|
|
|
- `web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
- 菜单编辑状态与 `parent_id` 改为字符串口径;
|
|
|
|
|
|
- ID 排序改为兼容字符串(纯数字优先数值比较,否则字典序)。
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 菜单路径项 `id` 改为字符串。
|
|
|
|
|
|
- `web/src/app/admin/users/page.tsx`
|
|
|
|
|
|
- 角色兜底项 `id` 改为字符串(`fallback-*`)。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 后端编译:
|
|
|
|
|
|
- `python3 -m py_compile api/app/schemas/admin.py api/app/api/v1/admin.py api/app/services/legacy_admin_rbac_service.py api/app/services/legacy_authz_service.py` -> 通过。
|
|
|
|
|
|
- `python3 -m compileall api/app` -> 通过。
|
|
|
|
|
|
- 前端构建:
|
|
|
|
|
|
- `npm run build:web` -> 失败,仍为既有问题:
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx:155`,`Card` 组件 `children` 类型不匹配(`ui-antd` 兼容层类型定义问题,非本轮新增)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 老表 `menu` 字段语义与当前前端展示字段并非一一对应(如 `component/cacheable`),当前仍为兼容映射;如需完全对齐 quiz UI 语义,后续需补充映射规则。
|
|
|
|
|
|
- `permissions` 仍是基于菜单编码映射的兼容推导;若线上老表菜单编码偏差,权限显示与鉴权可能出现边缘不一致,需要联调验证。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第三轮:前端构建门禁打通(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:第二轮后 `npm run build:web` 仍被前端类型问题阻断,影响发布门禁。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `antd Card` 类型兼容修复:
|
|
|
|
|
|
- `web/src/components/ui-antd.tsx`
|
|
|
|
|
|
- `Card` 包装器改用 `antd` 官方 `CardProps` 类型,不再依赖 `ComponentProps<typeof AntCard>` 推导。
|
|
|
|
|
|
- 对 `AntCard` 做显式可渲染组件收敛(`AntCardComponent`),避免 `JSX element type 'AntCard' does not have construct or call signatures`。
|
|
|
|
|
|
- 页面层统一复用兼容层 `Card`:
|
|
|
|
|
|
- `web/src/app/admin/mermaid-mgr/_components/mermaid-editor.tsx`
|
|
|
|
|
|
- `web/src/app/admin/mindmap/_components/mindmap-editor.tsx`
|
|
|
|
|
|
- 从 `antd` 直引 `Card` 改为 `@/components/ui-antd` 的 `Card`。
|
|
|
|
|
|
- 严格 TS 隐式 any 清理(与现有 strict 配置对齐):
|
|
|
|
|
|
- `web/src/app/admin/mermaid-mgr/_components/mermaid-editor.tsx`
|
|
|
|
|
|
- `web/src/app/admin/mermaid-mgr/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/mindmap/_components/mindmap-editor.tsx`
|
|
|
|
|
|
- `web/src/app/admin/schedule/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/todos/page.tsx`
|
|
|
|
|
|
- 补全 `onChange/onClick/onFinish/showTotal/footer` 等回调参数类型标注,消除 `noImplicitAny` 阻断。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm run build:web` -> 通过(TypeScript 检查通过 + 54 个页面静态生成完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本轮仅做类型与组件兼容修复,未改业务逻辑与接口契约。
|
|
|
|
|
|
- 后续若继续在 `web/src/app/admin/**` 新增 AntD 回调,仍需显式参数类型以避免 `strict` 下再次触发 `implicit any`。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第四轮:类型门禁巡检与基线固化(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:第三轮已打通 `build:web`,第四轮目标是做“全量巡检”防止同类问题回归。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次动作:
|
|
|
|
|
|
- 代码扫描:
|
|
|
|
|
|
- `web/src` 内 `import { Card } from "antd"`(避免回到不稳定类型入口);
|
|
|
|
|
|
- `onFinish/onChange/onClick/onPressEnter` 中常见未标注参数模式(`event/value/values/total/_`)。
|
|
|
|
|
|
- 类型基线检查:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false`。
|
|
|
|
|
|
|
|
|
|
|
|
- 结果:
|
|
|
|
|
|
- 扫描未发现新的高风险命中。
|
|
|
|
|
|
- `tsc --noEmit` 全量通过,`web` 当前类型门禁基线稳定。
|
|
|
|
|
|
|
|
|
|
|
|
- 影响:
|
|
|
|
|
|
- 第四轮未新增业务逻辑改动,属于稳定性巡检与基线确认。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第五轮:后端联调冒烟与运行时修复(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“继续第五轮”要求,对登录与后台角色/菜单主链路做联调冒烟,验证第二轮老表改造在运行容器中的真实表现。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次动作与发现:
|
|
|
|
|
|
- 容器代码加载校验:
|
|
|
|
|
|
- 初次冒烟发现运行中的 `api` 仍走旧登录契约(`email + password`),因此执行 `docker compose up --build -d api` 重新加载最新代码。
|
|
|
|
|
|
- 运行时阻断修复 1(启动失败):
|
|
|
|
|
|
- 重建后 `api` 启动报错:`ModuleNotFoundError: No module named 'bcrypt'`。
|
|
|
|
|
|
- 处理:`api/requirements.txt` 新增 `bcrypt==4.2.1`,重建 `api` 后恢复健康。
|
|
|
|
|
|
- 运行时阻断修复 2(`/admin/me/menus` 500):
|
|
|
|
|
|
- 冒烟命中 `500`,日志定位到 `legacy_authz_service.build_legacy_menu_tree` 使用了未定义变量 `node_id`。
|
|
|
|
|
|
- 处理:`api/app/services/legacy_authz_service.py` 将 `nodes[node_id]` 修正为 `nodes[legacy_id]`,重建后恢复。
|
|
|
|
|
|
|
|
|
|
|
|
- 冒烟验证(只读,不写库):
|
|
|
|
|
|
- 登录契约校验:
|
|
|
|
|
|
- `POST /api/v1/auth/login` 传 `{user_id, password}` -> 401(凭证错误,说明契约已生效);
|
|
|
|
|
|
- 传 `{email, password}` -> 422(缺少 `user_id`)。
|
|
|
|
|
|
- 管理后台主链路:
|
|
|
|
|
|
- `GET /api/v1/admin/roles` -> 200,`RolePublic.id/menu_ids` 为字符串;
|
|
|
|
|
|
- `GET /api/v1/admin/menus` -> 200,`MenuPublic.id/parent_id` 为字符串口径;
|
|
|
|
|
|
- `GET /api/v1/admin/me/menus` -> 200,菜单树根节点 `id` 为字符串;
|
|
|
|
|
|
- `GET /api/v1/admin/roles/sys_mgr/menus` -> 200,`menu_ids` 为字符串数组;
|
|
|
|
|
|
- `GET /api/v1/admin/permissions` -> 200。
|
|
|
|
|
|
|
|
|
|
|
|
- 相关文件:
|
|
|
|
|
|
- `api/requirements.txt`
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本轮未执行角色/菜单写接口(create/update/delete),避免对外部数据库产生变更;当前验证覆盖“登录契约 + 权限读取 + 菜单读取”读路径。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第六轮:修复日程页 Modal.footer 类型不兼容(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:`docker compose build web` 在 `web/src/app/admin/schedule/page.tsx:747` 失败,报错为 `Modal.footer` 回调签名不匹配(`OkBtn/CancelBtn` 被错误标注为 `() => ReactElement`)。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/admin/schedule/page.tsx`
|
|
|
|
|
|
- 补充 React 类型导入:`FC`、`ReactNode`。
|
|
|
|
|
|
- `Modal.footer` 回调类型从:
|
|
|
|
|
|
- `_origin: unknown`
|
|
|
|
|
|
- `{ OkBtn: () => ReactElement; CancelBtn: () => ReactElement }`
|
|
|
|
|
|
调整为:
|
|
|
|
|
|
- `_origin: ReactNode`
|
|
|
|
|
|
- `{ OkBtn: FC; CancelBtn: FC }`
|
|
|
|
|
|
- 保持现有按钮渲染与删除/保存逻辑不变,仅修复类型契约。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm run build:web` -> 通过(Next.js 编译、TypeScript 检查、静态页面生成全部完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 仅影响前端类型声明,不涉及接口契约、请求参数、业务分支和数据写入行为。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第七轮:后台系统菜单改用 AntD Menu 组件(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:当前后台左侧“系统菜单”是递归 `Button + Link`,移动端是 `DropdownMenu`。按要求切换为 Ant Design `Menu` 组件承载菜单树。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 新增 `Menu as AntMenu` 与 `MenuProps` 引入。
|
|
|
|
|
|
- 移除递归渲染函数 `renderMenuNodes` 与移动端 `flattenMenuPaths` 下拉菜单构建逻辑。
|
|
|
|
|
|
- 新增 `buildMenuItems`:把后端返回的 `MenuTreeItem[]` 转为 `AntMenu` 的 `items` 结构(支持嵌套)。
|
|
|
|
|
|
- 新增 `collectSubmenuKeys`:收集所有带子节点菜单并展开,保持与旧实现一致的“默认全展开”体验。
|
|
|
|
|
|
- 新增 `findActiveMenuState`:基于 `pathname` 计算 `selectedKeys/openKeys`,保证当前路由高亮准确。
|
|
|
|
|
|
- 桌面端左侧“系统菜单”改为 `AntMenu mode=\"inline\"` 渲染。
|
|
|
|
|
|
- 移动端菜单入口改为在卡片内直接渲染 `AntMenu mode=\"inline\"`(不再使用下拉菜单承载)。
|
|
|
|
|
|
- 顶部“账号”菜单保持原 `DropdownMenu` 方案不变。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `npm run build:web` -> 通过(Next.js 编译、TypeScript、静态页面生成全部完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 移动端菜单交互由“点击按钮弹出”改为“卡片内直接展示”,视觉高度会增加,但菜单可见性更高。
|
|
|
|
|
|
- 本次只调整菜单承载组件,不涉及菜单接口、权限判断和路由结构变更。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第八轮:菜单导航切回左侧布局(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:收到“menu 导航放到左侧”的要求,当前后台壳层为顶部横向 `Menu`,与期望不一致。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 移除顶部横向 `AntMenu(mode=\"horizontal\")` 导航区。
|
|
|
|
|
|
- 新增左侧栏布局(`md` 及以上):`AntMenu(mode=\"inline\")` 承载后台菜单树。
|
|
|
|
|
|
- 移动端菜单改为左侧 `Drawer`(`placement=\"left\"`)承载 `AntMenu`,顶部仅保留“菜单”按钮触发抽屉。
|
|
|
|
|
|
- 保留现有菜单数据来源(`/api/v1/admin/me/menus`)、路由高亮逻辑(`selectedKeys`)与账号区交互不变。
|
|
|
|
|
|
- 菜单展开状态统一为 `menuOpenKeys`,桌面侧栏与移动抽屉共用,保证一致性。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `npm run build:web` -> 通过(Next.js 编译、TypeScript、静态页面生成全部完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 布局从“顶部导航”改为“左侧导航”,横向空间分配会变化,但仅影响后台壳层,不涉及页面业务逻辑与接口契约。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第八轮:后台壳层改为顶部固定导航(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“参考 Ant Design 文档站顶部固定导航(左侧 Logo + 主导航)”要求,重构当前后台壳层布局。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 布局从“左侧固定菜单 + 内容头卡片”调整为“顶部固定导航 + 内容区”。
|
|
|
|
|
|
- 顶栏结构改为:左侧品牌 Logo(`Q + fquiz`)+ 中部主导航(`AntMenu mode=horizontal`)+ 右侧账号区。
|
|
|
|
|
|
- 保留现有菜单数据链路:继续通过 `/api/v1/admin/me/menus` 拉取并渲染树形菜单。
|
|
|
|
|
|
- 保留路由高亮逻辑,并补充 `openKeys` 计算用于移动端内嵌菜单展开。
|
|
|
|
|
|
- 新增移动端菜单折叠入口(`菜单/收起菜单`),避免小屏导航不可达。
|
|
|
|
|
|
- 保留 `menuError` 提示、登录态判断与账号退出逻辑,不改接口契约。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm run build:web` -> 通过(Next.js 编译、TypeScript 检查、静态页面生成全部完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 桌面端导航入口从左侧改为顶部,用户需要适应新的操作路径。
|
|
|
|
|
|
- 当顶级菜单数量较多时,水平菜单会进入 AntD 的溢出折叠(`...`)交互,属于组件默认行为。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第九轮:84 库用户/角色/菜单数据导出并初始化本地库(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“查询 84 的用户表、角色表、菜单表、菜单角色关系数据,然后初始化本地库”要求执行。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次动作(最小闭环):
|
|
|
|
|
|
- 远端 84 库(`223.109.142.84:5432/postgres`)连通与数据核验:
|
|
|
|
|
|
- 表存在:`users / user_role / menu / role_menu_rela`。
|
|
|
|
|
|
- 行数:`users=5`、`user_role=6`、`menu=64`、`role_menu_rela=123`。
|
|
|
|
|
|
- 数据导出留档:
|
|
|
|
|
|
- CSV 导出文件:
|
|
|
|
|
|
- `tmp/84-export/users_84.csv`
|
|
|
|
|
|
- `tmp/84-export/user_role_84.csv`
|
|
|
|
|
|
- `tmp/84-export/menu_84.csv`
|
|
|
|
|
|
- `tmp/84-export/role_menu_rela_84.csv`
|
|
|
|
|
|
- 初始化脚本导出:
|
|
|
|
|
|
- `tmp/84-export/legacy_auth_schema.sql`
|
|
|
|
|
|
- `tmp/84-export/legacy_auth_data.sql`
|
|
|
|
|
|
- `tmp/84-export/legacy_auth_data_wrapped.sql`
|
|
|
|
|
|
- 本地库初始化:
|
|
|
|
|
|
- 目标库:本地 `fquiz-db` 的 `postgres` 数据库(用户 `fquiz`)。
|
|
|
|
|
|
- 先 `DROP TABLE IF EXISTS public.role_menu_rela, public.menu, public.user_role, public.users CASCADE`。
|
|
|
|
|
|
- 回放 schema + data 完成建表和数据导入。
|
|
|
|
|
|
- 由于 `menu.parent_id` 自关联外键,导入数据时在同一会话启用 `session_replication_role=replica` 后回放,导入成功。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 远端与本地(postgres)按表对比 `count + md5(signature)` 全量一致:
|
|
|
|
|
|
- `users`: `5` / `a50fedde66f156b0442d792b42c355b7`
|
|
|
|
|
|
- `user_role`: `6` / `7fb7d2520f44efe25e8be15762a3bd3d`
|
|
|
|
|
|
- `menu`: `64` / `094b533fe91b853868a0f9e4356da49a`
|
|
|
|
|
|
- `role_menu_rela`: `123` / `3c752bb95375e80d835b198831d44535`
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本次初始化目标是本地 `postgres` 库,不影响本地 `fquiz` 库现有表数据。
|
|
|
|
|
|
- `users` 表为老工程结构(`user_id/user_name/password/state...`),与新表结构不同;后续若切回新 RBAC 表需区分数据库与表口径。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第十轮:数据库默认目标切换到本地并修复启动兼容(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“现在切到本地库,不用84了”要求,将默认数据库目标从 `223.109.142.84` 切到本地 `fquiz-db`。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `docker-compose.yml`
|
|
|
|
|
|
- `db` 服务移除 `local-db` profile,改为默认启动。
|
|
|
|
|
|
- `api` 新增 `depends_on: db (service_healthy)`。
|
|
|
|
|
|
- `api` 的默认 DB 参数切到本地:
|
|
|
|
|
|
- `DB_HOST=db`
|
|
|
|
|
|
- `DB_PORT=5432`
|
|
|
|
|
|
- `DB_NAME=postgres`
|
|
|
|
|
|
- `DB_USERNAME=fquiz`
|
|
|
|
|
|
- `DB_PASSWORD=fquiz`
|
|
|
|
|
|
- `api/app/core/config.py`
|
|
|
|
|
|
- 非 Docker 默认 DB 参数改为本机本地库:
|
|
|
|
|
|
- `db_host=127.0.0.1`
|
|
|
|
|
|
- `db_port=5433`
|
|
|
|
|
|
- `db_name=postgres`
|
|
|
|
|
|
- `db_username=fquiz`
|
|
|
|
|
|
- `db_password=fquiz`
|
|
|
|
|
|
- `.env.example`
|
|
|
|
|
|
- 同步改为本机本地库默认值(不再出现 84 默认地址)。
|
|
|
|
|
|
- `api/app/services/seed_service.py`
|
|
|
|
|
|
- `_seed_initial_admin` 中初始管理员状态由 `active` 调整为 `ENABLED`,兼容老 `users.state` 约束,解决本地库启动时 `users_state_check` 报错。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `python3 -m py_compile api/app/services/seed_service.py` -> 通过。
|
|
|
|
|
|
- `docker compose up -d --build api` -> 通过,`fquiz-api` 正常启动。
|
|
|
|
|
|
- `docker compose ps` -> `api/db/web` 全部 `healthy/up`。
|
|
|
|
|
|
- `GET /health` -> 200。
|
|
|
|
|
|
- `POST /api/v1/auth/login`(错误密码探测)-> 401(说明 API 可用且查询链路正常)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 默认目标已改为本地库;若后续要临时连外部库,需显式设置 `DATABASE_URL` 或覆盖 `DB_HOST` 等环境变量。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第十一轮:后台菜单改为左侧内嵌并支持右上角显隐(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“改成内嵌菜单,放在页面左侧,通过右上角菜单按钮隐藏/显示”要求调整后台壳层交互。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 移除移动端 `Drawer` 侧滑菜单方案,统一为页面内嵌左侧菜单。
|
|
|
|
|
|
- 新增状态 `menuVisible`,默认 `true`,控制左侧菜单区域显示/隐藏。
|
|
|
|
|
|
- 顶栏右上角“菜单”按钮改为全端可见,并切换文案:
|
|
|
|
|
|
- 菜单显示时:`隐藏菜单`
|
|
|
|
|
|
- 菜单隐藏时:`显示菜单`
|
|
|
|
|
|
- 内容区网格列根据 `menuVisible` 动态切换:
|
|
|
|
|
|
- 显示:`md:grid-cols-[280px_minmax(0,1fr)]`
|
|
|
|
|
|
- 隐藏:`md:grid-cols-1`
|
|
|
|
|
|
- 左侧菜单保留 `AntMenu inline` + `openKeys/selectedKeys` 逻辑,保持当前路由高亮与展开行为。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `next build` 多次在当前环境命中 `.next` 产物文件 `ENOENT`(非本次业务逻辑错误):
|
|
|
|
|
|
- Turbopack 路径:`_buildManifest.js.tmp` 丢失;
|
|
|
|
|
|
- Webpack 路径:`edge-runtime-webpack.js` copyfile 丢失。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本次仅改后台壳层菜单交互,不涉及 API 契约和业务数据写入。
|
|
|
|
|
|
- 当前构建环境存在 `.next` 产物落盘异常,影响 `build:web` 门禁稳定性(与菜单逻辑无直接耦合)。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第十二轮:支持主题色切换并持久化(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“支持主题色切换”要求,增加可视化主题色切换入口,并要求刷新后保持。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/components/ui-antd.tsx`
|
|
|
|
|
|
- 新增主题外观上下文 `ThemeAppearanceContext`。
|
|
|
|
|
|
- 新增 `useThemeAppearance()`,对外暴露:
|
|
|
|
|
|
- `accentColor`
|
|
|
|
|
|
- `setAccentColor(...)`
|
|
|
|
|
|
- 新增 `THEME_ACCENT_OPTIONS`(靛蓝/蓝色/青色/绿色/橙色/红色/粉色/紫色)。
|
|
|
|
|
|
- `Theme` 组件增加主题色状态与持久化:
|
|
|
|
|
|
- 启动时读取 `localStorage["fquiz:theme:accent-color"]`
|
|
|
|
|
|
- 切换后写回 localStorage
|
|
|
|
|
|
- 切换即更新 AntD `ConfigProvider` 的 `colorPrimary`,全局生效。
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 顶栏右侧新增主题色选择器(`Select`),使用 `THEME_ACCENT_OPTIONS` 渲染。
|
|
|
|
|
|
- 选择器值绑定 `useThemeAppearance().accentColor`,变更时调用 `setAccentColor`。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `npm run build:web` -> 通过(Next.js 编译、TypeScript、静态页面生成全部完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 主题色选择属于前端 UI 层改动,不影响后端接口与数据模型。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 登录页怪兽主视觉改为“毛怪 + 大眼仔”双角色(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“把登录页面的怪兽换成毛怪和大眼仔”要求,保留登录/注册链路不变,仅重做首页登录视觉。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/page.tsx`
|
|
|
|
|
|
- 保留 `useAuth` 登录/注册/退出与表单提交流程不变。
|
|
|
|
|
|
- 将单怪兽舞台替换为双角色舞台:`sulley + mike`。
|
|
|
|
|
|
- 保留“眼睛跟随鼠标”交互,并新增大眼仔眼球偏移参数(`MIKE_GAZE_MAX_X/Y`)。
|
|
|
|
|
|
- 保留“密码输入时挪开视线”交互:毛怪转头避视、大眼仔轻微眯眼。
|
|
|
|
|
|
- 替换旧 `.monster-*` 样式为 `.duo-* / .sulley-* / .mike-*` 样式,维持响应式布局与背景动效。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `npm run build:web` -> 通过(Next.js 编译、TypeScript、静态页面生成全部完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本次为前端视觉层改动,不涉及 API 契约、鉴权逻辑或后端数据结构。
|
|
|
|
|
|
- 角色形象为页面内 CSS 卡通实现,不依赖外部图片资源。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第九轮:按 AntD 配色收口全局变量(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:当前前端虽然已切到 AntD 组件栈,但大量页面仍使用历史 `--gray-* / --accent-*` 变量与 Tailwind 类,导致视觉不完全跟随 AntD 主题色。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/components/ui-antd.tsx`
|
|
|
|
|
|
- 在 `Theme` 内新增 `ThemeCssVarsScope`,通过 `antdTheme.useToken()` 把旧语义变量映射到 AntD token。
|
|
|
|
|
|
- 覆盖变量包括:
|
|
|
|
|
|
- AntD 直连变量:`--ant-color-primary`、`--ant-color-bg-layout`、`--ant-color-border-secondary`、`--ant-color-text-secondary`、`--ant-color-text`
|
|
|
|
|
|
- 旧语义变量:`--gray-*`、`--accent-*`、`--red-*`、`--green-*`、`--orange-*`、`--indigo-*`、`--color-panel-solid`、`--border`
|
|
|
|
|
|
- 通过 `display: contents` 避免新增布局层级影响页面结构。
|
|
|
|
|
|
- `web/src/app/globals.css`
|
|
|
|
|
|
- 新增上述变量的静态兜底值,避免主题注入前变量缺失。
|
|
|
|
|
|
- `body` 背景与文字颜色改为走 AntD 变量(`--ant-color-bg-layout`、`--ant-color-text`)。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `npm run build:web` -> 通过(Next.js 编译、TypeScript、静态页面生成全部完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本次不改接口与业务逻辑,仅调整前端主题变量层与全局视觉基线。
|
|
|
|
|
|
- 旧页面里保留的 `var(--gray/* --accent/*)` 写法将统一跟随 AntD token,后续可按需渐进式替换为原生 AntD token class/style。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第十轮:去掉前端 URL 的 `/admin` 前缀(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:希望用户侧访问地址不再出现 `/admin`,但保留现有 `app/admin/**` 页面实现与权限链路。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/middleware.ts`(新增)
|
|
|
|
|
|
- 新地址(不含 `/admin`)统一 rewrite 到现有 `/admin/**` 页面路由。
|
|
|
|
|
|
- 旧地址 `/admin/**` 自动 redirect 到无前缀地址,兼容历史链接与书签。
|
|
|
|
|
|
- 根路径 `/`、`/api`、`/_next`、常见静态文件请求走 bypass,不参与改写。
|
|
|
|
|
|
- 约定:原 `/admin` 首页映射为 `/dashboard`。
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 菜单数据加载后统一把 `path` 从 `/admin/**` 规范化为无前缀地址(`/admin` -> `/dashboard`)。
|
|
|
|
|
|
- 顶部 Logo 跳转从 `/admin` 改为 `/dashboard`。
|
|
|
|
|
|
- `web/src/app/page.tsx`
|
|
|
|
|
|
- 首页快捷入口改为无前缀地址:`/dashboard`、`/users`、`/requirements`。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `npm run build:web` -> 通过(含 Proxy/Middleware 生效,编译与静态生成完成)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 现有硬编码 `/admin/**` 链接仍可用,但会发生一次 30x 重定向到无前缀地址。
|
|
|
|
|
|
- Next.js 16 对 `middleware` 命名提示迁移到 `proxy`,当前功能正常;后续可按官方建议改名以消除提示。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 第十轮:下线 8 个后台功能(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按“删除生命倒计时、密钥管理、价格监控、历史答卷、诗词本、日记管理、家庭作业、试题管理功能”要求,执行最小闭环下线。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 菜单与权限口径收敛:
|
|
|
|
|
|
- `api/app/services/seed_service.py`
|
|
|
|
|
|
- 移除默认菜单:
|
|
|
|
|
|
- `admin.life_countdown`
|
|
|
|
|
|
- `admin.password`
|
|
|
|
|
|
- `admin.token_usage`
|
|
|
|
|
|
- `admin.history`
|
|
|
|
|
|
- `admin.vocabulary`
|
|
|
|
|
|
- `admin.diary`
|
|
|
|
|
|
- `admin.homework`
|
|
|
|
|
|
- `admin.question_bank`
|
|
|
|
|
|
- `ROLE_MENU_BINDINGS["admin"]` 同步移除上述菜单。
|
|
|
|
|
|
- 移除默认权限 `life_countdown.read/manage`。
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`
|
|
|
|
|
|
- 将上述 8 个菜单加入 `DISABLED_MENU_CODES`,保证老库已有记录也不会再出现在 `/api/v1/admin/me/menus`。
|
|
|
|
|
|
- 权限映射移除对应菜单码;补充 `admin.job_mgr -> question_bank.read/manage`,确保“作业监控”权限链路不受影响。
|
|
|
|
|
|
- `api/app/services/legacy_admin_rbac_service.py`
|
|
|
|
|
|
- 增加 `REMOVED_MENU_CODES` 过滤:菜单列表、角色菜单返回、权限推导、菜单可用性校验均排除已下线菜单。
|
|
|
|
|
|
- `api/app/services/admin_service.py`
|
|
|
|
|
|
- 受保护菜单集合同步移除上述 8 个菜单码(兼容回退路径)。
|
|
|
|
|
|
- `web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
- 前端受保护菜单集合同步移除上述 8 个菜单码。
|
|
|
|
|
|
|
|
|
|
|
|
- 后端接口下线:
|
|
|
|
|
|
- `api/app/api/router.py`
|
|
|
|
|
|
- 不再挂载 `diary_router` 与 `life_countdown_router`。
|
|
|
|
|
|
- `api/app/api/v1/admin.py`
|
|
|
|
|
|
- 删除密钥管理专用接口:
|
|
|
|
|
|
- `GET /api/v1/admin/password/models`
|
|
|
|
|
|
- `GET /api/v1/admin/password/models/{model_id}/keys`
|
|
|
|
|
|
- `POST /api/v1/admin/password/models/{model_id}/rotate-key`
|
|
|
|
|
|
|
|
|
|
|
|
- 前端页面下线:
|
|
|
|
|
|
- 删除路由页面:
|
|
|
|
|
|
- `web/src/app/admin/life-countdown/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/password/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/price-monitor/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/token-usage/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/history/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/poetry/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/diary/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/homework/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/question-bank/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/vocabulary/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/page.tsx` 移除上述功能卡片入口。
|
|
|
|
|
|
- `web/src/app/admin/vocabulary-proficiency/page.tsx` 移除“进入诗词本”跳转按钮。
|
|
|
|
|
|
- 保留“作业监控”功能:
|
|
|
|
|
|
- 将原 `question-bank` 页面实现迁移到 `web/src/app/admin/job/_components/job-question-bank-page.tsx`,
|
|
|
|
|
|
- `web/src/app/admin/job/page.tsx` 改为引用该实现。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 后端语法校验:
|
|
|
|
|
|
- `python3 -m py_compile api/app/services/seed_service.py api/app/services/legacy_authz_service.py api/app/services/legacy_admin_rbac_service.py api/app/services/admin_service.py api/app/api/v1/admin.py api/app/api/router.py` -> 通过。
|
|
|
|
|
|
- `python3 -m compileall api/app` -> 通过。
|
|
|
|
|
|
- 前端构建:
|
|
|
|
|
|
- `npm run build:web` -> 通过。
|
|
|
|
|
|
- 输出路由确认已不再生成:
|
|
|
|
|
|
- `/admin/life-countdown`、`/admin/password`、`/admin/price-monitor`、`/admin/token-usage`、`/admin/history`、`/admin/poetry`、`/admin/diary`、`/admin/homework`、`/admin/question-bank`、`/admin/vocabulary`。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本次下线为“菜单 + 路由 + 部分接口”闭环;`question_bank` 与 `vocabulary` 底层 API 仍保留,供“作业监控/分组管理/知识点管理/单词统计”等保留模块复用。
|
|
|
|
|
|
- 若线上老库仍有已下线菜单记录,当前会被服务层过滤,不再对外展示。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 下线 8 个后台功能模块(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按要求删除系统中的以下功能:
|
|
|
|
|
|
- 微信小程序(`admin.wxapp`)
|
|
|
|
|
|
- MD解析(`admin.mdresolve`)
|
|
|
|
|
|
- 数据查询(`admin.data_query`)
|
|
|
|
|
|
- 热搜(`admin.hot_search`)
|
|
|
|
|
|
- 文件识别(`admin.filedetector`)
|
|
|
|
|
|
- 百度网盘(`admin.baidu_pan`)
|
|
|
|
|
|
- 分组管理(`admin.tag`)
|
|
|
|
|
|
- 知识点管理(`admin.knowledge_point_mgr`)
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 前端:删除 8 个页面路由文件(访问即 404):
|
|
|
|
|
|
- `web/src/app/admin/wxapp/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/mdresolve/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/data-query/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/hot-search/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/filedetector/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/baidu-pan/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/group/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/knowledge/page.tsx`
|
|
|
|
|
|
- 前端:移除后台首页入口卡片:
|
|
|
|
|
|
- `web/src/app/admin/page.tsx`
|
|
|
|
|
|
- 前端:菜单管理页取消上述 8 个菜单码的“受保护菜单”限制(允许删除历史残留菜单):
|
|
|
|
|
|
- `web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
|
|
|
|
|
|
- 后端:菜单树硬过滤(即使老库仍有菜单记录,也不会下发给前端导航):
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`
|
|
|
|
|
|
- 新增 `DISABLED_MENU_CODES` 并在菜单树构建、权限推导时过滤。
|
|
|
|
|
|
- `api/app/services/admin_service.py`
|
|
|
|
|
|
- 新增 `REMOVED_MENU_CODES` 并在 `list_menus/get_menu_by_id/get_menu_by_code/create_menu/build_menu_tree/_load_menus_by_ids` 过滤。
|
|
|
|
|
|
- `api/app/services/legacy_admin_rbac_service.py`
|
|
|
|
|
|
- 将 8 个菜单码加入 `REMOVED_MENU_CODES`,统一影响菜单列表、角色菜单关联、权限推导。
|
|
|
|
|
|
|
|
|
|
|
|
- 后端:停用对应接口挂载与默认种子:
|
|
|
|
|
|
- `api/app/api/router.py`
|
|
|
|
|
|
- 移除 `hot_search_router` 与 `mdresolve_router` 挂载。
|
|
|
|
|
|
- `api/app/services/topic_registry.py`
|
|
|
|
|
|
- 移除 `admin.hot_search` 与 `admin.hot_search.follow_topics` topic 规则。
|
|
|
|
|
|
- `api/app/services/seed_service.py`
|
|
|
|
|
|
- 移除 8 个菜单定义与 admin 默认菜单绑定。
|
|
|
|
|
|
- 移除 `seed_hot_search_defaults` 导入与调用。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `python3 -m py_compile api/app/services/legacy_authz_service.py api/app/services/seed_service.py api/app/api/router.py api/app/services/topic_registry.py api/app/services/legacy_admin_rbac_service.py api/app/services/admin_service.py` -> 通过。
|
|
|
|
|
|
- `python3 -m compileall api/app` -> 通过。
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `npm run build:web` -> 通过;后台静态路由从 54 个下降到 36 个,已不再包含上述 8 个页面。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 本次不做数据库物理删行迁移;若库内仍有历史菜单记录,将被后端过滤而不可见。
|
|
|
|
|
|
- `api/app/api/v1/hot_search.py` 与 `api/app/api/v1/mdresolve.py` 文件仍保留在仓库,但未挂载到 `api_router`,外部不可访问。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 下线功能补充收口(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 补充改动:
|
|
|
|
|
|
- 删除历史别名页面 `web/src/app/admin/tag/page.tsx`,彻底下线“分组管理”的旧路由入口。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证补充:
|
|
|
|
|
|
- 因删除页面后 `.next` 残留类型缓存导致 `tsc` 引用旧路径,执行 `rm -rf web/.next` 后重跑:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过
|
|
|
|
|
|
- `npm run build:web` -> 通过
|
|
|
|
|
|
- 产物路由确认不再包含 `/admin/tag` 及本轮下线的 8 个功能页面。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 下线 4 个后台功能模块(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:按要求删除以下功能:
|
|
|
|
|
|
- 脚本管理(`admin.cron_task_mgr`)
|
|
|
|
|
|
- 待办管理(`admin.todos`)
|
|
|
|
|
|
- 作业监控(`admin.job_mgr`)
|
|
|
|
|
|
- JWT 生成器(`admin.jwt_generator`)
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 前端下线:
|
|
|
|
|
|
- 删除路由页面:
|
|
|
|
|
|
- `web/src/app/admin/cron/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/todos/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/job/page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/jwt-generator/page.tsx`
|
|
|
|
|
|
- 后台首页移除 4 个入口卡片:
|
|
|
|
|
|
- `web/src/app/admin/page.tsx`
|
|
|
|
|
|
- 菜单管理页移除 4 个菜单码受保护限制(允许清理历史残留):
|
|
|
|
|
|
- `web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
- 为保留“队列管理”能力,将原待办页面实现迁移到:
|
|
|
|
|
|
- `web/src/app/admin/jobqueue/_components/jobqueue-todo-page.tsx`
|
|
|
|
|
|
- `web/src/app/admin/jobqueue/page.tsx` 改为引用新组件。
|
|
|
|
|
|
|
|
|
|
|
|
- 后端菜单/权限链路下线:
|
|
|
|
|
|
- `api/app/services/seed_service.py`
|
|
|
|
|
|
- 移除 4 个菜单定义及 admin 默认菜单绑定。
|
|
|
|
|
|
- 移除 `jwt_generator.read/jwt_generator.manage` 默认权限与 admin 角色默认绑定。
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`
|
|
|
|
|
|
- 将 4 个菜单码加入 `DISABLED_MENU_CODES`,并移除对应菜单权限映射。
|
|
|
|
|
|
- 移除 `DEFAULT_ADMIN_PERMISSION_CODES` 中 `jwt_generator.*`。
|
|
|
|
|
|
- `api/app/services/legacy_admin_rbac_service.py`
|
|
|
|
|
|
- 将 4 个菜单码加入 `REMOVED_MENU_CODES`。
|
|
|
|
|
|
- `api/app/services/admin_service.py`
|
|
|
|
|
|
- 将 4 个菜单码加入 `REMOVED_MENU_CODES`,并从受保护删除集合中移除。
|
|
|
|
|
|
|
|
|
|
|
|
- 后端接口挂载下线:
|
|
|
|
|
|
- `api/app/api/router.py`
|
|
|
|
|
|
- 移除 `jwt_generator_router` import 与 `include_router`,JWT 生成器 API 不再对外挂载。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `python3 -m py_compile api/app/services/seed_service.py api/app/services/legacy_authz_service.py api/app/services/legacy_admin_rbac_service.py api/app/services/admin_service.py api/app/api/router.py` -> 通过。
|
|
|
|
|
|
- `python3 -m compileall api/app` -> 通过。
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
- `npm --workspace web exec next build --webpack` -> 通过;产物路由确认不再包含:
|
|
|
|
|
|
- `/admin/cron`
|
|
|
|
|
|
- `/admin/todos`
|
|
|
|
|
|
- `/admin/job`
|
|
|
|
|
|
- `/admin/jwt-generator`
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- `api/app/api/v1/jwt_generator.py` 文件仍保留在仓库,但已从路由汇总中移除,不可外部访问。
|
|
|
|
|
|
- 当前环境下 Next 构建偶发 `.next` 产物拷贝 `ENOENT` 警告(非本次改动引入,存在环境不稳定性);本轮最终构建已成功产出路由清单。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 修复 `/users` 首屏卡在 Loading(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:访问 `http://localhost:3000/users` 时,后台壳层页面一直停留在 `Loading admin workspace...`。
|
|
|
|
|
|
|
|
|
|
|
|
- 根因:
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx` 的 `loadMenus` 仅处理了接口返回 `!ok` 场景;
|
|
|
|
|
|
- 当 `fetchWithAuth("/api/v1/admin/me/menus")` 发生网络异常(例如 API 未启动、连接失败)抛出异常时,没有兜底 `catch/finally`,导致 `loadingMenus` 一直为 `true`。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- `loadMenus` 增加 `try/catch/finally`。
|
|
|
|
|
|
- 异常场景下会:
|
|
|
|
|
|
- 清空 `menuTree`
|
|
|
|
|
|
- 设置 `menuError`(显示可见错误)
|
|
|
|
|
|
- 在 `finally` 中统一 `setLoadingMenus(false)`,避免页面卡死在 loading。
|
|
|
|
|
|
- 无用户场景补充 `setMenuError("")`,避免遗留错误文案。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 仅涉及后台壳层菜单加载状态管理,不改接口契约与业务数据。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 默认 admin 视为全权限(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:要求“默认 admin 有全部权限”。
|
|
|
|
|
|
|
|
|
|
|
|
- 现状定位:
|
|
|
|
|
|
- 后端接口鉴权已具备 `admin` 角色兜底(`require_permission/require_any_permission` 中 `if "admin" in role_codes: allow`)。
|
|
|
|
|
|
- 前端权限判定 `hasPermission` 仅判断 `permission_codes.includes(...)`,未对 `admin` 角色做兜底,可能导致 admin 页面按钮/入口被误隐藏。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/components/auth-provider.tsx`
|
|
|
|
|
|
- `hasPermission` 调整为:
|
|
|
|
|
|
- 若用户角色包含 `admin`,直接返回 `true`;
|
|
|
|
|
|
- 否则按原逻辑判断 `permission_codes`。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 先清理 Next 类型缓存:`rm -rf web/.next`
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 仅影响前端可见性与交互开关判定,不改后端鉴权规则。
|
|
|
|
|
|
- 后端仍保持真实权限校验,前端放行不会绕过服务端安全边界。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 去掉登录后首页,直接进入后台(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:要求“去掉首页,登录完成直接进入后台”。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/page.tsx`
|
|
|
|
|
|
- 移除已登录态的首页欢迎面板(欢迎文案 / Ping / 快捷入口)。
|
|
|
|
|
|
- 新增登录态跳转:当 `!initializing && user` 时执行 `router.replace("/dashboard")`。
|
|
|
|
|
|
- 已登录时仅短暂显示“正在进入后台...”,避免闪现旧首页内容。
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 未登录访问后台时按钮文案从“返回首页”调整为“前往登录”(`/`)。
|
|
|
|
|
|
- 账号下拉中的“返回首页”调整为“后台首页”(`/dashboard`)。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 仅涉及前端路由与文案,不改后端接口与鉴权逻辑。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 右上角账号入口改为 Avatar(2026-04-23)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:要求“右上角账号改成 avatar 组件”。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 顶部账号下拉触发器由“账号”按钮改为 AntD `Avatar`。
|
|
|
|
|
|
- 头像文案取当前用户名首字母(大写),空值兜底 `U`。
|
|
|
|
|
|
- 保持原下拉菜单项不变(账号信息、后台首页、退出登录)。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 仅涉及前端展示与交互入口样式,不改业务逻辑与接口调用。
|