145 KiB
项目上下文记录
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_binaryonedir/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/+ 启动脚本(winrun.bat/unixstart.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间接依赖的 vulnerabledompurify@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 主要是已懒加载的 MonacoScriptPanel和 SwaggerApiDocs。 - 注意:
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.jsonJSON 解析、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,仅启用systemfeature;已验证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:9081sidecar,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中误残留的本机构建临时 NSIStemplate绝对路径;该路径不应进入源码或发布配置。 - 已验证
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命令:先弹出系统保存对话框,再使用 Rustreqwest按前端传入的 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移除 Tauridevtoolsfeature,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启用 Tauridevtoolsfeature,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,但数值清洗改为返回真正的 PythonNone/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 UIn-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 UIdarkTheme,修复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和旧 keytoken:请求优先读取新版 key,登录页会同时写入两个 key,并继续写入tokencookie。 - 旧版 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-editorSQL 编辑器,保留脚本读取、保存、执行和状态轮询接口;支持 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 行尾,避免 Windowscmd在 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, andscripts/build.sh. Targets areserver,desktop,docker, andall; 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 remains9081. - Desktop packaging uses Tauri 2 + Vue + Python sidecar. The build sets
VITE_API_BASE=http://127.0.0.1:19082, builds a PyInstaller one-filecapareport-serversidecar, and the desktop app starts it on127.0.0.1:19082. app/config.pysupportsCAPAREPORT_BASE_DIR; frozen PyInstaller server builds defaultBASE_DIRto the executable directory. The Tauri sidecar setsCAPAREPORT_BASE_DIRto the app data directory so runtime files are not written into the install directory.- Tauri startup creates app-data
cache/andlogs/, then copies bundledConfigure.jsonandReportScript.sqlon first run. Resource lookup supports both normal Tauri resources and the_up_directory generated for bundled../resources. - Windows desktop shutdown uses
taskkill /F /T /PIDbefore killing the shell child, which avoids PyInstaller one-file sidecar process leftovers. - Docker build now copies only required app files and frontend build output.
.dockerignoreexcludes local dependencies, caches, and generated output; deployment compose files are emitted underdist/docker/. app/main.pyaccepts--hostand--portand exposesrun_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, andscripts\build.bat desktop. Server portable/health, Docker container/health, and desktop sidecar/healthall 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 forscripts/build.ps1, Docker-hostedsh -n scripts/build.sh, andcargo check --manifest-path src-tauri\Cargo.tomlwith 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 becausesrc-tauri/capabilities/default.jsonreferences../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.mdhas 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 withscripts/build.*.
2026-05-20: Tauri desktop console and installer language
src-tauri/src/main.rsuses#![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.speckeeps Server Portable in console mode, but desktop one-file sidecar builds (CAPAREPORT_ONEFILE=1) use PyInstallerconsole=False; PyInstaller should selectrunw.exefor the sidecar so it also stays hidden behind the Tauri window.src-tauri/tauri.conf.jsonsets Windows installer localization throughbundle.windows.wix.language = "zh-CN"andbundle.windows.nsis.languages = ["SimpChinese"]. NSIS language keys must use NSIS names such asSimpChinese, while WiX/MSI uses locale names such aszh-CN.- Verification on Windows:
cargo check --manifest-path src-tauri\Cargo.tomlpassed,scripts\build.bat desktopgenerated the MSI and NSIS bundles, PE subsystem checks reportedWindows GUIfor bothcapacity-report-desktop.exeandcapareport-server.exe, and the generated NSIS script includedMUI_LANGUAGE "SimpChinese".
2026-05-20: Unified release output under dist
- The former
build/packaging source directory was renamed topackaging/to avoid confusing source-side packaging recipes with generated output.packaging/now holdsDockerfile,docker-compose.yml, the PyInstaller spec, and MySQL container config. scripts/build.ps1andscripts/build.shnow usedist/.tmp/for PyInstaller work output and copy final deliverables todist/server/,dist/desktop/, anddist/docker/. Successful builds removedist/.tmp,frontend/dist,src-tauri/target, andsrc-tauri/binaries.- Docker builds now include
Configure.jsonin the image and also create a deployabledist/docker/bundle containingcapacity-report-app-latest.tar,docker-compose.yml,Configure.json,ReportScript.sql,mysql/,cache/, andlogs/. - Server Portable still includes
Configure.jsonandReportScript.sqlinsidedist/server/CapacityReport-Server-<platform>-x64/. Tauri desktop still bundles both files throughsrc-tauri/tauri.conf.jsonresources 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.jsonin 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.pynow supports exporting/importing token records for configuration migration and batch deletion by token ID. Config download adds anApiTokensblock, 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.vuenow 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_tokensservice create/list/verify/enable/disable/export/import/batch-delete test passed, HTTP endpoints for create/list/update/config download/batch-delete passed on local port9081,.venv\Scripts\python.exe -m compileall apppassed, andnpm run buildpassed with only the existing Vite large chunk warning.
2026-05-25: API Token row visibility controls
frontend/src/components/ApiTokenManager.vuerenders 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 buildpassed 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_atin the metadata area.
2026-06-01: API documentation toolbar cleanup
frontend/src/components/ApiDocs.vueno longer registers a page-headercopy sampleaction, avoiding duplicate复制传参示例buttons on the API documentation page.- The API documentation card still keeps its local toolbar actions:
复制传参示例andOpenAPI JSON. - Verification performed:
npm run buildpassed, and generated frontend build output was removed after verification.
2026-06-01: Frontend entry chunk reduction
frontend/src/router.tsnow lazy-loadsFileWorkflow.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.vuenow lazy-loadsLoginView.vueand the hidden license activation dialog; the dialog UI and activation API flow moved tofrontend/src/components/LicenseActivationModal.vue.- Build verification:
npm run buildpassed. The baseindexchunk dropped from about572 kBto about461 kB; the remaining large chunks are stillApiDocs(swagger-ui-dist) andScriptPanel(monaco-editor).
2026-06-01: History detail file browser
app/api/routers/history.pyadds/api/history/filesfor browsing a history work directory by safe relative path, and/api/history/file/downloadfor downloading one file directly or one directory as a temporary ZIP. Both paths are constrained under the record'scache/work directory; download still rejects pending/processing records.frontend/src/components/HistoryPanel.vuekeeps 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.tsdefinesHistoryFileEntryandHistoryFilesResponse;app/main.pyadds 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 for20260519_172434, path traversal rejection, and single-file download oflog.txton 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.pynow keeps RJ directory status keys clean instead of prefixing them withrj:in the combined scheduler response.frontend/src/components/SettingsPanel.vuestrips any legacyrj:prefix before rendering the scheduler directory name, so the UI showsRJ/2.6G/...instead ofrj: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.vuesplits 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.cssnow 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 buildpassed. Browser inspection onhttp://127.0.0.1:9081/settingsconfirmed the two new tabs render correctly, the remote panel shows its own configuration and scheduler cards, and horizontal overflow remained at0.
2026-06-01: Settings remote scheduler refinement
frontend/src/components/SettingsPanel.vuekeeps远程数据源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.batstarts the Python backend on127.0.0.1:9081and the Vite frontend on127.0.0.1:5173for source-level debugging without requiringfrontend/dist.- Verification performed:
cmd /c debug.batstarted the debug backend/frontend,cd frontend && npm run buildpassed, and browser inspection confirmed the remote connection fields align in one row with no horizontal overflow. Debug processes andfrontend/dist/were removed after verification.
2026-06-01: Task runtime cleanup
app/api/routers/task_runtime.pycentralizes shared task-stage updates, processing license log output, and safe history-retention cleanup for manual processing and remote processing routes.app/api/routers/tasks.pyandapp/api/routers/remote.pynow reuse the shared helpers instead of carrying duplicate_set_task_stageand_log_license_checkimplementations.- Verification performed:
.venv\Scripts\python.exe -m compileall app,npm run build, andcargo check --manifest-path src-tauri\Cargo.tomlwith 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.pynow providesremove_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, andcargo check --manifest-path src-tauri\Cargo.tomlwith 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.tscentralizes 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, andcargo check --manifest-path src-tauri\Cargo.tomlwith 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
Pathimport fromapp/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, andnpm 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.pynow reuses the sharedset_task_stage()helper for manual SQL script task status updates.- Script execution status entries now include the same
stagefield 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, andcargo check --manifest-path src-tauri\Cargo.tomlwith 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.mdrecords 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.gitignoreso 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 asrequirements.txt, frontend packages such asfrontend/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通过;frontendnpm 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和独立 PyMySQLSELECT 1。 - 前端:系统设置「数据库」页新增「CellData 数据库配置」卡片;「远程数据源」页新增「CellData 数据源」卡片;「数据源 / 仓库」页说明 CellData 为独立辅助数据源,不影响主数据源/仓库选择。
- 验证:
python -m compileall -q app通过;frontendnpm run build通过(仅既有大 chunk 提示);构建产物与 Python 缓存已清理。
2026-06-24:精简系统设置与历史页文案
- 设置页说明文案去掉开发实现细节,只保留用户填写配置所需的短提示:主数据源/仓库、Metrix 连接、CellData 数据库/远程源、远程数据源、自动调度、目录映射、Sheet 过滤和字段映射等位置均已压缩。
- 历史删除确认中的“缓存文件”改为“相关文件”,避免把内部存储实现暴露给用户。
- 验证:
frontendnpm 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通过;frontendnpm run build通过(仅既有大 chunk 提示);构建产物与 Python 缓存已清理。
2026-06-25:数据管理数据库选择改为弹窗列表
- 数据管理页不再用下拉框切换数据库,改为表标题旁的图标按钮打开「选择数据库」弹窗;弹窗内为固定高度列表,超出高度滚动。
- 左侧标题只显示分类名(主数据库 / CellData),不显示具体库名,也不再显示“表”字;弹窗列表显示真实库名(如
主数据库:CapacityReport)。选择项后续新增更多数据库时继续扩展同一列表,不占用侧栏宽度。 - 验证:
frontendnpm 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通过;frontendnpm run build通过;远程定位可从最新年份2026年/300表选出2.6G与700M各自最新Result_300ZIP;用 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 配置拉取处理。
- 验证:
frontendnpm run build通过;构建产物已清理。
2026-06-25:数据处理卡片补说明按钮并规范 CellData 上传
- 数据处理页的容量数据卡片与 CellData 卡片左上角均显示数据类型,右上角均提供说明图标按钮,点击后以小弹窗展示所需文件格式和目录结构。
- CellData 卡片改为点击/拖拽文件夹上传,不再提供单文件选择;直接拖入单个 ZIP 会提示选择包含
Result_300ZIP 的文件夹。 - 验证:
frontendnpm run build通过;构建产物已清理。
2026-06-25:数据处理卡片并排展示
- 数据处理页容量数据与 CellData 两个卡片在宽屏下左右并排展示,窄屏下自动回落单列,减少对日志区域的挤压。
- 容量数据说明补充:启用 CellData 数据源时,处理容量数据前会先刷新 CellData;CellData 卡片按钮文案统一为「远程下载并处理」。
- 验证:
frontendnpm run build通过;构建产物已清理。
2026-06-25:数据处理卡片说明与上传方式调整
- 容量数据和 CellData 卡片左上角均标注数据类型,右上角均有说明按钮;容量数据说明弹窗明确启用 CellData 时会在处理容量数据前先更新 CellData。
- CellData 卡片点击后选择文件夹,拖拽也只接受文件夹;不支持单个 ZIP 文件直接拖入,避免缺少频段目录导致无法映射。
- 验证:
frontendnpm run build通过;构建产物已清理。
2026-06-25:远程数据源页收纳 CellData 规则设置
- 远程数据源页只保留容量数据源与 CellData 数据源两张连接配置卡片,宽屏下并排展示;CellData 的扫描路径、正则和映射 JSON 收纳到「规则设置」弹窗。
- CellData 规则弹窗包含扫描路径列表、路径说明入口、高级正则和 Monaco JSON 编辑器,支持格式化、校验、恢复默认映射和保存规则。
- 验证:
frontendnpm run build通过;构建产物已清理。
2026-06-25:精简 CellData 数据源路径配置
- CellData 数据源卡片去掉“远程目录”输入,连接根目录固定走
/;实际数据位置统一由「规则设置」中的扫描路径模板决定,避免两个路径概念混淆。 - 扫描路径占位符扩展支持
{maxmonth}、{maxday},并新增month_dir_regex、day_dir_regex高级正则配置;说明弹窗同步补充相关说明。 - 验证:
python -m compileall -q app通过;frontendnpm run build通过;构建产物与 Python 缓存已清理。
2026-06-25:CellData 扫描路径回到数据源卡片
- 扫描路径属于文件来源配置,已移回 CellData 数据源卡片中展示和维护;「规则设置」弹窗只保留高级正则与映射 JSON,避免弹窗承担过多基础配置。
- CellData 数据源不再展示“远程目录”,连接根目录固定为
/;实际文件位置完全由扫描路径控制。 - 扫描路径占位符支持
{maxyear}、{maxmonth}、{maxday}、{yyyy}、{yyyymm}、{yyyymmdd},并提供对应年份/月/日目录正则配置。 - 验证:
python -m compileall -q app通过;frontendnpm run build通过;构建产物与 Python 缓存已清理。
2026-06-25:优化 CellData 扫描路径排版
- CellData 数据源卡片中的扫描路径区域改为全宽列表布局,说明文字、说明按钮、路径输入、删除按钮和添加输入保持对齐,减少左侧拥挤。
- 验证:
frontendnpm run build通过;构建产物已清理。
2026-06-25:CellData 映射支持图形化编辑
- CellData「规则设置」弹窗中的映射规则增加“图形化 / JSON”切换。图形化模式可维护目标表、主键字段、主键表达式、来源目录、CSV 前缀和字段映射;字段映射支持“CSV 字段”和“固定值”两种模式。
- JSON 模式仍使用 Monaco 编辑器,支持格式化、校验、恢复默认;两种模式共用同一份
CellData.mappingJSON,切换时自动互转。 - 验证:
frontendnpm 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「规则设置」弹窗不再整体滚动;高级匹配、目标表、主键字段和主键表达式固定显示,图形化模式下仅来源列表滚动。
- “添加来源”按钮固定在来源列表下方,始终可见;弹窗底部保存按钮也保持可见。
- 验证:
frontendnpm run build通过;构建产物已清理。
2026-06-25:图形化来源支持折叠
- CellData 图形化映射中每个来源卡片支持展开/收起,来源头展示目录与 CSV 前缀摘要;“添加来源”按钮移动到映射规则标题区右侧。
- 验证:
frontendnpm run build通过;构建产物已清理。
2026-06-25:调整图形化映射添加来源位置
- “添加来源”按钮移动到主键表达式输入区下方右侧;点击后来源列表自动滚动到新增来源。
- 验证:
frontendnpm 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通过;frontendnpx vue-tsc --noEmit --noUnusedLocals --noUnusedParameters通过。
2026-06-25:收敛上传文件相对路径
- 新增
app.utils.files.safe_relative_path(),容量数据上传和 CellData 本地上传保存文件前统一过滤空片段、.与..,避免客户端文件名或webkitRelativePath中的路径穿越片段写出任务工作目录,同时保留合法的文件夹层级。 - 验证:
safe_relative_path典型路径断言通过;python -m compileall -q app通过;frontendnpm 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通过;frontendnpm run build通过;构建产物已清理。
2026-06-25:CellData 容量处理集成改进与前端处理进度优化
- 容量处理集成:
tasks.py和remote.py中的refresh_cell_data()调用改为_try_refresh_cell_data()包装函数,CellData 数据源未启用时直接跳过,CellData 处理失败时记录警告但继续执行容量处理,不再因 CellData SFTP 连接失败或无数据等原因导致整个容量处理任务失败。 - CellData 阶段标识:容量处理流程中 CellData 更新阶段会设置独立的
cell_datastage,前端可显示"更新 CellData..."状态文案;CellData 完成后日志输出导入行数、解析行数和跳过行数摘要。 - 前端阶段标签:
stageLabels新增cell_data: '更新 CellData...';importing标签从"上传数据中..."改为"导入数据中..."以避免与文件上传混淆。 - 前端结果摘要:CellData 独立处理或容量处理完成后,处理进度区域显示成功摘要(文件数、导入行数、跳过行数、耗时);
TaskStatus类型新增result?: CellDataResult字段。 - 验证:
python -m compileall -q app通过;frontendnpm 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通过;frontendnpm 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通过;frontendnpm 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→SQLNULL);删除二次确认;操作后自动刷新当前页。 - 行定位策略:以「整行原值」作为 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 走平台/importmode=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通过;frontendnpm 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,懒加载);侧边菜单「容量看板」置于「数据处理」下方(AppShellmenuKeys/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态,清单为空时禁用)。 - 验证:
frontendvue-tsc --noEmit通过;后端py_compile dashboard.py通过。
2026-06-26:容量看板布局重构(定高不滚动)+ KPI/图表调整
- 修复整页布局塌陷:上一版
.cap-dashboard { height:100% }在 Naiven-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-bodyflex 列三段=顶栏(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)适配矮窗口。 - 验证:
frontendnpm 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:新增
chartPalettecomputed(轴文字/轴线/分割线/tooltip 底色与文字/图例/饼描边/柱底色 两套值),所有 option 通过axisLine/axisLabel/splitLine/tooltipBase/legendStyle辅助函数读取,主题切换时 computed 重算、EChart.vue深度 watchsetOption(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 等)以保证浅色下对比度。 - 验证:
frontendnpm 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+缩写。 - 验证:
frontendvue-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)+「刷新」(iconRefreshOutline,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*保留(问题清单的筛选分段仍在用)。 - 验证:
frontendnpm 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-dashboardoverflow:hidden→overflow-y:auto(仍固定height:calc(100vh-64px));.cap-listmin-height:0→min-height:300px。视口够高时 flex 填满不滚动;过矮时卡片+图表+清单(≥300px) 总高超出 → 整页出纵向滚动条,可滚到问题小区清单。移除原@media(<=1180px)里多余的height:auto/overflow覆盖(统一由主规则处理)。 - 验证:后端
py_compile通过;frontendvue-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样式(复制/详情共用)。 - 验证:
frontendvue-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.pylifespan 启动时调用;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,待后续任务结束后重启生效。