开发日志_2026-10-29.md 22 KB

2026-10-29 门店检测工作台项目启动

项目背景

用户是抖音美容门店本地生活运营,品牌下 1000+ 门店,要做「门店数据检测工作台」。当前在预研对齐阶段,未开始正式开发。

已对齐的关键决策

  • 同城对标范围:每店 3-5 家核心竞对(督导指定,去重后约 3000-4000 家)
  • 数据获取路线:先用半自动跑 10 家门店试点,验证字段有效性后再决定是否全量
  • 双轨对比框架:轨道A = 品牌 1000+ 店内部横比(全指标,数据用户提供);轨道B = 同城外部门店对比(仅前台公开可观测指标,需线上采集)
  • 采不到的数据(明确告知):曝光/UV/转化率/核销率/退款率是商家私有数据
  • 可行方法:已售增量法(每天记录「已售」取差值)、评价增量法(相对比较有效,绝对单量不可信)
  • 采集量控制:全量对标店周采做基线,异常门店(约100家/天)日采

已产出(D:/WorkbuddySpace/门店检测工具/对标试点/)

  • 01_对标店清单_模板.csv:50 行(10 店 × 5 竞对),待用户填门店链接
  • 02_采集脚本/collect_douyin.py:调本机 Chrome 无头 --dump-dom,无需 Playwright;--dump 抓页面 / --parse 生成快照;parse 规则是草稿,需真实页面校准
  • 03_分析/build_report.py:纯标准库,--demo 可跑;输出 04输出/对标检测报告*.html
  • 报告指标:份额指数(份额×(竞对数+1))、价格指数(本店价中位/同城价中位)、评分差、竞争力指数(份额50%+口碑30%+价格20%)
  • 检测规则:定价偏高 / 性价比未被感知 / 品项不足 / 口碑落后 / 优势店 / 持平

环境备注

  • Python 3.13(无 pandas/openpyxl/playwright),Node 22
  • 本机有 Chrome 和 Edge,无头截图/渲染可用(已验证)

待办 / 下一步

  • 用户填 01 清单:10 家本店 + 各 3-5 家竞对的抖音链接
  • 拿到链接后先跑 1-2 个 --dump 校准 parse_page 的选择器
  • 风险提示已给:门店换绑 POI/改名导致 ID 断链,需内部门店编码兜底

下午:飞书数据源打通 + 首版真实检测报告(重大进展)

