# 2026-11-01 诊断规则重做(v2) ## 起点:用户反馈 「比起前端 UI 样式,门店检测的逻辑更需要调整。现在的门店诊断结果并不严谨, 诊断建议也不是根据门店实际问题给出的,而是一股脑全给。」 要求:先做思维导图统一梳理「每项指标没达到的问题 + 整改建议」,确认后再写进代码。 ## 第一步:用数据定位不严谨在哪 对 1409 家门店实测,找出 5 个硬伤: | 问题 | 实测 | 结论 | |---|---|---| | 核销金额基准 10000 当不达标线 | 全品牌中位 165 元,仅 8% 达标 | 命中 1023 家 = 噪音,不是诊断 | | 回复率 <50% | 命中 1305 家(93%) | 没有区分度 | | 评分 0 分 | 91 家被判「低于 4.3」 | 0 分是未开分,不是评分低 | | 差评率小样本 | 22 家「1-2 条评价」就判 | 一条差评 = 非常严重 | | 整改动作 | 9 条固定清单,每家全给 | 用户说的「一股脑全给」 | 补充发现(重要,推翻了之前的判断): - 源头 CSV **没有一个空单元格**,所有缺失都是字面 0 → 不是「导入丢了空值」,而是**平台用 0 表示「未发生/未开分」,代码当成了真实值** - 「待核销 = 意向成交 − 核销」在同源数据里 868 家会算出负数(没扣退款) → 文案里写的「真实未核销」是错的,已改成「估算未核销」 ## 第二步:思维导图(用户确认后才动代码) 产出: - `项目记录/规则设计_v2_思维导图.html`(自包含,可打印) - `项目记录/规则设计_v2_明细.md`(同一份规格的表格版) - 生成脚本按规格统一生成,文档与代码同源 结构:4 层漏斗(流量/转化/履约/口碑)× 16 条规则,5 档分级,1 棵诊断树,≤3 条动作。 ## 第三步:用户拍板的 4 个决定 1. **核销金额保留为考核项,但提高门槛** → 只在「核销率已达标」时才判客单价, 问题性质从「金额不够」变成「客单价低」,命中 1023 → 287 家 2. **差评率小样本仍然判,但封顶预警线** → 22 家从「非常严重」降为「预警线」,不再有 1 条差评判 R3 3. **评分 0 分仍算不达标,文案改「未开分」** → KPI 总数 323 不变,但文案与动作分开 4. **诊断树按漏斗顺序** → 违规 → 流量 → 转化 → 履约 → 口碑 ## 第四步:写进代码 ### backend/rules.py(重写) - `DEFAULT_THRESHOLDS` 新增 7 个可调门槛:visit_low / cvr_low / pend_high / hx_min_deal / amt_min_coupons / cp_min_new / cp_min_total / reply_min_new - 16 条规则,每条含 档位/层/级别/模板键/变量 - `diagnose()` 返回 problems / primary / secondary / actions / sev / tier / headline / hd_key - 根因去重用 if/elif 链保证互斥:零成交 → 成交未核销 → 核销率低 → 客单价低 - `bad_rate()` 改为返回 (ratio, 口径, 是否小样本),小样本在 diagnose 里封顶 R1 - 保留 `detect()` 兼容旧调用 - 新增 `V1_TEXTS`:v1 默认文案快照,用于迁移 ### backend/db.py - `get_thresholds()` 用默认值补全库里没有的新键(老库零迁移) - `get_texts()` 迁移:存档值 == v1 默认值 → 用新默认;否则视为用户自定义保留 (实测保留了用户的 3 处自定义:概览行模板、访问行模板、传素材动作文案) - `aggregate_period()` 补输出 reviews_new/bad_new/reviews_total/bad_total/lit —— 差评率判定需要原始计数,之前只算了一个 cp_rate 出来 ### backend/server.py - payload 增加 tier / headline / hd_key / primary / secondary / actions / problems - 保留 flags 字段(列表页、标签渲染继续可用) - 导出 CSV 增加「诊断结论 / 主因 / 全部问题 / 整改动作」四列, 整改动作只给诊断树的 ≤3 条 ### frontend/app.js - `diagnosisOf(s, X)`:用当前(可能未保存的)模板重新渲染问题与动作 - `renderFeedback()` 重写:概览 → 结论 → 主因+次要 → 待核销 → 流失 → 洞察 → ≤3 动作 - **删除 `previewFlags()`**(前端复刻的第二套判定规则), 改为直接用后端 problems + 模板键重渲染 → 规则唯一源真正落到 rules.py - 抽屉改为「结论横幅 + 主因 + 次要 + 指标条 + 折叠的其余提升点」 - 报告同步;【指标配置】面板接入 7 个新阈值 - 文案配置面板从 43 个字段扩到 65 个(新增 hd_* 结论句、新问题文案、新动作) ## 验证 - 规则命中数与原型脚本完全一致(LIT 867 / REPLY 822 / HX 695 / CP 349 / AMT 287 …) - 主因分布:违规 469、核销率低 417、客单价 185、访问不足 101、成交未核销 81 …(13 种主因) - 平均问题 3.15 条、平均动作 2.15 条(≤3 上限生效) - Node harness 全量 1409 家:残留变量 0、动作超 3 条 0、有问题无主因 0 - 报告渲染全量 1409 家:0 报错 - 导出接口 16 列、469 行正常 ## 已知遗留 - 「待核销」仍是估算值(缺后台真实未核销列)。要根治需要数据源提供该列。 - 回复率命中 822 家(58%)仍偏高,因为品牌确实 58% 的门店有新评价但没回复; 阈值 `reply_min_new` 可在面板调到 5,命中会降到 414 家。 - 洞察段仍是 6 条全列,未与主因联动;如需可下一步收敛为「主因相关的 2-3 条」。 --- # 第二轮:按用户编辑的可视化规则图落地(v2.1) ## 输入 用户在 `规则全景图_可编辑.html` 里改了 11 条规则、新增 1 条、删除 2 条, 导出 `规则修改_2026-11-01.json`。已用浏览器实时状态核对,导出的就是最终版。 ## 用户的改动 | 类型 | 内容 | |---|---| | 删除 | `VISIT0`(并入 VISIT,判定改为「访问 < 100」含 0)、`SCORE0`(并入 SCORE) | | 新增 | `新增评价低`(新增评价 < 10 条,T 级) | | 阈值 | 视频 0 → <10、点亮 0 → <10、转化率 2% → 10% | | 重命名 | 客单价偏低 → 核销金额偏低;退单率超线 → 商责退单率超线 | | 重写判定 | 核销金额去掉「核销率已达标」前置条件 | | 文案 | 12 条问题的动作全部改写为更具体的门店执行动作 | ## 两个需要我定的点(用户确认) 1. **核销金额独立判定** —— 只要金额 < 10000 就报,不管核销率(命中 1299 家 / 92%) 2. **问题全列、每条给动作** —— 不再截断到 3 条 ## 代码改动 - `rules.py` - 规则表 15 条;`DIAGNOSIS_ORDER` 去掉 VISIT0/SCORE0,加入 RVOL - 核销链改为互斥 if/elif,`AMT` 移出链外独立判定 - `SCORE` 一条规则内区分 0 分(走 `t_SCORE0`「未开分」文案) - 动作不再截断;新增 `_clean_action()` 去掉动作行首的 ✅,避免与「✅ {动作}」模板叠加 - 新增阈值 `video_low` / `lit_low` / `new_review_low`,`cvr_low` 默认 2 → 10 - `hd_key` 回退链:规则 key → 模板 key(区分未开分)→ 层 → OK - `db.py` - `set_texts()` 改为**只存与默认值不同的键** —— 以后改默认文案不会再被旧存档盖住,也不再需要 V1 快照比对(保留 V1 兼容历史存档) - 前端 - `diagnosisOf` 的动作覆盖全部问题;风险段、抽屉、报告全部改为「问题全列」 - 阈值面板接入 3 个新参数;文案面板移除 VISIT0、加入 RVOL ## 踩坑 - 用 `str.replace` 批量改文案时**误伤了 `V1_TEXTS` 快照**(`t_VISIT` / `t_VIDEO` 两处字符串完全相同), 导致迁移判断失效、旧值被当成用户自定义。已按 V1 真实值修复,并改为「只存差异」从根上避免这类问题。 - 用户把转化率判定写成 10%,但参数 `cvr_low` 还是 2% —— 条件文本和参数是两处,已按 10% 统一。 ## 当前命中(2026-10,1409 家) | 规则 | 命中 | 规则 | 命中 | |---|---|---|---| | 点亮偏低 | 1305 (93%) | 评分不达标 | 323 (23%) | | 核销金额偏低 | 1299 (92%) | 未核销积压 | 253 (18%) | | 转化率低 | 1213 (86%) | 成交未核销 | 221 (16%) | | 新增评价少 | 1170 (83%) | 商责退单率 | 165 (12%) | | 回复率偏低 | 822 (58%) | 访问过低 | 147 (10%) | | 核销率不达标 | 695 (49%) | 零成交 | 56 (4%) | | 视频量少 | 437 (31%) | 投诉率 | 11 (1%) | | 差评率超线 | 349 (25%) | | | 平均每家 6.01 条问题 / 6.01 条动作,单店最多 11 条。 ## 待观察 - 主因有 57%(798 家)落在「转化率低」,因为 CVR 阈值放到 10% 后命中 86%,且诊断树排第 4 位。 若觉得结论太单一,可把 CVR 在诊断树里往后挪,或把阈值收回到 5% 左右。 - 洞察段 6 条与问题列表内容重复度高,可考虑收敛。 --- # 第三轮:近30天滚动窗口(快照模式) ## 需求 用户要求:每天从抖音来客「报表集市」导出近30天数据并入库,分析口径围绕近30天滚动窗口。 ## 已发现的问题(动手前先验证) 把「按统计周期」的导出文件直接丢进旧版导入,会**静默写错**: 统计日期是 `2026-10-03-2026-11-01` 这种区间字符串,旧代码只截取开头 `2026-10-03`, 结果 **30 天的汇总被当成「10 月 3 日一天」的日报**,窗口结束日丢失。 (测试时误把 2 家测试门店写进真实库,已清理,KPI 复核无异常。) ## 已完成:快照数据模型 - `metrics` 新增 `window_start` / `window_end`,`granularity` 增加 `snapshot` - 老库自动迁移(PRAGMA 检查 + ALTER TABLE),无需手工操作 - `ingest.parse_range()` 识别 `2026-10-03-2026-11-01` / `~` / `至` / `/` 分隔等写法 - 区间 → `period` 记「截至日」、每店一行、`granularity='snapshot'` - 首尾同一天 → 自动退化为单日日报,不会误判 - `get_periods()` 返回快照标签「近30天 · 截至 11-01」并带窗口区间 - `aggregate_period()` 快照的「数据天数」按窗口长度算 - 前端周期下拉显示快照标签,顶部数据说明显示统计区间 - 月汇总数据与快照共存,互不影响 验证:隔离副本连续导入 11-01 / 11-02 两份快照,周期列表、聚合、窗口字段全部正确。 ## 进行中:生意经导出自动化 已确认的事实: - ego lite **已登录**生意经(河南怡呵美水光企业管理有限公司) - 平台**会记住上次勾选的维度和指标**,进门店 tab 后自动勾选 47 项,无需每天重选 - 建任务有每日次数限制(当时显示「今日剩余 29 次」) - 下载列表是 Bytedance 表格,每行有「下载」按钮 卡点:日期区间控件(byted-date-picker)点选不生效。 试过合成 click、真实 click、标记后 click,日格能拿到 `byted-date-selected` 样式但输入框值不变; 面板里存在多个 popper,疑点是我抓到的不是输入框对应的那一个。下一步需要重新定位 popper 与输入框的绑定关系。 尚未创建任何下载任务,未消耗配额。 ## 生意经接口已打通(关键进展) 放弃点 UI,改为抓接口。找到的统一网关: ``` POST https://www.life-data.cn/api/lowcode_api/query ?projectKey=shengyijing&pageId=15352&interface_id=0ac0bacd ``` 必带的请求头(少了会返回 code -1): ``` content-type: application/json; charset=utf-8 root-life-account-id: 7376197379193669659 life-account-id: 7376197379193669659 x-tt-trace-log: 01 ``` 请求体(创建「按日 × 日期区间 × 全部门店」的导出任务): ```json {"interface_id":"0ac0bacd","data_query":{ "data_query_type":"data_query", "indicators":[ 41 个字段,poi_id / enter_poi_cnt / verify_cert_cnt_1d / reply_rate_ratio ... ], "filters":{"operator":"and","filters":[ {"field":{"name":"date"},"filter_operator":"between","range_values":["20261003","20261101"]}, {"field":{"name":"poi_selector_json"},"filter_operator":"equal","value":"{全部门店选择器}"}, {"field":{"name":"ignore_zero_rows"},"filter_operator":"equal","value":1}]}, "group_by":["day"], "order_by":[{"order_field":"day","order_type":"desc"}], "extra":{}}} ``` 返回:`{"code":0,"status":"submit_success","task_id":"431b88fb-..."}` **意义**:日期区间完全由我们控制,彻底绕过了点不动的日历控件。 已捕获的其他接口: - `interface_id=d715cc19` —— 按 `query_task_name` 查任务(可用于轮询状态) - `interface_id=9e029004` —— 查 `total` / `available`(当日剩余建任务次数) - `interface_id=0ac0bacd` + `data_query_type=meta_query` —— 拉字段元数据(64 个字段) ## 待办 1. 轮询任务状态 → 拿下载地址(或找到能直接返回数据行的查询接口,连文件都不用下) 2. 把 JSON/文件转成 ingest 能吃的格式,落到 `data/inbox/` 3. 每日定时(launchd 或 server 内置线程) ## 清理 测试期间创建过 2 个任务(「同步测试_1101」「报表集市_门店」),均已撤销, 下载列表恢复为原来的 2 条已完成任务。 ## 同步链路跑通(端到端验证通过) ### 关键结论 1. **导出文件是 .xlsx**(不是 zip),现有导入器直接支持 2. 下载地址由任务接口返回的 `download_link` 给出,是**签名 URL**,有效期约 1 天 3. Python 直连被 CDN 挡(403 空响应,缺 secsdk 令牌),**走 ego 页面上下文调接口可行** 4. 从建任务到出下载地址约 **3.5 分钟**,脚本里轮询上限 10 分钟 ### 完整链路(已实测) ``` sync/run_sync.sh → ego 打开生意经(复用登录态) → POST interface_id=0ac0bacd 建任务(group_by=[],日期=今天-29~今天) → 轮询 interface_id=d715cc19 拿 download_link → page.fetch 下载 xlsx 到 data/inbox/门店数据__.xlsx → 服务端 watcher 20 秒内导入 → 文件名里的日期区间被识别 → 按快照入库 → 周期下拉出现「近30天 · 截至 11-01」 ``` ### 新增文件 - `sync/life_sync.mjs` —— 同步主脚本(建任务/轮询/下载) - `sync/run_sync.sh` —— 定时调用入口(带日志与失败标记) - `sync/com.yhm.lifesync.plist` —— launchd 每日定时模板 - `ingest.range_in_filename()` —— 文件名带日期区间时自动按快照入库 - `ingest` 支持显式 `window=(start,end)` 参数 ### 踩坑:一次真实的误写与修复 第一次同步时**服务还在跑旧代码**,没加载窗口识别,结果: - 30 天数据被当成「2026-10 月度汇总」,覆盖了原有 1409 家月度数据 修复:备份库 → 清掉污染行 → 重导原始 `门店数据_10月.csv` 恢复月度 → 再把 xlsx 按快照重导 修复后:`2026-10` 月度 1409 家 + `2026-11-01` 快照 1413 家,两者共存 **教训:改完 ingest 必须重启服务再触发收件箱导入。** ### 当前状态 - 快照周期「近30天 · 截至 11-01」1413 家,已是工作台默认周期 - KPI(该窗口):469→467 / 323→327 / 929→926 / 276→266 - 今日建任务配额剩余 26 次(同步 2 次 = 测试) ## 定时任务:launchd 走不通,改成服务内置调度 ### 先试了 launchd(失败) 配好 `~/Library/LaunchAgents/com.yhm.lifesync.plist`(每天 01:00),`launchctl load` 成功、日历项注册成功, 但触发后报 `/bin/bash: …/run_sync.sh: Operation not permitted`。 逐步排查: 1. 空环境 `env -i` 直接跑脚本 → **正常**,不是 PATH 问题 2. `launchctl submit` 探针 `cd` + `ls` → **成功**,不是目录不可达 3. 探针改用 `head 脚本路径` → **也被拒**,`head=1` 结论:**macOS TCC 保护 `~/Documents`,系统级 launchd 任务读不到这个目录里的文件内容**。 要绕过必须在「系统设置 → 隐私与安全性 → 完全磁盘访问」里手动把 `/bin/bash` 加进去。 已卸载并移除该 LaunchAgent,plist 留在 `sync/` 下作参考。 ### 改成服务内置调度(可用) 工作台服务本身是从终端启动的,具备该目录的读权限,所以把定时器放进服务里: - `server.daily_sync_loop()` 线程:算到下一个 01:00,睡到点再跑 - **启动补跑**:距上次成功超过 20 小时 → 启动 90 秒后自动补一次(解决关机/休眠错过) - `POST /api/sync` 手动触发,`GET /api/sync/status` 查状态 - 左侧栏新增【同步数据】按钮,点完每 5 秒轮询状态,完成后自动刷新数据 - `last_sync` 时间戳存 settings 表 ### 实测 - 启动补跑:21:11:01 触发 → 21:15:33 成功,下载 298KB,入库 1413 家 - 批次记录的周期已修正为 `2026-11-01`(之前误记成 `2026-11`) - 启动器加 `-u`,服务窗口能实时看到同步进度 ### 当前配置 - 每天 01:00 自动同步 - 快照周期「近30天 · 截至 11-01」1413 家,为工作台默认周期 - 月度 2026-10 数据 1409 家保留 ## 阈值改面板 = 直接改代码(v2.2) ### 需求 用户:「我想要的是在【指标配置】面板改数字,就会直接同步把规则逻辑一起修改」 —— 不要「代码默认值」和「库里自定义值」两套数字打架。 ### 实现 - 新增 `backend/codesync.py` - `write_defaults(T)`:把新阈值写回 `rules.py` 的 `DEFAULT_THRESHOLDS` 只替换已有键的「值」,保留键名/缩进/行尾注释/其它代码;原子写入 + 生成 `.bak` - 写完后清字节码缓存并 `importlib.reload(rules)`,立即生效 - `get_factory()`:首次运行时把出厂值快照到 `data/factory_thresholds.json` - `PUT /api/thresholds` → 写库 + 写回代码 - `POST /api/thresholds/reset` → 回到出厂值 + 同样写回代码 - 面板语义改为对照**出厂值**:显示「出厂值 / 已自定义」 - 保存成功提示区分「已生效,并同步写回代码默认值」/ 写回失败原因 ### 规则地图跟随 `gen_editable_map.py` 里所有判定条件中的数字改为从 `rules.DEFAULT_THRESHOLDS` 读取, 改阈值后重新生成,图上文字自动同步(不再写死「≥30 张」)。 ### 踩了两个坑 1. **正则分组用错**,把旧值和新值拼在一起,`"score_base": 4.34.3`、`"pend_high": 3030`, 直接把 `rules.py` 写坏。靠事前的 `.bak` 备份恢复。 教训:改源码的函数必须先在隔离副本里跑一遍,并且**必须校验语法**(ast.parse)再落盘。 2. **macOS 自带 Python 把 .pyc 放在 `~/Library/Caches/com.apple.python`**, 不在项目里的 `__pycache__`。删 `__pycache__` 无效,同尺寸同秒的改动会被旧字节码顶掉 (现象:源码是 10,导入却是 15)。已在 `write_defaults` 里主动清理该缓存路径。 ### 验证 连续 PUT 12 → 10 → 8 → 10,每次都用一个新进程从磁盘重新导入核对: 代码默认值、服务内默认值、源码三者完全一致。 ## UI:数据瘦身 + 放大字号 + 滚动加载 ### 起因 用户反馈「排版太紧凑,字体也小」,同时问「滚动加载会不会每次刷新渲染太多」。 量了一下发现真正的问题不是渲染,是**每次刷新要传 6.4 MB**: 同一份问题数据被下发了 4 遍(problems / flags / primary / secondary / actions)。 ### 1. 数据瘦身:6.4 MB → 1.9 MB(降 70%) - 后端只下发「模板键 + 变量」:`{k,t,l,v,c,p,a,x}`,文案由前端按当前模板渲染 - 删掉 `flags` / `primary` / `secondary` / `actions` / `cats`(都可从前端派生) - 前端新增 `decorateStore()`:加载后一次性还原成原来的结构,其余代码零改动 - 导出接口 `/api/export.csv` 改为按模板现场渲染(内容与原来一致) - KPI、分布统计、分类筛选改用 `tier` / `problems` 派生 ### 2. 放大字号与间距 - 基础字号 13.5 → 15px;12.5/11.5/10.5 档整体上调一档(现在 14/13/12) - 表格单元格内边距 11px → 14px,表头 10px → 12px - 卡片内边距 18/20 → 22/24;图表高度 222 → 290 - 收窄的 `.wrap` 最大宽 1320 → 1400,两侧留白加大 ### 3. 首屏 20 条 + 滚到底加载 - `FIRST_ROWS=20`、`STEP_ROWS=20`、`MAX_ROWS=300` - 去掉上一页/下一页,改成状态行「已显示 20 / 1413 家,继续下滑加载更多」 - 滚到距底部 600px 自动追加;到 300 条上限后提示用筛选缩小范围 - 冒烟测试:首屏 20 行、加载一次 40 行、300 行渲染 1ms / 157KB HTML ### 未做 - 密度切换开关(先按「舒适」档定死,用户看效果后再说) ### 后续:改回分页 用户反馈滚动加载不合适,改回分页: - `PAGE_SIZE = 10`,恢复上一页/下一页,状态行「第 1 / 142 页」 - 移除 `loadMore` / `nearBottom` / 滚动监听 / 300 条 DOM 上限 - 数据瘦身和字号放大保留 验证:第 1 页 10 行、第 2 页 10 行、末页(142)3 行,按钮禁用状态正确。 ### 排序控件拆成两个下拉 - 原因:原来 5 个选项把「字段」和「方向」写死在一起(如「按核销金额(低→高)」,方向不可切换) - 现在:`#fsort` 只选字段(严重度/核销金额/评分/核销率/访问量),`#forder` 选方向(倒序/正序) - 默认:严重度 + 倒序(与原来一致) - 空值(未开分、无核销率)无论正序倒序都排最后,不参与翻转 - 同值时按核销金额兜底排序 - 验证:5 字段 × 2 方向共 10 种组合,排序结果均正确 ### 列表增加列(7 列 → 13 列) 原来只有 评分/核销率/核销金额/退单率,漏了 R 级违规里的**投诉率、差评率**,也看不到流量和履约。 新增 6 列:**访问 / 客资(意向成交券)/ 待核销 / 投诉率 / 差评率 / 回复率** 配套调整: - 超标的值直接标红(R 级红 `#b5563a`,未达标金 `#c8952c`),扫一眼就能定位 - 评分 0 分显示「未开分」而不是 0.0;差评率无评价显示「无评价」,不参与排序翻转 - 「触发问题」列原来显示完整问题文案(含数字),与新增列重复且把行高撑到 127px, 改为显示**问题分类短名**(差评率超线 / 评分不达标 / 成交未核销…),最多 5 个 + 「+N」 - 列宽收紧:单元格内边距 14/12 → 13/10,标签字号 12 → 11.5 - `.tablewrap{overflow-x:auto}` 兜底,当前 1274px < 容器 1292px,不出现横向滚动条 - 行高 127px → 93px ## 口径变更:核销率分母改用「门店页成交券数」 ### 需求 用户:「门店页成交券数,现在统一改成这个。包括核销率」 —— 原来看板上的「客资」列其实是**门店意向成交券数**(intend_deal),用户要的是**门店页成交券数**(deal)。 ### 改动范围(全链路统一) | 位置 | 原来 | 现在 | |---|---|---| | 核销率 | 核销券 ÷ 意向成交券 | 核销券 ÷ **门店页成交券数** | | 待核销 | 意向成交券 − 核销券 | **成交券数** − 核销券 | | 零成交判定 | 意向成交券 = 0 | **成交券数** = 0 | | 成交未核销 | 意向成交券 > 0 且 核销 = 0 | **成交券数** > 0 且 核销 = 0 | | 核销率样本门槛 | 意向成交券 ≥ 5 | **成交券数** ≥ 5 | | 转化率分子 | 成交券数 | 不变(本来就是这个) | | 返单/投诉率加权 | 按意向成交券加权 | 按成交券数加权 | | 文案变量 {客资} {成交券数} | 意向成交券数 | **门店页成交券数** | | 表格「客资」列 | 意向成交券数 | 改名「成交券」,取成交券数 | | 报告数据卡 | 门店意向成交券数 | 门店页成交券数 | ### 影响(2026-11-01 数据) - 核销率 < 40% 的门店:926 → **910 家**(分母变小,核销率整体略升) - 中位核销率:27.8% → 28.1% - **核销率 > 100% 的门店:4 → 15 家**(成交券数可能小于核销券数,因为核销的是更早周期的券)—— 属正常现象,不做截断 - 其他 KPI 不变:R 467 / 评分 327 / 零核销 266 ### 备注 - 数据库里两个字段都保留(deal 与 intend_deal),只是**判定与展示统一用 deal** - 文案模板里用户写的 `{门店意向成交券数}` 通过别名仍然有效,但取的是成交券数的值