Files
CapacityReport/docs/project_context.md
T

145 KiB
Raw Blame History

项目上下文记录

2026-06-26:新增工具发布平台投稿文档(docs/upload)

  • 按工具平台投稿模板新增 docs/upload/ 三份文档:工具说明书.docx、测试报告.docx、工具详细介绍.md。
  • Word 文档用 python-docx 生成(一次性脚本写在 tmp/docs 下,生成后已删除,依赖装在 .venv,未写入 requirements.txt)。设置了中文字体(微软雅黑)、标题/章节层级、蓝色表头底纹的表格样式。
    • 工具说明书:介绍(名称/版本 3.0.0/作者 NIXEVOL)、安装与配置、使用指南(6 模块)、常见问题(含桌面版闪退=9081 占用、默认账号 root/Capacity 等)。
    • 测试报告:介绍/测试目的/测试环境/测试用例/测试结果/改进规划/性能评估/总结;测试人员与联系信息留「(请填写)」占位,测试日期 2026-06-26。
  • 内容均以实际项目为准;本机无 LibreOffice,无法自动渲染 PNG,改用 python-docx 回读校验结构(章节数、表格行列、表头正确)。
  • 提示:.docx/.md 不在 .gitignore 忽略范围,会随仓库提交。

2026-06-26:新增使用说明 USAGE.md + 文档去 Metrix

  • 新增根目录 USAGE.md(Web 端使用说明):登录(root/Capacity)、整体流程与数据处理管线 Mermaid 图、准备工作/各功能页/系统设置标签页/注意事项均用表格。内容以实际代码为准:处理阶段取 FileWorkflow.vue 的 stageLabels(远程下载/更新 CellData/授权校验/解压/转换 Excel/导入/运行脚本);系统设置 6 个标签(数据库、远程数据源、自动调度、规则映射、修改密码,及仅 Metrix 启用时的「数据源/仓库」);数据处理含容量数据 + CellData 两区、本地上传 vs 远程下载;任务锁串行、文件名时间戳、每目录 7 天、授权按数据日期等注意事项。README.md 增加指向 USAGE.md 的链接。
  • 开发文档/README 去掉 Metrix 描述(暂未使用):移除 requests/csv_processor/pipeline/platform 等仅服务 Metrix 的条目与字样。
  • 文档命名:开发文档由 docs/dev_guide.md 移到根目录 DEVELOPMENT.md;README/USAGE/DEVELOPMENT 三篇均在根目录,docs/ 仅保留 project_context.md。

2026-06-26:重写 README 与新增开发文档(以实际代码为准)

  • README.md 精简重写:系统简介、技术栈、6 个导航模块作用表、初次运行(默认账号 root/Capacity,需配套 FTP/SFTP 数据源 + MySQL 仓库)、运行与编译命令(复用 scripts/ 下 py 脚本,可复制即用)、以及跳转开发文档的锚点链接。去掉了原 README 中偏底层的「常用接口」「维护注意事项」等内容。
  • 新增 docs/dev_guide.md 开发文档:①技术栈与主要库(仅列实际用到的:后端 fastapi/uvicorn/pandas/openpyxl/chardet/pymysql/cryptography/paramiko/requests;前端 vue/vue-router/naive-ui/@vicons/echarts/monaco-editor/@tauri-apps/api + vite 构建链;Tauri tauri/shell/dialog/reqwest/sysinfo/open/serde);②目录结构及各目录/文件职责;③导航栏 6 功能(数据处理/容量看板/处理历史/数据管理/脚本编辑/系统设置)逐一用表格列出前端组件、后端路由、相关服务文件与职责,方便定位修改点。
  • 文档事实核对要点(以代码为准):默认账号在 app/auth.py(root/Capacity,存 auth.ini);运行时 SQL 为 ReportScript.sql 与 CellData.sql(app/config.py);历史记录存 cache/history.json(app/history.py);6 个路由页对应 frontend/src/router.ts;端口 9081。

2026-06-26:统一运行/编译脚本为 scripts/ 下纯 Python(傻瓜式,自动 venv)