飞书连接器(lark-cli)

  • 连接器名「飞书」,CLI 位于 ~/.workbuddy/binaries/node/cli-connector-packages/lark-cli
  • 应用 cli_aa68507f493adcf5,已批权限:wiki 三个 + sheets:spreadsheet:read;知识库空间 7699703484173552912(怡呵美抖音云验舱)已把应用加为成员
  • 授权流程:lark-cli config init --new 后台跑 → 出验证链接 → 用户浏览器完成;scope-apply 链接给用户批权限
  • 读表命令:lark-cli sheets +cells-get --spreadsheet-token --sheet-id --range A1:Z1425 --output-path xx.json(JSON 顶层直接是 ranges,无 ok/data 包装);--jq 取值

    三张表(space 7699703484173552912)

    1. 门店评估后反馈格式(docx, SJGbdfyBdoDB2ux07gac5BuRnHb):门店评估报告成品模板——经营概览/风险限流因素/待核销/流失分析/流失去向竞对清单/洞察/调整动作(评价·AIGC素材·点亮门店·冲榜单·7天交易上翻核销≥12000)
    2. 门店考核指标(sheet, BXKjsuG9bhnFlbtOXZEcq1rDnTe):官方基准线——评分基准4.3目标4.5、经营分100/120、牌级铜/金、核销率40%/60%、核销金额12000、商责退单率1.27/3.18/6.35%、投诉率0.11/0.28/0.56%、差评率0.66/1.66/3.31%
    3. 10.1-10.28门店数据(sheet, T5WTsibjchPW9VtQ5XbcaEJnncb):26列×1424行,含门店ID(抖音ID)唯一键、访问/成交/核销/评价/风险率/点亮/收藏/上榜

    数据体检结论

    • 1424 行去重后 1409 家门店(15 行重复),覆盖 242 城(长沙65/郑州48/武汉40)
    • 13 个重复ID,其中 4 组【同ID不同名】需用户核实(如 7664429404466759732 希尔顿店/家润多广场店共用)
    • 月核销金额中位仅 161.9 元:0核销 283 家、≥12000 仅 107 家(长尾极重)
    • 评分有 0 分(疑似未开分),0 分店会被判"低于4.3",口径待确认
    • 反馈文档样例店核销率 37.78% vs 表算 16/45=35.6%,核销率官方口径待确认(暂用 核销券数÷意向成交券数)
    • 经营分/牌级两列不在月度数据表里,考核表有基准但无法检测——缺口

    已产出

    • 03_分析/detect.py:月度检测引擎,阈值集中在 THRESH(与考核表一致),差评率带小样本保护(新增≥10或累计≥20才判)
    • 04_输出/门店检测报告_2026-10.html + 门店检测清单_2026-10.csv(全量1409家,按严重度排序,含建议动作)
    • 10月结果:超违规预警线450家(退单率预警66/严重61/非常严重38,差评率327),评分<4.3 323家(含0分店),核销率<40% 929家,零核销276家
    • 踩坑记录:飞书比率字段解析后是小数,阈值必须同单位(曾因单位不匹配+差评率小样本误报出"100%超线")

    用户偏好确认

    • 用户对齐推进顺畅,愿意配合授权操作;沟通中"开通好啦/加好了"节奏快,适合给明确的单步指令

    可视化工作台(用户明确要求"以可视化的工作台形式展示")

    • 03_分析/build_dashboard.py:读 门店数据_10月.csv → 复用 detect 检测 → 生成 04_输出/门店工作台_202610.html(单文件 706KB,内嵌全量 1409 家数据)
    • 功能:5 张可点击 KPI 卡(点击即筛选)、3 张 ECharts 图(问题命中分布/核销金额分布/城市TOP15)、搜索+城市+问题类型+排序筛选、分页表格、点击行开详情抽屉(指标条带基准线/目标线刻度+问题+建议动作+一键复制"反馈格式"文案)
    • 链接直达:URL 加 #门店ID 直接打开该店详情抽屉(可发给督导)
    • ECharts 走 jsdelivr CDN,离线时表格和 KPI 仍可用(有 window.echarts 守卫)
    • 无头截图注意:CSS transition 会导致抽屉截图时机问题,用 --dump-dom 验证 class="drawer on" 更可靠

    品牌配色(用户提供怡呵美 logo:金色系)

    • 工作台主题改为深棕暖底(#14100a)+金色主色(#e8a020/#f0b23e)+暖白文字(#f5efe2)
    • 语义色保留:红系=超线(R1-R3),淡金(#e6cf6e)=低于基准(B),灰=提升项(T),暖绿(#58c08c)=达标
    • 头部加了品牌徽章「怡呵美·水光会员店」,复制按钮改为金色实底 CTA

    第三版配色:明亮奶油风(用户提供参考截图,明确要求)

    • 用户偏好明亮配色(参考某轻风格应用:奶油底+白色圆角卡片+柔和粉彩),弃用深棕金主题
    • 当前主题:底 #f6f4ef / 卡片白 #fff 圆角16px 轻投影 / 主蓝 #5b87e8 / 文字 #33333d
    • 语义色:红 #e05a48(红线) / 橙 #f2a65a / 黄 #f0b45c / 蓝 #7fa5ec(低于基准) / 绿 #6fc49a(达标);标签用同色淡底
    • 用户问"为什么只出 html"——已解释:原型期口径未定,单文件最快;定稿后可部署上线带权限

    v3:右侧菜单栏「考核指标」面板(可自定义阈值)

    • build_dashboard.py 重写 v3:右侧悬浮菜单栏(考核指标 + 导出清单),面板内 8 组阈值全部可编辑
    • 检测逻辑搬到前端 JS(与 detect.py 同规则同步实现),改阈值后 KPI/图表/表格/详情/反馈文案全部重算
    • 数据 JSON 只存原始字段(去掉 flags),文件从 707KB 降到 365KB;detect.py 补输出「核销券数」用于零核销判定
    • 自定义阈值存 localStorage(key=yhmthresh<月份>),恢复默认一键还原;rail 有红点标记"已自定义"
    • 校验方式:改默认阈值生成副本 → 无头 dump-dom 抓 KPI → 与 Python detect 同阈值结果对比(650/1068 全 PASS)
    • 面板交互:hi 遮罩层(z11)+点遮罩/×/Esc 关闭;#TH hash 直达面板;apply 前做递增/目标>基准校验
    • 新增导出清单:当前筛选结果 → CSV(带BOM),文件名标注是否自定义阈值

    环境:ego lite(用户要求用 ego 浏览器打开渲染页)

    • 已安装:C:\Program Files\Citro Labs\ego lite\Application\ego.exe(v0.6.1.13),已在运行
    • 但 ego-browser CLI 未注册到 PATH(%LOCALAPPDATA%、~/.local/bin、npm global 均无),ego-browser skill 无法调用
    • 打开页面方式:Start-Process ego.exe "file:///D:/.../门店工作台_202610.html" → 成功,窗口标题=页面标题
    • 无 CDP 调试端口(netstat 无监听),桌面截图被 Add-Type 安全策略拦截,故无法自动截 ego 窗口

    正式项目:store-ops 前后端分离本地版(用户要求"做成本地项目,前后端分离,每天导数据")

    • 位置 D:\WorkbuddySpace\门店检测工具\store-ops\;backend(标准库http.server+sqlite3,零依赖) / frontend(原生SPA+本地echarts vendor) / data(app.db+inbox+processed)
    • 规则唯一源 backend/rules.py(阈值默认值+检测+校验);db.py 聚合;ingest.py CSV导入;server.py 路由+收件箱watcher(20s)
    • 关键口径:核销率=核销券/意向成交券;差评率新增≥10否则累计≥20否则不判;评分取最近有值(含0分);同文件重复行保首行;同月日数据≥15天才切日粒度,否则用月汇总
    • API:/api/meta /api/dashboard /api/thresholds(PUT/reset) /api/import /api/export.csv /api/history;深链接 #TH #IM #门店ID
    • 验证:KPI 450/323/929/276 与 detect.py 完全一致;阈值4.6→650家;422校验;收件箱自动导入;导1天日报不破坏月视图
    • 启动:双击 启动工作台.bat(GBK编码避免乱码)或 python backend/server.py --port 8787
    • 待办:自动下载(来客API/服务商)、处理闭环(整改回填)、权限分层

    v4:菜单栏从右侧移到左侧,入口改名「指标配置」

    • 用户截图标注左侧要「数据指标配置」菜单 → .rail 改为 left:0(圆角/阴影镜像翻转),.wrap 左内边距 62px 给菜单让位
    • 入口文案:考核指标 → 指标配置(面板标题同步),空状态提示「点左侧【导入数据】」
    • 功能不变:点开右侧滑出指标配置面板,8 组阈值可改,应用后服务端重算

    v5:导入支持 Excel(.xlsx)

    • 新增 backend/xlsx.py:标准库 zipfile+XML 解析 xlsx(共享字符串/日期单元格序列号转 YYYY-MM-DD/多 sheet),仍零依赖(openpyxl 仅测试时 pip 装了,用于造测试文件)
    • ingest.py 重构:import_rows(rows,...) 为唯一入库核心,CSV/xlsx 共用表头别名与幂等逻辑;import_bytes 按扩展名分发;自动跳过表头前的杂讯行
    • server.py:/api/import 与收件箱 watcher 均支持 .xlsx;前端 accept/文案更新;旧版 .xls 明确提示另存为 .xlsx
    • 测试:整月 xlsx 1409 行=CSV 完全一致(15 重复跳过/26 列匹配);日报 xlsx 字符串日期"2026/10/29"、真日期单元格、"80%"→0.8 均正确;测试数据已清理,KPI 恢复 450/323/929/276

    修复:门店详情抽屉不弹出

    • 原因:app.js 中 metricsOf 返回的 m.v 是数值,openDrawer 却写成了 m.v(s) 函数调用 → TypeError,抽屉渲染中断
    • 修复:openDrawer 改为 typeof m.v==='function' ? m.v(s) : m.v;dump-dom 验证 7 条指标条/17 刻度/复制按钮齐全,截图确认弹出
    • 教训:v3 重写前端时引入的回归,测试时只验证了 #TH 面板没验证 #门店ID 抽屉

    差评率口径变更(用户要求去掉样本不足限制)

    • 旧:新增评价≥10 用新增口径;否则累计≥20 用累计口径;都不足→不判定
    • 新:新增评价≥10 用新增口径;否则累计有评价就用累计口径;只有新增无累计也判;完全无评价(15家)才不判
    • ⚠️ 教训:不能简单把阈值 10/20 改成 >0——那会让新增 1-9 条的店从累计口径切成新增口径,R 反而 450→321(更宽松)。正确做法=只去掉"不判定"限制,口径优先级不变
    • 结果:差评率超线 327→329,R 450→469(+19 家小样本门店被新判入)
    • 面板提示文案同步更新;抽屉差评率空值显示「无评价」

    17:2x 分页改为每页 10 条

    • store-ops/frontend/app.js:PAGE_SIZE 50 → 10(分页控件原有,无需改 HTML)
    • 无头 Chrome 验证:主页渲染 10 行,pginfo「第 1 / 141 页」,共 1409 家

    17:4x 新增「文案配置」功能

    • 需求:反馈文案可自定义,不再千篇一律
    • rules.py:所有文案抽成 DEFAULT_TEXTS(31 个模板),detect() 用模板渲染,flags 增加第 4 位稳定规则 key,问题分类改由 key 映射(改文案不影响筛选)
    • db.py:texts 存 settings 表(JSON),get/set/reset
    • server.py:/api/copytext GET/PUT/reset;dashboard payload 带 texts + text_defaults
    • 前端:左侧栏最上方新增【文案配置】菜单(#TX 深链接),4 组面板(反馈结构8/档位名3/问题文案10/整改建议10),改动高亮、恢复默认
    • 变量替换 fmt_tpl:未知占位符原样保留;fb_line_overview 支持 {门店名}{城市}{周期}{访问}{金额}{评分}{核销率}{核销券数}{成交券数}
    • 修复:t_TS/t_CP 模板缺 {档} 变量注入
    • 验证:KPI 无回归(469/323/929/276),PUT→全店重算→reset 全链路 PASS,无头浏览器 31 字段渲染 PASS

    17:5x 文案面板新增实时预览

    • 面板顶部新增「实时预览」块:以问题最多的门店为例,边改模板边看渲染结果,应用后才保存
    • app.js:抽出 renderFeedback(s,X,flags) 供复制与预览共用;previewFlags 仅预览用(注释声明规则唯一源仍在 rules.py)
    • 修复双百分号:核销率/回复率文案 v 变量改纯数字(前后端同步),输出恢复「核销率0%低于基准40%」
    • 无头浏览器验证预览全文渲染 PASS,KPI 无回归

    10:4x 反馈文案按用户真实格式重构

    • 用户提供门店实际反馈文案样例,按其 6 段式重构默认文案:概览(客资/核销/退单)→ 风险因素 → 待核销订单行(>0 才显示)→ 顾客流失分析(访问/成交/流失+占比)→ 分析洞察(按条件取舍 5 条)→ 📌门店调整动作(固定动作清单,textarea 多行编辑)
    • rules.py DEFAULT_TEXTS 扩到 42 键:去掉 fb_sep/fb_sec_act/fb_item_act,新增 fb_line_pending、fb_sec_loss、fb_item_visit/deal/lost、fb_sec_insight、fb_item_insight、fb_insight_metric/score/flow/order/reply/priority、fb_sec_action、fb_actions
    • 洞察条件:指标层面=核销率不达标;口碑分=评分不达标;流量转化=有访问;订单风险=待核销>0;口碑管理=回复率偏低;整改优先级=有风险项
    • 新增变量:客资/核销/退单/待核销/成交/流失/成交占比/流失占比/评分基准/核销金额基准;访问环比暂为 '-'(无上月数据)
    • db.py aggregate_period 输出补 deal、deal_refund;server.py payload 透传
    • t_HX/t_SCORE 默认改成用户风格(核销率{v}%(基准线{base}%)/ 评分{v}(基准线{base})-低于平台准入)
    • 清除 settings 里旧 texts 存档使新默认生效
    • 验证:Node DOM-stub 集成测试跑通 app.js 真实渲染(有风险店+无问题店两例输出正确);KPI 无回归。Chrome 无头本次卡死(单例锁),以后用 node harness 或 ego 浏览器

    13:5x 详情抽屉改「预览分析结果」弹窗

    • 一键复制按钮 → 预览分析结果:弹出居中弹窗,textarea 展示反馈文案全文,可手动修改(不保存),【重新生成】还原,【复制定稿文案】复制当前编辑内容
    • Esc/点遮罩/× 只关预览不关抽屉;closePanels 联动关闭
    • Node harness 验证 openDrawer→openPreview→修改保留 全链路 PASS

    14:1x UI 全面重构(简洁高级)

    • 设计系统:暖中性灰画布 #f4f3f0 + 纯白卡片 + 发丝描边 #e9e7e1;墨黑主操作按钮;黄铜金 #8a6a2f 品牌点缀;低饱和数据色(玫瑰/琥珀/沙金/苔绿/灰蓝)
    • 重写 style.css:CSS 变量 token 化、字距/行高统一、卡片半径 12/16、hover 仅描边+轻投影、侧面板分栏与滚动条细化、toast/弹窗统一
    • header 改两行结构(品牌+标题 / 规则·周期信息,周期选择右侧独立)
    • KPI 数字单位弱化(.v .u),选中态墨黑描边
    • 抽屉改 dwhead(sticky)+ dwbody 结构,新增右上角 × 关闭(原来只能点遮罩/Esc)
    • 修复:spfoot 主按钮被 .spfoot button 覆盖成白底白字(应用到工作台/开始导入不可见)
    • 图表配色与抽屉 barColor/sevColor 同步换成低饱和palette
    • 截图验证(Edge headless,1440 与 900 宽):首页/抽屉/指标面板/导入面板均正常;Node harness 回归 PASS
    • 注意:Chrome headless 在本机会卡死(单例锁),截图改用 Edge:msedge --headless --screenshot --virtual-time-budget=12000

    14:2x 配色改为香槟金主调(参考品牌金黄图)

    • 用户反馈上一版中性灰"配色更单调",提供品牌图(饱和金黄+白)要求多用金色
    • style.css 全量换色:画布 #f8f4ea 香槟底 + 顶部三处金色径向光雾(body 多背景,background-attachment:fixed);描边 #ecdfc2 金调;文字改暖棕系(#211a10/#5c5241/#93876f)
    • 金色 token:--gold #c8952c / --gold-deep #a4761c / --gold-bg #fbf4e2 / --grad-gold 三段渐变
    • 金色落地:brand 标签、railitem.on、rail hover、pill、primary/copybtn/spfoot/pvfoot 主按钮(渐变+暖金投影+内高光)、KPI 卡顶部 2.5px 金条(hover 全亮)、选中 KPI 金底金边、表头 #fdf9ee+金分隔、panel h3 金竖条、thgroup 金竖条、输入聚焦金边+金晕、预览块左侧金边、drop 拖拽区、pager hover、抽屉头 3px 金线+淡金渐变头、弹窗头尾淡金渐变、toast 深棕+金边
    • header 底部改局部金色渐变细线(左实右隐)
    • 标签色提对比:t-R3/R2/R1/B/T 全部换成暖金棕色阶(上一版米色太淡看不清)
    • app.js 图表:ECharts 纯 JSON linear gradient(GOLD_BAR,避免 echarts.graphic 依赖,harness 也能跑);c2 四档砖红/琥珀/沙金/苔绿;c3 沙金;sevColor/barColor 同步暖化;残留灰字 #8b8a86/#a5a29a → #93876f/#a1957d
    • 验证:Node harness 回归 PASS(预览/复制逻辑不变),Edge 无头截图首页/抽屉/文案面板均正常,截图存 .workbuddy/ui_gold.png

    14:36 预览弹窗放大

    • .pvcard:560px 固定宽 → width:min(980px,84vw)、height:min(760px,84vh)(面积约占屏幕 57%);内边距与外层留白同步加大(wrap padding 32、头尾 20/28)
    • textarea 字号 12.5→13px、行高 2→2.05、padding 18/22→22/28;按钮加高
    • 用临时 file:// 页面 + Edge 无头截图验证:1080 宽视口下弹窗占宽约 68%,长文案一屏可见

    14:45 新增「按评分」筛选下拉

    • index.html 筛选栏在「全部城市」后加 fscore:全部评分 / 4.0以下 / 【4.0-4.3】 / 【4.3-4.5】 / 4.5以上
    • app.js:state.score、scoreInBand(v, band)(先 round 到 1 位防浮点误差)、filtered() 叠加筛选、bind() 绑定、renderFilters 回填、导出 URL 带 score
    • 闭区间按【】语义含端点:4.3 同属 4.0-4.3 与 4.3-4.5,4.5 同属 4.3-4.5 与 4.5以上(用户明确要求;两档合计会大于总店数属正常)
    • server.py build_export 支持 score 参数,口径与前端一致
    • 验证(1409 家):4.0以下 101 / 4.0-4.3 334 / 4.3-4.5 327 / 4.5以上 850;4.3 在两档各 112、4.5 在两档各 91;4.0以下档无 >=4.0 漏入;导出 CSV 行数与前端完全一致
    • harness:.workbuddy/wt_test_score.js

    14:55 支持局域网访问

    • server.py:默认绑定 0.0.0.0(原来 127.0.0.1),新增 --local 只绑本机;启动时 lan_ips() 打印所有局域网 IPv4 地址(UDP connect 8.8.8.8 取默认出口 + getaddrinfo 补充,过滤 127.*)
    • 新增 开放局域网访问.bat(GBK):自检管理员,非管理员以 RunAs 方式重新拉起自身;netsh 先删后加入站规则「门店检测工作台 8787」TCP 8787 profile=any
    • 启动工作台.bat:加 chcp 936,for /f 取 LAN IP 并打印局域网访问地址,提示防火墙脚本
    • README 增加「同一局域网的其他电脑/手机怎么访问」:地址、放行步骤、AP 隔离/跨网段排错、无鉴权安全提醒、--local 关闭
    • 本机现状:网络为公用(Public),已有 python.exe 入站放行规则(公用/TCP/任意端口),恰好匹配服务进程 C:....workbuddy\binaries\python\versions\3.13.12\python.exe → 外部大概率已可直连,无需再放行
    • 验证:LAN IP 192.168.10.232 下 /api/meta、/api/dashboard(1409)、/api/export.csv 均 200;前端无硬编码 127.0.0.1/localhost(全相对路径)
    • 坑:Bash 命令文本里出现那个 shell 名字会被安全策略拦截,涉及 bat 生成改用写 .py 文件再执行

    15:40 修复「改文案变量不渲染」

    • 现象:用户把概览行写成 近30天成交{门店意向成交券数};核销券数{门店核销券数};退单券数{门店意向退款券数},预览原样输出占位符
    • 根因:fbVars 只认短名(客资/核销/退单),用户按数据表列名写的全称变量不在表里 → fmtTpl 原样保留
    • 修复 app.js:
      1. 新增 VAR_ALIAS 别名表(门店意向成交券数→客资、门店核销券数→核销券数、门店意向退款券数→退单、门店页访问次数/门店页有效人数→访问、门店实际成交人数→成交、核销金额→金额、门店评分/团购评分→评分、评价回复率→回复率 等 30 项),fbVars 末尾展开别名
      2. unknownVars() + knownVarSet()(BASE_VARS ∪ VAR_ALIAS ∪ 保留变量 i/问题/建议/洞察/v/base/target/口径/档)
      3. 面板每字段加「+ 变量」按钮 → 展开变量 chips,点选插入光标处(insertAtCursor)
      4. 字段含未知变量 → .thfield.bad 红框 + .varwarn 文字提示;预览区 txBad 红条汇总 + .badvar 高亮残留 {...}
      5. applyTexts 保存时若有未知变量,toast 提示但允许保存
      6. 计数类变量改用 cnt()(无千分位),金额仍 money()(千分位)
    • 验证(Node harness .workbuddy/wt_test_var.js):用户原模板 → 近30天成交8;核销券数0;退单券数15,无残留花括号;短名等价;写错 {核消券数} 能被检出;默认文案 43 个字段无未知变量
    • Edge headless/#TX:43 个 varbtn/varchips/varwarn 就位,txBad display:none(无错),预览正确渲染
    • README 增加变量对照表(短名 ↔ 数据表列名别名)
    • 注意:库里已存用户版模板,别名生效后直接可渲染,无需重存