## 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` 均为 Up(api/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` 均为 Up(api/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` 均为 Up(api/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` 均为 Up(api/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` 均为 Up(api/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` 均为 Up(api/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 - 用户管理新增用户表单迁移到 Modal(2026-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 规范改造后台 UI(2026-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 双路径兜底,老库与新库均可显示“任务监控”入口。