2026-05-01 08:54:24 +08:00
|
|
|
|
## Work Log - 修复 API 启动阶段 users 主键列兼容问题(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 启动报错 `psycopg.errors.UndefinedColumn: column users.user_id does not exist`,触发点在 `seed_defaults -> _seed_permissions` 的关系加载 SQL。
|
|
|
|
|
|
- 当前 ORM 与外键约定统一使用 `users.user_id`,但历史库可能残留 `users.id` 主键列命名。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动:
|
|
|
|
|
|
- `api/app/core/database.py`
|
|
|
|
|
|
- 新增 `_ensure_user_pk_column_compatibility()`。
|
|
|
|
|
|
- 在 `init_db()` 执行 `Base.metadata.create_all()` 前,针对 PostgreSQL 做一次兼容检查:
|
|
|
|
|
|
- 若 `users` 表存在,且检测到仅有 `id` 而没有 `user_id`,自动执行:`ALTER TABLE users RENAME COLUMN id TO user_id`。
|
|
|
|
|
|
- 其余情况不改动(已是 `user_id` 或两者都不存在时直接跳过)。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 在 `fquiz-api` 容器内执行 `init_db()`:`init_db_ok`。
|
|
|
|
|
|
- 在 `fquiz-api` 容器内执行查询,确认当前数据库 `users` 列包含 `user_id`。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围:仅 PostgreSQL 且仅触发于“存在 `users.id` 且缺少 `users.user_id`”的历史库。
|
|
|
|
|
|
- 该变更属于启动期一次性 DDL 兼容动作;对已规范为 `users.user_id` 的库无行为变化。
|
2026-05-01 10:05:26 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 修复 API 启动时报 users.user_name / users.username 列不一致(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- API 启动阶段在 `seed_defaults -> _seed_permissions` 查询中触发 ORM 关系预加载,SQL 使用了 `users.user_name`,但当前 PostgreSQL `users` 表实际字段为 `username`,导致 `psycopg.errors.UndefinedColumn`,服务启动失败。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`api/app/core/config.py`
|
|
|
|
|
|
- 新增配置 `user_username_column`(环境变量 `USER_USERNAME_COLUMN`),可选值 `username` / `user_name`,默认 `username`。
|
|
|
|
|
|
- 文件:`api/app/models/user.py`
|
|
|
|
|
|
- `User.username` 列改为基于 `settings.user_username_column` 动态映射,兼容两类历史库结构。
|
|
|
|
|
|
- 文件:`docker-compose.yml`
|
|
|
|
|
|
- 为 `api` / `celery-worker` / `celery-beat` 注入 `USER_USERNAME_COLUMN` 环境变量透传。
|
|
|
|
|
|
- 文件:`.env.example`
|
|
|
|
|
|
- 新增 `USER_USERNAME_COLUMN=username` 示例配置。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `python3 -m py_compile api/app/core/config.py api/app/models/user.py api/app/services/seed_service.py` -> 通过。
|
|
|
|
|
|
- `USER_USERNAME_COLUMN=user_name POSTGRES_PORT=5434 docker compose up -d --no-deps api` -> 启动成功。
|
|
|
|
|
|
- `USER_USERNAME_COLUMN=user_name POSTGRES_PORT=5434 docker compose ps api` -> `Up (healthy)`。
|
|
|
|
|
|
- `curl -fsS http://127.0.0.1:8000/health` -> `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响面集中在 `User` 模型用户名字段映射。
|
|
|
|
|
|
- 运行环境需明确 `USER_USERNAME_COLUMN` 与目标数据库实际字段一致;配置错误会在启动阶段继续抛 `UndefinedColumn`。
|
2026-05-01 10:31:56 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - GitHub Actions 部署分支切换为 dev(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 当前 workflow 仅监听 `main` push,且 deploy job 条件写死为 `refs/heads/main`,导致 `dev` 推送不触发自动部署。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小改动):
|
|
|
|
|
|
- 文件:`.github/workflows/main.yml`
|
|
|
|
|
|
- `on.push.branches` 从 `main` 改为 `dev`。
|
|
|
|
|
|
- `deploy.if` 从 `github.ref == 'refs/heads/main'` 改为 `github.ref == 'refs/heads/dev'`。
|
|
|
|
|
|
|
|
|
|
|
|
- 预期行为:
|
|
|
|
|
|
- `git push origin dev`:自动触发构建,并在构建成功后执行 deploy。
|
|
|
|
|
|
- `main` 分支 push:不再触发该 workflow 自动部署链路。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 生产发布入口从 `main` 切换到 `dev`,需确认团队分支策略已同步。
|
|
|
|
|
|
- `workflow_dispatch` 若在非 `dev` 分支触发,deploy job 会被 `if` 条件跳过。
|
2026-05-01 10:49:29 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 修复 docker db 端口 5433 冲突并改为 5434(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- `docker compose` 启动 `db` 报错:`Bind for 0.0.0.0:5433 failed: port is already allocated`。
|
|
|
|
|
|
- 现有默认口径为宿主机映射 `5433->5432`,与本机已占用端口冲突。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`docker-compose.yml`
|
|
|
|
|
|
- `db.ports` 默认映射从 `${POSTGRES_PORT:-5433}:5432` 改为 `${POSTGRES_PORT:-5434}:5432`。
|
|
|
|
|
|
- 文件:`.env.example`
|
|
|
|
|
|
- `POSTGRES_PORT` 默认值从 `5433` 改为 `5434`。
|
|
|
|
|
|
- 本机直连 `DB_PORT` 默认值从 `5433` 改为 `5434`。
|
|
|
|
|
|
- 文件:`api/app/core/config.py`
|
|
|
|
|
|
- `db_port` 默认值从 `5433` 改为 `5434`,与环境模板和 compose 默认保持一致。
|
|
|
|
|
|
- 文件:`README.md`
|
|
|
|
|
|
- 本地 PostgreSQL 示例端口从 `localhost:5433` 更新为 `localhost:5434`。
|
|
|
|
|
|
- 文件:`MEMORY.md`
|
|
|
|
|
|
- 宿主机默认 `POSTGRES_PORT` 与本机直连 `DB_PORT` 长期口径同步更新为 `5434`。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `POSTGRES_PORT=5434 docker compose up -d db` -> `fquiz-db` 启动成功。
|
|
|
|
|
|
- `docker compose ps -a` -> `fquiz-db` 状态 `Up ... (healthy)`。
|
|
|
|
|
|
- `docker inspect fquiz-db --format '{{json .HostConfig.PortBindings}}'` -> `5432/tcp` 映射 `HostPort=5434`。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围:本地/部署侧依赖默认 `5433` 的连接配置需同步为 `5434`,否则会出现连接失败。
|
|
|
|
|
|
- 容器内服务间连接不受影响,仍通过 `db:5432` 通信。
|
2026-05-01 11:00:08 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 统一 GitHub 发布默认 PostgreSQL 端口为 5434(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 仓库本地 `docker-compose.yml` 默认端口已是 `5434`,但 GitHub Actions 发布脚本内联的 `docker-compose.prod.yml` 与首次生成 `.env` 仍使用 `5433`,存在口径不一致。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小改动):
|
|
|
|
|
|
- 文件:`.github/workflows/main.yml`
|
|
|
|
|
|
- 将发布脚本中 `db.ports` 默认映射从 `${POSTGRES_PORT:-5433}:5432` 改为 `${POSTGRES_PORT:-5434}:5432`。
|
|
|
|
|
|
- 将首次初始化 `.env` 模板中的 `POSTGRES_PORT=5433` 改为 `POSTGRES_PORT=5434`。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `rg -n "POSTGRES_PORT:-5434|POSTGRES_PORT=5434" .github/workflows/main.yml` 命中两处,未发现 workflow 内 `5433` 残留。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围:仅 GitHub 发布脚本默认值,不影响已存在且手工维护的服务器 `.env`。
|
|
|
|
|
|
- 若线上环境明确依赖 `5433`,需在服务器 `.env` 显式保留 `POSTGRES_PORT=5433`。
|
2026-05-01 11:21:57 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 修复 API 启动时报 users.password 列不存在(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 启动报错 `psycopg.errors.UndefinedColumn: column users.password does not exist`。
|
|
|
|
|
|
- 触发点在 `seed_defaults -> _seed_permissions` 的查询过程中,SQLAlchemy 关系预加载 `Role.users` 时会查询 `users` 全字段;当前 ORM 将 `password_hash` 绑定到 `users.password`,但目标库字段为 `password_hash`。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`api/app/core/config.py`
|
|
|
|
|
|
- 新增配置 `user_password_column`(环境变量 `USER_PASSWORD_COLUMN`),可选值 `password` / `password_hash`,默认 `password_hash`。
|
|
|
|
|
|
- 文件:`api/app/models/user.py`
|
|
|
|
|
|
- `User.password_hash` 改为基于 `settings.user_password_column` 动态映射,兼容两类历史库结构。
|
|
|
|
|
|
- 文件:`docker-compose.yml`
|
|
|
|
|
|
- 为 `api` / `celery-worker` / `celery-beat` 注入 `USER_PASSWORD_COLUMN` 环境变量透传。
|
|
|
|
|
|
- 文件:`.env.example`
|
|
|
|
|
|
- 新增 `USER_PASSWORD_COLUMN=password_hash` 示例配置。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `python3 -m py_compile api/app/core/config.py api/app/models/user.py api/app/services/seed_service.py` -> 通过。
|
|
|
|
|
|
- `rg -n "USER_PASSWORD_COLUMN|user_password_column" ...` 命中配置、模型、compose、env 示例,映射链路完整。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响面集中在 `User` 模型密码字段映射。
|
|
|
|
|
|
- 运行环境需确保 `USER_PASSWORD_COLUMN` 与目标数据库实际字段一致;若配置错误,启动阶段仍可能抛 `UndefinedColumn`。
|
2026-05-01 11:39:17 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 修复 API 启动时报 users.state 列不存在(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 启动报错 `psycopg.errors.UndefinedColumn: column users.state does not exist`。
|
|
|
|
|
|
- 触发点同样在 `seed_defaults -> _seed_permissions` 的关系预加载过程中,ORM 查询 `users` 全字段时固定引用了 `state`,但目标库实际字段为 `status`。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`api/app/core/config.py`
|
|
|
|
|
|
- 新增配置 `user_status_column`(环境变量 `USER_STATUS_COLUMN`),可选值 `status` / `state`,默认 `status`。
|
|
|
|
|
|
- 文件:`api/app/models/user.py`
|
|
|
|
|
|
- `User.status` 列改为基于 `settings.user_status_column` 动态映射,兼容两类历史库结构。
|
|
|
|
|
|
- 文件:`docker-compose.yml`
|
|
|
|
|
|
- 为 `api` / `celery-worker` / `celery-beat` 注入 `USER_STATUS_COLUMN` 环境变量透传。
|
|
|
|
|
|
- 文件:`.env.example`
|
|
|
|
|
|
- 新增 `USER_STATUS_COLUMN=status` 示例配置。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `rg -n "USER_STATUS_COLUMN|user_status_column"` 命中配置、模型、compose、env 示例,映射链路完整。
|
|
|
|
|
|
- `git diff` 检查仅包含本次预期的 4 个文件改动。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响面集中在 `User` 模型状态字段映射。
|
|
|
|
|
|
- 运行环境需确保 `USER_STATUS_COLUMN` 与目标数据库实际字段一致;若配置错误,启动阶段仍可能抛 `UndefinedColumn`。
|
2026-05-01 12:25:16 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 修复 API 启动时报 users.create_user / users.update_user 列不存在(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 发布部署日志报错 `psycopg.errors.UndefinedColumn: column users.create_user does not exist`,容器持续重启。
|
|
|
|
|
|
- 触发点在 `init_db -> seed_defaults`,`Role.users` 关系预加载会查询 `users` 全字段;当历史库缺失 `create_user/update_user` 时,启动阶段直接失败。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`api/app/core/database.py`
|
|
|
|
|
|
- 新增 `_ensure_user_audit_column_compatibility()` 并在 `init_db()` 中接入(位于 `Base.metadata.create_all()` 前执行)。
|
|
|
|
|
|
- 兼容策略:
|
|
|
|
|
|
- 若存在历史列 `create_by/created_by`,自动重命名为 `create_user`。
|
|
|
|
|
|
- 若存在历史列 `update_by/updated_by`,自动重命名为 `update_user`。
|
|
|
|
|
|
- 若目标列仍缺失,自动补齐 nullable 列:
|
|
|
|
|
|
- `ALTER TABLE users ADD COLUMN IF NOT EXISTS create_user VARCHAR(64)`
|
|
|
|
|
|
- `ALTER TABLE users ADD COLUMN IF NOT EXISTS update_user VARCHAR(64)`
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `git diff` 检查改动仅落在 `api/app/core/database.py` 与记忆文档。
|
|
|
|
|
|
- 启动期兼容逻辑为 PostgreSQL 定向执行;仅在 `users` 表存在且列不一致时触发 DDL,已对齐环境不会产生变更。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响面限定在 PostgreSQL 的 `users` 表审计字段兼容处理。
|
|
|
|
|
|
- 该兼容动作为启动期一次性 DDL,可能短暂持有 `users` 表 DDL 锁;对已有规范列名的库无行为变化。
|
2026-05-01 13:54:01 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 修复 /api/v1/admin/roles 在缺失 user_role 表时返回 500(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 复现路径:登录后调用 `GET /api/v1/admin/roles`,接口返回 `500`。
|
|
|
|
|
|
- 根因:`legacy_admin_rbac_service.list_roles` 固定查询 legacy 表 `user_role`,当库仅存在 modern RBAC 表(`roles/user_roles/role_menus`)时触发 `psycopg.errors.UndefinedTable`。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`api/app/services/legacy_admin_rbac_service.py`
|
|
|
|
|
|
- 新增 `user_role` 存在性探测:`_legacy_role_table_exists()`。
|
|
|
|
|
|
- `list_roles` 增加双链路读取:
|
|
|
|
|
|
- legacy 存在时保持原有 `user_role + role_menu_rela + menu` 查询;
|
|
|
|
|
|
- legacy 缺失时自动回退 `roles + role_menus + menus + role_permissions + permissions`。
|
|
|
|
|
|
- `get_role_by_id` 与 `list_role_menu_ids` 同步支持 modern 回退(兼容按 `id` 或 `code` 查角色)。
|
|
|
|
|
|
- 新增辅助函数:
|
|
|
|
|
|
- `_load_role_rows(..., role_source=...)`
|
|
|
|
|
|
- `_load_role_permission_codes_map(..., role_source=...)`
|
|
|
|
|
|
- 扩展辅助函数以支持 modern 回退:
|
|
|
|
|
|
- `_load_role_menu_ids_map(..., role_source=...)`
|
|
|
|
|
|
- `_load_menus_map(..., role_source=...)`
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `python3 -m py_compile api/app/services/legacy_admin_rbac_service.py` -> 通过。
|
|
|
|
|
|
- `git push origin HEAD:dev` -> 成功(提交 `2c3ad31`)。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围限定在后台角色读取接口(`/api/v1/admin/roles*`)查询链路。
|
|
|
|
|
|
- 对 legacy 表完整的数据库行为保持不变;仅在 `user_role` 缺失时触发 modern 回退逻辑。
|
2026-05-01 14:15:17 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 用户管理优化(编辑/检索/分页)(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-121` 要求用户管理支持:用户信息修改、用户检索、用户表格分页。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 后端 `users` 列表接口增强(检索 + 分页参数联动):
|
|
|
|
|
|
- 文件:`api/app/api/v1/users.py`
|
|
|
|
|
|
- `GET /api/v1/users` 新增查询参数:
|
|
|
|
|
|
- `keyword`:按 `user_id/email/username` 模糊检索
|
|
|
|
|
|
- `status`:按启用/禁用状态过滤
|
2026-05-01 19:36:50 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 菜单管理页面表格高度自适应与固定表头(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-142` 需要菜单管理页面表格高度随页面自适应,纵向滚动条仅出现在表格内部,并保持表头固定。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
- 新增动态高度状态与锚点:
|
|
|
|
|
|
- `tableScrollY`、`tableScrollAnchorRef`
|
|
|
|
|
|
- 常量 `MENU_TABLE_MIN_SCROLL_Y`、`MENU_TABLE_BOTTOM_RESERVE`
|
|
|
|
|
|
- 新增 `updateTableScrollY()`:
|
|
|
|
|
|
- 基于表格锚点 `getBoundingClientRect().top` 和 `window.innerHeight` 计算可用高度
|
|
|
|
|
|
- 对高度变化做 2px 阈值抑制,避免频繁抖动重渲染
|
|
|
|
|
|
- 新增监听:
|
|
|
|
|
|
- `window.resize` 触发重算
|
|
|
|
|
|
- `ResizeObserver` 监听锚点尺寸变化(筛选区换行、布局变化)触发重算
|
|
|
|
|
|
- 表格滚动改造:
|
|
|
|
|
|
- `scroll` 从 `{ x: 1200 }` 调整为 `{ x: 1200, y: tableScrollY }`
|
|
|
|
|
|
- 让纵向滚动收敛到表格体内,并由 AntD 自动固定表头
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 未执行编译/测试(按任务约束:不做编译检查、不安装依赖)。
|
|
|
|
|
|
- 代码检查确认改动仅涉及菜单管理页单文件逻辑。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围仅 `web/src/app/admin/menus/page.tsx` 的表格渲染高度计算逻辑。
|
|
|
|
|
|
- 极端小视口下表格最小高度受 `MENU_TABLE_MIN_SCROLL_Y=220` 限制,避免表格区域塌陷。
|
2026-05-01 19:53:16 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 菜单管理页表格高度二次修复(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 用户反馈菜单管理页“表格高度还是太高,页面出现了纵向滚动条”。
|
|
|
|
|
|
- 原实现使用固定底部预留常量估算 `scroll.y`,在部分视口和分页高度组合下仍可能偏大。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
- 高度计算改为“实时测量”:
|
|
|
|
|
|
- 读取 `.ant-table-wrapper` 与 `.ant-table-body` 的真实高度,动态计算 `nonBodyHeight`(表头/分页等非表体高度)。
|
|
|
|
|
|
- 以 `window.innerHeight - anchorTop - topGap - nonBodyHeight - viewportGap` 反推 `scroll.y`,避免固定常量误差。
|
|
|
|
|
|
- 兜底策略:
|
|
|
|
|
|
- 保留 `MENU_TABLE_FALLBACK_RESERVE` 作为初始/异常场景的回退计算。
|
|
|
|
|
|
- 最小高度下限调整为 `MENU_TABLE_MIN_SCROLL_Y=180`,减少小屏溢出概率。
|
|
|
|
|
|
- 渲染细节:
|
|
|
|
|
|
- 表格顶部间距从 `Table className mt-4` 调整到锚点容器 `className=\"mt-4\"`,避免 margin 参与高度计算时产生偏差。
|
|
|
|
|
|
- 触发重算条件补充:
|
|
|
|
|
|
- 在 `filteredMenus.length`、`loading` 变化时同步重算,覆盖分页和筛选引发的高度变化。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 未执行编译/测试(按任务约束:不做编译检查、不安装依赖)。
|
|
|
|
|
|
- 代码检查确认改动仅涉及菜单页面单文件高度计算逻辑。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围仅 `web/src/app/admin/menus/page.tsx`。
|
|
|
|
|
|
- 新逻辑依赖 AntD 现有 DOM 类名(`.ant-table-wrapper` / `.ant-table-body`);若后续升级 AntD 结构变化,需要同步调整选择器。
|
2026-05-01 14:15:17 +08:00
|
|
|
|
- 后端用户服务增强:
|
|
|
|
|
|
- 文件:`api/app/services/user_service.py`
|
|
|
|
|
|
- `list_users(...)` 支持 `keyword/status` 条件查询并对 `total` 同步计数。
|
|
|
|
|
|
- `update_user(...)` 支持修改 `email` 与 `username`:
|
|
|
|
|
|
- 统一 trim/归一化
|
|
|
|
|
|
- 重复值冲突校验
|
|
|
|
|
|
- 空值保护
|
|
|
|
|
|
- 用户更新请求模型补齐:
|
|
|
|
|
|
- 文件:`api/app/schemas/user.py`
|
|
|
|
|
|
- `UserUpdateRequest` 新增可选字段 `email`。
|
|
|
|
|
|
- 前端用户管理页增强:
|
|
|
|
|
|
- 文件:`web/src/app/admin/users/page.tsx`
|
|
|
|
|
|
- 新增“用户检索”区:关键字输入 + 状态筛选 + 搜索/重置。
|
|
|
|
|
|
- 用户列表请求改为受查询条件驱动(query key 包含分页/筛选参数)。
|
|
|
|
|
|
- 表格接入分页器(页码、每页条数、总数联动后端)。
|
|
|
|
|
|
- 新增“编辑用户”弹窗,支持修改邮箱/用户名/状态。
|
|
|
|
|
|
- 编辑提交仅传变更字段,避免无效更新。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证(未执行编译/构建,遵循当前任务约束):
|
|
|
|
|
|
- 代码走读与关键路径自检:
|
|
|
|
|
|
- `GET /api/v1/users` -> 支持 `limit/offset/keyword/status`。
|
|
|
|
|
|
- `PATCH /api/v1/users/{id}` -> 支持 `email/username/status` 更新。
|
|
|
|
|
|
- 前端列表查询参数与分页状态联动一致。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围集中在用户管理模块(`/admin/users` 与 `/api/v1/users*`)。
|
|
|
|
|
|
- 旧调用方不传 `keyword/status` 时行为保持兼容。
|
|
|
|
|
|
- 更新失败错误提示文案仍共用“not found or email/username exists”,后续如需更精确错误码可再拆分。
|
2026-05-01 16:41:36 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 线路管理分布图加入缩放 Slider 与比例显示(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-131` 要求“线路管理页面分布图优化:加入 slider 显示缩放比例”。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`web/src/components/power-line-cesium-map.tsx`
|
|
|
|
|
|
- 新增地图缩放 `Slider`(竖向),置于已有 `+/-/居中` 控件上方。
|
|
|
|
|
|
- 新增“缩放比例 xx%”文本展示。
|
|
|
|
|
|
- 新增缩放比例与相机高度的双向映射函数(对数映射),解决不同尺度下线性感知不均问题。
|
|
|
|
|
|
- 监听 `viewer.camera.changed`,实现鼠标滚轮/按钮缩放时比例实时同步。
|
|
|
|
|
|
- 拖动 Slider 时调用相机 `flyTo` 调整高度,保持当前位置不变,仅修改缩放。
|
|
|
|
|
|
- 新增防抖动状态控制(`sliderChangingRef`)与无效 setState 保护,减少高频相机事件导致的重复渲染。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 本次遵循任务约束,未执行编译/安装。
|
|
|
|
|
|
- 通过代码走读确认:
|
|
|
|
|
|
- `+/-` 按钮、鼠标滚轮、居中重置都会同步刷新缩放比例。
|
|
|
|
|
|
- Slider 拖动可直接驱动地图缩放。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围限定在线路管理分布图前端组件,不涉及后端接口与数据结构。
|
|
|
|
|
|
- 缩放比例为相对值(基于当前线路包围球动态计算),不同线路之间 100%/0% 对应的绝对相机高度不同,属于预期行为。
|
2026-05-01 16:43:21 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 线路管理塔杆列表分页(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-132` 要求“线路管理”的塔杆列表表格支持分页。
|
|
|
|
|
|
- 现状是前端固定请求 `limit=500` 并关闭表格分页,数据量大时浏览与定位效率较差。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`web/src/app/admin/power-lines/page.tsx`
|
|
|
|
|
|
- 新增塔杆列表分页状态:
|
|
|
|
|
|
- `towerPagination.current`(当前页)
|
|
|
|
|
|
- `towerPagination.pageSize`(每页条数,默认 20)
|
|
|
|
|
|
- 塔杆列表请求参数改为按视图分流:
|
|
|
|
|
|
- 表格视图:`limit=pageSize`,`offset=(current-1)*pageSize`
|
|
|
|
|
|
- 地图视图:保留 `limit=500`(保证地图仍可展示较完整线路点位)
|
|
|
|
|
|
- 表格接入 AntD 分页器:
|
|
|
|
|
|
- 使用接口返回 `total` 驱动总数展示
|
|
|
|
|
|
- 支持切换每页条数
|
|
|
|
|
|
- 页码与请求参数联动
|
|
|
|
|
|
- 新增筛选/线路切换时的页码重置:
|
|
|
|
|
|
- `selectedLineId / towerKeyword / towerTypeFilter / towerRiskFilter` 变化时自动回到第 1 页,避免落在空页。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证(未执行编译/构建,遵循任务约束):
|
|
|
|
|
|
- 代码走读确认:
|
|
|
|
|
|
- 后端 `GET /api/v1/lines/{line_id}/towers` 已支持 `limit/offset` 且返回 `total`。
|
|
|
|
|
|
- 前端分页状态、请求参数、表格分页器三者联动一致。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围:仅前端 `线路管理 -> 塔杆列表` 视图。
|
|
|
|
|
|
- 地图视图继续使用大页请求(500)避免点位显示回归。
|
2026-05-01 17:03:23 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 线路管理分布图移除 Slider(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 用户在 Issue `FL-131` 新评论要求:去掉 slider。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小改动):
|
|
|
|
|
|
- 文件:`web/src/components/power-line-cesium-map.tsx`
|
|
|
|
|
|
- 移除右上角竖向缩放 Slider。
|
|
|
|
|
|
- 移除“缩放比例 xx%”文本展示。
|
|
|
|
|
|
- 清理 slider 配套的缩放百分比状态、相机监听与映射函数。
|
|
|
|
|
|
- 保留原有 `+ / - / 居中重置` 缩放按钮能力不变。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 遵循任务约束,未执行编译检查、未安装依赖。
|
|
|
|
|
|
- 代码走读确认变更范围仅限 slider 相关逻辑。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围仅为线路管理分布图控件区 UI 与交互;后端接口和数据结构无影响。
|
2026-05-01 17:02:52 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 新增高程数据管理功能(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 目标是支撑线路走向图高程渲染,提供“高程数据集管理 + 杆塔高程回填任务”闭环能力。
|
|
|
|
|
|
- 约束:最小改动优先,不引入重型 GDAL 依赖,先落可运行方案。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 后端模型与任务:
|
|
|
|
|
|
- 新增 `api/app/models/elevation.py`
|
|
|
|
|
|
- `elevation_dataset`:存高程数据集元信息(挂载、文件路径、分辨率、样本统计、bbox、状态)。
|
|
|
|
|
|
- `elevation_apply_job`:存线路回填任务(模式、进度统计、状态、错误信息)。
|
|
|
|
|
|
- 新增 `api/app/tasks/elevation_tasks.py`
|
|
|
|
|
|
- Celery 任务 `apply_elevation_for_line_job`,异步执行指定 job。
|
|
|
|
|
|
- `api/app/core/celery_app.py`
|
|
|
|
|
|
- Celery include 扩展:加入 `app.tasks.elevation_tasks`。
|
|
|
|
|
|
- 后端 API 与服务:
|
|
|
|
|
|
- 新增 `api/app/schemas/elevation.py`(dataset/job 请求与响应模型)。
|
|
|
|
|
|
- 新增 `api/app/services/elevation_service.py`,提供:
|
|
|
|
|
|
- 数据集列表/创建/更新/分析;
|
|
|
|
|
|
- 回填任务列表/详情/创建;
|
|
|
|
|
|
- 回填执行逻辑(最近邻采样 CSV 点,写回 `power_line_tower.altitude_m`)。
|
|
|
|
|
|
- 回填结果写入 `raw_extra_json.elevation`(数据集来源、采样距离、时间)。
|
|
|
|
|
|
- 新增 `api/app/api/v1/elevation.py`:
|
|
|
|
|
|
- `GET /api/v1/elevation/datasets`
|
|
|
|
|
|
- `POST /api/v1/elevation/datasets`
|
|
|
|
|
|
- `PATCH /api/v1/elevation/datasets/{dataset_id}`
|
|
|
|
|
|
- `POST /api/v1/elevation/datasets/{dataset_id}/analyze`
|
|
|
|
|
|
- `GET /api/v1/elevation/jobs`
|
|
|
|
|
|
- `GET /api/v1/elevation/jobs/{job_id}`
|
|
|
|
|
|
- `POST /api/v1/elevation/jobs/apply-line`
|
|
|
|
|
|
- `api/app/api/router.py` 注册 elevation 路由。
|
|
|
|
|
|
- `api/app/core/database.py` + `api/app/models/__init__.py` 注册新模型,确保 `init_db` 自动建表。
|
|
|
|
|
|
- 权限/菜单/订阅:
|
|
|
|
|
|
- `api/app/services/seed_service.py`
|
|
|
|
|
|
- 新增权限:`elevation.read` / `elevation.manage`。
|
|
|
|
|
|
- 新增后台菜单:`admin.elevation` -> `/admin/elevation`。
|
|
|
|
|
|
- admin 默认菜单绑定新增 `admin.elevation`。
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`
|
|
|
|
|
|
- admin 默认权限加入 elevation 权限。
|
|
|
|
|
|
- `MENU_CODE_PERMISSION_MAP` 增加 `admin.elevation`。
|
|
|
|
|
|
- legacy synthetic 菜单补齐 `admin.elevation`。
|
|
|
|
|
|
- `api/app/services/topic_registry.py`
|
|
|
|
|
|
- 新增 topic 规则:`admin.elevation`。
|
|
|
|
|
|
- `api/app/services/admin_service.py` / `legacy_admin_rbac_service.py`
|
|
|
|
|
|
- 将 `admin.elevation` 设为受保护菜单(不可误删)。
|
|
|
|
|
|
- 前端页面与类型:
|
|
|
|
|
|
- 新增 `web/src/app/admin/elevation/page.tsx`
|
|
|
|
|
|
- 高程数据集管理(创建、分析、列表)。
|
|
|
|
|
|
- 回填任务管理(创建、进度/结果查看)。
|
|
|
|
|
|
- 支持跳转文件管理上传 CSV(复用现有文件系统)。
|
|
|
|
|
|
- `web/src/types/auth.ts` 增加 elevation 相关类型定义。
|
|
|
|
|
|
- `web/src/app/admin/page.tsx` 新增“高程数据管理”卡片入口。
|
|
|
|
|
|
- `web/src/app/admin/menus/page.tsx` 将 `admin.elevation` 加入前端受保护菜单编码集合。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 后端语法编译:
|
|
|
|
|
|
- `python3 -m compileall api/app` -> 通过。
|
|
|
|
|
|
- 前端构建:
|
|
|
|
|
|
- `npm run build:web` -> 通过。
|
|
|
|
|
|
- 构建产物中已包含路由:`/admin/elevation`。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 当前实现使用 CSV 点集“最近邻采样”,适合先跑通管理与回填流程;不是严格栅格插值方案。
|
|
|
|
|
|
- 未引入 GDAL/rasterio,部署更稳,但精度依赖 CSV 样本密度与坐标质量。
|
|
|
|
|
|
- 回填默认允许 `overwrite_all`,存在覆盖人工高程风险;前端默认展示“仅填空(推荐)”。
|
2026-05-01 18:09:18 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 高程管理支持 IMG/TIF 导入与回填(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 用户上传的高程数据为 `.img`(栅格),现有实现仅支持 CSV 点集,无法直接用于高程回填任务。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 后端服务能力扩展(文件格式识别 + 栅格采样):
|
|
|
|
|
|
- 文件:`api/app/services/elevation_service.py`
|
|
|
|
|
|
- 数据集创建时按扩展名自动识别并落库 `file_format`(支持 `.csv/.img/.tif/.tiff`)。
|
|
|
|
|
|
- 新增“按格式分流”执行:
|
|
|
|
|
|
- `csv`:沿用现有最近邻点集采样逻辑。
|
|
|
|
|
|
- `img/tif/tiff`:新增栅格像元采样逻辑,按杆塔经纬度写回 `power_line_tower.altitude_m`。
|
|
|
|
|
|
- 新增栅格分析逻辑:
|
|
|
|
|
|
- 从栅格读取 `width/height/bounds` 回写 `sample_count/bbox`。
|
|
|
|
|
|
- 对非 WGS84 CRS 增加告警,并在回填时自动执行坐标转换(WGS84 -> 栅格 CRS)。
|
|
|
|
|
|
- 回填溯源扩展:
|
|
|
|
|
|
- `raw_extra_json.elevation.sample_method` 对栅格标记为 `raster_pixel`。
|
|
|
|
|
|
- 增加 `sample_distance_source` 字段(CSV 为 `computed`,栅格为 `pixel_lookup`)。
|
|
|
|
|
|
- 依赖补齐:
|
|
|
|
|
|
- 文件:`api/requirements.txt`,新增 `rasterio==1.4.3`。
|
|
|
|
|
|
- 文件:`api/pyproject.toml`,新增 `rasterio>=1.4.0,<2.0.0`。
|
|
|
|
|
|
- 前端文案更新:
|
|
|
|
|
|
- 文件:`web/src/app/admin/elevation/page.tsx`
|
|
|
|
|
|
- 页面提示更新为支持 `CSV/IMG/TIF/TIFF`,空态与示例路径同步为栅格可用口径。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `python3 -m compileall api/app` -> 通过。
|
|
|
|
|
|
- `npm run build:web` -> 通过。
|
|
|
|
|
|
- 构建产物包含路由 `/admin/elevation`。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- `.img/.tif` 回填依赖 `rasterio`(及底层 GDAL 运行时),部署环境需确保镜像能成功安装该依赖。
|
|
|
|
|
|
- 栅格 bbox 直接来自源栅格 CRS;非经纬度坐标系场景会返回告警,便于识别与后续治理。
|
2026-05-01 19:29:51 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 去掉角色权限点与菜单权限码配置(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-139` 要求“去掉角色管理的权限点配置,菜单的权限码配置”。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 角色管理页面:`web/src/app/admin/roles/page.tsx`
|
|
|
|
|
|
- 移除权限点配置入口与相关请求链路:
|
|
|
|
|
|
- 移除 `permissions` 状态与 `/api/v1/admin/permissions` 加载请求。
|
|
|
|
|
|
- 新建/编辑角色表单移除 `permission_codes` 字段,仅保留 `code/name/menu_ids`。
|
|
|
|
|
|
- 角色更新请求不再提交 `permission_codes`。
|
|
|
|
|
|
- 列表展示移除“权限”列,仅展示“角色编码/角色名称/菜单/操作”。
|
|
|
|
|
|
- 搜索口径同步调整为“角色编码、名称、菜单”。
|
|
|
|
|
|
- 菜单管理页面:`web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
- 移除菜单权限码配置入口:
|
|
|
|
|
|
- 菜单表单移除 `permission_code` 字段。
|
|
|
|
|
|
- 新建/编辑菜单提交 payload 不再包含 `permission_code`。
|
|
|
|
|
|
- 列表展示移除“权限码”列。
|
|
|
|
|
|
- 搜索口径移除权限码匹配,关键词仅匹配“编码/名称/路径”。
|
|
|
|
|
|
- 后台首页文案:`web/src/app/admin/page.tsx`
|
|
|
|
|
|
- 角色管理说明改为“配置角色并分配菜单可见范围”。
|
|
|
|
|
|
- 菜单管理说明改为“维护后台导航结构、菜单层级与展示状态”。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证(遵循任务约束,未执行编译检查):
|
|
|
|
|
|
- `git diff` 已确认改动仅涉及上述三个前端文件。
|
|
|
|
|
|
- 代码扫描确认上述页面不再包含 `permission_codes` / `permission_code` 配置与展示逻辑。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围限定在前端管理页交互层;后端接口仍保持兼容,可继续返回权限相关字段但前端不再暴露配置入口。
|
|
|
|
|
|
- 若后续需彻底下线该能力(含后端字段/持久化),需单独评估接口契约与历史数据兼容。
|
2026-05-01 19:39:16 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 登录页面还原最简洁样式并保留记住密码(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-144` 要求将登录页还原为最简洁样式,保留“登录、记住密码”功能,并将标题改为“防雷计算”。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`web/src/app/page.tsx`
|
|
|
|
|
|
- 去除登录页注册模式相关状态与 UI(`mode/register/username/切换按钮`),仅保留登录流程。
|
|
|
|
|
|
- 页面主标题改为 `防雷计算`。
|
|
|
|
|
|
- 视觉样式收敛为简洁白底 + 居中卡片布局,移除装饰性图标块、渐变、复杂文案。
|
|
|
|
|
|
- 新增“记住密码”复选框:
|
|
|
|
|
|
- 勾选后登录成功时将用户 ID 与密码写入 `localStorage`;
|
|
|
|
|
|
- 未勾选时清理本地缓存;
|
|
|
|
|
|
- 页面加载时若已记住则自动回填账号密码并默认勾选。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 代码路径自检:登录仍走 `useAuth().login` 既有链路,未改动鉴权接口与路由跳转逻辑。
|
|
|
|
|
|
- 按任务约束未执行编译/安装依赖。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围:仅前端登录页 `web/src/app/page.tsx`。
|
|
|
|
|
|
- 风险:记住密码当前使用浏览器 `localStorage` 明文存储,存在本机安全暴露风险(符合需求但需知悉)。
|
2026-05-01 19:56:54 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 用户管理页面去掉权限列(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-145` 要求“用户管理页面去掉权限列”。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小改动):
|
|
|
|
|
|
- 文件:`web/src/app/admin/users/page.tsx`
|
|
|
|
|
|
- 在用户列表 `columns` 配置中移除“权限”列(`dataIndex: permission_codes`)及对应渲染逻辑。
|
|
|
|
|
|
- 其余列与用户管理交互(角色分配、状态切换、编辑、重置密码、删除)保持不变。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 代码走读确认:页面不再渲染权限列,且仅改动单文件单处表格列定义。
|
|
|
|
|
|
- 按任务约束未执行编译/安装依赖。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围仅前端用户管理页面展示层,不涉及后端接口与权限模型。
|
2026-05-01 20:08:30 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 修复系统写死颜色并支持主题变量切换(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-146` 要求修正系统中写死颜色,支持主题色切换,统一通过变量驱动。
|
|
|
|
|
|
- 现状存在多处硬编码:`error/global-error` 内联 hex,后台列表选中态 `bg-blue-50`,以及主题菜单徽标固定蓝色。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 文件:`web/src/app/globals.css`
|
|
|
|
|
|
- 新增主题语义变量桥接:`--fquiz-theme-*`(布局背景、容器背景、文本、边框、主色、阴影、选中态等)。
|
|
|
|
|
|
- 新增暗色模式变量覆盖:`:root[data-fquiz-theme="dark"]`。
|
|
|
|
|
|
- 新增统一行选中样式:`.fquiz-row-selected > td { background: var(--fquiz-theme-bg-active) !important; }`。
|
|
|
|
|
|
- 文件:`web/src/components/ui-antd.tsx`
|
|
|
|
|
|
- 保留主题算法逻辑,新增 `buildThemeVisualTokens(isDark)` 收敛布局/壳层/表头色常量来源,避免散落硬编码。
|
|
|
|
|
|
- 在 `ThemeCssVarsScope` 补充 `--ant-color-primary-bg` / `--ant-color-primary-bg-hover` / `--ant-color-primary-hover` 变量导出。
|
|
|
|
|
|
- 在主题切换时同步写入 `document.documentElement.dataset.fquizTheme`(`dark|light`),驱动 CSS 变量切换。
|
|
|
|
|
|
- 文件:`web/src/app/error.tsx`
|
|
|
|
|
|
- 将所有硬编码颜色替换为 `var(--fquiz-theme-*)` / `var(--ant-*)` 变量。
|
|
|
|
|
|
- 文件:`web/src/app/global-error.tsx`
|
|
|
|
|
|
- 同步替换硬编码颜色为主题变量。
|
|
|
|
|
|
- 文件:`web/src/app/admin/lightning-currents/page.tsx`
|
|
|
|
|
|
- 表格选中行样式由 `bg-blue-50` 改为 `fquiz-row-selected`。
|
|
|
|
|
|
- 文件:`web/src/app/admin/power-lines/atp-viewer/page.tsx`
|
|
|
|
|
|
- 表格选中行样式由 `bg-blue-50` 改为 `fquiz-row-selected`。
|
|
|
|
|
|
- 文件:`web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- 主题菜单徽标颜色由固定 `blue` 改为 `var(--fquiz-theme-primary, var(--ant-color-primary))`。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证(按任务约束未执行编译/安装依赖):
|
|
|
|
|
|
- `rg` 检查确认目标文件内 `#155eef/#101828/#f5f7fb/bg-blue-50` 已清理。
|
|
|
|
|
|
- `git diff` 检查改动范围仅涉及本次主题变量改造文件。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围为前端主题层与错误页展示层,不涉及后端接口行为。
|
|
|
|
|
|
- `fquiz-row-selected` 使用 `!important` 以覆盖 AntD 表格单元背景,后续若引入更高优先级行态样式需注意冲突。
|
2026-05-01 20:34:40 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 404 页面统一(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-148` 反馈登出时会短暂闪现“找不到页面”,希望将该页面作为统一 404 页面。
|
|
|
|
|
|
- 现状:前端 `web/src/app` 下没有 `not-found.tsx`,因此命中的是 Next.js 默认 404 页面,样式与系统其余页面不统一。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小改动):
|
|
|
|
|
|
- 文件:`web/src/app/not-found.tsx`
|
|
|
|
|
|
- 新增根级 `not-found` 页面,使用项目现有布局与主题变量(`--ant-color-text` / `--ant-color-text-secondary`)。
|
|
|
|
|
|
- 页面文案沿用用户反馈中的默认样式语义(`404` + `This page could not be found.`),用于全局未匹配路由统一展示。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 按任务约束未执行编译检查。
|
|
|
|
|
|
- 代码检查确认新增文件仅影响 404 展示入口,不涉及鉴权、路由重写或后端接口。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围仅前端全局 404 页面。
|
|
|
|
|
|
- 文案当前为英文(对齐原闪现页面),若后续需要中英双语可再单独调整。
|
2026-05-01 20:59:12 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 迁移 Celery 与任务/Worker 双监控页面到 fquiz(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 需求要求将 `modo-next` 的 Celery 调度与两类监控页(任务监控、Worker 监控)迁移到当前 `fquiz`。
|
|
|
|
|
|
- 仓库已有 Celery 与 `/admin/task-monitor`,缺口是“独立 Worker 监控页 + 对应 API/菜单入口”。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 后端新增 Worker 监控模型与接口:
|
|
|
|
|
|
- `api/app/schemas/worker_monitor.py`
|
|
|
|
|
|
- 新增 `WorkerMonitorOverviewResponse`、`WorkerMonitorTaskOverviewResponse` 及相关 item/summary 模型。
|
|
|
|
|
|
- `api/app/services/worker_monitor_service.py`
|
|
|
|
|
|
- 基于 Celery inspect 提供 Worker 概览(状态/队列/并发/处理量)。
|
|
|
|
|
|
- 提供单 Worker 任务快照(active/reserved/scheduled)与 recent 历史任务聚合。
|
|
|
|
|
|
- 复用现有 `task_monitor_service` 的通用解析工具,保持行为一致性。
|
|
|
|
|
|
- `api/app/api/v1/worker_monitor.py`
|
|
|
|
|
|
- 新增路由:
|
|
|
|
|
|
- `GET /api/v1/admin/workers/overview`
|
|
|
|
|
|
- `GET /api/v1/admin/workers/tasks?worker=...&recent_limit=...`
|
|
|
|
|
|
- 权限统一 `celery.read` / `celery.manage`。
|
|
|
|
|
|
- `api/app/api/router.py`
|
|
|
|
|
|
- 挂载 `worker_monitor` 路由。
|
|
|
|
|
|
|
|
|
|
|
|
- 前端新增独立 Worker 监控页:
|
|
|
|
|
|
- `web/src/app/admin/workers/page.tsx`
|
|
|
|
|
|
- 新增 Worker 列表页:支持名称/队列/在线状态筛选、自动刷新、手动刷新。
|
|
|
|
|
|
- 新增 Worker 任务抽屉:查看 active/reserved/scheduled/recent 四类任务明细(含 args/kwargs/error)。
|
|
|
|
|
|
- 数据源对齐新后端 API。
|
|
|
|
|
|
|
|
|
|
|
|
- 菜单与权限入口联动:
|
|
|
|
|
|
- `api/app/services/seed_service.py`
|
|
|
|
|
|
- 新增菜单 `admin.workers`(`/admin/workers`)。
|
|
|
|
|
|
- admin 默认菜单绑定加入 `admin.workers`。
|
|
|
|
|
|
- 调整后续菜单 `sort_order`,避免排序冲突。
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`
|
|
|
|
|
|
- 增加 `admin.workers -> celery.read/celery.manage` 权限映射。
|
|
|
|
|
|
- synthetic legacy menu rows 增加 `admin.workers`。
|
|
|
|
|
|
- 同步顺序号,保持 legacy 菜单序一致。
|
|
|
|
|
|
- `api/app/services/legacy_admin_rbac_service.py`
|
|
|
|
|
|
- `PROTECTED_MENU_CODES` 加入 `admin.workers`,避免误删。
|
|
|
|
|
|
- `api/app/services/admin_service.py`
|
|
|
|
|
|
- 菜单删除保护集合加入 `admin.workers`。
|
|
|
|
|
|
- `web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
- 前端受保护菜单集合加入 `admin.workers`。
|
|
|
|
|
|
- `web/src/app/admin/page.tsx`
|
|
|
|
|
|
- 后台首页新增“Worker监控”卡片入口。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 后端语法检查:
|
|
|
|
|
|
- `python3 -m py_compile api/app/schemas/worker_monitor.py api/app/services/worker_monitor_service.py api/app/api/v1/worker_monitor.py api/app/api/router.py api/app/services/seed_service.py api/app/services/legacy_authz_service.py api/app/services/admin_service.py` -> 通过。
|
|
|
|
|
|
- 前端构建:
|
|
|
|
|
|
- `rm -f web/.next/lock && npm run build:web` -> 通过。
|
|
|
|
|
|
- 构建产物路由包含:`/admin/workers`、`/admin/task-monitor`。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 影响范围:Celery 监控模块(新增 Worker 监控维度),权限仍复用 `celery.read/manage`。
|
|
|
|
|
|
- `recent_tasks` 依赖 Celery Redis result backend 中任务元数据是否含 `worker/hostname` 字段;若上游未写入,recent 列表会偏少,但不影响 active/reserved/scheduled 实时快照。
|
|
|
|
|
|
|
|
|
|
|
|
## Work Log - 新增 Scheduler + Flower + Worker 自动注册并切换监控数据源(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 新需求要求当前 `fquiz` 引入独立 `scheduler` 服务、`flower` 监控服务,监控页面改走 Flower,并提供 worker 自动注册机制。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
|
|
|
|
|
|
- 后端新增 `scheduler` 调度 API:
|
|
|
|
|
|
- `api/app/schemas/scheduler.py`
|
|
|
|
|
|
- 定义任务入队/撤销请求响应模型。
|
|
|
|
|
|
- `api/app/services/scheduler_service.py`
|
|
|
|
|
|
- 封装 `celery_app.send_task` 与 `celery_app.control.revoke`。
|
|
|
|
|
|
- `api/app/api/v1/scheduler.py`
|
|
|
|
|
|
- 提供:
|
|
|
|
|
|
- `GET /api/v1/scheduler/healthz`
|
|
|
|
|
|
- `POST /api/v1/scheduler/v1/tasks/enqueue`
|
|
|
|
|
|
- `POST /api/v1/scheduler/v1/tasks/revoke`
|
|
|
|
|
|
- 支持 `x-scheduler-token`(环境变量配置后生效)。
|
|
|
|
|
|
- `api/app/scheduler_main.py`
|
|
|
|
|
|
- 独立 scheduler 进程入口(只挂 scheduler 路由)。
|
|
|
|
|
|
- `api/app/api/router.py`
|
|
|
|
|
|
- 主 API 路由挂载 scheduler 与 flower monitor 路由。
|
|
|
|
|
|
|
|
|
|
|
|
- 后端新增 Flower 监控代理层(页面不直连 Flower):
|
|
|
|
|
|
- `api/app/schemas/flower_monitor.py`
|
|
|
|
|
|
- 定义 worker 概览与任务快照模型。
|
|
|
|
|
|
- `api/app/services/flower_monitor_service.py`
|
|
|
|
|
|
- 代理调用 Flower API:
|
|
|
|
|
|
- `/api/workers?refresh=...`
|
|
|
|
|
|
- `/api/workers?status=true`
|
|
|
|
|
|
- `/api/tasks?limit=...&workername=...`
|
|
|
|
|
|
- 统一解析 worker/task 字段、状态、时间戳。
|
|
|
|
|
|
- `api/app/api/v1/flower_monitor.py`
|
|
|
|
|
|
- 提供:
|
|
|
|
|
|
- `GET /api/v1/admin/flower/workers`
|
|
|
|
|
|
- `GET /api/v1/admin/flower/worker-tasks`
|
|
|
|
|
|
- 权限:`celery.read`/`celery.manage`。
|
|
|
|
|
|
|
|
|
|
|
|
- Worker 自动注册机制:
|
|
|
|
|
|
- `api/app/models/worker_registry.py`
|
|
|
|
|
|
- 新增 `worker_registry` 表模型。
|
|
|
|
|
|
- `api/app/services/worker_registry_service.py`
|
|
|
|
|
|
- worker 注册、离线标记、离线扫描。
|
|
|
|
|
|
- `api/app/core/worker_signals.py`
|
|
|
|
|
|
- 绑定 Celery 信号:`worker_ready` / `heartbeat_sent` / `worker_shutdown`。
|
|
|
|
|
|
- `api/app/tasks/worker_registry_tasks.py`
|
|
|
|
|
|
- 定时离线扫描任务。
|
|
|
|
|
|
- `api/app/core/celery_app.py`
|
|
|
|
|
|
- include 新任务模块,beat schedule 增加 `sweep_worker_registry_offline`。
|
|
|
|
|
|
- 引入 worker signal 注册。
|
|
|
|
|
|
- `api/app/core/database.py` + `api/app/models/__init__.py`
|
|
|
|
|
|
- 把 `worker_registry` 纳入 ORM 初始化与建表。
|
|
|
|
|
|
|
|
|
|
|
|
- 监控页面切 Flower:
|
|
|
|
|
|
- `web/src/app/admin/workers/page.tsx`
|
|
|
|
|
|
- 改为请求 `/api/v1/admin/flower/workers` 与 `/api/v1/admin/flower/worker-tasks`。
|
|
|
|
|
|
- 展示 Flower 维度字段(在线状态、并发、registered、processed、心跳、任务来源等)。
|
|
|
|
|
|
- `web/src/app/admin/task-monitor/page.tsx`
|
|
|
|
|
|
- 重构为 Flower 聚合视图:批量拉取每个 worker 任务快照并汇总状态分布/任务表。
|
|
|
|
|
|
- `api/app/services/task_monitor_service.py`
|
|
|
|
|
|
- 从原 inspect+redis 直读切换为基于 Flower 代理服务聚合,保持原接口契约。
|
|
|
|
|
|
|
|
|
|
|
|
- 调度链路接入 scheduler(可选):
|
|
|
|
|
|
- `api/app/services/elevation_service.py`
|
|
|
|
|
|
- `create_apply_job` 增加 `dispatch_mode`,支持 `scheduler_api`。
|
|
|
|
|
|
- `api/app/api/v1/elevation.py` 新增 `dispatchMode` 查询参数透传。
|
|
|
|
|
|
- 默认仍为 `celery_direct`,不破坏现有行为。
|
|
|
|
|
|
|
|
|
|
|
|
- 运行环境与编排配置:
|
|
|
|
|
|
- `docker-compose.yml`
|
|
|
|
|
|
- 新增 `scheduler` 服务(19100)。
|
|
|
|
|
|
- 新增 `flower` 服务(5555,basic auth)。
|
|
|
|
|
|
- `celery-worker` 增加 `CELERY_WORKER_QUEUES` 配置。
|
|
|
|
|
|
- API/worker/beat 注入 `SCHEDULER_*`、`FLOWER_*`、`WORKER_REGISTRY_TTL_SECONDS`。
|
|
|
|
|
|
- `.env.example`
|
|
|
|
|
|
- 新增 `SCHEDULER_API_BASE_URL`、`SCHEDULER_API_TOKEN`、`SCHEDULER_DEFAULT_QUEUE`。
|
|
|
|
|
|
- 新增 `FLOWER_API_BASE_URL`、`FLOWER_API_TIMEOUT_SECONDS`、`FLOWER_BASIC_AUTH`、`FLOWER_PORT`。
|
|
|
|
|
|
- 新增 `WORKER_REGISTRY_TTL_SECONDS`、`CELERY_WORKER_QUEUES`、`SCHEDULER_PORT`。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 后端语法校验通过:
|
|
|
|
|
|
- `python3 -m py_compile ...`(覆盖 scheduler/flower/worker_registry/celery/task-monitor 相关文件)
|
|
|
|
|
|
- 前端构建通过:
|
|
|
|
|
|
- `npm run build:web` -> 通过,页面路由包含 `/admin/workers`、`/admin/task-monitor`。
|
|
|
|
|
|
- Compose 渲染校验通过:
|
|
|
|
|
|
- `docker compose config` 渲染包含 `scheduler`、`flower` 服务以及关键 env/command 字段。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- Flower 代理链路新增了对 `FLOWER_BASIC_AUTH`、`FLOWER_API_BASE_URL` 的配置依赖,配置不一致会导致监控页 502。
|
|
|
|
|
|
- `task-monitor` 改为按 worker 聚合调用,worker 数量多时会增加 API 聚合开销。
|
|
|
|
|
|
- `dispatchMode=scheduler_api` 需确保 `scheduler` 服务可达;默认 `celery_direct` 兼容旧行为。
|
2026-05-01 21:49:45 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 文件管理默认后端切换为 MinIO(2026-05-01)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- 需求要求“文件管理改成 MinIO”。
|
|
|
|
|
|
- 运行层(`docker-compose.yml` / `.env.example` / workflow 部署模板)已是 `MINIO_ENABLED=true`,但后端配置默认值仍为 `false`,在未显式配置环境变量时会回退为 VFS。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小改动):
|
|
|
|
|
|
- 文件:`api/app/core/config.py`
|
|
|
|
|
|
- 将 `minio_enabled` 默认值从 `False` 调整为 `True`。
|
|
|
|
|
|
|
|
|
|
|
|
- 影响:
|
|
|
|
|
|
- 在无环境变量覆盖时,`seed_service` 的默认存储后端与挂载将落到 `files.s3.default`(MinIO)而非 `files.vfs.default`。
|
|
|
|
|
|
- 若环境显式设置 `MINIO_ENABLED=false`,仍可回退 VFS。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- 代码走读确认 `seed_service._default_file_storage_backends/_default_file_storage_mounts` 基于 `settings.minio_enabled` 分支,默认行为已切换到 MinIO。
|
2026-05-02 13:51:06 +08:00
|
|
|
|
|
|
|
|
|
|
## Work Log - 去掉仪表盘页面(2026-05-02)
|
|
|
|
|
|
|
|
|
|
|
|
- 背景:
|
|
|
|
|
|
- Issue `FL-166` 要求去掉后台“仪表盘页面”。
|
|
|
|
|
|
|
|
|
|
|
|
- 本次改动(最小闭环):
|
|
|
|
|
|
- 前端路由与默认跳转收口:
|
|
|
|
|
|
- `web/src/middleware.ts`
|
|
|
|
|
|
- `/admin`、`/dashboard` 统一重定向到 `/users`;
|
|
|
|
|
|
- 历史 `/admin/**` 仍保持去前缀重定向;
|
|
|
|
|
|
- 无前缀路径继续 rewrite 到 `app/admin/**`。
|
|
|
|
|
|
- `web/src/app/page.tsx`
|
|
|
|
|
|
- 登录态从跳转 `/dashboard` 改为跳转 `/users`。
|
|
|
|
|
|
- `web/src/app/admin/page.tsx`
|
|
|
|
|
|
- 仪表盘页面改为纯重定向页(`router.replace("/users")`),不再渲染工作台卡片。
|
|
|
|
|
|
- `web/src/app/admin/layout.tsx`
|
|
|
|
|
|
- `/admin` 归一化路径改为 `/users`;
|
|
|
|
|
|
- 账号下拉“后台首页”改为“用户管理”(`/users`)。
|
|
|
|
|
|
- `web/src/app/admin/roles/page.tsx`
|
|
|
|
|
|
- 无权限兜底按钮改为返回 `/users`。
|
|
|
|
|
|
- `web/src/app/admin/menus/page.tsx`
|
|
|
|
|
|
- 受保护菜单集合移除 `dashboard`。
|
|
|
|
|
|
- 后端菜单与权限链路清理:
|
|
|
|
|
|
- `api/app/services/seed_service.py`
|
|
|
|
|
|
- 删除 `dashboard` 种子菜单;
|
|
|
|
|
|
- `admin`/`user` 默认角色菜单绑定删除 `dashboard`;
|
|
|
|
|
|
- `admin.users` 排序调整为首位(`sort_order=10`)。
|
|
|
|
|
|
- `api/app/services/admin_service.py`
|
|
|
|
|
|
- `REMOVED_MENU_CODES` 增加 `dashboard`;
|
|
|
|
|
|
- 菜单删除保护集合移除 `dashboard`。
|
|
|
|
|
|
- `api/app/services/legacy_authz_service.py`
|
|
|
|
|
|
- `DISABLED_MENU_CODES` 增加 `dashboard`;
|
|
|
|
|
|
- `MENU_CODE_PERMISSION_MAP` 删除 `dashboard` 映射。
|
|
|
|
|
|
- `api/app/services/legacy_admin_rbac_service.py`
|
|
|
|
|
|
- `REMOVED_MENU_CODES` 增加 `dashboard`;
|
|
|
|
|
|
- `PROTECTED_MENU_CODES` 移除 `dashboard`。
|
|
|
|
|
|
- `api/app/services/topic_registry.py`
|
|
|
|
|
|
- 删除 `admin.dashboard` 主题规则。
|
|
|
|
|
|
- 记忆更新:
|
|
|
|
|
|
- `MEMORY.md` 新增“仪表盘下线口径(2026-05-02)”,并同步修正历史 `/dashboard` 默认入口描述为 `/users`。
|
|
|
|
|
|
|
|
|
|
|
|
- 验证:
|
|
|
|
|
|
- `rg -n "dashboard|/dashboard"` 检查运行代码,确认仅保留兼容重定向/过滤语义,不再保留仪表盘页面入口逻辑。
|
|
|
|
|
|
|
|
|
|
|
|
- 风险与影响:
|
|
|
|
|
|
- 历史收藏的 `/dashboard` 链接会跳转到 `/users`(兼容行为)。
|
|
|
|
|
|
- 默认 `user` 角色在无其他菜单绑定时,后台菜单可能为空;该改动符合“移除仪表盘菜单”的目标口径。
|