Files
fquiz/memory/2026-04-25.md
T
2026-04-26 00:14:25 +08:00

1224 lines
62 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## Work Log - 修复后台页面刷新后误判未登录(2026-04-25)
- 背景:
- 反馈“切菜单后刷新当前页面,会提示 `请先登录后再访问后台`”。
- 根因:
- 前端 `AuthProvider.refreshAccessToken()` 未做并发去重。
- 页面刷新阶段可能触发并发 refresh(例如初始化 bootstrap 与其他请求链路重叠)。
- 后端 refresh 会旋转 refresh token;并发请求中后发请求会带旧 token 命中失败,最终覆盖为未登录态。
- 本次改动(最小闭环):
- `web/src/components/auth-provider.tsx`
- 新增 `refreshPromiseRef`in-flight Promise 引用)。
- `refreshAccessToken()` 改为 single-flight
- 有进行中的 refresh 时直接复用;
- 无进行中时创建请求并在 `finally` 中安全释放引用。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 仅影响前端鉴权刷新并发控制,不改接口契约与权限判定逻辑。
- 该修复会降低页面刷新阶段误判登出概率,并减少重复 refresh 请求。
## Work Log - 打包发布镜像并更新容器(2026-04-25)
- 背景:
- 用户要求“打包发布镜像并更新容器”。
- 本次执行:
- 在仓库根目录执行:
- `docker compose build`
- `docker compose up -d`
- 发布后检查:
- `docker compose ps`
- `docker compose logs --tail=80 api`
- `docker compose logs --tail=80 web`
- `curl -fsS http://127.0.0.1:8000/health`
- `curl -I -fsS http://127.0.0.1:3000/`
- 验证结果:
- `api``web` 容器均已重建并启动。
- `api` 健康检查通过(`/health` 返回 200`{"status":"ok","service":"fquiz-api","version":"0.1.0"}`)。
- `web` 首页返回 `HTTP/1.1 200 OK`
- 风险与影响:
- 本次仅为镜像重建与容器滚动重启,不涉及代码改动或数据库结构变更。
## Work Log - 修复 localhost 刷新后丢登录态(2026-04-25
- 背景:
- 用户反馈:登录后进入 `http://localhost:3000/dashboard`,刷新页面后提示“请先登录后再访问后台”。
- 根因:
- `.env` 的前端 API 基址为 `http://127.0.0.1:8000`,而页面访问 host 为 `localhost`
- 浏览器在 `localhost -> 127.0.0.1` 场景下会形成跨站 cookie 语义,`refresh_token` 无法稳定参与刷新链路,导致硬刷新后 `AuthProvider` bootstrap refresh 失败并清空登录态。
- 本次改动(最小闭环):
- `web/src/lib/api.ts`
- 调整 `getApiBaseUrl()` 的 loopback 重写条件:
- 只要配置 host 是 loopback,且与当前页面 host 不同(例如 `127.0.0.1` vs `localhost`),就自动重写到当前页面 host,端口保持原配置(默认 `8000`)。
- 使用 `URL` 对象回写 `hostname`,兼容 IPv6 场景。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `docker compose build web && docker compose up -d web` -> 成功。
- `docker compose ps` -> `web/api/db` 均为 Upapi/db healthy)。
- `curl -I -fsS http://127.0.0.1:3000/dashboard` -> 200(路由重写正常)。
- 风险与影响:
- 仅影响前端运行时 API 基址解析,不改后端接口、cookie 配置和鉴权协议。
-`localhost/127.0.0.1` 混用访问更稳健,可避免刷新阶段误判未登录。
## Work Log - 后台顶部信息容器改为滚动时固定(2026-04-25)
- 背景:
- 用户要求:当页面内容过多出现纵向滚动条时,顶部用户信息/主题切换区域不要随内容一起滚动。
- 本次改动(最小闭环):
- `web/src/app/admin/layout.tsx`
- 将主内容区“后台管理标题 + 用户信息”横向容器改为 `sticky`,固定在顶部导航(64px)下方:
- `sticky top-16 z-40`
- 增加半透明背景、底边框与 `backdrop-blur`,避免滚动时内容穿透影响可读性。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `docker compose build web && docker compose up -d web` -> 成功。
- `docker compose ps` -> `web/api/db` 均为 Upapi/db healthy)。
- 风险与影响:
- 仅影响后台页顶部视觉与滚动行为,不涉及接口、鉴权和数据逻辑。
## Work Log - 新增线路与杆塔管理模块(2026-04-25)
- 背景:
- 需要基于 `test.csv` 的输电线路数据,落地“线路实体 + 杆塔实体”并提供后台管理能力。
- 本次改动(最小闭环):
- 后端模型与接口:
- 新增模型:
- `api/app/models/line.py``power_line`
- `api/app/models/line_tower.py``power_line_tower`
- 新增 Schema
- `api/app/schemas/line.py`
- 新增服务:
- `api/app/services/line_service.py`
- 线路 CRUD
- 杆塔 CRUD
- CSV 导入(UTF-8/GBK 兼容、表头额外列兼容、`-1` 归一化)
- CSV 导出
- 新增路由:
- `api/app/api/v1/lines.py`
- `/api/v1/lines*`
- `/api/v1/lines/{line_id}/towers*`
- `/api/v1/lines/towers/{tower_id}`
- 接入总路由:
- `api/app/api/router.py`
- 接入模型初始化:
- `api/app/models/__init__.py`
- `api/app/core/database.py`
- 权限与菜单:
- `api/app/services/seed_service.py` 新增权限:
- `line.read` / `line.manage`
- `tower.read` / `tower.manage`
- admin 角色默认授予上述权限。
- 新增后台菜单:
- `admin.power_lines` -> `/admin/power-lines`
- admin 默认菜单绑定新增 `admin.power_lines`
- 前端菜单管理保护集合新增 `admin.power_lines`
- `web/src/app/admin/menus/page.tsx`
- 后端受保护菜单集合同步新增 `admin.power_lines`(防止误删):
- `api/app/services/admin_service.py`
- `api/app/services/legacy_admin_rbac_service.py`
- 前端页面:
- 新增:
- `web/src/app/admin/power-lines/page.tsx`
- 功能:
- 线路列表/筛选/新建/编辑/删除
- 杆塔列表/筛选/新建/编辑/删除
- 杆塔 CSV 导入与导出
- 类型补充:
- `web/src/types/auth.ts` 新增线路/杆塔相关类型定义
- 验证:
- 后端语法:
- `python3 -m py_compile api/app/models/line.py api/app/models/line_tower.py api/app/schemas/line.py api/app/services/line_service.py api/app/api/v1/lines.py api/app/api/router.py api/app/core/database.py api/app/services/seed_service.py` -> 通过
- `python3 -m compileall api/app` -> 通过
- 前端类型与构建:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过
- `npm run build:web` -> 通过(包含 `/admin/power-lines` 路由产物)
- 风险与影响:
- `power_line*` 为新表,`create_all` 模式下可自动创建,但不覆盖既有表结构;后续演进建议补 Alembic 迁移。
- CSV 导入对“超出表头的额外列”做了兼容落库(`raw_extra_json`),避免因源文件列漂移中断导入。
## Work Log - 更正滚动需求:固定顶部导航栏(Avatar/主题按钮)(2026-04-25
- 背景:
- 用户澄清:需要固定的是“最顶部导航栏(包含 Avatar 与主题切换)”,不是主内容区标题栏。
- 本次改动(最小闭环):
- `web/src/app/admin/layout.tsx`
- 顶部导航栏从 `fixed` 调整为 `sticky top-0 z-50`,保证随页面纵向滚动始终固定在视口顶部。
- 对应移除内容容器为 fixed 预留的 `pt-[64px]`,避免多余上边距。
- 回退主内容区标题栏为普通流布局(不再 sticky)。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `docker compose build web && docker compose up -d web` -> 成功。
- `docker compose ps` -> `web/api/db` 均为 Upapi/db healthy)。
- 风险与影响:
- 仅影响后台布局滚动行为与间距,不涉及业务逻辑与接口。
## Work Log - 去掉外层左侧 padding 使导航贴边(2026-04-25
- 背景:
- 用户反馈左侧导航距离左边界约 24px,确认是外层容器 `px-*` 导致。
- 本次改动(最小闭环):
- `web/src/app/admin/layout.tsx`
- 将后台主栅格容器从统一 `px-*` 改为左右分离:
- 左侧:`md` 及以上固定 `pl-0`(移除左 padding
- 右侧:保持响应式 `pr-3 sm:pr-4 xl:pr-6`
- 目标:在桌面端让左侧导航贴到左边界,同时不改变右侧留白。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `docker compose build web && docker compose up -d web` -> 成功。
- `docker compose ps` -> `web/api/db` 均为 Upapi/db healthy)。
- 风险与影响:
- 仅影响后台横向边距与视觉布局,不涉及业务逻辑、接口和权限。
## Work Log - 重新打包发布镜像并更新容器(2026-04-25)
- 背景:
- 用户要求重新执行一次完整发布流程(构建镜像 + 更新容器)。
- 本次执行:
- `docker compose build`
- `docker compose up -d`
- 发布后验证:
- `docker compose ps``api/web/db` 均为 Up`api/db` healthy。
- `docker compose logs --tail=60 api`:启动完成,`/health` 200。
- `docker compose logs --tail=60 web`Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health`:返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/`:返回 `HTTP/1.1 200 OK`
- 风险与影响:
- 本次仅容器重建与滚动重启,存在短时服务切换窗口,不涉及数据库结构变更。
## Work Log - 移除后台页面通用“后台管理/用户邮箱”头信息(2026-04-25
- 背景:
- 用户要求去掉每个页面顶部重复出现的“后台管理、系统管理员、admin@asiainfo.com”信息。
## Work Log - 新增 Wine 执行器与实时测试日志(2026-04-25)
- 背景:
- 用户要求开发“通过 Wine 调用 Windows exe”的功能,执行时能实时看到日志,并提供测试能力。
- 本次改动(最小闭环):
- 后端:
- 新增 `api/app/schemas/wine.py`Wine 状态与执行请求 schema。
- 新增 `api/app/services/wine_service.py`
- 检测 `wine --version`
- 通过 `asyncio.create_subprocess_exec` 调用 Wine,不走 shell。
- `stdout/stderr` 合并为 SSE 事件实时输出。
- 支持超时终止、客户端断开时终止进程。
- EXE 与工作目录限制在 `WINE_ALLOWED_ROOT` 下,避免任意路径执行。
- 新增 `api/app/api/v1/wine.py`
- `GET /api/v1/wine/status`
- `POST /api/v1/wine/test/stream`
- `POST /api/v1/wine/run/stream`
- `api/app/api/router.py` 注册 Wine 路由。
- `api/app/core/config.py` / `.env.example` / `docker-compose.yml` 新增配置:
- `WINE_BINARY_PATH`
- `WINE_ALLOWED_ROOT`
- `WINE_DEFAULT_TIMEOUT_SECONDS`
- `WINE_MAX_TIMEOUT_SECONDS`
- 权限与菜单:
- 新增 `wine.read` / `wine.manage`
- 新增菜单 `admin.wine_runner` -> `/admin/wine-runner`
- 同步 admin 默认菜单绑定、受保护菜单集合、legacy 权限映射。
- 前端:
- 新增 `web/src/app/admin/wine-runner/page.tsx`
- Wine 状态检测。
- EXE 路径、工作目录、参数、超时配置。
- 执行测试/停止。
- 使用 `fetchWithAuth` 读取后端流式响应并实时追加日志。
- 后台首页新增 “Wine执行器” 入口。
- 菜单管理保护集合新增 `admin.wine_runner`
- 验证:
- `python3 -m py_compile api/app/schemas/wine.py api/app/services/wine_service.py api/app/api/v1/wine.py api/app/api/router.py api/app/core/config.py api/app/services/seed_service.py api/app/services/legacy_authz_service.py api/app/services/admin_service.py api/app/services/legacy_admin_rbac_service.py` -> 通过。
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 直接运行 Wine 状态服务验证未完成:宿主 Python 环境未安装 FastAPI 依赖,`python3 -c ...``ModuleNotFoundError: No module named 'fastapi'`
- Ant Design CLI 查询尝试未完成:默认 npm cache 在沙箱内只读;切换 `/tmp/npm-cache` 后 CLI 安装/执行未稳定返回,已停止该尝试。前端以 TypeScript 作为有效门禁。
- 风险与影响:
- 后端执行 EXE 属于高风险能力,当前仅允许 `wine.manage` 权限调用,并限制路径在 `WINE_ALLOWED_ROOT` 下。
- Docker API 镜像默认未安装 Wine;部署环境需自行安装 Wine 或通过 `WINE_BINARY_PATH` 指向可执行文件,否则状态检测会显示不可用。
- 停止操作会终止当前 Wine 进程;若 Windows 程序自行派生子进程,仍可能需要部署侧进一步加进程组/容器隔离策略。
- 本次改动(最小闭环):
- `web/src/app/admin/layout.tsx`
- 删除主内容区通用头块(`后台管理` 标题 + 当前用户名/邮箱)。
- 清理关联无用代码:
- 移除 `Heading`/`Flex` 引入;
- 移除 `flattenMenuTree``flatMenus/currentTitle` 计算。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `docker compose build web && docker compose up -d web` -> 成功。
- `docker compose ps` -> `web/api/db` 均为 Upapi/db healthy)。
- 风险与影响:
- 仅影响后台页面展示层,不涉及接口、权限和数据逻辑。
## Work Log - 全局滚动条样式改造成 Ant 风格(2026-04-25
- 背景:
- 用户要求将页面滚动条改造成接近 Ant Design 文档站风格。
- 本次改动(最小闭环):
- `web/src/app/globals.css`
- 新增全局滚动条样式:
- Firefox`scrollbar-width: thin` + `scrollbar-color`
- WebKit`::-webkit-scrollbar` / `::-webkit-scrollbar-thumb` / `::-webkit-scrollbar-track`
- 颜色基于 Ant token 变量(含回退值),避免主题切换时风格割裂。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 容器构建与更新成功(见下条日志)。
- 风险与影响:
- 仅影响前端视觉层滚动条样式,不涉及业务逻辑。
## Work Log - 修复 web 镜像构建链路(postinstall 脚本缺失)(2026-04-25
- 背景:
- 重新构建 `web` 镜像时,`npm ci` 触发 `postinstall` 报错:`Cannot find module /app/scripts/sync-cesium-assets.mjs`
- 根因:
- `web/Dockerfile``npm ci` 前仅复制 `package.json/package-lock.json`,未复制 `scripts/` 目录。
- 本次改动(最小闭环):
- `web/Dockerfile`
-`npm ci` 前补充:`COPY scripts ./scripts`
- 验证:
- `docker compose build web && docker compose up -d web` -> 成功。
- `docker compose ps` -> `web/api/db` 均为 Upapi/db healthy)。
- `docker compose logs --tail=40 web` -> Next.js Ready。
- 风险与影响:
- 仅影响 web 镜像构建阶段文件准备,不改变运行时业务逻辑。
## Work Log - 线路 Cesium 展示可行性评估(2026-04-25
- 背景:
- 用户询问“当前杆塔/线路管理是否可用 Cesium 展示线路,并给出方案或缺失项”。
- 评估结论:
- 可行。现有数据模型已具备线路可视化最小条件:杆塔经纬度 + 海拔 + 序号。
- 当前前端尚未接入任何地图引擎,`web` 依赖中无 `cesium`
- 证据定位:
- 后端杆塔模型已包含 `longitude` / `latitude` / `altitude_m``seq_no`(可拼线路折线):
- `api/app/models/line_tower.py`
- 线路杆塔查询按 `seq_no asc` 返回,适合前端直接生成 polyline:
- `api/app/services/line_service.py` -> `list_line_towers`
- `api/app/api/v1/lines.py` -> `GET /api/v1/lines/{line_id}/towers`
- 前端线路页已能拿到杆塔坐标并展示表格,但未做地图渲染:
- `web/src/app/admin/power-lines/page.tsx`
- 缺失项(接入前建议补齐):
- 坐标系元数据(WGS84/GCJ-02/CGCS2000)未显式存储,可能导致地图偏移难以排查。
- 当前塔列表接口单次 `limit` 上限为 `1000`,前端页面固定请求 `500`;超长线路会被截断,地图需补全分页拉取或专用几何接口。
- 目前 schema 未限制经纬度范围(仅 `float`),建议加范围校验避免脏坐标影响渲染。
- 验证:
- `rg -n "cesium|Cesium|mapbox|leaflet|openlayers|maplibre|deck\\.gl" web api package.json web/package.json` -> 无结果(当前未接入地图引擎)。
- `python3` 抽样读取 `test.csv`:34 条杆塔记录,经纬度有效 34 条,满足 Cesium MVP 展示条件。
## Work Log - 线路 Cesium MVP 实施(2026-04-25
- 背景:
- 用户要求“先实现 MVP 版本”。
- 本次改动(最小闭环):
- 前端依赖与构建链路:
- `web/package.json`
- 新增依赖 `cesium`
- 新增脚本:
- `postinstall`: `node scripts/sync-cesium-assets.mjs`
- `prebuild`: `node scripts/sync-cesium-assets.mjs`
- 新增脚本 `web/scripts/sync-cesium-assets.mjs`
- 兼容 workspace hoist(优先 `web/node_modules`,回退 `../node_modules`
-`Cesium``Assets/ThirdParty/Workers/Widgets` 同步到 `web/public/cesium`
- `web/.gitignore` 增加 `public/cesium`(避免提交生成资产)
- `web/src/app/layout.tsx` 增加 Cesium Widgets 全局样式导入
- `web/src/types/antd.d.ts` 增加 Cesium css 模块声明
- 页面能力:
- 新增组件 `web/src/components/power-line-cesium-map.tsx`
- 基于 Cesium `Viewer` 渲染线路折线(按 `seq_no` 排序)
- 渲染杆塔点位(带风险等级颜色)
- 默认显示起止塔号标签(点位 <=30 时显示全量标签)
- 空数据与初始化失败提示
- 改造 `web/src/app/admin/power-lines/page.tsx`
- 新增“表格/地图”视图切换
- 地图视图复用当前筛选后的杆塔数据(塔号/模型/塔型/风险等级)
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `npm run build:web` -> 通过(`/admin/power-lines` 页面产物正常生成,`prebuild` 触发 Cesium 资产同步)。
- 风险与影响:
- 当前为 MVP:仅实现线路折线 + 杆塔点位,不含杆塔 3D 模型与地形分析。
- 若单条线路点位非常大(>500)仍受现有页面查询口径影响;后续建议补分页全量拉取或专用几何接口。
## Work Log - 新增雷电流数据管理模块(2026-04-25)
- 背景:
- 需要将原始雷电流序列转化为可用于防雷计算的特征参数,并具备后台可管理能力(导入、查询、统计、预览)。
- 本次改动(最小闭环):
- 后端数据模型:
- 新增 `api/app/models/lightning_event.py``lightning_current_event`
- 事件元数据(地域/设备/天气/合成标记)
- 特征参数(`peak_current_ka``wavefront_time_t1_us``half_value_time_t2_us``steepness_ka_per_us``action_integral_j_ohm``wave_shape``polarity``stroke_count`
- 新增 `api/app/models/lightning_sample.py``lightning_current_sample`
- 采样点时序(`seq_no``time_us``current_ka`
- 后端能力:
- 新增 schema`api/app/schemas/lightning.py`
- 新增服务:`api/app/services/lightning_service.py`
- 原始 TXT/CSV 序列解析
- 时间轴构建(显式 time 列或采样间隔)
- 特征提取(T1/T2、陡度、I²t、波形分类、多回击识别)
- 事件 CRUD、采样分页查询、峰值超越概率(P 曲线)
- 新增路由:`api/app/api/v1/lightning.py`
- `GET /api/v1/lightning-currents`
- `POST /api/v1/lightning-currents/import`
- `GET /api/v1/lightning-currents/stats/exceedance`
- `GET/PATCH/DELETE /api/v1/lightning-currents/{event_id}`
- `GET /api/v1/lightning-currents/{event_id}/samples`
- 接入总路由:`api/app/api/router.py`
- 接入模型预加载:`api/app/models/__init__.py``api/app/core/database.py`
- 权限与菜单:
- `api/app/services/seed_service.py` 新增权限:
- `lightning.read`
- `lightning.manage`
- admin 默认角色授予上述权限。
- 新增默认菜单:`admin.lightning_currents` -> `/admin/lightning-currents`
- 前端页面:
- 新增 `web/src/app/admin/lightning-currents/page.tsx`
- 导入原始序列并提取特征
- 事件筛选列表
- 事件详情(核心防雷参数)
- 采样点预览(前 200
- 峰值超越概率表(P 曲线)
- 首页卡片接入:`web/src/app/admin/page.tsx`
- 菜单保护集合接入:`web/src/app/admin/menus/page.tsx`
- 类型补充:`web/src/types/auth.ts`
- 验证:
- 后端语法:
- `python3 -m py_compile api/app/models/lightning_event.py api/app/models/lightning_sample.py api/app/schemas/lightning.py api/app/services/lightning_service.py api/app/api/v1/lightning.py api/app/api/router.py api/app/core/database.py api/app/services/seed_service.py api/app/models/__init__.py` -> 通过。
- `python3 -m compileall api/app` -> 通过。
- 前端类型与构建:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `npm run build:web` -> 通过(包含 `/admin/lightning-currents` 路由产物)。
- 风险与影响:
- 采样点按关系型表存储(`lightning_current_sample`),超大序列导入会增加写入耗时与存储占用。
- 当前 T1/T2、多回击识别采用工程化自动提取算法(可用于工程筛查),如需严格对齐特定实验标准可在后续版本引入可配置算法参数。
## Work Log - 雷电流模块文案更名(2026-04-25)
- 背景:
- 用户要求将功能模块名称改为“雷电幅值统计”。
- 本次改动(最小闭环):
- `api/app/services/seed_service.py`
- 默认菜单 `admin.lightning_currents``name` 从“雷电流管理”调整为“雷电幅值统计”。
- `web/src/app/admin/page.tsx`
- 后台首页卡片标题同步改为“雷电幅值统计”。
- `web/src/app/admin/lightning-currents/page.tsx`
- 页面登录提示与主卡片标题文案同步为“雷电幅值统计”。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 仅文案调整,不涉及接口路径、权限码与数据结构变更。
## Work Log - 打包镜像并发布更新(含 Next.js 页面导出修复)(2026-04-25
- 背景:
- 用户要求“打包镜像并发布更新”。
- 发布过程与问题:
- 首次执行 `docker compose build` 时,`web``next build` 的 TypeScript 阶段失败:
- `src/app/admin/models/page.tsx` 默认导出带自定义 props`scene`),不符合 App Router `page.tsx` 导出约束。
- 本次改动(最小闭环):
- 前端修复:
- 新增 `web/src/app/admin/models/models-page-content.tsx` 承载可复用页面主体。
- `web/src/app/admin/models/page.tsx` 改为无参默认导出包装,仅渲染 `scene="models"`
- `web/src/app/admin/mcp-server/page.tsx``web/src/app/admin/orchestration/page.tsx` 改为复用 `models-page-content.tsx`
- 发布执行:
- `docker compose build`
- `docker compose up -d`
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `docker compose ps` -> `api/web/db` 均为 Up`api/db` healthy。
- `docker compose logs --tail=80 api` -> 启动完成,`/health` 200。
- `docker compose logs --tail=80 web` -> Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health` -> `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/` -> `HTTP/1.1 200 OK`
- 风险与影响:
- 发布包含前端页面导出结构修复,影响范围限定在 `models/mcp-server/orchestration` 三个页面的组件复用入口,不改变接口契约。
- 容器更新存在短时切换窗口;本次不涉及数据库结构变更。
## Work Log - 下线文件管理功能(2026-04-25
- 背景:
- 用户要求删除当前系统中的文件管理功能。
- 本次改动(最小闭环):
- 后端:
- 移除文件管理 API 路由挂载:
- 删除 `api/app/api/v1/admin_files.py`
- `api/app/api/router.py` 不再 include `admin_files_router`
- 删除文件管理服务与存储驱动实现:
- 删除 `api/app/services/file_service.py`
- 删除 `api/app/services/storage_driver.py`
- 删除 `api/app/schemas/file_storage.py`
- 清理权限/菜单默认配置:
- `api/app/services/seed_service.py` 移除 `file.read`/`file.manage`
- 移除默认菜单 `admin.files``/admin/knowledge-set`
- `admin` 默认菜单绑定移除 `admin.files`
- 移除默认文件存储 backend/mount 初始化逻辑(`_seed_file_storage`
- 清理鉴权与订阅映射:
- `api/app/services/legacy_authz_service.py` 移除 `file.*` 权限与 `admin.files` 映射
- `api/app/services/topic_registry.py` 移除 `admin.files` 主题规则
- `api/app/services/admin_service.py``api/app/services/legacy_admin_rbac_service.py` 取消 `admin.files` 受保护状态(并在 legacy removed 列表中标记为移除菜单)
- 前端:
- 删除文件管理页面:
- 删除 `web/src/app/admin/files/page.tsx`
- 删除 `web/src/app/admin/knowledge-set/page.tsx`
- `web/src/app/admin/page.tsx` 移除“知识集管理”入口卡片
- `web/src/app/admin/menus/page.tsx` 受保护菜单集合移除 `admin.files`
- 验证:
- 后端语法:
- `python3 -m py_compile api/app/api/router.py api/app/services/legacy_authz_service.py api/app/services/topic_registry.py api/app/services/admin_service.py api/app/services/legacy_admin_rbac_service.py api/app/services/seed_service.py` -> 通过。
- 前端类型:
- 首次执行 `npm --workspace web exec tsc --noEmit --pretty false``.next/types` 缓存残留已删除页面引用失败;
- 清理缓存后执行:
- `rm -rf web/.next`
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 现网数据库若已存在 `admin.files` 菜单记录,本次代码不会直接删库;在 legacy 菜单树策略下该菜单会被过滤为移除项。
- 本次仅下线文件管理能力,不触及既有文件存储表结构(`file_storage_*`)数据。
## Work Log - 参考 modo-next 迁移并恢复文件管理(FastAPI 实现,2026-04-25
- 背景:
- 用户要求“参考 `/root/.openclaw/workspace/modo-next` 的文件管理功能,迁移到当前系统,后端用 py 实现”。
- 本次改动(最小闭环):
- 后端(FastAPI):
- 恢复文件管理主链路(挂载点 + 目录索引 + 文件操作):
- `api/app/api/v1/admin_files.py`
- `api/app/services/file_service.py`
- `api/app/services/storage_driver.py`
- `api/app/schemas/file_storage.py`
- 总路由接回:
- `api/app/api/router.py` 重新 include `admin_files_router`
- 权限、菜单、topic、鉴权映射恢复:
- `api/app/services/seed_service.py` 恢复 `file.read` / `file.manage``admin.files` 菜单、默认 VFS/S3 存储后端与挂载点初始化;
- `api/app/services/legacy_authz_service.py` 恢复 `admin.files` -> `file.*` 映射;
- `api/app/services/topic_registry.py` 恢复 `admin.files` 订阅规则;
- `api/app/services/admin_service.py` / `api/app/services/legacy_admin_rbac_service.py``admin.files` 恢复为受保护菜单。
- 参考 modo-next 增强点(目录打包下载):
- 新增 `GET /api/v1/admin/files/download-zip`
- `file_service` 新增目录递归读取 + 内存 zip 打包能力。
- 前端:
- 恢复文件管理页面与知识集入口:
- `web/src/app/admin/files/page.tsx`
- `web/src/app/admin/knowledge-set/page.tsx`
- `web/src/app/admin/page.tsx` 恢复“知识集管理”卡片;
- `web/src/app/admin/menus/page.tsx` 恢复 `admin.files` 受保护项。
- 对齐增强点:
- 文件管理页面目录行新增“下载目录”按钮,调用 `/api/v1/admin/files/download-zip`
- 验证:
- 后端语法:
- `python3 -m py_compile api/app/api/router.py api/app/api/v1/admin_files.py api/app/schemas/file_storage.py api/app/services/file_service.py api/app/services/storage_driver.py api/app/services/seed_service.py api/app/services/legacy_authz_service.py api/app/services/topic_registry.py api/app/services/admin_service.py api/app/services/legacy_admin_rbac_service.py` -> 通过。
- 前端类型:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 本次为“恢复 + 增强”改动,重新启用了 `file.read/file.manage``admin.files` 链路;若依赖最小权限策略,需确认角色权限配置是否符合预期。
- 目录 zip 下载采用内存打包,大目录大文件场景会占用较多 API 内存;后续可按需升级为临时文件流式下载方案。
## Work Log - 统一系统滚动条样式到主页面基线(2026-04-25)
- 背景:
- 用户反馈系统内滚动条样式不统一,要求与主页面滚动条样式一致。
- 本次改动(最小闭环):
- `web/src/app/globals.css`
- 新增全局滚动条 token`--fquiz-scrollbar-thumb``--fquiz-scrollbar-thumb-hover`
-`scrollbar-width/scrollbar-color``html, body` 扩展为 `*`,统一所有滚动容器(尤其 Firefox)。
- 统一 `*::-webkit-scrollbar*` 使用同一套 token。
- `scrollbar-antd` 类仅保留 `scrollbar-gutter: stable`,移除重复的颜色/尺寸定义,避免局部与全局样式漂移。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 仅影响前端滚动条视觉样式,不涉及业务逻辑、接口与权限。
- 在 Firefox 中,之前未显式声明滚动条样式的局部滚动容器也会统一为主页面风格。
## Work Log - 打包镜像并发布更新(2026-04-25,晚间重发)
- 背景:
- 用户要求再次执行“打包镜像并发布更新”。
- 本次执行:
- `docker compose build`
- `docker compose up -d`
- 发布后验证:
- `docker compose ps``api/web/db` 均为 Up,且 `api/db` healthy。
- `docker compose logs --tail=80 api`:API 启动完成,健康检查请求返回 200。
- `docker compose logs --tail=80 web`Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health`:返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/`:返回 `HTTP/1.1 200 OK`
- 风险与影响:
- 本次仅镜像重建与容器滚动更新,不涉及数据库结构变更。
## Work Log - 修复 Cesium SPZ 依赖导致的前端 chunk 语法错误(2026-04-25
- 背景:
- 浏览器报错:`Uncaught SyntaxError: Octal escape sequences are not allowed in template strings`
- 报错 chunk`2117a04a.ddf56f789729a94a.js`
- 根因:
- Cesium `1.140.0` 依赖链中的 `@spz-loader/core@0.3.1` 把 SPZ WASM 二进制以内联模板字符串打进前端 chunk。
- 该模板字符串中包含 `\00` / `\001` 等八进制转义形态,浏览器解析阶段直接报错。
- 当前业务地图仅使用 Cesium Viewer/Entity/Polyline/Point,不使用 SPZ/Gaussian splats。
- 本次改动(最小闭环):
- `web/src/lib/spz-loader-core-shim.ts`
- 新增 `loadSpz` / `loadSpzFromUrl` 轻量 shim。
- 若未来实际加载 SPZ 内容,显式抛出 `SPZ Gaussian splat decoding is disabled in this build.`
- `web/next.config.ts`
- 增加 webpack alias,将 `@spz-loader/core` 指向本地 shim,避免问题依赖进入浏览器 chunk。
- 为恢复构建门禁,顺手修复现有 AntD + React 19 类型阻断:
- `web/src/app/admin/layout.tsx`
- `web/src/app/admin/page.tsx`
- `web/src/app/admin/menus/page.tsx`
- `web/src/app/admin/roles/page.tsx`
- `web/src/app/admin/users/page.tsx`
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `npm run build:web` -> 通过。
- 本地构建产物检查:
- `rg -l --text '@spz-loader/core|load_spz|couldn.t allocate memory' web/.next/static/chunks` -> 无匹配。
- `rg -l --text 'SPZ Gaussian splat decoding is disabled' web/.next/static/chunks` -> 命中本地 shim chunk。
- `node --check web/.next/static/chunks/4912.c2dc9fb5bf5449a0.js` -> 通过。
- Docker 发布:
- `docker compose build web` -> 通过。
- `docker compose up -d web` -> 成功。
- 运行中容器验证:
- `docker compose ps``web` Up`api/db/redis` healthy。
- `docker compose logs --tail=60 web`Next.js Ready。
- `curl -I -fsS http://127.0.0.1:3000/` -> `HTTP/1.1 200 OK`
- `curl -sS -I http://127.0.0.1:3000/_next/static/chunks/2117a04a.ddf56f789729a94a.js` -> `HTTP/1.1 404 Not Found`
- 容器内 `grep -R -l 'load_spz\|@spz-loader/core\|couldn.t allocate memory' .next/static/chunks` -> 无匹配。
- 风险与影响:
- 常规 Cesium 地图能力保留。
- 如果后续需要加载 SPZ/Gaussian splats,需要移除 shim 并改为上游依赖修复或单独的安全 WASM 加载方案。
## Work Log - 拆出雷电分布统计独立菜单入口(2026-04-25)
- 背景:
- 用户指出《雷电数据.txt》对应能力应该有基于该数据开发的页面。
- 本次改动(最小闭环):
- 前端:
- 新增独立路由 `web/src/app/admin/lightning-distribution/page.tsx`,访问地址 `/admin/lightning-distribution`
- 调整 `web/src/app/admin/lightning-currents/page.tsx`
-`/admin/lightning-distribution` 下只展示分布统计相关能力;
- 保留分布导入、Ng/网格热力、Cesium 散点地图、杆塔缓冲区、实测/合成对比、周/月报、P 曲线;
- 隐藏雷电流幅值页专属的原始序列导入、事件列表、事件详情与采样预览。
- `web/src/app/admin/page.tsx` 新增“雷电分布统计”首页入口卡片。
- `web/src/app/admin/menus/page.tsx` 新增受保护菜单 `admin.lightning_distribution`
- 后端:
- `api/app/services/seed_service.py` 新增默认菜单:
- `admin.lightning_distribution` -> `/admin/lightning-distribution`,权限 `lightning.read`
- admin 默认菜单绑定新增 `admin.lightning_distribution`
- `admin_service` / `legacy_admin_rbac_service` / `legacy_authz_service` 同步补充保护集合、权限映射与 legacy admin 默认权限。
- 验证:
- `python3 -m py_compile api/app/services/seed_service.py api/app/services/admin_service.py api/app/services/legacy_admin_rbac_service.py api/app/services/legacy_authz_service.py` -> 通过。
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `npm run build:web` -> 通过,构建产物包含 `/admin/lightning-distribution`
- 风险与影响:
- 仅新增入口并复用现有雷电分布统计接口与页面底座,不新增数据表和接口契约。
- 已运行容器若要看到新菜单,需要重新构建/重启前后端服务并触发默认菜单种子同步。
## Work Log - 打包镜像并发布更新(2026-04-25,连续重发)
- 背景:
- 用户再次要求执行“打包镜像并发布更新”。
- 本次执行:
- `docker compose build`
- `docker compose up -d`
- 发布后验证:
- `docker compose ps``api/web/db/minio` 均为 Up`api/db` healthy。
- `docker compose logs --tail=80 api`API 启动完成,`/health` 请求返回 200。
- `docker compose logs --tail=80 web`Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health`:返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/`:返回 `HTTP/1.1 200 OK`
- 构建提示:
- Next.js 构建仍提示 `middleware` 文件约定已 deprecated,建议后续迁移到 `proxy`
- 风险与影响:
- 本次仅镜像重建与容器滚动更新,不涉及数据库结构变更。
- `api` 日志包含 `InsecureKeyLengthWarning`JWT HMAC key 长度低于建议值),不影响本次发布成功,但建议后续将 `JWT_SECRET_KEY` 升级为至少 32 字节。
## Work Log - 修复 Next.js chunk 丢失导致页面白屏(2026-04-25
- 背景:
- 本地访问 `http://localhost:3000` 出现报错:
- `Loading chunk 5782 failed. (missing: .../_next/static/chunks/*.js)`
- 该类问题通常由浏览器缓存中的旧 chunk 清单与当前构建产物不一致触发。
- 本次改动(最小闭环):
- `web/src/lib/chunk-error.ts`
- 新增 chunk 错误识别与恢复工具:
- 识别 `Loading chunk ... failed` / `ChunkLoadError` / 动态 import 失败等模式;
- 提供“一次性自动刷新”逻辑,防止无限刷新循环。
- `web/src/components/chunk-load-recovery.tsx`
- 新增全局监听组件:监听 `window error``unhandledrejection`,命中 chunk 错误时自动刷新一次。
- `web/src/app/layout.tsx`
- 接入 `ChunkLoadRecovery`,让所有页面共享该容错能力。
- `web/src/app/error.tsx`
- 新增路由级错误边界 UI;chunk 失配时自动刷新,并提供“重试/刷新页面”手动恢复按钮。
- `web/src/app/global-error.tsx`
- 新增全局错误边界 UI,覆盖 root layout 级异常场景。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `npm run build:web` -> 通过(Next.js 16 构建完成,路由产物正常)。
- 风险与影响:
- 仅影响前端异常恢复链路,不涉及接口契约、权限与数据库。
- 若用户浏览器禁用 sessionStorage,则“防重复刷新标记”为 best-effort;仍可通过错误页按钮手动刷新恢复。
## Work Log - 修复页面滚动后 Modal 顶部遮挡(2026-04-25
- 背景:
- 用户反馈:页面滚动到底部时打开 Modal,弹窗在顶部被屏幕遮挡。
- 根因:
- `web/src/app/globals.css``快乐工作特效``body` 使用了 `filter` 动画。
- `filter` 会改变 `position: fixed` 的定位上下文,导致挂载到 `body` 的 AntD `Modal` 在滚动场景出现错位/遮挡。
- 本次改动(最小闭环):
- `web/src/app/globals.css`
- 保留 `:root.fquiz-happy-work body` 动画开关。
- 将关键帧从 `filter` 动画改为 `background-color` 轻微脉冲(`color-mix`),避免影响 fixed 定位。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 仅影响“快乐工作特效”视觉表现;不涉及业务逻辑、接口与权限。
- Modal 定位恢复为相对视口,滚动场景下不再被顶部裁切。
## Work Log - 打包镜像并发布更新(2026-04-25,夜间重发)
- 背景:
- 用户要求执行“打包镜像并发布更新”。
- 本次执行:
- `docker compose build`
- `docker compose up -d`
- 发布后验证:
- `docker compose ps``api/web/db` 均为 Up,且 `api/db` healthy。
- `docker compose logs --tail=80 api`API 启动完成,`/health` 请求返回 200。
- `docker compose logs --tail=80 web`Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health`:返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/`:返回 `HTTP/1.1 200 OK`
- 风险与影响:
- 本次仅镜像重建与容器滚动更新,不涉及数据库结构变更。
## Work Log - 修复线路地图 Chunk 失败不自动恢复(2026-04-25
- 背景:
- 线路管理地图视图出现 `地图加载失败`,错误为 `Loading chunk ... failed`
- 根因是 Cesium `import("cesium")` 在组件内被 `try/catch` 捕获,导致全局 chunk 恢复监听未触发。
- 本次改动(最小闭环):
- `web/src/components/power-line-cesium-map.tsx`
-`import("cesium")` 失败的 `catch` 分支里接入 `reloadOnceOnChunkError(error)`
- 命中 chunk 错误时先触发自动刷新恢复,再兜底展示错误。
- `web/src/components/chunk-load-recovery.tsx`
- 移除挂载时清理 marker 的逻辑,避免持续 chunk 失败时反复刷新。
- `web/src/lib/chunk-error.ts`
- 单次刷新标记改为“带时间戳冷却窗口”(2 分钟),避免刷新死循环,同时保留后续恢复能力。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- `npm run build:web` -> 通过。
- 风险与影响:
- 仅影响前端异常恢复策略,不涉及接口契约、权限和数据库。
- 若 chunk 在冷却窗口内持续不可用,将停止自动刷新并保留页面错误提示,避免无限重载。
## Work Log - 新增雷电分布统计模块(空间统计 + 资产关联 + 报表,2026-04-25
- 背景:
- 用户要求基于《雷电数据.txt》(经纬度 + 电流幅值)落地“雷电分布统计”能力,覆盖:
- 网格化地闪密度(Ng
- 电流极值/均值与极性占比
- 雷电热力图 + 散点分布 + P 曲线
- 杆塔缓冲区风险分析
- 实测/合成分布对比
- 周报/月报汇总
- 本次改动(最小闭环,前后端联动):
- 后端(FastAPI + SQLAlchemy
- 新增分布导入接口(TXT/CSV 经纬度电流)与清洗逻辑:
- `POST /api/v1/lightning-currents/import-distribution`
- 自动过滤非法行/非法坐标,落库到 `lightning_current_event`(无波形样本)
- 新增空间统计接口:
- `GET /api/v1/lightning-currents/stats/distribution`
- 返回网格统计(Ng/Imax/Iavg/正极占比)、散点数据、P 曲线、极性统计、来源统计
- 新增资产关联接口:
- `GET /api/v1/lightning-currents/stats/tower-buffer`
- 支持 tower_id 或自定义坐标 + 半径(km)缓冲区分析,输出风险等级与建议
- 新增合成对比接口:
- `GET /api/v1/lightning-currents/stats/compare-synthetic`
- 输出实测/合成统计与网格余弦相似度
- 新增周期报表接口:
- `GET /api/v1/lightning-currents/reports/distribution?period=week|month`
- 输出近 7 天/30 天雷击次数、Imax/Iavg、Ng、最严重事件
- 主要文件:
- `api/app/schemas/lightning.py`
- `api/app/services/lightning_service.py`
- `api/app/api/v1/lightning.py`
- 前端(Next.js + AntD
- `web/src/app/admin/lightning-currents/page.tsx` 扩展为“雷电分布统计工作台”:
- 分布筛选(经纬度范围、网格尺寸、年限、阈值)
- 分布导入按钮(调用 import-distribution
- 分布摘要指标(Ng、Imax/Iavg、极性与来源)
- 网格热力表(按雷击次数着色)
- 杆塔缓冲区分析表单 + 风险结果 + 命中事件表
- 实测/合成对比 + 周/月报卡片
- P 曲线优先展示空间统计返回结果
- 新增 Cesium 地图组件:
- `web/src/components/lightning-distribution-map.tsx`
- 支持热力网格(矩形半透明着色)+ 雷击散点(按电流幅值分色)
- 补充类型定义:
- `web/src/types/auth.ts`
- 验证:
- 后端语法:
- `python3 -m py_compile api/app/schemas/lightning.py api/app/services/lightning_service.py api/app/api/v1/lightning.py` -> 通过
- 前端类型:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过
- 前端构建:
- `npm run build:web` -> 通过(含 `/admin/lightning-currents`
- 风险与影响:
- 当前空间统计采用经纬度近似换算(非 PostGIS 精确地理计算);在高纬或超大范围场景误差会增大。
- `import-distribution` 为高吞吐导入,超大文件建议分批导入以降低单次事务压力。
- 杆塔缓冲区分析当前为查询结果级风险判定(返回风险等级与建议),如需“自动写回杆塔风险字段”可在后续补充持久化开关与审计策略。
## Work Log - 打包镜像并发布更新(2026-04-25,深夜重发)
- 背景:
- 用户要求再次执行“打包镜像并发布更新”。
- 本次执行:
- `docker compose build`
- `docker compose up -d`
- 发布后验证:
- `docker compose ps``api/web/db` 均为 Up,且 `api/db` healthy。
- `docker compose logs --tail=80 api`API 启动完成,`/health` 请求返回 200。
- `docker compose logs --tail=80 web`Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health`:返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/`:返回 `HTTP/1.1 200 OK`
- 风险与影响:
- 本次仅镜像重建与容器更新,不涉及数据库结构变更。
## Work Log - Docker Compose 接入 MinIO 并切换文件管理默认后端(2026-04-25)
- 背景:
- 用户要求为系统增加 MinIO 组件,并让文件管理功能连接 MinIO。
- 本次改动(最小闭环):
- `docker-compose.yml`
- 新增 `minio` 服务(API `9000` + Console `9001`)。
- 新增 `minio-init` 服务(使用 `minio/mc` 自动创建 `MINIO_BUCKET`)。
- `api` 服务新增 MinIO 环境变量,并依赖 `minio``minio-init`
- 新增数据卷 `fquiz_minio_data`
- `api/app/core/config.py`
- 新增 MinIO 配置项:`minio_enabled/minio_endpoint/minio_access_key/minio_secret_key/minio_bucket/minio_region`
- `api/app/services/seed_service.py`
- 文件存储种子改为按 `MINIO_ENABLED` 动态切换默认后端:
- 开启时:`files.s3.default` 启用且设为默认,`main` 挂载指向 S3。
- 关闭时:回退 `files.vfs.default`
- 对已存在后端记录也会更新 `status/is_default/config_json`,保证切换生效。
- `.env` / `.env.example`
- 增加 MinIO 相关变量与端口/镜像默认值。
- 验证:
- `python3 -m py_compile api/app/core/config.py api/app/services/seed_service.py` -> 通过。
- `docker compose config` -> 通过。
- `docker compose up -d minio minio-init api` + `docker compose up --build -d api` -> 成功。
- `docker compose ps -a` -> `minio` 运行中,`minio-init` `Exited (0)`
- `docker compose logs --tail=80 minio-init` -> bucket 创建成功(`Bucket created successfully local/fquiz-files`)。
- 数据库校验(`postgres` 库):
- `file_storage_backends``files.s3.default``enabled + is_default=true``files.vfs.default``disabled`
- `file_storage_mounts.main``backend_code=files.s3.default`
- 风险与影响:
- 当前使用默认凭据 `minioadmin/minioadmin`,仅适合开发环境;生产需替换强口令并限制端口暴露。
## Work Log - 打包镜像并更新重启(2026-04-25)
- 背景:
- 用户要求执行“打包镜像并更新重启”。
- 本次执行:
- `docker compose build`
- `docker compose up -d`
- 发布后验证:
- `docker compose ps``api/web/db/minio` 均为 `Up``api/db``healthy`
- `docker compose logs --tail=80 api`API 启动完成,`/health` 持续返回 200。
- `docker compose logs --tail=80 web`Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health`:返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/`:返回 `HTTP/1.1 200 OK`
- 风险与影响:
- 本次为镜像重建与容器滚动重启,存在短时服务切换窗口,不涉及数据库结构变更。
## Work Log - 用户管理新增用户表单迁移到 Modal2026-04-25
- 背景:
- 用户要求将“用户管理”页面的新增用户表单从页面内联区域改为弹窗输入。
- 本次改动(最小闭环):
- `web/src/app/admin/users/page.tsx`
- 新增 `createUserModalOpen` 状态与打开/关闭处理。
- 原“新增用户”卡片内联 `Form` 改为提示文案 + `新增用户` 按钮触发。
- 新增“新增用户”`Modal`,内部复用原有创建表单字段、校验规则与提交逻辑。
- 创建成功后自动关闭弹窗并刷新用户/角色列表;创建中禁止关闭弹窗。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 仅调整前端交互承载位置,不涉及接口契约、权限和数据库。
## Work Log - 菜单管理页面去掉顶部统计区块(2026-04-25)
- 背景:
- 用户要求菜单管理页面移除顶部“总菜单数/启用/禁用/顶级菜单”统计展示。
- 本次改动(最小闭环):
- `web/src/app/admin/menus/page.tsx`
- 删除顶部统计区块渲染(四个 `Statistic` 卡片)。
- 清理未使用的 `Statistic` 引入与 `stats` 计算逻辑。
- 保留筛选表单、菜单列表与新建/编辑弹窗能力不变。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 仅影响页面展示,不涉及接口、权限和数据逻辑。
## Work Log - 全部去掉外层间距并去掉圆角(2026-04-25)
- 背景:
- 用户要求“全部去掉外层间距,去掉圆角”。
- 本次改动(最小闭环):
- `web/src/app/admin/layout.tsx`
- 顶栏容器去掉 `max-width` 与外层左右 padding。
- 主栅格容器去掉 `max-width` 与外层左右 padding。
- 主内容容器由 `py-4 md:px-6` 调整为 `py-0 px-0`(去掉外层间距)。
- 进入后台时给 `body` 增加 `fquiz-admin-flat` 类,离开后台移除。
- `web/src/app/globals.css`
- 新增 `body.fquiz-admin-flat` 作用域:对元素与伪元素统一 `border-radius: 0 !important`,去掉后台页面与弹窗圆角。
- `web/src/components/ui-antd.tsx`
- `Theme` 默认 `radius``medium` 调整为 `none`
- AntD token `borderRadius` fallback 调整为 `RADIUS_MAP.none`
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 后台视觉风格将显著变为“直角 + 贴边”,包括头像/标签/弹窗等圆角元素。
- 仅影响前端样式,不涉及接口、权限与数据逻辑。
## Work Log - 角色管理页面支持搜索(2026-04-25)
- 背景:
- 用户要求角色管理页面支持搜索。
- 本次改动(最小闭环):
- `web/src/app/admin/roles/page.tsx`
- 新增搜索状态 `searchKeyword`
- 新增 `filteredRoles`,基于关键词对角色进行前端过滤,匹配字段包括:
- 角色编码 `code`
- 角色名称 `name`
- 权限编码列表 `permission_codes`
- 菜单名称/编码(通过 `menu_ids` 映射)
- 页面新增搜索输入框(支持清空),位于角色列表头部。
- 列表统计文案改为“总数 + 匹配数”。
- 无匹配时显示“未找到匹配角色,请调整搜索关键词”。
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 本次为前端本地过滤,不改变后端接口契约和权限逻辑。
- 当角色规模极大时,本地过滤性能可能下降;若后续角色数增长明显,可再升级为后端关键词查询。
## Work Log - 打包镜像并发布更新(2026-04-25,夜间再次重发)
- 背景:
- 用户要求执行“打包镜像并发布更新”。
- 本次执行:
- `docker compose build`
- `docker compose up -d`
- 发布后验证:
- `docker compose ps``api/web/db/minio` 均为 Up`api/db` healthy。
- `docker compose logs --tail=80 api`API 启动完成,`/health` 请求返回 200。
- `docker compose logs --tail=80 web`Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health`:返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/`:返回 `HTTP/1.1 200 OK`
- 风险与影响:
- 本次仅镜像重建与容器滚动更新,不涉及数据库结构变更。
## Work Log - 恢复后台圆角(2026-04-25
- 背景:
- 用户要求“恢复圆角”。
- 本次改动(最小闭环):
- `web/src/app/globals.css`
- 移除 `body.fquiz-admin-flat` 下全局强制 `border-radius: 0 !important` 的规则。
- `web/src/app/admin/layout.tsx`
- 移除进入后台时给 `body` 增加 `fquiz-admin-flat` 的逻辑。
- 保留已调整的贴边布局与外层间距策略。
- `web/src/components/ui-antd.tsx`
- `Theme` 默认 `radius` 恢复为 `medium`
- AntD token `borderRadius` fallback 恢复为 `RADIUS_MAP.medium`
- 验证:
- `rg -n "fquiz-admin-flat|admin-flat-ui|borderRadius: RADIUS_MAP\\[radius\\] \\?\\? RADIUS_MAP\\.none|radius = \\"none\\"" web/src` -> 无匹配。
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 仅恢复前端视觉圆角,不涉及接口、权限、数据结构。
- 外层贴边/去外层间距布局未回退。
## Work Log - 打包镜像并发布更新(2026-04-25,再次执行)
- 背景:
- 用户要求执行“打包镜像并发布更新”。
- 本次执行:
- `docker compose build`
- `docker compose up -d`
- 发布后验证:
- `docker compose ps``api/web/db/minio` 均为 Up`api/db` healthy。
- `docker compose logs --tail=80 api`API 启动完成,`/health` 请求返回 200。
- `docker compose logs --tail=80 web`Next.js Ready。
- `curl -fsS http://127.0.0.1:8000/health`:返回 `{"status":"ok","service":"fquiz-api","version":"0.1.0"}`
- `curl -I -fsS http://127.0.0.1:3000/`:返回 `HTTP/1.1 200 OK`
- 风险与影响:
- 本次仅镜像重建与容器滚动更新,不涉及数据库结构变更。
## Work Log - 接入 Redis + Celery + Beat 后端调度(2026-04-25
- 背景:
- 用户明确要求“加 redis 组件,上 Celery + Beat”。
- 本次改动(最小闭环):
- 依赖:
- `api/requirements.txt` 新增 `celery[redis]==5.5.3`
- `api/pyproject.toml` 新增 `celery[redis]>=5.5.0,<6.0.0`
- 后端配置:
- `api/app/core/config.py` 新增 `CELERY_BROKER_URL``CELERY_RESULT_BACKEND``CELERY_TIMEZONE``SCHEDULER_EXPIRE_INTERVAL_SECONDS` 配置。
- 新增 `api/app/core/celery_app.py`,统一配置 Celery app、Redis broker/result backend 与 Beat schedule。
- 任务模块:
- 新增 `api/app/tasks/`
- 新增任务 `app.tasks.schedule_tasks.expire_overdue_schedule_items`
- `api/app/services/calendar_event_service.py` 将日程过期逻辑公开为 `expire_overdue_events()`
- `api/app/services/todo_service.py` 新增 `expire_overdue_todos()`
- Compose
- `docker-compose.yml` 新增 `redis``celery-worker``celery-beat` 服务。
- `.env.example` 新增 Redis/Celery/调度间隔配置项。
- 验证:
- `python3 -m py_compile api/app/core/config.py api/app/core/celery_app.py api/app/tasks/__init__.py api/app/tasks/schedule_tasks.py api/app/services/calendar_event_service.py api/app/services/todo_service.py` -> 通过。
- `docker compose config` -> 通过,能渲染 `redis``celery-worker``celery-beat`
- `docker compose build api celery-worker celery-beat` -> 通过,`celery-5.5.3``redis-5.2.1` 安装成功。
- `docker compose up -d redis api celery-worker celery-beat` -> 成功。
- `docker compose ps --status running` -> `api/celery-worker/celery-beat/redis/db/minio/web` 均为 running`api/db/redis` healthy。
- `docker exec fquiz-redis redis-cli ping` -> `PONG`
- `docker exec fquiz-celery-worker celery -A app.core.celery_app.celery_app inspect registered` -> 已注册 `app.tasks.schedule_tasks.expire_overdue_schedule_items`
- 手动投递 `expire_overdue_schedule_items` -> worker 执行成功,返回 `{'expired_calendar_events': 0, 'expired_todos': 0}`
- Beat 日志显示已周期投递 `expire-overdue-schedule-items`
- `curl -fsS http://127.0.0.1:8000/health` -> API 健康。
- `curl -I -fsS http://127.0.0.1:3000/` -> Web 首页 200。
- 风险与影响:
- 新增 Redis 数据卷 `fquiz_redis_data` 与端口 `6379`
- `celery-worker` 当前以容器 root 用户运行,Celery 会输出安全警告;生产环境建议后续在 API Dockerfile 中新增非 root 用户并为 worker/beat 指定用户。
- 当前 Beat schedule 使用本地文件 `/tmp/celerybeat-schedule`,适合当前单 Beat 实例;不要横向启动多个 Beat 实例,避免重复投递。
## Work Log - 按 Ant Design 规范改造后台 UI2026-04-25
- 背景:
- 用户明确要求“按照 ant design 的设计规范改造当前系统,不要最小改动,要严格按照 ant design 的设计规范改造”。
- 本次改动(系统级前端改造):
- AntD 主题与 Provider
- `web/src/components/ui-antd.tsx`
- `Theme` 改为 `ConfigProvider + App` 包裹,接入 `zh_CN` locale。
- 默认强调色恢复 AntD 蓝色体系(`blue/#1677ff`)。
- 圆角 token 调整到 AntD 常规基线(`medium=6``large=8`)。
- 增加 AntD token CSS 变量桥接:背景、圆角、间距、阴影等。
- 增加 Layout/Menu/Card/Table component token 配置。
- 主题偏好 localStorage 初始化改为 microtask,避免 React lint 的同步 effect setState 告警。
- `web/src/app/layout.tsx`
- 根 Theme 默认 `accentColor` 改为 `blue`
- 后台布局:
- `web/src/app/admin/layout.tsx`
- 从自绘 header/grid/aside 改为 AntD `Layout/Header/Sider/Content`
- 增加桌面侧边栏收起/展开。
- 增加移动端 `Drawer` 菜单入口。
- 增加 Breadcrumb + 页面标题 + 描述的 AntD 页面头。
- 账号区和主题区统一为 AntD `Dropdown/Button/Avatar`
- `web/src/app/globals.css`
- 增加 `admin-design-*` 布局类,统一 64px Header、24px 内容区留白、Sider 粘性高度、移动端 16px 内容留白。
- 不使用全局 `.ant-*` 覆盖,布局样式通过项目自有 class + AntD token 变量表达。
- 工作台与核心页面:
- `web/src/app/admin/page.tsx`
- 改为 AntD `Statistic` 汇总 + `Row/Col/Card/Tag/Avatar` 模块入口。
- 模块入口 URL 改为公开路径(如 `/users`),减少 `/admin/*` 重定向依赖。
- 增加 `Wine执行器` 入口。
- `web/src/app/admin/roles/page.tsx`
- 从自绘 table/dialog/input/checkbox 迁移为 AntD `Card/Table/Form/Modal/Select/Input/App message/modal`
- 权限点和可见菜单改为 `Select mode="multiple"`
- 保留角色搜索、创建、编辑、删除能力。
- `web/src/app/admin/users/page.tsx`
- 列表 Card 直接使用 AntD Card,并将“新增用户”动作收口到列表 Card extra,减少单按钮卡片。
- `web/src/app/admin/menus/page.tsx`
- 使用 AntD `App.useApp()` message,去掉独立 message context holder。
- 列表 Card 直接使用 AntD Card。
- `web/src/components/row-action-menu.tsx`
- 从 Radix 兼容 `DropdownMenu` 改为 AntD `Dropdown + Button`
- 验证:
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 针对本次改动文件执行:
- `npx eslint src/app/admin/layout.tsx src/app/admin/page.tsx src/app/admin/roles/page.tsx src/app/admin/users/page.tsx src/app/admin/menus/page.tsx src/components/row-action-menu.tsx src/components/ui-antd.tsx` -> 通过。
- `npm run build:web` -> 通过(Next.js 16 构建完成,33 个 app routes 生成成功)。
- `git diff --check -- <本次改动文件>` -> 通过。
- 说明:
- 尝试按 `ant-design` 技能要求运行官方 CLI
- `npx antd info ... --format json` -> 失败(不是官方 CLI 可执行包)。
- `npx @ant-design/cli info ... --format json` -> 下载后长时间卡住,已终止卡住进程。
- 因 CLI 在当前环境不可用,本次以官方 AntD 组件 API 类型、本地 TypeScript、Next build 和 AntD 设计规范口径兜底。
- `npm --workspace web run lint` 全量仍失败,主要来自 `web/public/cesium` 生成资产与历史页面 hook/any 问题;本次改动文件的 targeted lint 已通过。
- 风险与影响:
- 后台视觉与交互范围变更较大:恢复 AntD 内容区留白、页面标题、Breadcrumb、Sider 折叠和移动端 Drawer。
- 这是前端 UI 改造,不涉及后端接口、权限码和数据库结构。
- 因全局后台 layout 改造覆盖所有后台页面,建议发布前做一次浏览器人工走查:桌面、移动端、浅色/暗黑/紧凑主题。
## Work Log - 新增任务监控模块(2026-04-25
- 背景:
- 用户要求“补充任务监控功能”。
- 本次改动(最小闭环):
- 后端:
- 新增 `api/app/schemas/task_monitor.py`:任务监控聚合响应 schema。
- 新增 `api/app/services/task_monitor_service.py`
- 聚合 `Requirement``Todo` 的状态/优先级分布。
- 输出关键指标:需求总量/活跃/完成、待办总量/活跃/完成/超期。
- 输出风险清单:高优先级需求、滞留需求、超期待办。
- 按权限分层返回(有哪类权限返回哪类数据)。
- 新增 `api/app/api/v1/task_monitor.py``GET /api/v1/admin/task-monitor/overview`
- 路由注册:`api/app/api/router.py` 接入 `task_monitor_router`
- 菜单与权限映射:
- `api/app/services/seed_service.py`:新增默认菜单 `admin.task_monitor``/admin/task-monitor`)并加入 admin 默认菜单绑定。
- `api/app/services/legacy_authz_service.py`:新增 `admin.task_monitor` 权限映射(`requirement.read` + `todo.read`)与 legacy synthetic 菜单兜底。
- `api/app/services/legacy_admin_rbac_service.py`:将 `admin.task_monitor` 加入受保护菜单集合。
- `web/src/app/admin/menus/page.tsx`:受保护菜单集合新增 `admin.task_monitor`,避免误删。
- 前端:
- 新增 `web/src/app/admin/task-monitor/page.tsx`
- 监控参数(风险项上限、滞留阈值小时)可调。
- 展示指标卡、分布标签、风险表格(高优先级需求/滞留需求/超期待办)。
- 无权限与未登录态提示完整。
- `web/src/app/admin/page.tsx`:新增“任务监控”工作台入口卡片。
- 验证:
- 后端语法:
- `python3 -m py_compile api/app/schemas/task_monitor.py api/app/services/task_monitor_service.py api/app/api/v1/task_monitor.py api/app/api/router.py api/app/services/legacy_authz_service.py api/app/services/legacy_admin_rbac_service.py api/app/services/seed_service.py` -> 通过。
- 前端类型:
- `rm -rf .next`(清理过期类型产物)
- `npm --workspace web exec tsc --noEmit --pretty false` -> 通过。
- 风险与影响:
- 任务监控为聚合读接口,不改原有需求/待办 CRUD 链路。
- 需求数据当前无独立 `due_at` 持久字段,滞留判断基于 `update_date` 与阈值小时。
- 菜单通过 seed + legacy synthetic 双路径兜底,老库与新库均可显示“任务监控”入口。