把分散的运行/编译入口(根 run.bat/debug.bat/start.sh/dev.py、scripts/build.{sh,ps1,bat}、supervisord.conf、packaging/Dockerfile)清理掉,统一改为 scripts/ 下只依赖标准库的 Python 脚本,可直接 python scripts/xxx.py 运行:

  • scripts/_env.py:共享工具。自动创建 .venv(标准库 venv,不使用 uv),按 requirements.txt 的 sha256(存 .venv/.requirements.hash)变化自动重装依赖;自动装前端依赖;检测 Node.js / Rust(cargo,rustc) / Docker,缺失时打印安装引导并退出;提供 build_frontend(可传 VITE_API_BASE)、PyInstaller 打包(build_server_binary onedir/onefile)、build_tauri_sidecar(按 rust host triple 命名复制到 src-tauri/binaries)、remove_path(限工作区内)等助手。额外包用 pip show 探测是否已装。
  • scripts/dev.py:开发测试(移植旧 dev.py)——后端 uvicorn --reload(9081) + 前端 Vite HMR(5174),多进程流式日志、Ctrl+C 统一退出。
  • scripts/run.py:本地运行(替代 run.bat)——构建前端(缺失时) + python -m app.main,支持 --host/--port/--rebuild。
  • scripts/tauri_dev.py:桌面端测试运行——构建前端(desktop api base) + 构建 sidecar(缺失时) + cargo tauri dev,--rebuild 强制重建。
  • scripts/build_tauri.py:桌面版编译——--platform current|windows|linux|macos,与宿主不一致时报错提示需本机构建(Tauri 不可靠交叉编译);Windows 复用旧 ps1 的 NSIS 模板定制(默认装 D:\Program Files\CapacityReport、内置 WebView2 离线安装器走 tauri.conf.json),临时改 tauri.conf.json 的 nsis.template 后构建并还原;产物收集到 dist/desktop/。
  • scripts/build_server.py:Server 便携版——PyInstaller onedir + 前端 dist + Configure.json/ReportScript.sql/CellData.sql + cache//logs/ + 启动脚本(win run.bat/unix start.sh),zip 打包,--no-archive 跳过。
  • scripts/build_docker.py:Docker 编译/更新——以根 Dockerfile + docker/entrypoint.sh(前端预构建、/data 卷、uvicorn)为准;build(默认)生成 dist/docker/ 离线包(tar+compose+配置+mysql),update 重新构建并 docker compose ... up -d --force-recreate,--no-save 跳过 tar。
  • scripts/clean.py:清理 __pycache__/*.pyc、编译产物(dist、frontend/dist、.vite、src-tauri/target、src-tauri/binaries、各 .cache)、运行时临时数据(cache/logs/uploads);--deep 再清 .venv/node_modules。遍历跳过 .git/.venv/node_modules,仅删工作区内路径。
  • scripts/gen_license_code.py 保留。

清理与统一:

  • 删除 scripts/build.sh、scripts/build.ps1、scripts/build.bat、根 run.bat/debug.bat/start.sh/dev.py、supervisord.conf、packaging/Dockerfile(supervisord 多阶段那套已废弃,确认 app/ 无 supervisor 引用、根 Dockerfile 用 docker/entrypoint.sh)。
  • 重写 packaging/docker-compose.yml 匹配根 Dockerfile:app 服务挂 capacity-data:/data 命名卷(不再 /app 挂载 + supervisord 环境变量),保留 MySQL 服务与 mysql/ 初始化/配置。
  • 运行时 SQL 文件确认为 ReportScript.sql 与 CellData.sql(app/config.py:CELLDATA_SCRIPT = BASE_DIR / "CellData.sql",非 CellDataScript.sql)。便携版/Docker 离线包按此打包。
  • 环境检测:Tauri 桌面端用 Rust(非 Go),脚本检测 Node.js + Rust(+Docker 镜像);用户最初提到的「go」实为 Rust。
  • README.md 改写「运行与编译脚本」表格与各分项说明,目录结构条目改为 scripts/(py 脚本) 与根 Dockerfile。
  • 验证:9 个脚本 python -m py_compile 全通过;clean.py/build_docker.py/build_tauri.py --help 正常。

2026-06-01:修复前端 npm audit moderate 漏洞

  • frontend/package.json 增加 overrides.dompurify=3.4.7,将 monaco-editor@0.55.1 间接依赖的 vulnerable dompurify@3.2.7 覆盖到安全版本。
  • 未执行 npm audit fix --force,因为 npm 建议的自动修复会把 Monaco 降级到 0.53.0,属于破坏性方向;override 保持 Monaco 版本不变,风险更小。
  • 已验证 npm audit --json 返回 0 漏洞,npm ls monaco-editor dompurify 显示 monaco-editor@0.55.1 -> dompurify@3.4.7 overridden,npm run build 通过。

2026-06-01:Naive UI 自动按需导入

  • frontend/vite.config.ts 增加 unplugin-vue-components、unplugin-auto-import 和 NaiveUiResolver,模板中的 n-* 组件改为构建期自动按需导入;dts 关闭以避免生成额外类型文件。
  • frontend/src/main.ts 移除 app.use(naive) 全量注册,保留脚本中对 useMessage、useDialog、darkTheme 等 Naive UI API 的显式导入。
  • 已验证 npm run build 通过:主入口 JS 从约 1497KB 降到约 572KB,gzip 从约 415KB 降到约 171KB;剩余大 chunk 主要是已懒加载的 Monaco ScriptPanel 和 Swagger ApiDocs。
  • 注意:npm install 报告 2 个 moderate audit 项,未执行 npm audit fix --force,避免自动升级引入额外风险。

2026-06-01:前端非首页路由懒加载

  • frontend/src/router.ts 保留首屏 FileWorkflow 同步加载,将 HistoryPanel、DatabasePanel、SettingsPanel 改为动态导入,和已有的 ScriptPanel、ApiDocs 保持一致。
  • 已验证 npm run build 通过:主入口 JS 从约 1556KB 降到约 1497KB,非首页页面拆成独立小 chunk;ScriptPanel 和 ApiDocs 仍是独立懒加载重 chunk。
  • 当前剩余大 chunk 主要来自 Monaco Editor、Swagger UI 和主包中的 Naive UI/Vue 生态;Monaco/Swagger 已经不影响首屏,若继续压主入口体积,下一步应评估 Naive UI 按需引入。

2026-06-01:完善 RJ 自动调度日/周粒度识别

  • app/utils/file_dates.py 新增文件日期范围解析:XXX_YYYYMMDDHHMM 视为单日文件,XXX_YYYYMMDDHHMM_YYYYMMDDHHMM 按起止时间展开自然日,结束时间为零点时按右开区间处理。
  • app/services/auto_scheduler.py 的 RJ 检查改为按目录最新 ZIP 自动识别 daily 或 weekly:日粒度目录要求目标自然周 7 天都存在,周粒度目录要求有一个 ZIP 覆盖目标自然周;空 RJ 目录继续视为停推并跳过。
  • 自动调度普通 4G/5G 目录扫描会排除已配置的 RJ 目录,避免 expected_directories=[] 时 RJ 周目录被普通 7 天规则误判阻塞。
  • app/services/remote_download.py 的调度下载筛选改为使用日期覆盖范围:单日文件只要覆盖目标日即下载,多日/周文件必须覆盖完整目标周才下载,避免 ready 后漏下或误下 RJ 周文件。
  • Configure.json 将 RJ/700M/700RJGD、RJ/700M/700RJYD 加入 RJ 数据目录,并补充 700MRJGD、700MRJYD 字段映射;processor.py 避免多个源字段别名映射到同一目标字段时生成重复列。
  • 配置上传接口现在会导入/保存 RJData,前端类型补充 rj_data 和调度状态中的 granularity 字段。
  • 已验证:后端 AST 语法检查、Configure.json JSON 解析、npm run build、真实 SFTP 清单识别、MySQL 临时导入 700RJYD 样本并清理测试表均通过;前端构建仅保留既有大 chunk 警告。

2026-05-29:新增 RJ 周数据处理功能

  • 新增 RJData 配置块到 app/config.py,支持 enabled、weekly_directories 和 table_field_mappings 配置项,用于管理 RJ 周数据目录和字段映射。
  • app/services/auto_scheduler.py 新增 RJWeeklyDirectoryStatus 数据类和 _check_rj_weekly_ready() 方法,支持检查 RJ 周数据目录是否包含目标周的文件。
  • 自动调度逻辑改为:现有 7 天目录检查 且 RJ 周数据检查都满足时才触发处理,两个条件是 AND 关系。
  • app/processor.py 新增 _get_field_map_for_table() 方法和 _find_rj_data_directories() 方法,支持 RJ 表使用专用字段映射。
  • RJ 数据目录结构:/CapacityReportData/RJ/2.6G/2.6RJGD/ 和 RJ/2.6G/2.6RJYD/,每个目录每周一个 ZIP 文件。
  • 目标表名映射:2.6RJGD -> 2_6GRJGD,2.6RJYD -> 2_6GRJYD。
  • 字段映射配置:开始时间、结束时间、gNBId、cellId、gNBplmn、上下行总流量_GB。
  • Configure.json 新增 RJData 配置块,包含启用状态、周数据目录列表和表字段映射。
  • 已验证:.venv\Scripts\python.exe -m compileall app 通过;GD 和 YD 数据字段映射测试成功,6 个字段全部匹配。

2026-05-25:新增远程自动调度和每目录 7 天处理窗口

  • 新增 app/utils/file_dates.py,统一解析文件名中的第一个 YYYYMMDDHHMM 或 YYYYMMDDHHMMSS 时间戳,并提供按目录筛选最近 7 个自然日文件的工具;本地手动上传和远程下载后的 ZIP、Excel、CSV 处理都会按所在目录只保留最近 7 天文件,未携带日期且同目录没有任何可识别日期时保留兼容。
  • app/services/remote_download.py 增加远程 ZIP 清单扫描和筛选下载:普通远程处理按每个远程目录下载最近 7 天 ZIP;自动调度触发时按 ready flag 中记录的目标日期精确下载,若没有匹配 ZIP 不会回退全量下载,避免误处理新旧混杂数据。
  • app/config.py 增加 RemoteData.auto_scheduler 配置,包含 enabled、check_interval_hours、expected_directories 和 week_offset。自动调度开启时后端会强制 RemoteData.enabled=True 和 auto_delete_source=True,前端也同步灰显并强制打开相关开关。
  • 新增 app/services/auto_scheduler.py 后台线程:应用启动后按配置间隔检查 FTP/SFTP 目录,使用本机当前日期计算目标自然周(week_offset=0 为上周,-1 为上上周),但文件覆盖情况完全以 ZIP 文件名日期为准;全部目录覆盖 7 天后写入 cache/auto_scheduler/ready.flag,下一轮检测再触发远程下载并处理。
  • 调度成功且远程源文件清理成功后会删除 ready flag;处理失败、触发失败或源文件清理失败会保留 ready flag 供下轮重试。扫描失败会记录 scan_failed,连续失败次数通过状态接口返回,前端会显示红色失败状态。
  • app/api/routers/remote.py 新增 /api/remote/scheduler/status 和 /api/remote/scheduler/trigger,并将远程处理启动逻辑抽成 start_remote_processing_job() 供手动按钮和调度器复用。
  • frontend/src/components/SettingsPanel.vue 在远程数据源配置中加入自动调度区域:启用开关、检查间隔、目标周期、预期目录维护、调度状态、刷新状态和立即检查。配置下载/上传会随 RemoteData 一起携带自动调度配置。
  • 已验证:文件名日期解析、目标周计算、每目录 7 天筛选、调度开启强制删除源文件配置、调度日期精确筛选逻辑均通过临时 Python 片段;.venv\Scripts\python.exe -m compileall app 与 npm run build 通过,前端构建仅保留既有 Vite 大 chunk 警告。
  • 后续调整:预期目录可访问但完全没有 ZIP 文件时,自动调度会把该目录标记为 skipped/已停推,不再阻塞其他目录就绪;但所有目录都为空时不会写入 ready flag,也不会触发处理。

2026-05-25:修复 API Token 指定日期输入不可见

  • frontend/src/components/ApiTokenManager.vue 中创建/编辑 Token 的到期日期控件从 n-date-picker 改为原生 input[type=date],避免日期选择组件在弹窗内出现占位但输入框不可见的问题。
  • 原生日期输入继续使用 YYYY-MM-DD 字符串绑定到 tokenForm.expires_at,后端 /api/tokens/create 和 /api/tokens/update 请求体不变;仅补充本地样式以匹配当前主题和 Naive UI 表单尺寸。
  • 已验证:npm run build 和 .venv\Scripts\python.exe -m compileall app 通过;浏览器实测 系统设置 > API Token > 生成 Token > 指定日期 下日期输入框可见,并可输入 2026-12-31。

2026-05-25:拆分 API Token 管理和 API 文档

  • 前端删除旧 frontend/src/components/ApiCenter.vue,拆为 ApiTokenManager.vue 和 ApiDocs.vue:API Token 管理迁入 系统设置 > API Token 独立分页,左侧菜单“API 中心”改为“API 文档”,只展示 Swagger 文档。
  • API 文档正式路由为 /api-docs,旧 /api-center 保留为前端兼容别名;后端 /api/docs-ui 改为跳转 /api-docs。Swagger UI 仍从登录后可见的 /api/openapi.json 加载,Token 传递示例指向系统设置中的 API Token 分页。
  • app/main.py 的 OpenAPI 后处理增加中文 tag、接口 summary/description、常用请求示例和稳定 operationId;业务 API 声明登录 JWT 或 API Token 鉴权,配置/授权/Token 管理/文档接口仍只声明登录 JWT。Swagger 前端隐藏底部 Schemas 区域,减少噪音。
  • 修复登录页按钮点击不触发登录的问题:登录按钮改为显式调用 submit(),保留密码框回车提交,并在 loading 时防止重复提交。
  • 已验证:.venv\Scripts\python.exe -m compileall app、npm run build 通过;真实 HTTP 检查未登录 /api/openapi.json 返回 401、登录后返回 CapacityReport API;浏览器实测点击登录按钮可登录,左侧显示 API 文档,系统设置显示 API Token 分页,API 文档页可见中文 Swagger 分组。

2026-05-23:新增 API Token 和离线 API 文档

  • API Token 验收补强:非永久 Token 必须明确传入到期日期,非法或缺失到期日期返回 400;到期、停用、重生成旧 Token 均会拒绝业务 API。已实测 API Token 可执行 /api/database/execute 和 /api/database/table/query,但不能访问 /api/tokens 管理接口。
  • frontend/src/components/ApiCenter.vue 的 Swagger UI 改为通过 apiUrl('/api/openapi.json') 加载文档,并在请求拦截器中只在未手动填写 Authorization 时补登录 JWT;桌面端或配置 VITE_API_BASE 时,Try it out 请求会自动补全后端基址,避免相对 /api/* 请求打到错误 origin。
  • 新增 app/services/api_tokens.py 和 app/api/routers/api_tokens.py:API Token 存储在运行时 api_tokens.json,只保存 HMAC-SHA256 哈希、前后缀、启用状态、到期时间和最近使用信息;完整 Token 仅在创建或重生成时返回一次。api_tokens.json 已加入 .gitignore。
  • app/auth.py 增加登录态和访问态解析:登录态只接受 JWT/cookie,业务访问态接受登录 JWT、Authorization: Bearer <api-token> 和 X-API-Token。Token 管理、系统配置、授权和 API 文档仍要求登录后访问。
  • app/main.py 的全局鉴权中间件改为 JWT + API Token 双鉴权;业务 API 可由 API Token 调用,/api/openapi.json 和 /api/docs-info 仅登录后可见。OpenAPI schema 同时声明 BearerAuth 和 ApiTokenHeader,便于外部系统对接。
  • 前端新增 frontend/src/components/ApiCenter.vue,侧边栏新增 API 中心;页面支持 Token 列表、创建、编辑启停/有效期、重生成、删除、复制一次性完整 Token,并内嵌本地 swagger-ui-dist 文档。API 中心懒加载,避免 Swagger UI 影响普通页面首屏。
  • 新增前端依赖 swagger-ui-dist,并在 frontend/package.json 中关闭 Scarf 安装期匿名统计配置,确保运行期和离线部署不依赖外网 CDN。
  • 已验证:.venv\Scripts\python.exe -m compileall app、npm run build 通过;本地服务实测未登录访问 /api/openapi.json 返回 401,登录创建临时 Token 成功,API Token 可访问 /api/database/tables 且不能访问 /api/tokens,登录访问 /api/openapi.json 成功,非法到期日期返回 400,临时 Token 已删除。

2026-05-22:统一日志框与桌面端下载路径反馈

  • 数据处理页菜单从“数据上传”改为“数据处理”,路由标题同步改为“数据处理”。
  • 上传/处理日志、历史详情日志和脚本执行日志统一使用分级日志渲染:默认/INFO 跟随主题文字色,SUCCESS 绿色,WARNING 黄色,ERROR 红色;日志框背景和滚动条颜色跟随主题,支持横纵向滚动。
  • 数据处理页日志高度改为响应式上限,避免长任务日志把外层页面撑出纵向滚动条。
  • 脚本编辑页的手动运行日志移到编辑器下方,编辑器与日志框共享页面高度;脚本运行状态保存在前端全局状态中,切换页面回来可继续轮询或查看上次运行结果,运行结束不自动隐藏日志。
  • 桌面端下载完成弹窗会显示保存路径,并提供“打开所在文件夹”;新增 Tauri 命令 open_path_in_file_manager 通过系统文件管理器打开下载目录。

2026-05-21:桌面端 sidecar 进程改为跨平台管理

  • Tauri 桌面端启动/关闭后端 sidecar 不再调用 Windows netstat、tasklist、taskkill 等控制台命令,避免启动和退出时闪过 DOS 窗口。
  • 桌面端启动 sidecar 后会在应用数据目录写入 server.pid;下次启动前读取该 pid,并通过 sysinfo 跨平台确认进程名为 capareport-server 后再终止残留进程,pid 被复用为其他程序时不会误杀。
  • 关闭桌面端时只使用 Tauri shell 的 CommandChild.kill() 停止当前 sidecar,并删除 server.pid;若 9081 被非本程序占用,则启动前直接报端口占用错误。
  • 新增 Rust 依赖 sysinfo,仅启用 system feature;已验证 npm run build 和带临时 sidecar 占位文件的 cargo check --manifest-path src-tauri\Cargo.toml 通过,验证产物已清理。

2026-05-21:收紧系统设置页头部空间

  • 系统设置页移除了内容卡片内重复的“系统设置/更新时间”标题栏,保留外层统一页面标题,减少首屏垂直空间占用。
  • 配置更新时间改为页面头部动作区的文本项,显示在“下载配置”按钮左侧;窄屏下沿用全局头部规则隐藏辅助文本。

2026-05-21:增加下载完成提示弹窗

  • 数据表 CSV/XLSX 导出、历史数据压缩包下载和配置文件下载在下载流程完成后会弹出 Naive UI 成功对话框,使用绿色成功图标提示用户文件已下载完成。
  • 提示逻辑统一放在 frontend/src/composables/downloadFeedback.ts;桌面端会在 Tauri 原生保存流程确认写入后提示,用户取消保存时不弹完成提示,Web 端会在浏览器下载触发后提示。

2026-05-21:排查离线机器桌面端白屏

  • 运行时外链扫描确认:frontend/src、app、src-tauri/src 中没有 CDN、在线字体或外网业务接口;桌面端前端只访问本机 http://127.0.0.1:9081 sidecar,src-tauri/tauri.conf.json 的 https://schema.tauri.app/config/2 只是编辑器/构建 schema,不参与用户机器运行。
  • 离线白屏的主要风险点是 Windows WebView2 Runtime:Tauri 默认 webviewInstallMode 为 downloadBootstrapper,目标机器没有外网且未预装 WebView2 时,安装或启动阶段可能无法正常创建 WebView。src-tauri/tauri.conf.json 已改为 bundle.windows.webviewInstallMode = { type: "offlineInstaller", silent: true },新的 Windows 安装包会内置 WebView2 离线安装器。
  • 清理了 src-tauri/tauri.conf.json 中误残留的本机构建临时 NSIS template 绝对路径;该路径不应进入源码或发布配置。
  • 已验证 npm run build 和带临时 sidecar 占位文件的 cargo check --manifest-path src-tauri\Cargo.toml 通过;构建产物和临时 sidecar 占位文件需在提交前清理。

2026-05-21:修复桌面端下载不弹保存路径

  • 桌面端不再依赖 WebView 的 <a download> 行为保存文件;frontend/src/api/client.ts 在 Tauri 环境下会通过 @tauri-apps/api/core 调用原生命令,普通浏览器和 Server Portable 仍保留原有 Blob 下载逻辑。
  • src-tauri/src/main.rs 新增 download_to_file 命令:先弹出系统保存对话框,再使用 Rust reqwest 按前端传入的 HTTP 方法、URL、Header 和请求体流式请求后端接口,并写入用户选择的路径;用户取消保存时不报错,HTTP 错误会带回前端并继续触发 401 退出登录逻辑。
  • 新增依赖 @tauri-apps/api、tauri-plugin-dialog、reqwest 和 serde;Tauri schema 文件会因 dialog 插件更新,src-tauri/gen/schemas/ 仍需保留在版本库中用于 VS Code JSON 校验。
  • 已验证 npm run build、.venv\Scripts\python.exe -m compileall app、cargo fmt --manifest-path src-tauri\Cargo.toml --check 和带临时 sidecar 占位文件的 cargo check --manifest-path src-tauri\Cargo.toml 均通过;验证后已清理 frontend/dist、src-tauri/target、src-tauri/binaries 和 Python 缓存。

2026-05-20:统一端口、升级 3.0.0 并收敛桌面安装行为

  • 应用户要求,应用访问端口统一回 9081:Server Portable、Docker 宿主机映射、Tauri 桌面 sidecar、桌面前端 VITE_API_BASE 和前端 Tauri 兜底 API 地址均使用 http://127.0.0.1:9081;桌面版启动前只会清理同名 capareport-server.exe 的残留监听进程,避免误杀其它占用 9081 的程序。
  • 版本统一提升为 3.0.0,同步更新后端 APP_VERSION、健康检查、侧边栏显示、Tauri 配置和 Cargo 包版本。
  • run.bat 不再因 frontend/dist/index.html 缺失直接退出;缺少前端构建产物时会检查 npm、按需执行 npm ci,然后自动运行 npm run build 再启动后端。
  • 桌面版去除 release DevTools:src-tauri/Cargo.toml 移除 Tauri devtools feature,tauri.conf.json 移除窗口 devtools 配置,前端在 Tauri 环境下阻止右键浏览器菜单和 F12/Ctrl+Shift+I。
  • Windows NSIS 安装器改为 per-machine,并在未选择自定义安装目录时默认落到 D:\Program Files\CapacityReport;如果没有 D 盘,则使用系统 Program Files\CapacityReport。scripts/build.ps1 构建桌面版时会临时生成 Tauri NSIS 模板并恢复 tauri.conf.json,避免旧安装记录把默认路径带回 C 盘。默认授权到期日仍由 app/services/license.py 的 DEFAULT_EXPIRES_ON 控制。
  • 桌面端不再提供服务重启功能:前端移除重启按钮和等待遮罩,后端删除 /api/service/restart、/api/service/status 以及对应 runtime 重启实现,避免桌面 sidecar 无法可靠自重启时误导用户。
  • 登录后连续点击左上角品牌图标 8 次会主动打开授权延期窗口,窗口显示当前激活 key 标签并允许连续提交激活码,每次成功后按新的到期日刷新下一次 key。
  • 已验证 cmd /c scripts\build.bat desktop 可生成 dist\desktop\CapacityReport_3.0.0_x64-setup.exe;静默安装后 capacity-report-desktop.exe、capareport-server.exe、Configure.json 和 ReportScript.sql 均位于 D:\Program Files\CapacityReport,注册表 InstallLocation 指向 D 盘。已启动安装后的桌面程序验证 sidecar /health 返回 3.0.0,并验证配置、脚本和授权接口可读取;验证后已停止测试进程并清理中间产物。

2026-05-20:修复桌面版跨源预检导致配置网络错误

  • 桌面版前端访问 127.0.0.1:19082 属于 WebView 跨源请求,带 Authorization 或上传配置文件时浏览器会先发 OPTIONS 预检;app/main.py 的 JWT 中间件现在直接放行 OPTIONS,让 FastAPI CORS 中间件返回允许头,避免配置读取和配置上传显示“网络错误”。
  • 桌面版版本提升为 2.0.3,同步更新 app/main.py、健康检查、服务状态、Tauri 配置、Cargo 包版本和侧边栏版本号,避免同版本安装包覆盖时难以确认是否装到新包。
  • src-tauri/Cargo.toml 启用 Tauri devtools feature,tauri.conf.json 主窗口设置 devtools: true;Windows release 桌面包可按 F12 或右键打开开发者工具排查真实请求。
  • 已用真实 uvicorn 服务验证 Origin: http://tauri.localhost 下 /api/config/full 和 /api/config/upload 的 OPTIONS 预检均返回 200,并且登录后 /api/config/full 可正常返回;随后执行 scripts\build.bat desktop 生成 dist\desktop\CapacityReport_2.0.3_x64-setup.exe,静默安装启动后验证 /health 返回 2.0.3、配置读取正常、脚本读取正常、配置上传返回 200。

2026-05-20:修复桌面版残留 sidecar 和卸载用户数据选择

  • src-tauri/src/main.rs 启动 sidecar 前会先清理占用 19082 的旧 capareport-server 监听进程,避免卸载/重装或异常退出后连到旧服务;启动后不只检查端口可连接,还会请求 /health 返回 HTTP 200 才继续。
  • frontend/src/api/client.ts 在 Tauri 运行环境下即使构建时未注入 VITE_API_BASE,也会兜底使用 http://127.0.0.1:19082,并保留短暂 fetch 重试,避免桌面版出现配置页默认空值和脚本页 Failed to fetch。
  • Windows 桌面包收敛为 NSIS setup.exe,不再同时产出 MSI;新增 src-tauri/windows/nsis-hooks.nsh,卸载前会尝试关闭桌面进程和 sidecar,卸载后会询问是否删除 %APPDATA%\com.nixevol.capacityreport 中的配置、脚本、授权、缓存和日志。
  • 已执行 scripts\build.bat desktop,产物为 dist\desktop\CapacityReport_2.0.2_x64-setup.exe;脚本已自动清理 dist/.tmp、frontend/dist、src-tauri/target 和 src-tauri/binaries。
  • 已用新 NSIS 包静默覆盖安装并启动桌面版验证:/health 正常,/api/config/full 读取到 32 个字段映射,/api/script/content 成功读取 AppData 下的 ReportScript.sql;验证结束后已停止测试启动的桌面和 sidecar 进程。

2026-05-20:修复桌面版启动期配置和脚本加载竞态

  • 桌面版运行配置和脚本仍从安装包资源 Configure.json、ReportScript.sql 首次复制到系统 AppData 后读取;安装目录中的 _up_ 是 Tauri 对 ../ 资源的打包目录,不是后端实际运行目录。
  • src-tauri/src/main.rs 在启动 Python sidecar 后会等待 127.0.0.1:19082 可连接,最多等待 20 秒;如果端口没有起来,会主动杀掉刚启动的 sidecar 并让启动失败,避免前端先加载导致配置页停在默认空表单、脚本页停在“正在加载”。
  • frontend/src/api/client.ts 对普通 fetch 请求增加短暂重试,处理桌面 sidecar 启动或服务重启瞬间的 Failed to fetch;上传 XHR 不做自动重试,避免重复上传。
  • 已实测当前安装目录 D:\Program Files\CapacityReport\_up_ 和运行目录 %APPDATA%\com.nixevol.capacityreport 均存在配置与脚本,http://127.0.0.1:19082/health、/api/config/full、/api/script/content 均能读取;本次修复的是前端初始请求早于 sidecar 就绪的竞态。
  • 已执行 .venv\Scripts\python.exe -m compileall app、npm run build 和带临时 sidecar 占位文件的 cargo check --manifest-path src-tauri\Cargo.toml,均通过;生成产物随后清理。

2026-05-20:修复登录失败误提示会话过期

  • frontend/src/api/client.ts 不再把 /api/login 的 401 响应当作全局会话过期处理,登录失败会按后端真实错误显示“账号或密码错误”。
  • 已登录业务接口遇到 401 时仍会清理本地 token 并切回登录页,但 AppShell 不再额外弹出全局“登录已过期”提示,避免组件自身错误提示和全局提示同时出现。
  • 默认登录密码仍由 app/auth.py 定义为 Capacity,大小写敏感;如本地 auth.ini 未修改,输入小写 capacity 会按正常登录失败处理。
  • 已执行 npm run build,构建通过;前端构建仅保留 Vite 大 chunk 提示,生成产物随后清理。

2026-05-20:增加按 ZIP 数据日期校验的使用期限限制

  • 新增 app/services/license.py 和 /api/license/status、/api/license/activate:本地 license.dat 用 XOR+HMAC 方式加密保存到期日期,缺失时自动初始化为 2026-06-20,文件已加入 .gitignore。
  • 授权校验不读取系统日期;本地上传处理和远程下载完成后的处理入口会遍历任务目录下 ZIP 文件名,提取 YYYYMMDDHHMM 或 YYYYMMDDHHMMSS 时间戳并取最大日期作为数据日期,超过授权到期日则任务失败并返回 LICENSE_EXPIRED 详情。
  • 激活码为当前到期日期 YYYY/MM/DD 字符串的 SHA-256 hex;每次激活只按当前加密文件里的到期日校验,成功后顺延 30 天,因此旧激活码不能重复顺延。
  • frontend/src/components/FileWorkflow.vue 在任务因授权过期失败时弹出激活框,显示 key: YYYY/MM/DD,输入激活码成功后本地上传任务会继续处理,远程任务会重新发起远程下载处理。
  • 如果任务中没有 ZIP,或 ZIP 文件名没有可识别时间戳,当前实现会写入警告并跳过授权日期比对,避免误伤直接 CSV/Excel 上传流程;如需强制所有数据都必须带 ZIP 日期,可在 check_processing_allowed() 中收紧该策略。
  • 已执行授权逻辑临时目录验证、.venv\Scripts\python.exe -m compileall app、uvx --offline ruff check . 和 npm run build,均通过;前端构建仅保留 Vite 大 chunk 提示,生成产物已清理。

2026-05-19:配置按请求实时重载

  • app/state.py 新增 reload_config() 和 current_config(),后端接口不再长期依赖启动时的 state.config 快照;读取配置、下载配置、数据库接口、健康检查、本地处理、远程处理和脚本执行入口都会从 Configure.json 重新加载最新配置。
  • 配置保存类接口会先重载当前文件再修改对应配置块并保存,避免用户手工更新 Configure.json 后,被某个单项保存接口用旧内存配置覆盖。
  • 本地/远程处理任务启动时会读取一次最新配置并作为任务快照传入 DataProcessor;任务运行过程中不再反复重载,避免处理中途改配置导致同一任务前后规则不一致。
  • 已执行 .venv\Scripts\python.exe -m compileall app、uvx --offline ruff check . 和 npm run build,均通过;前端构建仅保留 Vite 大 chunk 提示。

2026-05-19:补全字段映射配置

  • 当前本地 Configure.json 的 ExtractField 已按旧版可用映射补全:基站名称 增加 ENBFunction名称,ERAB流量 增加 ERAB流量(新高负荷)_1538186901014-7-0,上行流量_GB/下行流量_GB 增加 上行流量(GB)/下行流量(GB)。
  • 4G/5G 数值字段显式补回 Type: float/int,避免依赖 SQL 脚本推断类型;AppConfig.load() 已验证能读取 32 个字段映射和正确的 SheetFilter。
  • 修改配置时需要注意 Windows PowerShell 管道的中文编码问题;如果要脚本化写入 Configure.json,优先从已有 UTF-8 JSON 读取并用 Unicode escape 合并,避免把中文字段写成 ????。

2026-05-19:清理生成 CSV 并支持历史原始数据下载

  • DataProcessor 现在会追踪 ZIP 解压出的 CSV 和 Excel 转换生成的 CSV,只有这些处理过程中生成的临时 CSV 会在对应 CSV 成功导入后自动删除;原始 ZIP、Excel 和用户本来上传/远程下载得到的原始 CSV 不会被误删。
  • ZIP 解压从 extractall() 改为逐条安全解压,会跳过越界路径条目,并在解压 CSV 时登记为后续可清理的临时文件。
  • POST /api/history/download 会校验历史任务目录必须位于 cache/ 下,任务完成后才能下载;接口将整个历史工作目录压缩为 ZIP 返回,并通过 BackgroundTask 在响应结束后删除临时压缩包。
  • frontend/src/components/HistoryPanel.vue 在历史列表的“详情”左侧增加“下载”按钮,下载时显示 loading,未完成任务禁用下载,避免重复点击和下载不完整的历史数据。
  • 已执行 .venv\Scripts\python.exe -m compileall app、uvx --offline ruff check . 和 npm run build,均通过;本次未启动浏览器或 headless Chrome。

2026-05-19:调整数值异常值归零和完成后日志高度

  • DataProcessor 数值字段清洗策略从异常值写入 NULL 改为写入 0:空串、-、--、长短横线、NA/N/A/NULL/NONE/NAN/\N 以及其它无法转数值的文本都会归零,正常 0 不受影响。
  • 数值格式继续清理千分位逗号、全角逗号、半角/全角百分号和空白;例如 12,345.123 会导入为 12345.123,95%/95% 会导入为 0.95。
  • frontend/src/components/FileWorkflow.vue 在任务完成或失败后给处理进度区增加 finished 状态,frontend/src/styles.css 让完成后的日志框使用自适应最大高度,避免上传区恢复显示后日志仍按运行中高度撑开页面。
  • 已执行数值转换样例验证、.venv\Scripts\python.exe -m compileall app、uvx --offline ruff check . 和 npm run build,均通过。

2026-05-19:修复 CSV 导入阶段数值截断错误

  • DataProcessor 仍会根据 ReportScript.sql 的 MODIFY COLUMN 提前把业务数值字段建成 INT/FLOAT,但数值清洗改为返回真正的 Python None/int/float,避免 pandas <NA> 或异常文本被 PyMySQL 当作字符串写入数值列。
  • 数值字段导入前会把空串、-、--、长短横线、NA/N/A/NULL/NONE/NAN/\N 等源 CSV 占位符转为数据库 NULL,正常 0 保留为 0;逗号/全角逗号、半角/全角百分号和空白仍按数值格式清理。
  • 该问题本质是新版提前按 SQL 类型建表后,MySQL 严格模式会在 CSV 导入阶段拒绝脏数值;旧版多为字符串先落库,所以不会在导入阶段出现 Data truncated for column。
  • 已执行数值转换样例验证、.venv\Scripts\python.exe -m compileall app 和 uvx --offline ruff check .,均通过。

2026-05-19:优化处理进度阶段显示和日志跟随

  • ProcessLogger 新增轻量阶段回调,DataProcessor.process() 会在远程下载后依次上报 extracting、converting、importing、scripting、completed/failed 阶段。
  • /api/process/status 和 /api/task/status 返回当前 stage,本地上传处理和远程下载处理都通过 state.processing_tasks 与全局任务锁同步阶段,前端轮询即可实时显示“远程下载中 / 解压数据中 / 上传数据中 / 运行脚本中”等状态。
  • frontend/src/components/FileWorkflow.vue 的处理进度卡片新增“保持最新 Log”勾选框,勾选后新日志到达会自动滚动到日志底部;当前任务提示不再显示原始阶段码,改为中文阶段文本。
  • 已执行 .venv\Scripts\python.exe -m compileall app、uvx --offline ruff check . 和 npm run build,均通过。

2026-05-19:清理后端冗余代码和未用依赖

  • app/database.py 移除未使用的 SQLAlchemy 连接池、engine 属性、dispose() 空释放路径和未引用的 delete_rows();数据库访问统一保留现有 PyMySQL 上下文连接。
  • app/api/routers/database.py、app/api/routers/health.py 和 app/processor.py 同步去除无效 dispose() 调用,避免保留没有实际资源释放意义的样板代码。
  • requirements.txt、run.bat 和 README.md 移除 SQLAlchemy 依赖和说明;build/build.py 清理无用端口常量、内联导入和宽泛异常捕获。
  • 已清理本地 .ruff_cache/ 与重复的 ReportScript.sql.bak;已执行 .venv\Scripts\python.exe -m compileall app build、uvx ruff check .、uvx vulture app build --min-confidence 80 和 npm run build,均通过。

2026-05-19:移除旧版 HTML 前端和双端口托管

  • 删除 frontend_old/ 旧版 HTML/CSS/JS 前端及其本地 Monaco 资源,项目只保留 Vue 3 新前端。
  • app/main.py 移除旧版前端托管、/old 路由、9082 端口和双 socket 分流逻辑,运行时只监听 9081 并托管 frontend/dist。
  • run.bat、build/Dockerfile、build/docker-compose.yml、build/build.py、build/README.md 和 README.md 同步移除旧版端口说明及 19082 -> 9082 映射。
  • 已执行 .venv\Scripts\python.exe -m compileall app build,旧版引用扫描未发现剩余可执行入口。

2026-05-19:修复数据管理导出下拉选择不触发弹窗

  • frontend/src/AppShell.vue 将页头下拉动作从模板事件表达式 @select 改为 :on-select 回调属性,确保 Naive UI 下拉菜单选择 CSV/XLSX 后会真正执行页面动作。
  • 修复数据管理页点击“导出”下拉项后 CSV/XLSX 表选择弹窗不显示的问题。
  • 已执行 npm run build,构建通过;构建只保留 Vite 原有大 chunk 提示。

2026-05-19:优化数据管理导出入口和弹窗宽度

  • frontend/src/composables/pageHeader.ts 和 frontend/src/AppShell.vue 为页面顶部动作支持 Naive UI 下拉菜单,按钮内显示下拉箭头。
  • frontend/src/components/DatabasePanel.vue 将顶部“导出 CSV / 导出 XLSX”两个按钮合并为一个“导出”下拉按钮,点击后选择 CSV 或 XLSX 再进入对应表选择弹窗。
  • CSV 和 XLSX 导出弹窗改为固定 420px 内的响应式宽度,避免在宽屏下铺满整页;表选择列表增加边框和背景,视觉上更集中。
  • 已执行 npm run build,构建通过;构建只保留 Vite 原有大 chunk 提示。

2026-05-19:调整数据管理导出交互并支持多表 XLSX

  • frontend/src/components/DatabasePanel.vue 将导出入口移到页面顶部,并放在“删除全部表”按钮左侧;内容区工具栏只保留刷新、清空、删除当前表。
  • 点击“导出 CSV”会弹出全部表单选弹窗,用户选择一张表后下载 CSV;点击“导出 XLSX”会弹出全部表多选弹窗,用户可选择多张表并下载同一个 XLSX。
  • app/api/routers/database.py 的 /api/download 支持 table_names,XLSX 会按表名分 sheet 写入同一工作簿,sheet 名会兼容 Excel 的非法字符和 31 字符限制;CSV 仍限制单表导出。
  • frontend/src/api/client.ts 的 POST 下载会优先使用后端 Content-Disposition 文件名,便于多表导出使用服务端生成的文件名。
  • 已执行 .venv\Scripts\python.exe -m compileall app 和 npm run build,均通过;构建只保留 Vite 原有大 chunk 提示。

2026-05-19:优化数据表导出临时文件清理

  • app/api/routers/database.py 的 /api/download 导出接口增加格式校验,只允许 csv 和 xlsx。
  • 导出文件仍临时写入 cache/,但 FileResponse 发送完成后会通过 BackgroundTask 自动删除;写入失败时也会清理半成品文件,避免导出残留占用服务器磁盘。
  • 已清理 cache/ 中旧的导出缓存文件 2 个,仅保留处理历史目录和 history.json。
  • 已执行 .venv\Scripts\python.exe -m compileall app,编译检查通过。

2026-05-19:调整上传框操作按钮为换行显示

  • frontend/src/components/FileWorkflow.vue 移除上传框操作区里无效的 <br>,避免在 flex 布局中形成异常间距。
  • frontend/src/styles.css 将 .upload-zone-actions 改为纵向 flex 布局,使“或者点击选择文件”和“远程下载并处理”按钮固定分两行显示。
  • 已执行 npm run build,构建通过;本次按用户要求未启动浏览器或 headless Chrome。

2026-05-19:调整连接配置页卡片布局

  • frontend/src/components/SettingsPanel.vue 将连接配置页改成左列堆叠“数据库配置”和“处理历史保留”,右列显示“远程数据源”,避免右侧远程数据源卡片高度把处理历史保留卡片挤到很下面。
  • frontend/src/styles.css 新增 .settings-connection-stack,左列卡片之间使用固定 18px 间距。
  • 已执行 npm run build;已通过本机 Chrome DevTools 验证设置页中数据库配置与处理历史保留同列显示,间距为 18px,远程数据源位于右列。

2026-05-19:新增处理历史保留配置并完善配置导入导出

  • app/config.py 新增 HistoryRetention 配置块,包含 enabled 和 keep_count;keep_count=0 表示不保留已结束处理历史,关闭开关时不自动删除历史。
  • app/history.py 新增按保留数量清理已结束历史的能力,只清理 completed/failed 记录及其 cache/<task_id> 工作目录,不删除 pending/processing 记录。
  • app/api/routers/tasks.py 和 app/api/routers/remote.py 在本地上传处理、远程下载并处理任务结束后自动应用历史保留规则。
  • app/api/routers/config.py 新增 /api/config/history-retention 保存接口;配置下载改为从当前内存配置生成完整 JSON,确保导出的配置始终包含 RemoteData 和 HistoryRetention;配置上传也会恢复这两个配置块。
  • frontend/src/components/SettingsPanel.vue 在连接配置页新增“处理历史保留”卡片,可设置自动清理开关和保留最近次数。
  • 已执行 .venv\Scripts\python.exe -m compileall app、临时目录历史清理验证、配置导入导出验证和 npm run build;已用本机 Chrome DevTools 验证设置页新增卡片可见。

2026-05-19:调整上传页远程下载入口

  • frontend/src/components/FileWorkflow.vue 将“远程下载并处理”按钮移动到拖拽上传框内部,删除独立的“远程自动化”卡片,上传页首屏只保留一个主要操作区域。
  • 远程入口说明“从已配置的 FTP/SFTP 目录递归下载数据,然后自动开始处理。”改为按钮 hover tooltip 展示;按钮点击使用事件阻止冒泡,避免触发拖拽框的本地文件选择逻辑。
  • frontend/src/styles.css 清理远程自动化卡片样式,新增拖拽框内操作区样式。
  • 已执行 npm run build;已通过本机 Chrome DevTools 验证 /upload:远程按钮位于拖拽框内,外部远程卡片 DOM 数量为 0,tooltip 文案正常显示。

2026-05-19:修复规则映射窄宽度滚动

  • frontend/src/styles.css 将系统设置的规则映射区域改为 tab 内部滚动容器,避免宽度或高度不足时被 overflow: hidden 裁切导致 Sheet 过滤规则 卡片不可达。
  • 浏览器宽度不足触发单列布局时,规则映射区按 Sheet 过滤规则 在上、字段映射配置 在下排列,字段映射卡片限制高度并继续使用内部字段列表滚动。
  • 已执行 npm run build;已通过本机 Chrome DevTools 以约 1074px 视口验证 /settings 规则映射页:Sheet 卡片可见、容器可纵向滚动、文档没有横向溢出。

2026-05-19:移除数据管理表格重复横向滚动条

  • frontend/src/components/DatabasePanel.vue 移除了上一版额外添加的 .database-horizontal-scrollbar 外置滚动条和同步滚动逻辑,避免与 Naive UI DataTable 自带横向滚动条同时显示。
  • 数据表仍保留 scroll-x 和列最小宽度计算,由 Naive UI 原生表格滚动条负责横向浏览,字段结构折叠头继续保留“字段结构 / 收起字段结构”状态文案。
  • 已执行 npm run build;已通过本机 Chrome DevTools 验证 /database 中外置滚动条 DOM 数量为 0,表格自身仍存在横向溢出滚动。

2026-05-19:修复数据管理表格滚动和字段结构收起

  • frontend/src/components/DatabasePanel.vue 为数据表增加明确的 scroll-x 宽度和底部外置横向滚动条,滚动条会与 Naive UI 表格内部横向滚动位置双向同步,避免字段结构区域或分页区域遮挡表格底部横向滚动入口。
  • 字段结构区域从默认 n-collapse 改为受控折叠头,展开后标题显示“收起字段结构”,再次点击恢复“字段结构”,并使用本地图标箭头表示展开状态。
  • 字段结构明细使用内部滚动容器限制高度,数据表主体保持 flex 占位,避免展开字段结构后挤掉分页或整页出现不必要滚动。
  • 已执行 npm run build;已通过本机 Chrome DevTools 验证 /database 中表格横向滚动条可见且与表格滚动同步,字段结构展开/收起文案正常切换。

2026-05-19:压缩系统设置页布局高度

  • frontend/src/styles.css 调整系统设置页为固定高度布局,外层 settings-workspace 减小 padding 并隐藏溢出,避免主内容区出现整页滚动条。
  • 连接配置页 .settings-section-grid 作为 tab 内部滚动容器,浏览器高度变小时只滚动连接配置内容,不裁切远程数据源表单。
  • 字段映射配置卡片在规则映射页中占满可用高度,卡片内容区使用 flex 固定 header/footer,字段列表通过内部纵向滚动条浏览,避免主页面滚动或内容溢出。
  • Naive UI 当前卡片内容区 DOM class 为 .n-card-content,样式同时兼容 .n-card__content;字段映射项必须 flex: 0 0 auto,否则列表项会被 flex 压缩而无法形成真实滚动高度。

2026-05-19:拆分系统设置页并支持远程源文件自动清理

  • frontend/src/components/SettingsPanel.vue 的系统设置改为 Naive UI Tabs:连接配置页放数据库配置和远程数据源,规则映射页放 Sheet 过滤规则和字段映射配置,修改密码独立一页,避免设置内容堆在一个长页面。
  • RemoteData 配置新增 auto_delete_source 开关;前端在远程数据源配置中显示“处理成功后删除源文件”,默认关闭。
  • app/services/remote_download.py 新增远程源文件清理能力,下载阶段会记录本次实际下载的远程文件路径;自动清理只删除这些文件,不删除目录,也不会删除处理期间新进入远程目录的文件。
  • app/api/routers/remote.py 在远程下载并处理成功后才会执行源文件清理;清理失败只写入警告日志,不改变已完成的数据处理结果。
  • 已执行 .venv\Scripts\python.exe -m compileall app 和 npm run build,均通过;未启动浏览器或 headless Chrome。

2026-05-18:新增 FTP/SFTP 远程自动化处理

  • Configure.json 新增 RemoteData 配置,包含启用状态、协议、主机、端口、用户名、密码、远程目录、FTP 被动模式、超时时间和源文件自动清理开关;app/config.py 会兼容旧配置并在保存时写回该配置块。
  • 新增 app/services/remote_download.py,FTP 使用标准库 ftplib,SFTP 使用 paramiko,会递归下载远程目录下的全部文件和文件夹到本地任务缓存目录。
  • 新增 app/api/routers/remote.py,POST /api/remote/test 用于测试远程连接,POST /api/remote/start 会创建历史任务、下载远程数据并复用 DataProcessor 完成现有处理流程。
  • frontend/src/components/SettingsPanel.vue 新增“远程数据源”配置卡片,支持 FTP/SFTP 切换、保存和测试连接;frontend/src/components/FileWorkflow.vue 新增“远程下载并处理”入口。
  • 远程任务启动后会把全局任务阶段设置为 downloading,前端处理进度页会显示“远程下载中...”,下载完成后再切换为既有数据处理流程。
  • 新增依赖 paramiko,当前 .venv 已执行 uv pip install -r requirements.txt;已执行 .venv\Scripts\python.exe -m compileall app 和 npm run build,均通过;未启动浏览器或 headless Chrome。

2026-05-18:完善服务重启交互和运行时兼容

  • frontend/src/AppShell.vue 的重启按钮点击后会先弹出确认框,确认后显示全屏“正在重启服务”遮罩和旋转加载动画,避免用户重复操作。
  • 重启请求发出后前端会轮询 /api/service/status,服务恢复时自动刷新页面;重启过程中请求中断会被视为正常情况继续等待。
  • app/api/routers/service.py 和 app/services/runtime.py 统一重启逻辑:优先使用 supervisor 重启,失败时退回进程退出;Windows 本地依赖 run.bat 循环拉起,容器环境会识别 Docker/containerd/k8s 并交给 supervisor 或容器重启策略拉起。
  • /api/service/status 返回值新增 container 字段,用于前端或排障区分容器运行时。
  • 已执行 .venv\Scripts\python.exe -m compileall app 和 npm run build,均通过;未启动浏览器或 headless Chrome。

2026-05-18:修正字段映射标题换行

  • frontend/src/styles.css 调整设置页字段映射卡片头部布局,“字段映射配置”和字段数量标签不再被搜索框挤压换行。
  • 字段搜索框改为弹性宽度,优先占用剩余空间,并保留最小宽度和最大宽度约束。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:优化数据管理表列表和导出入口

  • frontend/src/components/DatabasePanel.vue 的 MySQL 表列表顶部新增“表”标题和刷新图标按钮,刷新按钮复用 loadTables() 并在加载中显示 loading,避免重复刷新。
  • 数据表导出从独立 CSV/XLSX 按钮改为 Naive UI 下拉按钮,用户先选择 CSV 或 XLSX 格式再下载。
  • 导出请求期间按钮显示 loading 和当前格式文案,并禁用下拉入口,避免大数据表导出等待期间被重复点击。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:修复数值字段转换失败

  • app/processor.py 会从 ReportScript.sql 的 ALTER TABLE ... MODIFY COLUMN ... float/int 自动补全缺失的字段类型提示,配置中未标 Type 的数值字段在导入阶段也会按数值清洗和落库。
  • 数值清洗只处理格式问题:空值保留为 NULL 后由脚本 IFNULL 归零,千分位逗号、中文逗号、百分号、空格和制表符会被移除,正常数值保持不变,正常 0 不再被误判为空值。
  • 执行 SQL 脚本时仍保留 MySQL 严格模式;在 ALTER 转数值前会对目标表的相关数值列做一次保险清洗,兼容已经导入过的旧字符串表。
  • SQL 语句执行失败后不再继续执行后续语句,避免前置 ALTER 失败后继续产生大量 Unknown column 和临时表不存在的级联错误,并让任务正确进入失败状态。

2026-05-18:修正历史详情日志滚动条颜色

  • frontend/src/styles.css 为历史详情 colored-log-panel 单独设置滚动条颜色,避免继承全局 hover 颜色后在深色日志背景里不可见。
  • 日志框滚动条轨道使用深色,滑块和 hover 状态使用更亮的灰蓝色,同时补充横向/纵向滚动条和 corner 样式。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:优化历史详情日志查看

  • frontend/src/components/HistoryPanel.vue 的历史详情“处理日志”标题右侧新增复制按钮,点击后复制当前详情日志文本,优先使用 Clipboard API,失败时回退到 textarea 复制。
  • 历史详情日志不再使用 n-log,改为自定义 colored-log-panel,日志框固定高度并同时支持横向和纵向滚动,不自动换行。
  • 日志行按内容识别级别并着色:INFO 为蓝色,SUCCESS/COMPLETED 为绿色,WARN/WARNING 为黄色,ERROR/FAILED 为红色。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:切换为圆形侧边栏收缩触发器

  • frontend/src/AppShell.vue 的 n-layout-sider 收缩触发器从 show-trigger="bar" 改为 show-trigger="arrow-circle",恢复为 Naive UI 文档中侧栏右侧居中的圆形箭头按钮样式。
  • 侧边栏收缩状态仍通过 handleSidebarCollapsed() 写入 localStorage.sidebarCollapsed。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:恢复侧边栏原生收缩触发器

  • frontend/src/AppShell.vue 移除顶部标题栏里的自定义汉堡收缩按钮,改用 Naive UI n-layout-sider 的 show-trigger="bar" 原生触发器。
  • 侧边栏收缩状态仍写入 localStorage.sidebarCollapsed,刷新页面后保持用户上次的展开/收缩状态。
  • frontend/src/styles.css 清理自定义 .sidebar-toggle 样式,避免顶部标题栏出现额外按钮。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:修正折叠侧边栏菜单图标居中

  • frontend/src/styles.css 的折叠侧边栏菜单项强制改为 flex 居中布局,避免 Naive Menu 折叠时透明文本列继续占据 grid 空间导致图标偏左。
  • 折叠态下隐藏菜单文本列和箭头列,并让图标容器自身水平垂直居中,保持选中背景和图标中心对齐。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:优化历史详情弹窗信息布局

  • frontend/src/components/HistoryPanel.vue 打开历史详情后会自动调用 /api/history/size 计算占用,不再需要用户点击“计算占用”按钮。
  • 历史详情基础信息从 Naive UI n-descriptions 表格改为自定义键值列表,统一为左侧标题、右侧值,长路径和值会自动换行。
  • 占用计算期间显示“计算中...”,失败时显示“计算失败”并保留错误 toast。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:数据管理页切换时刷新表列表

  • frontend/src/components/DatabasePanel.vue 在数据管理页激活时会重新执行 loadTables(),确保从其他页面切回时左侧表列表拉取最新状态。
  • 离开数据管理页时会清空表列表、当前选中表和表数据,避免已删除的表在下次进入前短暂残留。
  • 表列表请求增加 tableLoadToken,忽略离开页面后返回的旧请求,防止过期响应把已清空的列表重新写回。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:合并数据管理页快速导入检测入口

  • frontend/src/components/DatabasePanel.vue 移除数据库状态卡片里的独立“重新检测”文字按钮,把刷新动作合并到“快速导入”的状态徽标上。
  • 点击“可用 / 未启用 / 检测中”徽标会自动重新检测并刷新状态;成功不弹 toast,失败仍显示错误提示。
  • 数据库状态卡片去掉为底部按钮预留的额外内边距,布局更紧凑。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:处理任务运行时隐藏上传区域

  • frontend/src/components/FileWorkflow.vue 新增 taskInProgress 计算状态;当存在活动任务或任务状态未完成/失败时,上传区和已选文件列表不再渲染。
  • 上传文件阶段仍保留已选文件和上传进度;后端处理任务开始后页面只显示处理进度卡片和日志,避免已完成上传列表继续占据首屏。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:修复主题按钮图标和折叠侧栏版本显示

  • frontend/src/AppShell.vue 的主题切换按钮现在根据 themeName 动态显示 MoonOutline 或 SunnyOutline,切换主题后图标和标题同步变化。
  • 侧边栏底部版本信息拆分为版本标签、版本号和 Power by 文案;折叠侧边栏时只保留纯版本号 v2.0.2,隐藏“版本:”和 Power by。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-18:修复登录页回车提交

  • frontend/src/components/LoginView.vue 的登录按钮改为原生 submit 类型,继续复用 n-form 的 @submit.prevent 登录流程。
  • 密码输入框增加 @keydown.enter.prevent="submit" 兜底,用户输完密码按回车即可触发登录,无需手动点击按钮。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-15:取消数据管理页初始化成功提示

  • frontend/src/components/DatabasePanel.vue 进入页面时仍会自动执行数据库连接检测和数据库信息刷新,但连接成功不再弹出 toast,避免切换到数据管理页时产生无意义提示。
  • 用户手动点击“重新检测”时仍保留成功提示;连接失败或接口异常仍会显示错误 toast。
  • 已执行 npm run build,构建通过;未启动浏览器或 headless Chrome。

2026-05-15:优化新版前端图标和侧边栏选中态

  • frontend/src/composables/pageHeader.ts 的页头动作图标从 emoji 字符串改为 Vue 组件,页面按钮统一传入 @vicons/ionicons5 图标组件,构建后随前端资源本地打包,适合内网运行。
  • AppShell.vue 的折叠侧边栏按钮、主题切换按钮和各页面页头动作已移除 emoji 图标;当前前端源码中仅保留主品牌图标 📊。
  • styles.css 优化侧边栏菜单选中态:展开态使用浅色背景、品牌色描边和左侧短标记,折叠态收敛为居中的 40px 图标块,避免选中背景过宽。
  • 本次只执行 npm run build 做构建验证,未按用户要求启动浏览器或 headless Chrome。

2026-05-15:修复新版前端夜间模式组件颜色

  • 新增 frontend/src/composables/theme.ts 作为前端共享主题状态,统一读写 localStorage.theme 并同步 document.documentElement[data-theme]。
  • App.vue 的 n-config-provider 现在会在夜间模式下使用 Naive UI darkTheme,修复 n-card、n-input、n-form、n-menu、n-button 等组件仍按亮色主题渲染的问题。
  • AppShell.vue 的主题切换改为调用共享主题逻辑,避免 AppShell 和 Naive Provider 各自维护主题状态。
  • styles.css 补充工作卡片、卡片标题、表单标签、菜单图标和菜单文字颜色兜底,防止局部组件样式覆盖暗色文本。
  • 已执行 npm run build,构建通过,仅有 Monaco/Vite 大 chunk 体积警告;已用 headless Chrome 打开新版 /settings 并预置 theme=dark 验证:页面、卡片标题、表单标签、输入框文字、字段映射标题和顶部按钮均为暗色主题可读颜色。

2026-05-15:对齐新版前端主体布局并修复全局拖拽默认行为

  • 新版 Vue 前端主体内容继续按旧版 frontend_old/ 的工作区布局对齐:上传页保留旧版上传区尺寸和文件列表结构,数据库页恢复左侧表列表 + 右侧数据区,设置页恢复左右列,脚本页恢复编辑器容器和底部状态栏。
  • frontend/src/composables/pageHeader.ts 新增页面顶部副标题和动作注册机制;各页面把原本散落在页面内部的主要动作注册到 AppShell 顶栏,避免每个页面重复实现标题栏。
  • AppShell.vue 在捕获阶段统一拦截带 Files 的 dragover/drop 默认行为,修复文件拖到新版页面空白处时浏览器打开文件或弹出下载的问题;真正的文件处理仍由上传区自己的 drop 事件完成。
  • 上传区 FileWorkflow.vue 明确使用 .prevent.stop 处理拖拽事件,并继续支持文件和目录拖拽;目录读取使用 webkitGetAsEntry() 递归遍历,文件路径按相对路径去重。
  • 已执行 npm run build,构建通过,仅有 Monaco/Vite 大 chunk 体积警告;已用 headless Chrome 验证新版 /upload 上传区位于 x=252,y=88,width=1156,height=220,拖到页面空白处不会跳转,拖到上传区会加入 drag-test.csv。

2026-05-15:恢复新版数据库页左右工作区布局

  • frontend/src/components/DatabasePanel.vue 已从纵向卡片堆叠改回旧版主体布局:左侧固定 240px 数据表列表,右侧为表数据面板,左下角显示数据库版本和快速导入状态。
  • 数据库连接状态不再占用页面顶部;“重新检测”保留在左下状态块中,表列表刷新和删除全部放在左侧列表顶部。
  • 右侧表数据区在未选择表时显示“请选择左侧的数据表”,选择表后显示表名、总行数、刷新、CSV、XLSX、清空、删除、数据表格、字段结构和分页。
  • 已执行 npm run build;并用 headless Chrome 对照旧版 http://127.0.0.1:9082/ 与新版 http://127.0.0.1:9081/database,确认两边数据库主体均为横向 flex,左栏宽 240px,右侧内容区占用剩余宽度。

2026-05-15:修复旧版前端未登录闪烁

  • frontend_old/js/app.js 现在会在首页初始化前检查登录 token;未登录时直接跳到旧版登录页,避免首页继续初始化并反复请求 API 造成未授权提示闪烁。
  • 旧版前端鉴权统一兼容 capacity_report_token 和旧 key token:请求优先读取新版 key,登录页会同时写入两个 key,并继续写入 token cookie。
  • 旧版 API 401、XHR 上传 401 和退出登录都会清理两个本地 token key 及 cookie,并跳转到 /login.html;通过 /old/... 路径访问旧版时会跳转到 /old/login.html。
  • 已用 headless Chrome 验证:清空本地存储后访问 http://127.0.0.1:9082/ 会进入 http://127.0.0.1:9082/login.html;按本机 auth.ini 登录后回到旧版首页,/api/cache/size 携带 token 调用返回 200。

2026-05-15:新版上传页对齐旧版布局并恢复拖拽上传

  • frontend/src/components/FileWorkflow.vue 的上传页内容区已按旧版 frontend_old/index.html 的上传结构重排,保留新版侧边导航和顶部标题栏,只对齐页面主体中的上传区、文件列表、上传进度和处理日志布局。
  • 上传区支持点击选择文件,也支持把文件或文件夹直接拖拽到页面;目录拖拽使用 DataTransferItem.webkitGetAsEntry() 递归读取,readEntries() 会循环读取完整批次,兼容 Chrome 目录拖拽一次只返回部分条目的情况。
  • 上传文件统一过滤 .zip、.xlsx、.xls、.csv,路径会归一化为 /,并按相对路径去重;文件状态显示为等待上传、上传中、已完成或失败。
  • 旧版对照端口仍为 9082,新版端口仍为 9081;已用 headless Chrome 对比 9082/ 与 9081/upload,新版上传框尺寸、虚线边框、圆角和文案与旧版基本一致,并通过模拟拖拽 drag-test.csv 验证文件列表能正常出现。
  • 构建验证命令为 cd frontend && npm run build;当前只存在 Vite 大 chunk 体积警告,构建本身通过,frontend/dist/ 仍按 .gitignore 作为本地构建产物处理。

2026-05-15:拆分新旧前端访问端口

  • python -m app.main 现在由同一个 FastAPI 进程同时监听 9081 和 9082,共享后端运行状态、任务锁和 API。
  • 9081 固定服务新版 Vue 3 前端,9082 固定服务 frontend_old/ 旧版 HTML/CSS/JS 前端;旧版页面仍通过 /old/... 加载本地 Monaco 等静态资源。
  • app.main:app 保留为新版单端口 ASGI 实例,app.main:old_app 保留为旧版单端口 ASGI 实例,app.main:split_app 用于按请求端口切换前端。
  • run.bat、supervisord.conf、Dockerfile、Docker Compose 和离线构建脚本已同步新旧端口:本地为 9081/9082,容器宿主机映射为 19081/19082。

2026-05-15:增加旧版前端对照入口和新版路由

  • 从旧提交 54773f547f6fcb853d73785f05ff5ac39ab2e5f5 恢复原生 HTML/CSS/JS 前端到 frontend_old/,包含旧版 index.html、login.html、样式、脚本和本地 Monaco 资源。
  • 后端在 app/main.py 中通过 /old 和 /old/... 托管 frontend_old/,旧版静态资源统一改为 /old/... 前缀;旧版页面仍复用当前 /api/... 接口,便于和新版直接对比。
  • 新版 Vue 前端新增 vue-router,页面路径为 /upload、/history、/database、/script、/settings;菜单切换会更新浏览器地址,刷新时由 FastAPI SPA fallback 返回新版入口,不再固定回到主页。
  • frontend/dist/ 仍是本地构建产物,只用于运行验证,不进入版本库;源码运行时需要先在 frontend/ 执行 npm install 和 npm run build。

2026-05-15:恢复前端工作台交互质量

  • 前端工作台布局重新对齐旧版 54773f547f6fcb853d73785f05ff5ac39ab2e5f5 的信息架构:左侧导航、顶部标题栏、紧凑后台式内容区,导航项使用“数据上传 / 处理历史 / 数据管理 / 脚本编辑 / 系统设置”。
  • ScriptPanel.vue 不再使用普通 textarea,改为 monaco-editor SQL 编辑器,保留脚本读取、保存、执行和状态轮询接口;支持 SQL 高亮、行号、缩略图、光标行列状态和未保存状态。
  • Monaco 通过 Vue 异步组件按需加载,避免脚本编辑器依赖进入首屏主包;Vite worker 类型由 frontend/src/vite-env.d.ts 提供。
  • SettingsPanel.vue 的字段提取配置恢复为结构化树状配置:字段名、字段类型、提取来源列表、搜索、增删和去重保存,不再要求用户直接编辑 JSON。
  • 新增前端运行依赖 monaco-editor,构建时仍会生成 frontend/dist/,该目录继续作为构建产物忽略,不进入版本库。

2026-05-15:修复 Windows 启动脚本编码问题

  • run.bat 改为纯 ASCII 输出,并规范为 CRLF 行尾,避免 Windows cmd 在 PowerShell 中执行 UTF-8 中文批处理时把提示文本解析成碎片命令。
  • 启动脚本仍使用 .venv\Scripts\python.exe、检查 Python 依赖和 frontend/dist/index.html,实际启动方式保持 python -m app.main 不变。
  • 后续如需中文启动提示,优先放到 PowerShell 脚本或应用日志中,不建议直接写入 .bat。

2026-05-15:后端拆分与前端迁移

当前架构

  • 后端入口收敛到 app/main.py,只负责创建 FastAPI 应用、注册中间件、注册路由和托管前端构建产物。
  • API 按业务拆分到 app/api/routers/:
    • auth.py:登录和修改密码。
    • upload.py:上传会话和文件上传。
    • tasks.py:任务锁、处理启动、处理状态。
    • history.py:历史记录、日志和记录删除。
    • database.py:数据库测试、表查询、表维护和导出。
    • config.py:配置读取、保存、上传和下载。
    • cache.py:缓存大小统计。
    • script.py:SQL 脚本读取、保存和执行。
    • health.py:健康检查。
  • 运行时共享状态放在 app/state.py,包括配置实例、历史管理器、处理任务、上传会话和全局任务锁。
  • 登录、密码文件和 Token 逻辑放在 app/auth.py,继续使用本地 auth.ini。
  • 文件大小等工具函数放在 app/utils/files.py。

前端

  • 旧 static/ 原生 HTML/CSS/JS 已替换为 frontend/。
  • 前端技术栈为 Vue 3 + TypeScript + Vite + Naive UI。
  • 构建产物位于 frontend/dist,由 FastAPI 根路由托管;/assets 映射到 frontend/dist/assets。
  • 未构建前端时,后端会返回 503,并提示执行 cd frontend && npm install && npm run build。
  • Vite 开发服务器将 /api 和 /health 代理到后端 http://localhost:9081。

部署与运行

  • Windows 本地运行使用 run.bat,优先使用 uv 创建的 .venv\Scripts\python.exe。
  • run.bat 会检查 Python 依赖和 frontend/dist/index.html,缺少前端产物时要求先构建前端。
  • Docker 构建改为多阶段:
    • node:22-slim 阶段安装前端依赖并执行 npm run build。
    • python:3.13.11-slim 阶段安装后端依赖,复制应用代码,再复制前端构建产物。
  • .dockerignore 只排除 frontend/node_modules、frontend/dist 等本地产物,不再排除完整前端源码。

依赖与清理

  • Python 依赖保留当前代码实际使用项:fastapi、uvicorn[standard]、python-multipart、pymysql、cryptography、pandas、openpyxl、chardet、supervisor。
  • 已移除未使用的 sqlparse、aiofiles、python-dateutil。
  • 旧静态目录、根目录打包产物、日志和 Python 编译缓存属于可清理产物,不应提交。

注意事项

  • 当前项目按每周整包替换使用,不维护旧版 API 兼容层;但核心处理流程、配置文件和 ReportScript.sql 仍沿用现有语义。
  • ReportScript.sql 是业务处理链路的一部分,重构接口或前端时不要改写 SQL 语义。
  • auth.ini、cache/、dist/、frontend/dist/、frontend/node_modules/ 均为本地运行或构建产物,不进入版本库。

2026-05-20: Cross-platform packaging

  • Added one-command build entry points: scripts/build.bat, scripts/build.ps1, and scripts/build.sh. Targets are server, desktop, docker, and all; script output stays ASCII to avoid console encoding issues on Windows.
  • Server Portable uses PyInstaller one-dir mode and packages the backend executable with frontend/dist, Configure.json, ReportScript.sql, cache/, logs/, and launch scripts. The default server port remains 9081.
  • Desktop packaging uses Tauri 2 + Vue + Python sidecar. The build sets VITE_API_BASE=http://127.0.0.1:19082, builds a PyInstaller one-file capareport-server sidecar, and the desktop app starts it on 127.0.0.1:19082.
  • app/config.py supports CAPAREPORT_BASE_DIR; frozen PyInstaller server builds default BASE_DIR to the executable directory. The Tauri sidecar sets CAPAREPORT_BASE_DIR to the app data directory so runtime files are not written into the install directory.
  • Tauri startup creates app-data cache/ and logs/, then copies bundled Configure.json and ReportScript.sql on first run. Resource lookup supports both normal Tauri resources and the _up_ directory generated for bundled ../ resources.
  • Windows desktop shutdown uses taskkill /F /T /PID before killing the shell child, which avoids PyInstaller one-file sidecar process leftovers.
  • Docker build now copies only required app files and frontend build output. .dockerignore excludes local dependencies, caches, and generated output; deployment compose files are emitted under dist/docker/.
  • app/main.py accepts --host and --port and exposes run_server() so portable launchers, Docker, and the Tauri sidecar share the same backend entry point.
  • Windows verification completed: scripts\build.bat server -NoArchive, scripts\build.bat server, scripts\build.bat docker, and scripts\build.bat desktop. Server portable /health, Docker container /health, and desktop sidecar /health all returned HTTP 200; desktop first run also copied config and SQL into app data.
  • Cleanup verification completed: .venv\Scripts\python.exe -m compileall app, npm run build, PowerShell AST parse for scripts/build.ps1, Docker-hosted sh -n scripts/build.sh, and cargo check --manifest-path src-tauri\Cargo.toml with a temporary sidecar placeholder all passed. Linux/macOS native server and desktop packages still need native OS verification.
  • src-tauri/gen/schemas/ is intentionally tracked because src-tauri/capabilities/default.json references ../gen/schemas/desktop-schema.json; do not ignore or delete these schema files during cleanup, otherwise VS Code JSON validation reports a missing schema.
  • README.md has been rewritten to document local startup, Server Portable, Tauri desktop, Docker, Linux/macOS build commands, configuration blocks, common APIs, and cleanup rules. Keep future build instructions in sync with scripts/build.*.

2026-05-20: Tauri desktop console and installer language

  • src-tauri/src/main.rs uses #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] so Windows release builds use the GUI subsystem and do not open an extra console window when launched from Explorer or the installer shortcut.
  • packaging/capareport-server.spec keeps Server Portable in console mode, but desktop one-file sidecar builds (CAPAREPORT_ONEFILE=1) use PyInstaller console=False; PyInstaller should select runw.exe for the sidecar so it also stays hidden behind the Tauri window.
  • src-tauri/tauri.conf.json sets Windows installer localization through bundle.windows.wix.language = "zh-CN" and bundle.windows.nsis.languages = ["SimpChinese"]. NSIS language keys must use NSIS names such as SimpChinese, while WiX/MSI uses locale names such as zh-CN.
  • Verification on Windows: cargo check --manifest-path src-tauri\Cargo.toml passed, scripts\build.bat desktop generated the MSI and NSIS bundles, PE subsystem checks reported Windows GUI for both capacity-report-desktop.exe and capareport-server.exe, and the generated NSIS script included MUI_LANGUAGE "SimpChinese".

2026-05-20: Unified release output under dist

  • The former build/ packaging source directory was renamed to packaging/ to avoid confusing source-side packaging recipes with generated output. packaging/ now holds Dockerfile, docker-compose.yml, the PyInstaller spec, and MySQL container config.
  • scripts/build.ps1 and scripts/build.sh now use dist/.tmp/ for PyInstaller work output and copy final deliverables to dist/server/, dist/desktop/, and dist/docker/. Successful builds remove dist/.tmp, frontend/dist, src-tauri/target, and src-tauri/binaries.
  • Docker builds now include Configure.json in the image and also create a deployable dist/docker/ bundle containing capacity-report-app-latest.tar, docker-compose.yml, Configure.json, ReportScript.sql, mysql/, cache/, and logs/.
  • Server Portable still includes Configure.json and ReportScript.sql inside dist/server/CapacityReport-Server-<platform>-x64/. Tauri desktop still bundles both files through src-tauri/tauri.conf.json resources and copies them to app data on first run.

2026-05-25: API Token management improvements

  • API Token records now persist the complete token value in api_tokens.json in addition to the HMAC hash, prefix, and suffix. Existing hash-only records remain readable but cannot expose the full token; the UI asks users to regenerate those tokens before copying.
  • app/services/api_tokens.py now supports exporting/importing token records for configuration migration and batch deletion by token ID. Config download adds an ApiTokens block, and config upload restores it when present.
  • Token update is a partial update path: callers may change only name, enabled, or expiration fields without accidentally changing unspecified fields.
  • frontend/src/components/ApiTokenManager.vue now shows selectable token rows, a batch delete button, a compact per-row action dropdown, copy-token action, and enable/disable action. New token creation defaults to a specified expiration date one month after the current browser date, while permanent tokens remain available via the radio option.
  • OpenAPI and README text were updated to describe repeatable token copying, token migration through config upload/download, and batch delete.
  • Verification performed: api_tokens service create/list/verify/enable/disable/export/import/batch-delete test passed, HTTP endpoints for create/list/update/config download/batch-delete passed on local port 9081, .venv\Scripts\python.exe -m compileall app passed, and npm run build passed with only the existing Vite large chunk warning.

2026-05-25: API Token row visibility controls

  • frontend/src/components/ApiTokenManager.vue renders Token values as a compact row with right-side icon buttons: an eye button toggles masked/full Token display, and a copy button copies the complete Token directly from the row.
  • The per-row operation dropdown now keeps edit, enable/disable, regenerate, and delete actions; copying is surfaced beside the Token value for faster repeated use.
  • Build verification: npm run build passed with only the existing Vite large chunk warning.
  • Follow-up UI adjustment: the eye/copy buttons now sit immediately after the Token text instead of being pushed to the far right, and Token rows show created_at in the metadata area.

2026-06-01: API documentation toolbar cleanup

  • frontend/src/components/ApiDocs.vue no longer registers a page-header copy sample action, avoiding duplicate 复制传参示例 buttons on the API documentation page.
  • The API documentation card still keeps its local toolbar actions: 复制传参示例 and OpenAPI JSON.
  • Verification performed: npm run build passed, and generated frontend build output was removed after verification.

2026-06-01: Frontend entry chunk reduction

  • frontend/src/router.ts now lazy-loads FileWorkflow.vue, matching the other main pages and keeping the data processing page out of the base entry chunk until the route is opened.
  • frontend/src/AppShell.vue now lazy-loads LoginView.vue and the hidden license activation dialog; the dialog UI and activation API flow moved to frontend/src/components/LicenseActivationModal.vue.
  • Build verification: npm run build passed. The base index chunk dropped from about 572 kB to about 461 kB; the remaining large chunks are still ApiDocs (swagger-ui-dist) and ScriptPanel (monaco-editor).

2026-06-01: History detail file browser

  • app/api/routers/history.py adds /api/history/files for browsing a history work directory by safe relative path, and /api/history/file/download for downloading one file directly or one directory as a temporary ZIP. Both paths are constrained under the record's cache/ work directory; download still rejects pending/processing records.
  • frontend/src/components/HistoryPanel.vue keeps the processing log at the bottom of the task detail modal, and adds a 详情 / 文件 tab area above it. The file tab shows breadcrumb navigation, parent/refresh controls, directory/file type, size, modified time, and per-item download actions.
  • frontend/src/types.ts defines HistoryFileEntry and HistoryFilesResponse; app/main.py adds Chinese OpenAPI descriptions and examples for the new history file APIs.
  • Verification performed: .venv\Scripts\python.exe -m compileall app, npm run build, direct history file listing for 20260519_172434, path traversal rejection, and single-file download of log.txt on a temporary local server all passed. Build output and Python caches were removed after verification.

2026-06-01: RJ scheduler display cleanup

  • app/services/auto_scheduler.py now keeps RJ directory status keys clean instead of prefixing them with rj: in the combined scheduler response.
  • frontend/src/components/SettingsPanel.vue strips any legacy rj: prefix before rendering the scheduler directory name, so the UI shows RJ/2.6G/... instead of rj:RJ/2.6G/....
  • This is display-only cleanup; the underlying RJ directory detection and readiness logic were not changed.

2026-06-01: Settings page split

  • frontend/src/components/SettingsPanel.vue splits the former combined connection page into a dedicated 数据库配置 tab and a separate 远程数据源 tab.
  • Database-related settings now stay together with 数据库配置 and 处理历史保留; remote automation settings now own the FTP/SFTP fields, auto-delete toggle, scheduler configuration, and scheduler status panel.
  • frontend/src/styles.css now uses dedicated layout classes for the database and remote settings panes, with independent scrolling and responsive single-column stacking on narrower screens.
  • Verification performed: cd frontend && npm run build passed. Browser inspection on http://127.0.0.1:9081/settings confirmed the two new tabs render correctly, the remote panel shows its own configuration and scheduler cards, and horizontal overflow remained at 0.

2026-06-01: Settings remote scheduler refinement

  • frontend/src/components/SettingsPanel.vue keeps 远程数据源 focused on FTP/SFTP connection fields. Protocol, host, port, timeout, and FTP passive mode render on one row when width allows; remote automation and delete-source toggles now sit below 远程目录.
  • 自动调度 is now a separate settings tab. Scheduler controls are disabled unless 启用远程自动化 is on, and turning off remote automation automatically turns off scheduler enablement in the current form state and saved payload.
  • debug.bat starts the Python backend on 127.0.0.1:9081 and the Vite frontend on 127.0.0.1:5173 for source-level debugging without requiring frontend/dist.
  • Verification performed: cmd /c debug.bat started the debug backend/frontend, cd frontend && npm run build passed, and browser inspection confirmed the remote connection fields align in one row with no horizontal overflow. Debug processes and frontend/dist/ were removed after verification.

2026-06-01: Task runtime cleanup

  • app/api/routers/task_runtime.py centralizes shared task-stage updates, processing license log output, and safe history-retention cleanup for manual processing and remote processing routes.
  • app/api/routers/tasks.py and app/api/routers/remote.py now reuse the shared helpers instead of carrying duplicate _set_task_stage and _log_license_check implementations.
  • Verification performed: .venv\Scripts\python.exe -m compileall app, npm run build, and cargo check --manifest-path src-tauri\Cargo.toml with a temporary sidecar placeholder all passed. Generated build output, Python caches, and temporary Tauri sidecar files were removed after verification.

2026-06-01: Download cleanup helper

  • app/utils/files.py now provides remove_file_safely() for best-effort temporary file cleanup.
  • Database table export and history archive download routes now reuse this helper instead of carrying duplicate private _remove_file() functions.
  • Verification performed: .venv\Scripts\python.exe -m compileall app, npm run build, and cargo check --manifest-path src-tauri\Cargo.toml with a temporary sidecar placeholder all passed. Generated build output, Python caches, and temporary Tauri sidecar files were removed after verification.

2026-06-01: Clipboard helper cleanup

  • frontend/src/composables/clipboard.ts centralizes browser clipboard writes with the existing hidden-textarea fallback.
  • API documentation, API Token management, and history detail log copying now reuse writeClipboardText() instead of each component carrying its own clipboard fallback.
  • Verification performed: npm run build, .venv\Scripts\python.exe -m compileall app, and cargo check --manifest-path src-tauri\Cargo.toml with a temporary sidecar placeholder all passed. Generated build output, Python caches, and temporary Tauri sidecar files were removed after verification.

2026-06-01: Final cleanup pass

  • A follow-up static import scan removed the leftover unused Path import from app/api/routers/database.py.
  • Final verification included .venv\Scripts\python.exe -m compileall app, npm run build, a lightweight Python AST unused-import scan, .venv\Scripts\python.exe -m pip check, and npm audit --omit dev.
  • Remaining scan hits are intentional runtime/cleanup console messages or behaviorally different format helpers; no further low-risk cleanup item was found in the final pass.

2026-06-01: Script task status cleanup

  • app/api/routers/script.py now reuses the shared set_task_stage() helper for manual SQL script task status updates.
  • Script execution status entries now include the same stage field shape used by processing and remote tasks while preserving the existing status values.
  • Verification performed: .venv\Scripts\python.exe -m compileall app, npm run build, and cargo check --manifest-path src-tauri\Cargo.toml with a temporary sidecar placeholder all passed. Generated build output, Python caches, and temporary Tauri sidecar files were removed after verification.

2026-06-02: Platform architecture planning

  • docs/platform_architecture_plan.md records the planned standalone Web data-processing platform architecture, module boundaries, submodule strategy, data flow, storage/history model, and staged roadmap.
  • The future platform workspace is reserved as platform/ under the current repository root and is ignored by CapaReport through .gitignore so exploratory platform development does not affect this project.
  • The design intentionally treats CapaReport as a reference implementation only; reusable ideas should be extracted by responsibility rather than copied into one large module.
  • platform/ is explicitly isolated from CapaReport: it must not use this repository's virtual environment, dependency files such as requirements.txt, frontend packages such as frontend/node_modules, build scripts, configs, runtime data, or source modules.

2026-06-23:双模式后端(自带 FTP/MySQL + Metrix 平台可选,两侧独立)

把应用做成「自包含 + Metrix 可选」:源与仓库各自可在直连与 Metrix 间独立选择,互不依赖。基于原版(pre-M2 全功能:FTP/MySQL/查看导出/license)叠加 Metrix 后端。

  • 配置 app/config.py:新增 source_type(ftp/sftp/metrix)、warehouse_type(mysql/metrix)、MetrixConfig(base_url/token/storage_id/database_conn_id/target_database/recent_days/data_dir_to_table),保留 MySQLConfig/RemoteDataConfig;Configure.json 新增 SourceType/WarehouseType/Metrix(token 隐藏于 to_dict,含于 to_file_dict);缺省向后兼容(source_type 缺省取 RemoteData.protocol,warehouse 缺省 mysql)。
  • 源工厂 app/services/platform.py::make_source_downloader:按 source_type 返回 RemoteDataDownloader(FTP/SFTP) 或 PlatformStorageDownloader(Metrix 储存),接口一致。platform.py 改用 MetrixConfig(token 从配置读),并扩展 PlatformClient 增 list_tables/table_columns/table_data/submit_export/download_job_file 供仓库代理。
  • 仓库分派:remote.py/tasks.py/script.py 按 warehouse_type 分流——mysql 走原版 DataProcessor(直连、LOAD DATA、单会话报表 SQL);metrix 走 app/services/pipeline.py(CsvProcessor → 平台 import → run-script single_session)。auto_scheduler.py 扫描也改用 make_source_downloader。
  • 仓库视图代理 app/warehouse.py:make_warehouse(config) → 直连返回原版 DatabaseManager,Metrix 返回 MetrixWarehouse(用平台 API 实现 get_tables/get_table_info/query_table/truncate/drop/drop_all/execute_sql 同接口);routers/database.py 的 _db() 透明切换,/api/download 在 metrix 模式代理到平台导出任务(避免分页上限丢行)。
  • 路由 routers/config.py:新增 POST /api/config/backend(类型)、/api/config/metrix(连接),配置上传也识别 SourceType/WarehouseType/Metrix。
  • 前端 SettingsPanel.vue:新增「数据源/仓库」标签——源/仓库单选 + Metrix 连接卡片(地址/Token/storage_id/database_conn_id/目标库/recent_days)+ 保存/测试储存;保留原 MySQL/远程数据源标签与 DatabasePanel 查看导出。types.ts 加 source_type/warehouse_type/metrix+MetrixConfig。
  • 重要修复:routers/database.py 全部处理函数由 async def 改为 def——这些是阻塞式(直连 pymysql / Metrix HTTP / 大表导出轮询),放在事件循环里会冻结单 worker(实测大表导出把 /health 也卡死);改 def 后 FastAPI 用线程池执行。
  • 容器:main.py 重新支持 CAPAREPORT_FRONTEND_DIR(代码/前端在 /app、运行态 /data 分离,robocopy 覆盖后补回);.dockerignore 放开 frontend/dist;requirements.txt 含 requests + pymysql/cryptography/paramiko(双模式都要)。Token 改存配置,entrypoint 不再需要环境变量。
  • 验证:前端 npm run build(vue-tsc)通过;镜像构建成功;容器冒烟(Metrix 模式)端到端通过——登录/config/full(新字段)/tables/table info/table-data/execute/导出代理全部 200,行数与列数正确。直连 MySQL 路径为原版未改代码。

2026-06-24:精简(去 API 文档 / API Token)+ 设置页卡片自适应 + 授权默认期改 2026-12-30

随双模式集成一起进入 metrix-integration 分支。去掉与数据处理无关的对外 API 能力,业务接口仅保留登录态访问:

  • 删除 API Token 与离线 API 文档:删 app/api/routers/api_tokens.py、app/services/api_tokens.py、frontend/src/components/ApiDocs.vue、ApiTokenManager.vue;前端去掉 router.ts/AppShell.vue 的 api-center 路由与菜单、package.json 的 swagger-ui-dist 依赖、types.ts 的 ApiToken* 类型、vite-env.d.ts 的 swagger 声明、SettingsPanel.vue 的「API Token」分页。
  • 后端解耦:auth.py::resolve_access_context 只保留 JWT(去掉 api_token 分支);main.py 去掉 api_tokens 路由注册、touch_token_usage、/api/openapi.json /api/docs-ui 文档端点,并删除随之不可达的整套 OpenAPI 定制(custom_openapi/TAG_LABELS/OPENAPI_TAGS/OPENAPI_OPERATION_DOCS 及 _make_operation_id 等辅助、get_openapi 导入、LOGIN_ONLY_API_PATHS),LOGIN_ONLY_API_PREFIXES 去掉 /api/tokens;config.py 去掉配置下载/上传里的 ApiTokens 字段。
  • 授权默认到期日:app/services/license.py::DEFAULT_EXPIRES_ON 由 2026-06-20 改为 2026-12-30,前端兜底文案(FileWorkflow.vue、LicenseActivationModal.vue)同步;授权功能本身保留(连点品牌图标 8 次打开延期窗口)。
  • 设置页排版:styles.css 的 .settings-database-stack 由纵向 column 改为 row wrap,子卡 flex:1 1 360px;min-width:320px,宽屏并排、窄屏自动换行;「处理历史保留」卡加 work-card-narrow(flex-grow:0 + max-width)显著收窄;规则同时作用于「数据源/仓库」与「数据库」两个标签页;清理已失效的 .settings-token-panel 规则。
  • 验证:python -m compileall app 通过;前端 npm run build(vue-tsc)通过,产物中不再出现 swagger/ApiDocs chunk。

2026-06-24:Metrix 模式报表 SQL 固定按本地 ReportScript.sql 执行(移除库内脚本 script_id 死路径)

  • 背景:Metrix 平台 POST /run-script 同时支持 content(直接执行 SQL 文本)与 script_id(执行平台数据库里保存的脚本,且 script_id 会覆盖 content)。CapacityReport 期望「无论哪种触发,Metrix 模式都执行本应用本地的 ReportScript.sql」,不使用平台库内保存的脚本。
  • 现状确认:pipeline.py/warehouse.py 所有 run_script 调用本就只传 content(报表 SQL 来自 read_report_sql() 读取本地 ReportScript.sql),从不传 script_id,行为已正确。
  • 改动:app/services/platform.py::run_script 删除一直未被调用的 script_id 参数与对应 body 分支,方法只构造 content,从代码层面杜绝走平台库内脚本那条路;签名由 (conn_id, script_id=None, content="", ...) 改为 (conn_id, content="", ...),现有调用全用 content= 关键字、conn_id 位置参,未受影响。
  • 验证:python -m compileall app 通过;全仓 app 内除该行注释外无 script_id 引用。

2026-06-24:数据目录映射统一为 DataMappings

  • 背景:UD 与 RJ 在处理阶段本质都是「源目录 -> 暂存表」。此前 UD 使用 UDData.directories,RJ 使用 RJData.weekly_directories + 代码内置目录名到表名映射,概念重复且前端容易继续堆卡片。
  • 配置:删除 UDData / RJData 两套配置,改为顶层 DataMappings。DataMappings.directories 每行结构为 {path, table, ready_rule},ready_rule=daily 表示目标周每日 7 天检查,ready_rule=auto 表示按目录最新 ZIP 自动识别日粒度或周粒度;RJ 原字段映射并入 DataMappings.table_field_mappings,按目标表名覆盖全局字段映射。MetrixConfig 仍只保留平台连接信息。
  • 处理链路:直连 MySQL 的 DataProcessor 与 Metrix 仓库模式的 CsvProcessor 都只读取 DataMappings.directories。一个表可对应多个目录:每个目录先按最近日期筛选 CSV,再合并导入同一张暂存表(Metrix 模式写 .out/{table}.csv,MySQL 模式逐文件导入同表)。表级字段映射存在时优先使用 DataMappings.table_field_mappings[table],否则使用全局 ExtractField。
  • 自动调度:原 RJ 专用检查改为通用自动粒度检查。ready_rule=auto 的目录会从普通每日扫描中排除,并单独按最新 ZIP 判断日/周粒度;如果配置里只有自动粒度目录,只要这些目录就绪也可触发调度。
  • 前端:设置页「规则映射」左侧独立滚动配置栏中只保留一个「数据目录映射」卡片,每行可编辑目录、暂存表与就绪规则,并保存到 /api/config/data-mappings。后续新增目录类映射继续加同一张表,不再新增配置卡片。
  • 验证:python -m compileall -q app 通过;frontend npm run build 通过(仅既有大 chunk 提示);构建产物与 Python 缓存已清理。

2026-06-24:新增 CellData 远程源与数据库配置入口

  • 背景:后续需要引入 CellData 自动化处理,处理完成报表 SQL 后还会从 CellData 数据库表匹配数据并写入结果表。本轮先只落配置与界面,不接入实际提取/处理/入库流水线。
  • 配置:新增顶层 CellData 配置块,包含 RemoteData(FTP/SFTP 连接,默认远程目录 /CellData,不参与现有自动调度)与 MySQL_DBInfo(默认库名 celldata)。CellData 数据库可与主仓库 MySQL 相同,也可指向独立数据库。
  • 后端接口:新增 /api/config/cell-data/remote、/api/config/cell-data/mysql 保存接口,以及 /api/config/cell-data/remote/test、/api/config/cell-data/mysql/test 测试接口;测试逻辑分别复用 RemoteDataDownloader 和独立 PyMySQL SELECT 1。
  • 前端:系统设置「数据库」页新增「CellData 数据库配置」卡片;「远程数据源」页新增「CellData 数据源」卡片;「数据源 / 仓库」页说明 CellData 为独立辅助数据源,不影响主数据源/仓库选择。
  • 验证:python -m compileall -q app 通过;frontend npm run build 通过(仅既有大 chunk 提示);构建产物与 Python 缓存已清理。

2026-06-24:精简系统设置与历史页文案

  • 设置页说明文案去掉开发实现细节,只保留用户填写配置所需的短提示:主数据源/仓库、Metrix 连接、CellData 数据库/远程源、远程数据源、自动调度、目录映射、Sheet 过滤和字段映射等位置均已压缩。
  • 历史删除确认中的“缓存文件”改为“相关文件”,避免把内部存储实现暴露给用户。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:数据管理支持切换主数据库与 CellData 数据库

  • 数据管理页左侧表列表新增数据库选择,可在主数据库与 CellData 数据库之间切换;选项名称跟随系统设置里的主仓库库名和 CellData.MySQL_DBInfo.dbname。
  • 后端数据库接口新增 database_source 参数,main 保持原有直连 MySQL / Metrix 仓库逻辑,cell_data 使用 CellData.MySQL_DBInfo 创建独立 MySQL 仓库。表列表、表结构、分页数据、清空、删除、删除全部、执行 SQL 和导出均按该参数选择数据库。
  • CellData 数据库当前只支持直连 MySQL 配置;Metrix 仓库模式只影响主数据库。
  • 验证:python -m compileall -q app 通过;frontend npm run build 通过(仅既有大 chunk 提示);构建产物与 Python 缓存已清理。

2026-06-25:数据管理数据库选择改为弹窗列表

  • 数据管理页不再用下拉框切换数据库,改为表标题旁的图标按钮打开「选择数据库」弹窗;弹窗内为固定高度列表,超出高度滚动。
  • 左侧标题只显示分类名(主数据库 / CellData),不显示具体库名,也不再显示“表”字;弹窗列表显示真实库名(如 主数据库:CapacityReport)。选择项后续新增更多数据库时继续扩展同一列表,不占用侧栏宽度。
  • 验证:frontend npm run build 通过(仅既有大 chunk 提示);构建产物已清理。

2026-06-25:CellData cellinfo 来源与映射规则(待实现)

  • 数据来源:SFTP 127.0.0.1:2022 开发环境中,CellData 原始文件位于 /网优日常优化数据文档/日常性能报表/2026年/300表/{700M,2.6G}/。目录下文件为 Result_300_*.zip;文件时间取 ZIP 文件名末尾时间戳(如 20260620132109),不要用 SFTP 修改时间。
  • ZIP 结构:压缩包内部包含若干 CSV,例如 LTE_ITBBU_CellInfo_*.csv、LTE_SDR_CellInfo_*.csv、NR_CellInfo_*.csv、NetworkInfoStat_*.csv、SpecificColumn/...、others/...。核心入库来源先按文件名前缀识别 LTE_ITBBU_CellInfo、LTE_SDR_CellInfo、NR_CellInfo。
  • 编码注意:样本中 NR_CellInfo 用 GBK/GB18030 解码中文正常,按 UTF-8 会乱码;后续读取 CSV 时需要做编码探测或优先兼容 GBK。
  • 目标表:celldata.cellinfo,字段为 CGI/eNodeBID/CellID/PLMN/基站名称/小区名称/频点/带宽/制式/功率/网络。其中 CGI 由 PLMN-eNodeBID-CellID 拼接生成。
  • 2.6G 映射:
    • LTE_ITBBU_CellInfo:eNodeBID<-eNBId,CellID<-cellLocalId,PLMN<-plmn,基站名称<-eNBName,小区名称<-CellName,频点<-frequency,带宽<-bandWidth,制式<-radioMode,功率<-cpSpeRefSigPwr,网络="4G"。
    • LTE_SDR_CellInfo:同 LTE_ITBBU_CellInfo。
    • NR_CellInfo:eNodeBID<-gNBId,CellID<-cellLocalId,PLMN<-plmn,基站名称<-gNBName,小区名称<-CellName,频点<-ssbFrequency,带宽<-carrierBandwidth,制式="2.6G",功率<-powerPerRERef,网络="5G"。
  • 700M 映射:
    • LTE_ITBBU_CellInfo:eNodeBID<-eNBId,CellID<-cellLocalId,PLMN<-plmn,基站名称<-eNBName,小区名称<-CellName,频点<-frequency,带宽<-bandWidth,制式<-radioMode,功率<-cpSpeRefSigPwr,网络="4G"。
    • NR_CellInfo:eNodeBID<-gNBId,CellID<-cellLocalId,PLMN<-plmn,基站名称<-gNBName,小区名称<-CellName,频点<-ssbFrequency,带宽<-carrierBandwidth,制式="700M",功率<-powerPerRERef,网络="5G"。

2026-06-25:实现 CellData 预处理与单独刷新入口

  • 配置:CellData 新增 scan_paths、year_dir_regex、file_name_regex、file_time_regex 与 mapping。默认扫描路径为 /网优日常优化数据文档/日常性能报表/{maxyear}年/300表;默认 ZIP 过滤为 Result_300_*.zip;默认映射写入 cellinfo 并生成 CGI={PLMN}-{eNodeBID}-{CellID}。
  • 设置页:CellData 数据源卡片新增扫描路径列表、路径说明弹窗、三个高级正则输入、映射 JSON 编辑框,以及“校验 JSON / 恢复默认映射 / 保存规则”操作。说明弹窗包含路径模板、占位符、正则和多目录示例,避免在表单页堆长文案。
  • 后端:新增 app/services/cell_data.py,负责路径模板解析(含 {maxyear}/{yyyy}/{yyyymm}/{yyyymmdd})、按扫描目录下一级子目录选择最新 ZIP、解析目标 CSV、执行 JSON 映射、清空并批量写入 celldata.cellinfo。CSV 解码优先 UTF-8/UTF-8-SIG,回退 GB18030/GBK。
  • 接口:新增 app/api/routers/cell_data.py,提供 POST /api/cell-data/process/start 与 /status,数据处理页新增独立 CellData 卡片,可只刷新 CellData,不跑容量处理。
  • 接入:本地上传、远程手动和自动调度入口都会在容量处理前调用 CellData 预处理;CellData 单独处理和容量处理共用现有全局任务锁,避免并发写库。
  • 验证:python -m compileall -q app 通过;frontend npm run build 通过;远程定位可从最新年份 2026年/300表 选出 2.6G 与 700M 各自最新 Result_300 ZIP;用 SFTP MCP 读取的小样本 ZIP 验证解析和入库,celldata.cellinfo 写入 1 行且中文字段正常(样本 CGI=460-00-12683845-1)。

2026-06-25:CellData 卡片支持本地上传处理

  • 数据处理页 CellData 卡片改为与主上传区一致的拖拽/点击上传样式,支持拖入或选择多个 Result_300_*.zip,也支持选择文件夹上传。
  • 新增 /api/cell-data/process/upload,上传后复用 CellData 解析入库逻辑;若 ZIP 不在 700M/2.6G 等目录下且无法识别频段,会跳过无法唯一匹配的 CSV。
  • CellData 卡片仍保留「远程刷新」操作,用于按系统设置中的 CellData SFTP/FTP 配置拉取处理。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:数据处理卡片补说明按钮并规范 CellData 上传

  • 数据处理页的容量数据卡片与 CellData 卡片左上角均显示数据类型,右上角均提供说明图标按钮,点击后以小弹窗展示所需文件格式和目录结构。
  • CellData 卡片改为点击/拖拽文件夹上传,不再提供单文件选择;直接拖入单个 ZIP 会提示选择包含 Result_300 ZIP 的文件夹。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:数据处理卡片并排展示

  • 数据处理页容量数据与 CellData 两个卡片在宽屏下左右并排展示,窄屏下自动回落单列,减少对日志区域的挤压。
  • 容量数据说明补充:启用 CellData 数据源时,处理容量数据前会先刷新 CellData;CellData 卡片按钮文案统一为「远程下载并处理」。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:数据处理卡片说明与上传方式调整

  • 容量数据和 CellData 卡片左上角均标注数据类型,右上角均有说明按钮;容量数据说明弹窗明确启用 CellData 时会在处理容量数据前先更新 CellData。
  • CellData 卡片点击后选择文件夹,拖拽也只接受文件夹;不支持单个 ZIP 文件直接拖入,避免缺少频段目录导致无法映射。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:远程数据源页收纳 CellData 规则设置

  • 远程数据源页只保留容量数据源与 CellData 数据源两张连接配置卡片,宽屏下并排展示;CellData 的扫描路径、正则和映射 JSON 收纳到「规则设置」弹窗。
  • CellData 规则弹窗包含扫描路径列表、路径说明入口、高级正则和 Monaco JSON 编辑器,支持格式化、校验、恢复默认映射和保存规则。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:精简 CellData 数据源路径配置

  • CellData 数据源卡片去掉“远程目录”输入,连接根目录固定走 /;实际数据位置统一由「规则设置」中的扫描路径模板决定,避免两个路径概念混淆。
  • 扫描路径占位符扩展支持 {maxmonth}、{maxday},并新增 month_dir_regex、day_dir_regex 高级正则配置;说明弹窗同步补充相关说明。
  • 验证:python -m compileall -q app 通过;frontend npm run build 通过;构建产物与 Python 缓存已清理。

2026-06-25:CellData 扫描路径回到数据源卡片

  • 扫描路径属于文件来源配置,已移回 CellData 数据源卡片中展示和维护;「规则设置」弹窗只保留高级正则与映射 JSON,避免弹窗承担过多基础配置。
  • CellData 数据源不再展示“远程目录”,连接根目录固定为 /;实际文件位置完全由扫描路径控制。
  • 扫描路径占位符支持 {maxyear}、{maxmonth}、{maxday}、{yyyy}、{yyyymm}、{yyyymmdd},并提供对应年份/月/日目录正则配置。
  • 验证:python -m compileall -q app 通过;frontend npm run build 通过;构建产物与 Python 缓存已清理。

2026-06-25:优化 CellData 扫描路径排版

  • CellData 数据源卡片中的扫描路径区域改为全宽列表布局,说明文字、说明按钮、路径输入、删除按钮和添加输入保持对齐,减少左侧拥挤。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:CellData 映射支持图形化编辑

  • CellData「规则设置」弹窗中的映射规则增加“图形化 / JSON”切换。图形化模式可维护目标表、主键字段、主键表达式、来源目录、CSV 前缀和字段映射;字段映射支持“CSV 字段”和“固定值”两种模式。
  • JSON 模式仍使用 Monaco 编辑器,支持格式化、校验、恢复默认;两种模式共用同一份 CellData.mapping JSON,切换时自动互转。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:修正 LTE_SDR 小区名称映射

  • LTE_SDR_CellInfo 的小区名称字段实际为 cellName(小写 c),不是 CellName;默认 CellData 映射和 Configure.json 已同步修正。
  • 使用 2.6G 样本重新导入后,celldata.cellinfo 中 4G/5G 的 小区名称 空值数均为 0。
  • 验证:python -m compileall -q app 通过。

2026-06-25:固定图形化映射基础区与添加来源按钮

  • CellData「规则设置」弹窗不再整体滚动;高级匹配、目标表、主键字段和主键表达式固定显示,图形化模式下仅来源列表滚动。
  • “添加来源”按钮固定在来源列表下方,始终可见;弹窗底部保存按钮也保持可见。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:图形化来源支持折叠

  • CellData 图形化映射中每个来源卡片支持展开/收起,来源头展示目录与 CSV 前缀摘要;“添加来源”按钮移动到映射规则标题区右侧。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:调整图形化映射添加来源位置

  • “添加来源”按钮移动到主键表达式输入区下方右侧;点击后来源列表自动滚动到新增来源。
  • 验证:frontend npm run build 通过;构建产物已清理。

2026-06-25:清理后端直接 print 诊断输出

  • app/history.py、app/processor.py、app/api/routers/task_runtime.py 中的异常诊断从直接 print() 改为模块级 logging,避免后台任务和历史清理在 stdout 中产生零散噪音,同时保留必要警告信息。
  • app/main.py 中的启动横幅 print() 保留,仍用于命令行直接启动时提示版本、配置更新时间和访问地址。
  • 验证:CapacityReport\.venv\Scripts\python.exe -m compileall -q app 通过;frontend npx vue-tsc --noEmit --noUnusedLocals --noUnusedParameters 通过。

2026-06-25:收敛上传文件相对路径

  • 新增 app.utils.files.safe_relative_path(),容量数据上传和 CellData 本地上传保存文件前统一过滤空片段、. 与 ..,避免客户端文件名或 webkitRelativePath 中的路径穿越片段写出任务工作目录,同时保留合法的文件夹层级。
  • 验证:safe_relative_path 典型路径断言通过;python -m compileall -q app 通过;frontend npm run build 通过;构建产物已清理。

2026-06-25:连接测试接口改为线程池执行

  • /api/remote/test、/api/config/cell-data/remote/test、/api/config/cell-data/mysql/test 改为同步路由函数,保持响应结构不变,但让 FastAPI 在线程池中执行 FTP/SFTP、Metrix 平台 HTTP 与 MySQL 连接测试,避免慢连接或超时阻塞事件循环。
  • 验证:.venv\Scripts\python.exe -m compileall -q app 通过;frontend npm run build 通过;构建产物已清理。

2026-06-25:CellData 容量处理集成改进与前端处理进度优化

  • 容量处理集成:tasks.py 和 remote.py 中的 refresh_cell_data() 调用改为 _try_refresh_cell_data() 包装函数,CellData 数据源未启用时直接跳过,CellData 处理失败时记录警告但继续执行容量处理,不再因 CellData SFTP 连接失败或无数据等原因导致整个容量处理任务失败。
  • CellData 阶段标识:容量处理流程中 CellData 更新阶段会设置独立的 cell_data stage,前端可显示"更新 CellData..."状态文案;CellData 完成后日志输出导入行数、解析行数和跳过行数摘要。
  • 前端阶段标签:stageLabels 新增 cell_data: '更新 CellData...';importing 标签从"上传数据中..."改为"导入数据中..."以避免与文件上传混淆。
  • 前端结果摘要:CellData 独立处理或容量处理完成后,处理进度区域显示成功摘要(文件数、导入行数、跳过行数、耗时);TaskStatus 类型新增 result?: CellDataResult 字段。
  • 验证:python -m compileall -q app 通过;frontend npm run build(vue-tsc)通过;构建产物已清理。

2026-06-25:ReportScript.sql 性能优化与标识符规范化

  • Buffer Pool:脚本头部新增 SET GLOBAL innodb_buffer_pool_size = 1073741824(1 GB),原值 128 MB 不足以容纳 4G/5G 各 500 万行的工作集,导致 UPDATE...JOIN 等操作变成磁盘随机 I/O。
  • 消除标记-删除模式:4G 部分的 DLPRB_MAX 和 CCE_MAX、5G 部分的 DLPRB_MAX 原先各用 ADD COLUMN insert → UPDATE...JOIN → ADD INDEX → DELETE → DROP COLUMN 五步标记并删除重复行,现改为 INSERT...WHERE NOT EXISTS 一步完成,共减少约 15 条冗余 DDL/DML。这正是导致 CCE_MAX JOIN 4G_MAX UPDATE 跑 >1 小时的直接原因。
  • 标识符规范化:全文所有表名和列名统一加反引号,避免以数字开头的表名(如 4G、5G)和中文列名在不同 MySQL 版本或 SQL 模式下引起解析歧义。
  • 业务逻辑未变:忙时取法(ULPRB > DLPRB > CCE 优先级)、结果表聚合和 IFNULL 归零逻辑均保持原样。

2026-06-25:修复 ISO8601 日期时间导入时区偏移

  • 根因:源 CSV 中日期时间格式为 2026-06-15T00:00:00+08:00(ISO 8601 带时区),pd.to_datetime(format='ISO8601') 会自动转为 UTC(2026-06-14 16:00:00),导致入库后比实际壁钟时间偏移 -8 小时。
  • 修复:processor.py::_convert_datetime_column 在 ISO8601 解析前先用正则剥离时区后缀(+08:00、-05:30、Z)和 T 分隔符,再按朴素日期时间解析,保留原始壁钟时间。
  • SQL 清理:ReportScript.sql 删除 4G/5G 的 DATE_ADD(INTERVAL 8 HOUR) 补偿语句,因为数据导入阶段已正确保留本地时间,不再需要 SQL 层面修正。
  • 验证:python -m compileall -q app 通过。

2026-06-25:CellData 脚本编辑与跨库表复制

  • 新增 CellDataScript.sql 脚本路径(config.py::CELLDATA_SCRIPT = BASE_DIR / "CellDataScript.sql"),与 ReportScript.sql 并列,用于 CellData 数据导入后执行的 SQL。
  • 脚本 API(script.py)三个接口(读取/保存/执行)新增 script_type 参数(report / celldata),默认 report 保持向后兼容;CellData 脚本执行在 CellData 数据库上下文中运行。
  • 新增 cell_data.py::execute_celldata_script():在 CellData MySQL 库上执行 CellDataScript.sql,复用 DataProcessor.parse_sql_script 解析。
  • 新增 cell_data.py::copy_celldata_tables_to_capacity():列出 CellData 库所有表,逐表 SHOW CREATE TABLE → 目标库建表 → 分批 SELECT * / INSERT INTO 复制数据;两库相同时跳过。
  • CellData 独立处理(远程 / 本地上传)完成后自动执行 CellData 脚本(不复制表)。
  • 容量处理集成(tasks.py / remote.py 的 _try_refresh_cell_data):CellData 数据更新 → 执行 CellData 脚本 → 复制表到容量库 → 后续 ReportScript.sql 可直接引用 CellData 表。
  • 前端脚本编辑页(ScriptPanel.vue)页头下拉按钮切换「容量报表脚本」和「CellData 脚本」;运行按钮文案统一为「运行」,跟随当前脚本类型执行对应库的 SQL。
  • 验证:python -m compileall -q app 通过;frontend npm run build(vue-tsc)通过;构建产物已清理。

2026-06-25:Metrix 平台模式按需启用 + 数据源合并为外部储存

  • Metrix 平台开关:新增 AppConfig.metrix_enabled(默认 false),存储为 Configure.json 的 MetrixEnabled;关闭时 source_type 和 warehouse_type 自动回落为 external / mysql。
  • 开关入口:连点品牌图标 8 次打开的「授权延期」弹窗底部新增「启用 Metrix 平台」开关(LicenseActivationModal.vue),通过 POST /api/config/metrix-enabled 保存。
  • 条件显示:设置页「数据源 / 仓库」标签页仅在 metrix_enabled=true 时显示;未启用时该页不可见,系统默认走外部储存 + MySQL 直连。
  • 数据源合并:source_type 从 ftp | sftp | metrix 改为 external | metrix;FTP/SFTP 协议选择保留在远程数据源配置的 RemoteData.protocol 中,external 统一代表外部储存。旧值 ftp/sftp 自动规范化为 external。
  • 全局状态:metrixEnabled 通过 composables/metrixEnabled.ts 共享响应式状态,AppShell 登录后和激活弹窗切换时同步更新。
  • 验证:python -m compileall -q app 通过;frontend npm run build(vue-tsc)通过;构建产物已清理。

2026-06-26:数据管理增强(列宽可调 + 行编辑/删除 + 模板/导入)与 CellData 处理日志细化

数据管理(frontend/src/components/DatabasePanel.vue + app/api/routers/database.py + app/database.py + app/warehouse.py):

  • 数据表列宽可拖拽:n-data-table 每列加 resizable + width,scroll-x 计入新增操作列宽度。
  • 新增固定右侧「操作」列:每行「编辑 / 删除」。编辑弹窗按列字段逐项填写后保存(清空某字段=写入 NULL,前端空串→null,后端 None→SQL NULL);删除二次确认;操作后自动刷新当前页。
  • 行定位策略:以「整行原值」作为 WHERE 条件 + LIMIT 1(NULL 用 IS NULL),无主键表也能精确改/删单行、避免误伤重复行。后端 DatabaseManager.update_row/delete_row(参数化)与 MetrixWarehouse.update_row/delete_row(经 execute_sql 字面量 SQL)。
  • 工具栏新增「模板」「导入」(在 刷新/清空/删除 同组):模板下载当前表字段的 CSV 表头(POST /api/database/table/template,FileResponse);导入上传 CSV(POST /api/database/table/import,multipart,sync def 走线程池)。导入按模板校验:CSV 表头必须与表字段完全一致,缺字段/多字段一律 400 失败;通过后追加导入(DatabaseManager.import_csv 走 bulk_insert;Metrix 走平台 /import mode=append、create_table=false)。
  • 新接口均支持 database_source(main/cell_data) 双库;前端用 client.upload(multipart) 导入、download(POST) 下模板。

CellData 处理日志细化(app/services/cell_data.py):

  • _parse_zip_files(解压/解析):逐 ZIP 打「解压 {频段}/{文件名}(KB)」+「含 N 个 CSV」,逐 CSV 打「解析 {文件名}(频段):有效 X / 跳过 Y 行」,每包小计,末尾打「累计有效 / 去重后 / 累计跳过」。
  • _replace_cellinfo(上传/导入):打「准备写入表/库」「已连接」「确认表结构」「清空表(TRUNCATE)」「写入中 written/total 行」分批进度「已提交,成功写入 N 行」,失败回滚也记录。

附带修复:frontend/src/vite-env.d.ts 增加 declare module 'monaco-editor/esm/vs/basic-languages/mysql/mysql.js',修复 ScriptPanel SQL 补全的深层导入缺类型声明导致 vue-tsc(npm run build)失败(TS7016)。

  • 验证:python -m compileall -q app 通过;frontend npm run build(vue-tsc)通过(DatabasePanel chunk≈124KB)。

2026-06-26:容量看板(4G/5G 高负荷分析大屏)

  • 后端 app/api/routers/dashboard.py(main.py 注册):基于「主仓库」(make_warehouse,直连 MySQL 或 Metrix) 的 4G/5G 结果表聚合分析,4 个接口:
    • GET /api/dashboard/status → {has_4g,has_5g,ready}(两表都在才 ready);
    • GET /api/dashboard/overview?rat=4g|5g → 汇总(总数/高负荷/利用率预警/高流量预警/正常/平均下行利用率/总流量) + 问题分布饼 + 制式/带宽/站型/频段 分组统计 + 下行利用率 10 档直方 + Top10 高负荷小区;
    • GET /api/dashboard/cells?rat&problem&keyword&page&page_size → 问题小区清单(按 高负荷>高流量预警>利用率预警 + 下行利用率 排序,可筛选);
    • GET /api/dashboard/cell?rat&id → 单小区全字段 + 优化建议 + 同扇区同 PLMN 兄弟小区。
    • 4G 指标用 PUSCH/PDSCH 利用率与 YY-RRC,5G 用 PRB 利用率与 RRC 平均;execute_sql 原始 SQL,用户输入(id/keyword) 转义。
  • 前端:新增依赖 echarts;components/EChart.vue(echarts 封装,ResizeObserver 自适应 + dispose);components/CapacityDashboard.vue(科技感大屏:4G/5G 分段切换、6 张汇总卡片含数字滚动、6 个图表(环形/直方/分组柱/饼/横向柱)、问题小区清单(筛选+分页+点击行打开)、右侧详情抽屉(关键指标 + 优化建议 + 同扇区兄弟小区))。无结果表时横纵居中「请先进行数据处理」。
  • 路由 /dashboard(name=dashboard,懒加载);侧边菜单「容量看板」置于「数据处理」下方(AppShell menuKeys/menuOptions + StatsChartOutline)。看板自带深色科技风(径向辉光/玻璃拟态/霓虹色),不随应用明暗主题;图表 echarts 自定义深色配色。
  • 验证:npm run build(vue-tsc)通过(CapacityDashboard 懒加载 chunk≈1.16MB 含 echarts);后端 compileall 通过;各接口 SQL 经 MCP 对真实数据验证(4G 高负荷 792 / 5G 46,同扇区邻区 6–8 个)。

2026-06-26:容量看板配色统一 + 整页不滚动 + 清单导出

  • 组件配色统一:CapacityDashboard.vue 整体用 <n-config-provider :theme="darkTheme" :theme-overrides="naiveDark"> 包裹,强制看板内所有 Naive 组件(数据表/搜索框/分页/抽屉/Empty/按钮)走深色 + 青色(#22d3ee)强调色,解决浅色应用主题下表格/搜索/分页与深色大屏不匹配的问题。naiveDark 覆盖 DataTable(透明 td、半透明 th、淡边框)、Input(深色半透明底)、Pagination(深色项+青色激活)、Drawer(#0c1422)、Empty。抽屉内自定义 .cap-* 样式由 var(--td-*) 改为固定深色值,不再跟随应用主题。
  • 整页不滚动:.cap-dashboard 由 overflow:auto 改为 height:100%; overflow:hidden; display:flex; flex-direction:column(父链 .content 高 calc(100vh-64px) 为确定值)。布局分三段:顶栏(auto) → .cap-spin(flex:0 0 auto,包裹卡片+图表) → .cap-list(flex:1,占满剩余)。清单已移出 n-spin 成为 .cap-body 直接 flex 子项以获得确定高度;表格 n-data-table 加 flex-height + height:100%,由 .cap-table-wrap(flex:1 min-height:0) 提供高度,表体内部纵向滚动而非整页滚动。图表改为 2 行 3 列等宽网格,高度 clamp(136px,16vh,184px) 随视口自适应;卡片/字号整体缩小。窄屏(<1100px) 回退为 overflow:auto 多列换行。
  • 清单导出:后端新增 GET /api/dashboard/export?rat&problem&keyword(dashboard.py,sync def 走线程池),WHERE 与 cells 完全一致(同 problem/keyword 筛选、同排序、无分页),导出全部命中行为 CSV(utf-8-sig,FileResponse + BackgroundTask 清理 CACHE_DIR 临时文件);列含 CGI/NCGI、小区名称、制式/带宽/站型/频段、上下行利用率%、日均流量、用户数、高负荷问题、优化建议。前端清单工具栏「查询」旁加「导出」按钮(downloadGet,exporting 态,清单为空时禁用)。
  • 验证:frontend vue-tsc --noEmit 通过;后端 py_compile dashboard.py 通过。

2026-06-26:容量看板布局重构(定高不滚动)+ KPI/图表调整

  • 修复整页布局塌陷:上一版 .cap-dashboard { height:100% } 在 Naive n-layout-content(.content=height:calc(100vh-64px); overflow:auto) 结构下未解析为确定高度,导致 flex:1 的清单塌成 0、下方露白、加载态只剩顶部一条。改为 .cap-dashboard { height: calc(100vh - 64px); box-sizing:border-box; overflow:hidden; flex column }(视口定高,不依赖父级百分比,与 .content 等高故无页面滚动条)。窄屏(<1180px) 回退 height:auto; overflow:auto。
  • 清单占满剩余 + 表头固定:.cap-body flex 列三段=顶栏(0) / .cap-overview(0,n-spin 包裹卡片+图表) / .cap-list(flex:1)。清单作为 .cap-body 直接 flex 子项;n-data-table 用 flex-height + height:100%,由 .cap-table-wrap(flex:1 min-height:0) 给高,表体内部纵向滚动、表头与 scroll-x 横向条不跟随滚动。
  • KPI 卡片 7 个(一行,宽度缩小):新增「平均上行利用率」(summary.avg_ul,后端 SQL 加 AVG(ul)*100);「总日均流量」改为 formatFlow() 自动换算单位 B/KB/MB/GB/TB/PB(源值 GB,≥1024 逐级进位,<1 逐级降级),4G≈780.1 TB / 5G≈2.34 PB。
  • 图表两行三列:行一=负荷问题分布(环形) / 上行利用率分布(直方) / 下行利用率分布(直方);行二=制式分布(分组柱) / 站型分布(饼) / 频段标记小区(横向柱)。删除带宽分布;后端 overview 删 by_band、util_hist 拆为 ul_hist+dl_hist(复用 util_hist(col) 函数)。
  • 制式分布排除「未知」:group_by 增 skip_unknown 参数(WHERE 制式 IS NOT NULL AND <> ''),制式分布只剩 TDD/FDD。
  • 行间距:统一用 flex gap:12px,卡片/图表 panel 内边距收紧,避免叠压。图表高度 clamp(108px,13vh,160px) 适配矮窗口。
  • 验证:frontend npm run build(vue-tsc+vite) 通过;后端 py_compile 通过;4G/5G 的 avg_ul/total_flow、制式排除空值、上下行直方均经 MCP 对真实数据验证。

2026-06-26:容量看板适配日/夜双主题

  • 跟随应用主题:复用全局 composables/theme.ts 的 themeName(light|dark,写 documentElement[data-theme])。看板 isLight = computed(themeName==='light')。
  • Naive 组件:n-config-provider :theme 绑定 lightTheme|darkTheme;:theme-overrides 绑定 naiveLight|naiveDark(两套 DataTable/Input/Pagination/Drawer/Empty 覆盖,浅色强调色用 #0891b2、深色用 #22d3ee)。
  • ECharts:新增 chartPalette computed(轴文字/轴线/分割线/tooltip 底色与文字/图例/饼描边/柱底色 两套值),所有 option 通过 axisLine/axisLabel/splitLine/tooltipBase/legendStyle 辅助函数读取,主题切换时 computed 重算、EChart.vue 深度 watch setOption(opt,true) 自动重绘。
  • CSS:硬编码颜色抽成 --cap-* 变量(bg/panel/card/border/shadow/text 系列/soft-bg/tag 等),定义在 :global([data-theme='dark']) 与 :global([data-theme='light'])(documentElement) 上——这样 teleport 到 body 的详情抽屉也能继承同一套变量。浅色:白底玻璃卡片 + 柔和阴影 + 深色文字;深色:原科技风径向辉光。强调色(青/紫/玫红/琥珀)与 .cap-spark/分段激活态在两主题保持一致。卡片 icon/底色条改用更深的实色(#06b6d4/#f43f5e 等)以保证浅色下对比度。
  • 验证:frontend npm run build(vue-tsc+vite) 通过。

2026-06-26:容量看板默认 5G + 数值轴刻度防重叠

  • 默认制式:看板进入默认 rat='5g'(原 4g)。
  • 修复矮图表数值轴刻度重叠:图表高度仅 clamp(108px,13vh,160px),上行/下行利用率分布 0-10% 桶计数极大(约 1.9w)且带千分位,ECharts 自动放 5-6 条刻度导致 Y 轴标签纵向叠压。新增 abbrNum()(≥1万→「x万」、≥1千→「xk」、≥1亿→「x亿」)与 valueAxis()(splitNumber:3 + 缩写 formatter),套用到上/下行直方与制式分布的数值轴;频段标记小区横向柱的数值 x 轴同样加 splitNumber:3+缩写。
  • 验证:frontend vue-tsc --noEmit 通过。

2026-06-26:容量看板标题/操作并入框架页头

  • 参照「处理历史」做法,看板不再自绘标题栏:删除 .cap-topbar(标题/副标题/制式切换/刷新)。改用 composables/pageHeader.ts 的 setPageHeader/resetPageHeader 把内容注入 AppShell 顶部 page-header(与其他页一致,标题取路由 meta「容量看板」)。
  • 注入内容:subtitle「高负荷小区分析 · 实时数据」;actions = 4G / 5G 两个按钮(激活=type:primary, variant:solid,未激活=default+outline,点击 switchRat)+「刷新」(icon RefreshOutline,loading/disabled 绑 loadingOverview)。因 PageHeaderAction.type/variant 非响应式,用 watch([rat, ready], applyPageHeader) 在制式切换/就绪时重建 actions;onBeforeUnmount 调 resetPageHeader 清理;未就绪(无结果表)时不注入。
  • 清理:移除 ratOptions 及 .cap-topbar/.cap-title/.cap-spark/.cap-sub/.cap-controls/.cap-refresh 样式;.cap-seg* 保留(问题清单的筛选分段仍在用)。
  • 验证:frontend npm run build(vue-tsc+vite) 通过。

2026-06-26:看板页头去副标题 + 站型/频段排除未知 + 矮屏可滚动

  • 去掉页头副标题「高负荷小区分析 · 实时数据」:applyPageHeader 只传 actions,不传 subtitle。
  • 站型分布、频段标记小区也排除「未知」:overview 的 by_station、by_freq 调用加 skip_unknown=True(同制式分布,WHERE 列 IS NOT NULL AND <> '')。
  • 矮屏可滚动:.cap-dashboard overflow:hidden → overflow-y:auto(仍固定 height:calc(100vh-64px));.cap-list min-height:0 → min-height:300px。视口够高时 flex 填满不滚动;过矮时卡片+图表+清单(≥300px) 总高超出 → 整页出纵向滚动条,可滚到问题小区清单。移除原 @media(<=1180px) 里多余的 height:auto/overflow 覆盖(统一由主规则处理)。
  • 验证:后端 py_compile 通过;frontend vue-tsc --noEmit 通过。

2026-06-26:看板小区详情抽屉优化

  • 抽屉标题 CGI 与小区名称上下两行:.cap-detail-head 改 flex-direction:column。
  • 标签区去掉重复的「频段」tag(5G 制式值与频段常同为如 700M 显得重复),保留 制式/带宽/站型。
  • 指标卡片重排为:物理站 → 扇区 → 上行利用率 → 下行利用率 → 日均流量 → 用户数 → 小区功率 → 是否高负荷(detailMetrics 顺序调整)。
  • 优化建议右上角加复制按钮:copySuggestion() 复用 composables/clipboard.writeClipboardText 复制 detailSuggestion,成功/失败 message 提示;.cap-suggest-head 改 space-between 布局。
  • 同扇区同运营商小区每项加详情图标按钮(OpenOutline),点击 openDetail(sib.id) 在抽屉内切换到该小区详情;.cap-sib-item 改 flex 行(.cap-sib-body 占主 + 右侧 .cap-icon-btn)。新增通用 .cap-icon-btn 样式(复制/详情共用)。
  • 验证:frontend vue-tsc --noEmit 通过。

2026-06-26:CellData.sql 新增 cellinfo→sector 逆推(特征库 + 补缺不覆盖)

  • 背景:celldata.cellinfo(自动处理、有数据源)→ celldata.sector(原人工整理)。新脚本自动逆推 sector 的 扇区/物理站/制式/频段/带宽/站型/网络。原 区域 列经全项目检索无任何引用(其余「区域」均为 UI 文案),已 DROP COLUMN 删除,CellData.sql INSERT 同步去除。
  • 特征库 sector_band_ref(频点区间+PLMN→制式/频段,10 条):700M/广电同频 763.25 用 PLMN 区分(460-00/460-15);4.9G 用频点≥4000;4G FDD900/1800、TDD F/A/E/D 频按频点分档。3DMM 在 cellinfo 无任何字段标注(cellinfo.制式 仅 700M/TDD/FDD/2.6G,那 1400 个 sector-3DMM 在 cellinfo 全是 TDD/4G);按"3DMM 用 TDD 制式规则",脚本依频点判 TDD/D频 即正确,故制式实际正确率≈100%。
  • 逆推 staging _sector_infer:预处理小区名(全角括号→半角、【】→()、去空格/制表符)→ 剥设备码正则 [A-Z0-9]+-Z[A-Z0-9]{2}-[0-9]+$ 得 base;站型(码尾 W=室分 / 名称含"微小"=微站 / 否则宏站);制式频段经特征表 JOIN(未命中回落 cellinfo 制式);物理站(非700M 删全部成对括号+清悬空+回贴(微小X);700M 取「外层去CBN-的前2字地市前缀」匹配同前缀括号内容、否则取外层——通用不写死江门,3字地市取前2字仍可);扇区=物理站+扇区号(700M 末位/其余 %100)。
  • 落库:INSERT 仅补 sector 中缺失 CGI(不清空、不覆盖已有行,保人工修正如 3DMM/15M/纠正物理站),末尾 DROP staging;sector_band_ref 作为持久特征库保留。
  • 准确率(MCP 实测,重叠 66001):网络 100%、制式 97.88%(排除 3DMM 即 100%)、频段 97.6%、带宽 99.75%、站型 99.94%、物理站 99.59%、扇区 99.20%;残差为不可还原的人工差异(室分多载波编号、700M 个别人工编号、源数据制表符等)。详见 docs/sector_inference_research.md。
  • 关键坑:MySQL 字符串字面量会吞掉未知转义的反斜杠,正则字面量需写 \\((.sql 文件)/ JSON 调用需 \\\\(;ICU 正则字符类内的 [ ] 易误判,统一把名称中的 [] 转 () 后只处理圆括号。

2026-06-26:前置检查补全「库不存在自动创建」

  • 问题:原 db_init 只建表不建库,库(schema)不存在时连接 database=dbname 直接失败,库始终建不出来。
  • 修复:app/db_init.py 新增 _ensure_database(用不带 database 的连接执行 CREATE DATABASE IF NOT EXISTS \库` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci)与 _ensure_databases(遍历 DB_KEYS=(celldata, capacityreport),主库仅直连 MySQL 模式);ensure_required_tables` 开头先建库再建表。建库走独立库清单不依赖建表 SQL(主库无建表文件但仍需建库)。库名以配置为准、反引号去冲突;best-effort 不阻断。
  • 调用链不变:main 启动 lifespan + execute_celldata_script 前均会触发,故启动/手动上传/容量处理前库都会自愈。需 MySQL 账号有建库权限(root 默认有);Metrix 模式主库走平台不在此建。
  • 校验:py_compile 通过;MCP 验证 CREATE DATABASE IF NOT EXISTS 语法/权限有效(建临时库→确认→删除)。db_init/README.md 同步更正(原写"只建表不建库")。

2026-06-26:修复看板问题清单固定列重叠(透明背景透出下层列)

  • 现象:问题小区清单横向滚动时,右固定列「问题」与滚动区「日均流量」列视觉重叠。
  • 根因:naive DataTable override 把 tdColor 设为 transparent(为融入玻璃面板),导致固定列(CGI 左固定 / 问题 右固定)背景透明,滚动时透出下层普通列内容。
  • 修复:新增主题变量 --cap-table-fixed-bg/--cap-table-fixed-bg-hover(深色 #111c2e/#18283f,浅色 #fff/#eaf6fb),用 :deep 给 .n-data-table-th/td--fixed-left/right 设不透明背景(含 tr:hover)。非固定列仍保持透明融入面板。
  • 校验:vue-tsc 通过。

2026-06-26:配置导入补全 MetrixEnabled(导出导入字段全对齐)

  • 问题:config.py::to_file_dict(导出)含 12 字段,但 api/routers/config.py::_apply_config_data(导入)漏处理 MetrixEnabled → 导入后「启用 Metrix 平台」开关不恢复,且可能出现 SourceType=metrix 但 metrix_enabled=false 的不一致。
  • 修复:导入开头读取 MetrixEnabled;并在未启用 Metrix 时强制 source_type=external/warehouse_type=mysql(与 /api/config/metrix-enabled 开关行为一致)。前端导出/导入直接传整份 Configure.json 走 /api/config/download、/api/config/upload,不在前端拆字段,故后端补全即全覆盖。
  • 校验:导出字段集合 vs 导入处理集合比对,「导出但未导入(除时间戳 Update)」为空;py_compile 通过。

2026-06-26:Docker 一键编排补齐(应用 + MySQL + sftpgo)

  • packaging/docker-compose.yml:在原 capacity-app + capacity-mysql 基础上新增 sftpgo 服务(drakkan/sftpgo:v2.7.1,SFTP 2022、Web 18080:8080,卷 sftpgo-config/sftpgo-data,SFTPGO_LOADDATA_FROM 导入 SFTP 用户)。capacity-app 加 build 上下文与一组连接环境变量(DB_HOST/PORT/USER/PASSWD、MAIN_DB_NAME、CELLDATA_DB_NAME、SFTP_HOST/PORT/USER/PASSWD),depends_on mysql(healthy)+sftpgo。
  • packaging/sftpgo/sftpgo-init.json:自动建 SFTP 用户 capacity/capacity123(home /srv/sftpgo/data/capacity);Web 管理员 admin/gmcc123 由 env 创建。
  • packaging/mysql/init/01-init-db.sql:补建 celldata 库(原只建 CapacityReport);表仍由前置检查按需建。
  • 修复镜像缺文件:根 Dockerfile 原只拷 Configure.json/ReportScript.sql,漏了 CellData.sql 与 db_init/(容器内跑 CellData/前置检查会缺);现增拷 CellData.sql、db_init/、整个 docker/。docker/entrypoint.sh 增加播种 CellData.sql、db_init/ 到 /data,并在首次播种时调用新脚本 docker/apply_env_config.py 按 env 改写 Configure.json 的数据库/SFTP 连接(用户后续界面改动不被覆盖)。
  • packaging/README.md:一键编排使用说明(构建前端→compose build/up、默认账号、放数据路径、数据卷)。
  • 校验:docker compose config -q 通过;JSON/py_compile 通过。
  • 文档:packaging/README.md 重写为「一键构建整套系统」完整指南(方式A 联网 build+up、方式B 内网离线 load+up、默认账号、上传数据路径、数据卷、运维命令);主 README.md 增「Docker 编排」段落并链接 packaging/README.md。
  • 修复 scripts/build_docker.py 离线包缺口:make_bundle 原只拷 mysql/,现补拷 sftpgo/ 与 packaging/README.md(compose 引用 ./sftpgo/sftpgo-init.json,否则离线包启动缺文件)。
  • 离线镜像:F:\CR\env\images 已 docker save 三个基础镜像(mysql_8.0.44.tar/sftpgo_v2.7.1.tar/python_3.13.11-slim.tar)+ load_images.py(扫描同目录 *.tar 逐个 docker load -i ./xxx.tar,已实测导入成功)。注:F: 盘离线资产不在仓库内。

2026-06-26:测试数据抽取工具(本地 test/,已 gitignore)

  • .gitignore 新增忽略 test/ 与 temp/(生成的测试数据)。test/ 目录及其脚本不入库,仅本地用。
  • test/make_test_data.py:交互式从完整 CapacityReportData 源目录抽小样本,输出到 <仓库>/temp/CapacityReport(结构同源 4G/5G/RJ,每次生成前先清空)。启动询问「源目录」「每频段数量(默认500)」。
  • 抽取规则:按数据文件夹为单位,4G 主文件按 制式 列拆 TD-LTE(TDD)/LTE FDD(FDD) 各取数量;每频段 = test/dump.csv 清单中属于该频段的小区(优先全保留) + 指定数量其他小区;保留全部列与时序仅删行;RJ 日均流量整体原样复制。小区主键 4G=eNodeBId-cellId、5G/RJ=网元ID-cellId(注意 4G CSV 同时含网元ID,需以 eNodeBId 为准并保留制式拆分)。
  • test/dump.csv:首行 CGI 表头,其后每行一个 CGI/NCGI(自动去 PLMN 前缀匹配,无注释);用于固定保留高负荷等特定小区。抽取数量由运行时输入决定(默认 500)。
  • 实测:源 673MB→样本(500/频段) 约 34MB;优先小区与制式拆分均验证正确。

2026-06-26:容量处理无条件同步 CellData→容量库(覆盖手动上传场景)

  • 问题:原 _try_refresh_cell_data(tasks.py / remote.py)首行 if not cell_data.remote_data.enabled: return,把「远程拉取 + 执行 CellData.sql + copy_celldata_tables_to_capacity」整体锁在 FTP/SFTP 开关后。手动上传 CellData 入库(无 FTP)时,容量处理不会把 celldata 的 cellinfo/sector 复制到 capacityreport,导致 ReportScript 富集用的是旧/缺失数据(celldata 与容量为不同库时)。
  • 改法:解耦——FTP 远程拉取 refresh_cell_data 仍仅在 remote_data.enabled 时执行;execute_celldata_script + copy_celldata_tables_to_capacity 改为容量处理时无条件执行,独立 try/except,best-effort(celldata 无数据/连不上、或 celldata 与容量同库则内部跳过,不阻断容量处理)。tasks.py 与 remote.py 两处同改。
  • 效果:无论 FTP 自动拉取还是手动上传 CellData,容量处理都会先把最新 cellinfo/sector 同步到 capacityreport 再跑报表。

2026-06-26:数据库前置检查 / 缺表自动初始化(db_init)

  • 目的:运行前自动检查两库「必须存在的结构表」,缺表则按预设 SQL 自动建好,避免运行中因缺表报错。
  • 目录 db_init/(一个目录,文件名 <库标识>.<表名>.sql):<库标识> 决定连哪个库且库名以用户配置为准——celldata→cell_data.mysql(始终直连)、capacityreport→mysql(仅 warehouse_type=='mysql' 直连时检查,Metrix 模式跳过)。当前文件:celldata.cellinfo.sql、celldata.sector.sql、celldata.sector_band_ref.sql(含 10 条预设频段规则)。README.md 说明命名/时机/规则。
  • 必须存在表分析:celldata 的 sector 无任何流程会自动建(CellData.sql 直接 INSERT,缺表必报错),sector_band_ref 需持久+预设,cellinfo 兜底(正常由导入 CREATE TABLE IF NOT EXISTS 自建)。capacityreport 的 4G_UD/5G_UD、4G_结果表/5G_结果表、复制来的 sector/cellinfo 全由导入/ReportScript/跨库复制以 DROP+CREATE 动态生成(结构随源字段变),不前置强建以免冲突。
  • 实现 app/db_init.py::ensure_required_tables(app_config, logger=None):扫描 db_init/*.sql 按库分组;SHOW TABLES 取现有表,仅当目标表不存在时用 DataProcessor.parse_sql_script 拆分并执行该文件(故 sector_band_ref 预设只在首建时写入,绝不覆盖用户自定义);逐库/逐表 try/except,best-effort 不阻断。
  • 接入:app/main.py lifespan 启动时调用;execute_celldata_script 执行 CellData.sql 前调用(确保 sector/sector_band_ref 就位)。
  • CellData.sql 同步:移除原 DROP TABLE sector_band_ref; CREATE; INSERT 重建块,改为依赖前置检查持久维护(用户可在库中自行增改频段规则不被冲掉);其余逆推逻辑不变,小节重排为 1/2.x/3。
  • 前提:数据库本身需已存在(本机制只建表不建库)。本地无 pymysql(运行态在 Docker,requirements 已含),端到端以 py_compile + 三表 CREATE 语法(MCP)验证。

2026-06-26:离线可用性全面审计(运行期零外网)

结论:运行期已完全离线就绪,无需改运行时代码;外网仅「构建期」需要。审计证据:

运行期(无外网)已满足:

  • 前端 dist 完全自包含:所有 JS/CSS、图标(@vicons/ionicons5 按需 tree-shake 进 JS)、Monaco 图标字体 codicon-*.ttf 均为本地资源。rg --no-ignore 扫描整个 dist,出现的 http(s) 字符串全是无害标识符/文档链接:127.0.0.1/host.docker.internal(本地后端地址)、json-schema.org/w3.org(JSON Schema 方言 ID 与 XML/SVG 命名空间,仅作字符串永不下载)、github.com/vuejs.org/naiveui.com/microsoft.com(库源码注释与报错文档链接,用户点击才跳)。无 CDN、无在线字体(@font-face)、无外部 <script>/<link>、无 importmap。
  • Monaco:worker 经 Vite ?worker 本地打包(editor.worker/json.worker 均在 dist/assets),MonacoEnvironment.getWorker 返回本地 worker,不走 AMD loader / CDN。
  • 后端仅连「用户配置的内网端点」:FTP/SFTP(ftplib/paramiko)、Metrix API(requests,base_url 默认 host.docker.internal)、MySQL(pymysql)。无互联网请求、无授权联网校验(services/license.py 本地校验)、无运行期 pip install。
  • 容器 entrypoint.sh 仅 uvicorn 启动 + 播种默认配置,不联网。

外网仅构建期需要(在有网机器/内网镜像源完成,产物离线运输):

  • 前端 npm ci && npm run build(npm registry)。
  • 镜像 pip install -r requirements.txt(PyPI)+ 基础镜像 python:3.13.11-slim(Docker registry;Dockerfile 已注明内网无 dockerhub 时需本地预先存在该镜像)。
  • 离线重建可选做法:内网 PyPI/npm 镜像源,或预下载 wheels + pip install --no-index --find-links、npm ci --offline。

2026-08-05:部署第二套独立 CapacityReport 实例

  • 新增 packaging/docker-compose.capacityrepost.yml,只编排 Web 与 MySQL:容器名固定为 capacityrepost-web、capacityrepost-mysql。
  • Web 发布宿主机 19082 到容器 9081;MySQL 只 expose 3306,不发布宿主机端口,数据导入导出统一走 Web。
  • 两个容器仅加入显式桥接网络 capacityrepost-network;运行数据使用独立命名卷 capacityrepost-web-data、capacityrepost-mysql-data,不复用旧实例资源。
  • Web 首次启动通过 DB_HOST=capacityrepost-mysql 写入新数据卷内的 Configure.json;MySQL 初始化独立的 CapacityReport、celldata 数据库。
  • 当前待重启镜像使用不可变标签 capacityrepost-web:baaea9a,服务器部署目录为 /opt/capacityrepost。健康检查 GET /health 已验证应用与 MySQL 均正常,首页可访问。
  • 同机旧实例 capacity-report-app(19081)与 capacity-mysql(13306)是受保护资源;部署第二实例时禁止对旧容器执行停止、重建、改名、改网络、改卷或 compose down。

2026-08-06:修复日间流量暂存表大小写不一致

  • Linux MySQL 使用 lower_case_table_names=0,表名大小写敏感。数据映射实际创建 2_6GRJYD、700MRJYD、2_6GRJGD、700MRJGD,但 ReportScript.sql 第 126、127 条语句曾使用对应的小写名称,导致任务固定报 1146 表不存在。
  • 四处 SQL 引用已统一为与 Configure.json 数据映射及实际导入表一致的大小写;脚本解析仍为 157 条,线上 /data/ReportScript.sql 已同步更新且校验和一致。
  • 运行中的任务会保留启动时已经解析的旧 SQL;热更新脚本不重启 Web,下一次新任务才会读取修复后的内容。
  • 全脚本审计覆盖 32 个表标识:配置输入、脚本内建表和线上实际表之间无剩余大小写错配/冲突,且按 157 条语句执行顺序检查无“表尚未创建便引用”和未加反引号的表名。
  • 修复镜像 capacityrepost-web:c054b48 已部署并重启 Web;MySQL 和旧实例未重启。线上以同一数据库执行第 126、127 条核心查询通过,移动/广电临时校验结果分别为 23,227/23,107 行,临时表已删除。
  • 自动调度保持启用,正式任务 20260806_170846 已启动;因完整处理耗时较长,后续结果由用户自行观察。

2026-08-06:统一 CellData 与容量库排序规则

  • 第 136 条 SQL 的 1267 错误来自跨表 CGI 关联:容量结果表使用 utf8mb4_unicode_ci,CellData 复制来的 sector/cellinfo 保留源表 utf8mb4_0900_ai_ci;第 136-139 条四个 CGI/NCGI 关联均有同类风险。
  • copy_celldata_tables_to_capacity 在目标空表创建后、插入前读取目标数据库的 @@character_set_database/@@collation_database 并执行 ALTER TABLE ... CONVERT,复制表不再继承不兼容的源排序规则;字符集和排序规则名称限定为字母数字下划线。
  • CellDataProcessor、DatabaseManager 和三份 db_init 建表 SQL 均显式使用 utf8mb4_unicode_ci,避免 MySQL 8 在只写 DEFAULT CHARSET=utf8mb4 时回落到 utf8mb4_0900_ai_ci。
  • 线上 celldata 与 CapacityReport 两库的 sector/cellinfo 已迁移为 utf8mb4_unicode_ci;4G/5G 结果表分别关联 sector/cellinfo 的四组真实查询均通过。自动重试任务 20260806_180436 保持运行,未重启容器。
  • 永久修复镜像标记为 capacityrepost-web:baaea9a;任务运行期间只更新服务器 Compose 并加载镜像,不重建 Web,待后续任务结束后重启生效。