# 2026-10-31 迁移到 macOS + 验收修复 ## 背景 从 Windows(Workbuddy 环境,`D:\WorkbuddySpace\门店检测工具\`)迁到 macOS。 迁移包 `门店检测工作台_迁移包_20261030.zip` 解压到本机后接续开发。 ## 环境 - macOS,系统自带 Python 3.9.6(`/usr/bin/python3`),零第三方依赖,符合原设计 - 项目路径:`门店检测工作台/store-ops/` - 服务默认 `127.0.0.1:8787` ## 安装验收结果(全部 PASS) - `data/app.db` 完好:1409 家门店、1 个导入批次、2026-10 周期 - KPI 与迁移说明自检值一致:**1409 / 469 / 323 / 929 / 276** - 用户自定义阈值保留:`hx_amt_base = 10000`(默认 12000),面板标「自定义」 - 用户自定义文案保留:43 个模板字段,其中 3 个为自定义,概览行变量别名正常渲染(无残留花括号) - 详情抽屉:7 条指标条 / 17 个基准刻度 / 5 个问题项 / 预览按钮 - 预览弹窗:按模板生成 698 字反馈文案,`badvars=0` - 文案配置面板:8 组、43 字段、43 个「+ 变量」按钮,实时预览正常 - 指标配置面板:8 组、16 个输入框 - 导入面板:导入历史正常 - 导出 CSV:零核销筛选 276 家 + 表头,BOM 与中文列名正常 - 收件箱 watcher(隔离副本验证):丢入 CSV → 20 秒内入库并归档到 `processed/` ## 新增:macOS 启动器 - `store-ops/启动工作台.command`(可执行) - 自动探测 Python 3.7+,版本不够给安装指引 - 参数:`[端口] --local --no-open` - 启动前检查端口占用,占用时提示已有实例 - 默认 `--open` 自动开浏览器 - README「启动」与「目录结构」、迁移说明第二节补 macOS 用法 - 注意:`开放局域网访问.bat` 是 Windows 专用;macOS 首次运行在系统弹窗里点「允许」即可 ## 修复:文件名日期解析把「年月」误读成「年月日」(严重,会写错月份) - 现象:导入 `门店数据_2026-10.xlsx`(无日期列、整月汇总)→ 周期被写成 **2026-01**, 且被当成 **日粒度**、日期 `2026-01-00`(非法日期) - 根因:旧正则 `(20\d{2})[-_.]?(\d{1,2})[-_.]?(\d{1,2})` 三段全可选分隔符, `2026-10.xlsx` 被回溯匹配成 `2026` + `1` + `0` - 修复 `ingest.guess_period_date` 重写,按「完整日期 → 年月 → 仅月份」优先级,且逐级校验合法性: - 日粒度只认分隔符齐全且年月日合法的写法:`2026-10-30` / `2026/10/30` / `2026.10.30` / `2026年10月30日` / `20261030` / `10.28` - 年月:`2026-10` / `2026.10` / `2026年10月` / `202610` / `10月` - 月/日非法(如 13 月、0 日)自动退回上一级,不再产生 `2026-01-00` - 回归测试 16 个文件名用例全 PASS - 连带修复:导入回包的 `granularity` / `period` 改为**按实际入库行**统计 - 原来 `granularity` 只看传入的 `date` 参数,带「日期」列的 CSV 会误报成 `period` - 跨月文件现在回包 `periods` 明细,`period` 取行数最多的月份(前端按它刷新视图) ## 验证(隔离副本 `/tmp/storeops_test`,不动真实数据) - 月汇总 CSV / 月汇总 XLSX / 日数据 CSV(含重复行)/ 跨月 CSV / 重复导入幂等 —— 全部符合预期 - 真实库 KPI 重启后无回归:469/323/929/276 - 测试文件与进程已清理 ## 环境备注(与 Windows 时代的差异) - 原记录「Chrome headless 会卡死」「Edge headless 截图」都是 Windows 结论;本机用 ego 浏览器(Chromium)验证,正常 - `启动工作台.bat` / `开放局域网访问.bat` 仅 Windows 可用,保留不删(团队里可能还有 Windows 机器) ## 新增:单店分析报告(可打印 A4 / 可下载单文件 HTML) - 需求:用户选择优先做「单店分析报告导出」,使用场景桌面优先、手机随后 - 入口:详情抽屉底部按钮行(`预览分析结果` 金色主按钮 + `导出报告` 白色次按钮),Esc 先关报告再关抽屉 - 报告五段:01 关键指标(复用 metricsOf/barColor 的指标条,带基准/目标/三级违规线刻度)→ 02 风险与限流因素(问题 + 建议动作表)→ 03 经营数据(8 张数据卡)→ 04 分析洞察 → 05 门店调整动作 - 顶部操作:【打印 / 另存为 PDF】(`window.print()`,走系统打印)与【下载 HTML】(自包含单文件,样式内联) - 新文件 `frontend/report.css`:报告专属样式,**自带全部依赖**(不依赖 style.css), 这样下载出去的单文件 HTML 与工作台内看到的长相完全一致 - 打印:`@page A4` + `body.rp-on` 作用域下隐藏工作台外壳,普通页面按 Cmd+P 不受影响; `-webkit-print-color-adjust:exact` 保证金色/语义色打出来 - 手机:`max-width:640px` 下指标单列、数据卡两列,375px 实测无横向溢出 ### 关键设计决定 - **报告不新增后端接口**:检测规则在后端(rules.py),文案渲染在前端(fbVars/fmtTpl), 报告属于「渲染层」,所以放在前端生成,避免把变量替换逻辑再抄一份到后端 - 为让报告与反馈文案共用同一套洞察条件,把 `renderFeedback` 里的洞察段抽成 `insightTexts(s, X, flags)` - 回归验证:抽函数前后对全部 1409 家门店的 `feedbackText()` 做稳定哈希比对, 汇总哈希 `e86ee9` 完全一致、逐店差异 0 —— 重构对外零变化 ### 踩坑 - `.rphead` 是 `
`,被 style.css 的全局 `header{display:flex;justify-content:space-between}` 命中,标题被挤到右侧;显式 `display:block` 并关掉 `header::after` 的装饰线 - 全局 `th{background:#fdf9ee}` 等表格样式会串到报告表头;report.css 里把表头样式写全, 否则「工作台内预览」和「下载的 HTML」会长得不一样 - A4 分页:`h2` 加 `page-break-after:avoid` + `h2 + *{break-before:avoid}`,避免章节标题孤零零留在页尾 - 空态文案曾重复成「本期无明显异常,本期无风险项。」—— 直接渲染 `fb_no_issue` 模板,不再拼后缀 ## 待办(沿原 README「后续可做」) - 自动下载:接抖音来客/服务商 API 定时拉数,替代手动导出 - 处理闭环:异常门店的整改动作记录与回填 - 权限分层:区域经理/督导只看自己片区 - 报告批量导出:按城市/督导一次导出多店 PDF