Compare commits

..

2 Commits

Author SHA1 Message Date
xiaoban
5bd587318a 自动备份 2026-06-19 08:10:01 2026-06-19 08:10:01 +08:00
xiaoban
a0a9ea9800 每日总结更新 20260619 2026-06-19 08:00:01 +08:00
9 changed files with 180 additions and 128 deletions

View File

@ -630,3 +630,12 @@ To https://git.valavala.com/ai_member_only/ai_member_xiaoban
3703b73..2b86823 master -> master 3703b73..2b86823 master -> master
[2026-06-17 08:10:02] 工作区备份成功:自动备份 2026-06-17 08:10:01 [2026-06-17 08:10:02] 工作区备份成功:自动备份 2026-06-17 08:10:01
[2026-06-18 08:10:01] 开始备份工作区... [2026-06-18 08:10:01] 开始备份工作区...
[master 9d6999a] 自动备份 2026-06-18 08:10:01
4 files changed, 62 insertions(+), 27 deletions(-)
delete mode 100644 tmp_daily_summary.md
remote: . Processing 1 references
remote: Processed 1 references in total
To https://git.valavala.com/ai_member_only/ai_member_xiaoban
3685359..9d6999a master -> master
[2026-06-18 08:10:03] 工作区备份成功:自动备份 2026-06-18 08:10:01
[2026-06-19 08:10:01] 开始备份工作区...

View File

@ -100,3 +100,7 @@
{"type":"memory.recall.recorded","timestamp":"2026-06-17T13:45:52.647Z","query":"makee交易系统 交易系统权限","resultCount":3,"results":[{"path":"memory/2026-05-28.md","startLine":504,"endLine":536,"score":1},{"path":"memory/2026-05-28.md","startLine":337,"endLine":366,"score":1},{"path":"memory/2026-05-28.md","startLine":530,"endLine":557,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-06-17T13:45:52.647Z","query":"makee交易系统 交易系统权限","resultCount":3,"results":[{"path":"memory/2026-05-28.md","startLine":504,"endLine":536,"score":1},{"path":"memory/2026-05-28.md","startLine":337,"endLine":366,"score":1},{"path":"memory/2026-05-28.md","startLine":530,"endLine":557,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-17T13:46:02.081Z","query":"makee 系统 后台 管理 权限 登录","resultCount":2,"results":[{"path":"memory/2026-05-28.md","startLine":551,"endLine":580,"score":1},{"path":"memory/2026-05-28.md","startLine":504,"endLine":536,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-06-17T13:46:02.081Z","query":"makee 系统 后台 管理 权限 登录","resultCount":2,"results":[{"path":"memory/2026-05-28.md","startLine":551,"endLine":580,"score":1},{"path":"memory/2026-05-28.md","startLine":504,"endLine":536,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T00:09:26.923Z","query":"bi_vala_order 订单表 order database","resultCount":5,"results":[{"path":"memory/2026-05-24.md","startLine":106,"endLine":126,"score":1},{"path":"memory/2026-05-25.md","startLine":1,"endLine":26,"score":1},{"path":"memory/2026-05-24.md","startLine":85,"endLine":110,"score":1},{"path":"memory/2026-06-17.md","startLine":20,"endLine":30,"score":1},{"path":"memory/2026-05-24.md","startLine":46,"endLine":71,"score":1}]} {"type":"memory.recall.recorded","timestamp":"2026-06-18T00:09:26.923Z","query":"bi_vala_order 订单表 order database","resultCount":5,"results":[{"path":"memory/2026-05-24.md","startLine":106,"endLine":126,"score":1},{"path":"memory/2026-05-25.md","startLine":1,"endLine":26,"score":1},{"path":"memory/2026-05-24.md","startLine":85,"endLine":110,"score":1},{"path":"memory/2026-06-17.md","startLine":20,"endLine":30,"score":1},{"path":"memory/2026-05-24.md","startLine":46,"endLine":71,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T03:21:04.151Z","query":"字段对齐 column contract 三表 汇总 full_refresh","resultCount":5,"results":[{"path":"memory/2026-05-28.md","startLine":572,"endLine":602,"score":1},{"path":"memory/2026-05-13.md","startLine":1,"endLine":16,"score":1},{"path":"memory/2026-05-24.md","startLine":46,"endLine":71,"score":1},{"path":"memory/2026-05-24.md","startLine":66,"endLine":92,"score":1},{"path":"memory/2026-05-28.md","startLine":596,"endLine":624,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T04:44:32.687Z","query":"陈逸鸫审批 S2U16 数据导出 王璐辰","resultCount":3,"results":[{"path":"memory/2026-06-17.md","startLine":1,"endLine":23,"score":1},{"path":"memory/2026-05-24.md","startLine":46,"endLine":71,"score":1},{"path":"memory/2026-05-24.md","startLine":66,"endLine":92,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T10:17:31.215Z","query":"知识巩固做题记录 数据表","resultCount":3,"results":[{"path":"memory/2026-05-24.md","startLine":46,"endLine":71,"score":1},{"path":"memory/2026-05-24.md","startLine":85,"endLine":110,"score":1},{"path":"memory/2026-05-24.md","startLine":66,"endLine":92,"score":1}]}
{"type":"memory.recall.recorded","timestamp":"2026-06-18T10:17:37.951Z","query":"知识巩固 表名 vala_game 做题记录 knowledge_consolidation","resultCount":4,"results":[{"path":"memory/2026-05-24.md","startLine":46,"endLine":71,"score":1},{"path":"memory/2026-05-24.md","startLine":85,"endLine":110,"score":1},{"path":"memory/2026-05-24.md","startLine":106,"endLine":126,"score":1},{"path":"memory/2026-06-17.md","startLine":20,"endLine":30,"score":1}]}

View File

@ -1,6 +1,6 @@
{ {
"version": 1, "version": 1,
"updatedAt": "2026-06-18T00:09:26.923Z", "updatedAt": "2026-06-18T10:17:37.951Z",
"entries": { "entries": {
"memory:memory/2026-05-24.md:1:30": { "memory:memory/2026-05-24.md:1:30": {
"key": "memory:memory/2026-05-24.md:1:30", "key": "memory:memory/2026-05-24.md:1:30",
@ -176,13 +176,13 @@
"endLine": 71, "endLine": 71,
"source": "memory", "source": "memory",
"snippet": "### 增强: 报告开头加入角色基本信息 (2026-05-24) [刘庆逊提出] 在 studytime-analysis 输出中加入角色基本信息,包括: - 角色ID、账号ID、角色名字、性别、年龄、账号手机号后4位 **数据源(新增)** - MySQL Online `vala_user` 库 - `vala_app_character` 表id, account_id, nickname, gender(0=女/1=男), birthday(varchar \"YYYY-MM-DD\") - `vala_app_account` 表id, tel(已脱敏如 186****1625) - 手机号已脱敏直接取后4位年龄从 birthday 计算 **修改文件** - `skills/studytime-analysis/scripts/studytime_analysis.py`:新增 MySQL 连接函数 `get_mysql_connection()` 和 `fetch_role_info(role_id)`,更新 `format_report()` 输出基本角色信息 - 已验证 2895 正常运行输出 - 已同步 SkillHub + Git ### Unit 显示修复: 季度名称 → 全局单元编号 (2026-05-24) [刘庆逊提出] HTML 报告中 Unit 列显示错误——显示的是季度名称(如\"小镇时光\"\"钢铁之心\"而非单元数字0-48。 **根因分析** - `vala_game_chapter`MySQL无 `unit_", "snippet": "### 增强: 报告开头加入角色基本信息 (2026-05-24) [刘庆逊提出] 在 studytime-analysis 输出中加入角色基本信息,包括: - 角色ID、账号ID、角色名字、性别、年龄、账号手机号后4位 **数据源(新增)** - MySQL Online `vala_user` 库 - `vala_app_character` 表id, account_id, nickname, gender(0=女/1=男), birthday(varchar \"YYYY-MM-DD\") - `vala_app_account` 表id, tel(已脱敏如 186****1625) - 手机号已脱敏直接取后4位年龄从 birthday 计算 **修改文件** - `skills/studytime-analysis/scripts/studytime_analysis.py`:新增 MySQL 连接函数 `get_mysql_connection()` 和 `fetch_role_info(role_id)`,更新 `format_report()` 输出基本角色信息 - 已验证 2895 正常运行输出 - 已同步 SkillHub + Git ### Unit 显示修复: 季度名称 → 全局单元编号 (2026-05-24) [刘庆逊提出] HTML 报告中 Unit 列显示错误——显示的是季度名称(如\"小镇时光\"\"钢铁之心\"而非单元数字0-48。 **根因分析** - `vala_game_chapter`MySQL无 `unit_",
"recallCount": 27, "recallCount": 31,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 27, "totalScore": 31,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-25T05:47:41.388Z", "firstRecalledAt": "2026-05-25T05:47:41.388Z",
"lastRecalledAt": "2026-06-18T00:09:26.923Z", "lastRecalledAt": "2026-06-18T10:17:37.951Z",
"queryHashes": [ "queryHashes": [
"9aff8ec9594a", "9aff8ec9594a",
"566b5958861e", "566b5958861e",
@ -210,7 +210,11 @@
"a87866c0fa75", "a87866c0fa75",
"54487377b5d1", "54487377b5d1",
"ee73b9da86b6", "ee73b9da86b6",
"ee468f64688e" "ee468f64688e",
"872ac2ac6438",
"f4b72dd59b18",
"f536bf691608",
"d83437ba9cad"
], ],
"recallDays": [ "recallDays": [
"2026-05-25", "2026-05-25",
@ -244,13 +248,13 @@
"endLine": 110, "endLine": 110,
"source": "memory", "source": "memory",
"snippet": "- `skills/studytime-analysis/scripts/studytime_analysis.py` — 重写 `fetch_chapter_info_map()`,新增全局 unit_index 计算HTML 模板更新为 Level/Unit/Lesson 三列 - 已为角色 32009zyl重新生成 HTML 并发送 - 已同步 Git + SkillHub ## 新建技能: studycourse-analysis (2026-05-24) [刘庆逊提出] 创建角色上课情况分析技能,从四维度分析角色学习数据。 ### 技能结构 - `skills/studycourse-analysis/SKILL.md` — 技能定义 - `skills/studycourse-analysis/scripts/studycourse_analysis.py` — Python 分析脚本 ### 四步分析 1. **基础信息**:角色姓名/年龄/账号ID/手机号后4位/注册时间/购买渠道/设备/首末次完课 2. **完课耗时**:平均值/中位数、异常检测(<10min / >20min)、前后半段趋势 3. **中互动正确率**Perfect/Good/Oops/Pass/Failed 占比和趋势 4. **知识巩固**:完成率、正确率得分分布 ### 数据源 | 类型 | 库 | 表 | 用途 | |------|-----|-----|------| | MySQL vala_user | vala_app_character | 角色信息、pu", "snippet": "- `skills/studytime-analysis/scripts/studytime_analysis.py` — 重写 `fetch_chapter_info_map()`,新增全局 unit_index 计算HTML 模板更新为 Level/Unit/Lesson 三列 - 已为角色 32009zyl重新生成 HTML 并发送 - 已同步 Git + SkillHub ## 新建技能: studycourse-analysis (2026-05-24) [刘庆逊提出] 创建角色上课情况分析技能,从四维度分析角色学习数据。 ### 技能结构 - `skills/studycourse-analysis/SKILL.md` — 技能定义 - `skills/studycourse-analysis/scripts/studycourse_analysis.py` — Python 分析脚本 ### 四步分析 1. **基础信息**:角色姓名/年龄/账号ID/手机号后4位/注册时间/购买渠道/设备/首末次完课 2. **完课耗时**:平均值/中位数、异常检测(<10min / >20min)、前后半段趋势 3. **中互动正确率**Perfect/Good/Oops/Pass/Failed 占比和趋势 4. **知识巩固**:完成率、正确率得分分布 ### 数据源 | 类型 | 库 | 表 | 用途 | |------|-----|-----|------| | MySQL vala_user | vala_app_character | 角色信息、pu",
"recallCount": 19, "recallCount": 21,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 19, "totalScore": 21,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-25T05:47:41.388Z", "firstRecalledAt": "2026-05-25T05:47:41.388Z",
"lastRecalledAt": "2026-06-18T00:09:26.923Z", "lastRecalledAt": "2026-06-18T10:17:37.951Z",
"queryHashes": [ "queryHashes": [
"9aff8ec9594a", "9aff8ec9594a",
"566b5958861e", "566b5958861e",
@ -270,7 +274,9 @@
"cf2a036061cf", "cf2a036061cf",
"b2c23ece6608", "b2c23ece6608",
"206acd60d69d", "206acd60d69d",
"ee468f64688e" "ee468f64688e",
"f536bf691608",
"d83437ba9cad"
], ],
"recallDays": [ "recallDays": [
"2026-05-25", "2026-05-25",
@ -337,19 +343,20 @@
"endLine": 126, "endLine": 126,
"source": "memory", "source": "memory",
"snippet": "| MySQL vala_user | vala_app_character | 角色信息、purchase_season_package | | MySQL vala_user | vala_app_account | 下载渠道、手机号、注册时间 | | MySQL vala | vala_game_chapter + season_package | 章节映射 | | PostgreSQL vala | user_course_detail | 课程激活/到期时间 | | PostgreSQL vala | user_login_app_info | 设备信息 | | PostgreSQL vala | user_chapter_play_record_0~7 | 完课记录(play_status=1) | | PostgreSQL vala | user_component_play_record_0~7 | 中互动记录(play_result) | | PostgreSQL vala | user_chapter_settlement_data_0~7 | 巩固数据(settlement_data JSON) | ### 关键发现 - **设备信息**来自 `user_login_app_info`device_name/model/type/os_info/city - **购买渠道**来自 `vala_app_account.download_channel` + `key_from` - **巩固判断**`settlement_data.practiceS", "snippet": "| MySQL vala_user | vala_app_character | 角色信息、purchase_season_package | | MySQL vala_user | vala_app_account | 下载渠道、手机号、注册时间 | | MySQL vala | vala_game_chapter + season_package | 章节映射 | | PostgreSQL vala | user_course_detail | 课程激活/到期时间 | | PostgreSQL vala | user_login_app_info | 设备信息 | | PostgreSQL vala | user_chapter_play_record_0~7 | 完课记录(play_status=1) | | PostgreSQL vala | user_component_play_record_0~7 | 中互动记录(play_result) | | PostgreSQL vala | user_chapter_settlement_data_0~7 | 巩固数据(settlement_data JSON) | ### 关键发现 - **设备信息**来自 `user_login_app_info`device_name/model/type/os_info/city - **购买渠道**来自 `vala_app_account.download_channel` + `key_from` - **巩固判断**`settlement_data.practiceS",
"recallCount": 5, "recallCount": 6,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 5, "totalScore": 6,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-27T13:30:03.421Z", "firstRecalledAt": "2026-05-27T13:30:03.421Z",
"lastRecalledAt": "2026-06-18T00:09:26.923Z", "lastRecalledAt": "2026-06-18T10:17:37.951Z",
"queryHashes": [ "queryHashes": [
"71463fe40be2", "71463fe40be2",
"c6c7ff4ed75d", "c6c7ff4ed75d",
"2d6e2b982050", "2d6e2b982050",
"c4fd4a35d234", "c4fd4a35d234",
"ee468f64688e" "ee468f64688e",
"d83437ba9cad"
], ],
"recallDays": [ "recallDays": [
"2026-05-27", "2026-05-27",
@ -376,25 +383,27 @@
"endLine": 16, "endLine": 16,
"source": "memory", "source": "memory",
"snippet": "# 2026-05-13 工作日志 ## 文档权限规则修正 [Cris 确认] **问题:** AGENTS.md 中「权限告知规则」未区分用户身份对所有用户包括业务负责人李应瑛一视同仁地回复「请添加Bot为知识空间成员」。这导致业务负责人被不必要的技术细节阻塞。 **修正:** 更新 AGENTS.md 第3条权限告知规则按用户身份分级处理 - 业务负责人(刘庆逊、李应瑛)→ 不告知权限问题,直接联系 Cris 处理 - 其他用户 → 保持原有提示 **验证:** 对 `小斑` 文档Tn23wQkUQilduAkvgwscTGhgnUd执行了完整的读/写(追加)/删除测试Bot身份权限全部正常。 ## lark-cli 绑定 完成了 lark-cli 与 OpenClaw 的绑定bot-only 模式),后续飞书 API 调用无需额外配置。", "snippet": "# 2026-05-13 工作日志 ## 文档权限规则修正 [Cris 确认] **问题:** AGENTS.md 中「权限告知规则」未区分用户身份对所有用户包括业务负责人李应瑛一视同仁地回复「请添加Bot为知识空间成员」。这导致业务负责人被不必要的技术细节阻塞。 **修正:** 更新 AGENTS.md 第3条权限告知规则按用户身份分级处理 - 业务负责人(刘庆逊、李应瑛)→ 不告知权限问题,直接联系 Cris 处理 - 其他用户 → 保持原有提示 **验证:** 对 `小斑` 文档Tn23wQkUQilduAkvgwscTGhgnUd执行了完整的读/写(追加)/删除测试Bot身份权限全部正常。 ## lark-cli 绑定 完成了 lark-cli 与 OpenClaw 的绑定bot-only 模式),后续飞书 API 调用无需额外配置。",
"recallCount": 5, "recallCount": 6,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 5, "totalScore": 6,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-28T07:37:09.223Z", "firstRecalledAt": "2026-05-28T07:37:09.223Z",
"lastRecalledAt": "2026-06-03T03:03:56.621Z", "lastRecalledAt": "2026-06-18T03:21:04.151Z",
"queryHashes": [ "queryHashes": [
"7031af54381b", "7031af54381b",
"f22544a8757c", "f22544a8757c",
"a556c36dcd13", "a556c36dcd13",
"9acf19355c6a", "9acf19355c6a",
"1382c5611b17" "1382c5611b17",
"872ac2ac6438"
], ],
"recallDays": [ "recallDays": [
"2026-05-28", "2026-05-28",
"2026-05-29", "2026-05-29",
"2026-05-30", "2026-05-30",
"2026-06-03" "2026-06-03",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"agents.md", "agents.md",
@ -414,13 +423,13 @@
"endLine": 92, "endLine": 92,
"source": "memory", "source": "memory",
"snippet": "**根因分析** - `vala_game_chapter`MySQL无 `unit_index` 字段 - `big_map_chapter`PostgreSQL有 `unit_index` 字段,但仅包含 A1 数据,且与 `vala_game_chapter` 无直接关联键 - 两者 ID 空间不重叠big_map: ~1720-2070game_chapter: ~55-399UUID 也不匹配 **映射方案** - 每个 season_package 内,`lesson_type=1` 的章节按 `id` 排序,每 5 个连续章节组成一个单元 - Season 0序章/L1-U0所有章节属于 Unit 0 - Season 1-4每个 season 有 12 个单元60 个 lesson 章节) - 全局 unit_index = base_offset(season_of_quarter) + unit_within_season - base_offset: 0→0, 1→1, 2→13, 3→25, 4→37 **关键 Bug**:初版按 `season_of_quarter` 分组时 A1 和 A2 混在一起,因为相同季度值合并了。修复:改为按 `(level, season_of_quarter)` 分组。 **验证结果** - A1: Unit 0-4849 个单元),与 big_map_chapter 的 unit_index 范围一致 - A2: Unit 0-4950 个单元,比 A1 多 1 个) *", "snippet": "**根因分析** - `vala_game_chapter`MySQL无 `unit_index` 字段 - `big_map_chapter`PostgreSQL有 `unit_index` 字段,但仅包含 A1 数据,且与 `vala_game_chapter` 无直接关联键 - 两者 ID 空间不重叠big_map: ~1720-2070game_chapter: ~55-399UUID 也不匹配 **映射方案** - 每个 season_package 内,`lesson_type=1` 的章节按 `id` 排序,每 5 个连续章节组成一个单元 - Season 0序章/L1-U0所有章节属于 Unit 0 - Season 1-4每个 season 有 12 个单元60 个 lesson 章节) - 全局 unit_index = base_offset(season_of_quarter) + unit_within_season - base_offset: 0→0, 1→1, 2→13, 3→25, 4→37 **关键 Bug**:初版按 `season_of_quarter` 分组时 A1 和 A2 混在一起,因为相同季度值合并了。修复:改为按 `(level, season_of_quarter)` 分组。 **验证结果** - A1: Unit 0-4849 个单元),与 big_map_chapter 的 unit_index 范围一致 - A2: Unit 0-4950 个单元,比 A1 多 1 个) *",
"recallCount": 14, "recallCount": 17,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 14, "totalScore": 17,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-28T09:07:57.953Z", "firstRecalledAt": "2026-05-28T09:07:57.953Z",
"lastRecalledAt": "2026-06-17T09:59:49.133Z", "lastRecalledAt": "2026-06-18T10:17:31.215Z",
"queryHashes": [ "queryHashes": [
"c6c7ff4ed75d", "c6c7ff4ed75d",
"c59410788b42", "c59410788b42",
@ -435,7 +444,10 @@
"02e468d377f4", "02e468d377f4",
"a87866c0fa75", "a87866c0fa75",
"54487377b5d1", "54487377b5d1",
"ee73b9da86b6" "ee73b9da86b6",
"872ac2ac6438",
"f4b72dd59b18",
"f536bf691608"
], ],
"recallDays": [ "recallDays": [
"2026-05-28", "2026-05-28",
@ -445,7 +457,8 @@
"2026-06-09", "2026-06-09",
"2026-06-12", "2026-06-12",
"2026-06-16", "2026-06-16",
"2026-06-17" "2026-06-17",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"vala-game-chapter", "vala-game-chapter",
@ -1386,23 +1399,25 @@
"endLine": 602, "endLine": 602,
"source": "memory", "source": "memory",
"snippet": "**需求:行课记录新增当日进线→当天行课 + 7天首课率 + 销售排名 + 日报展示** **数据摸底结果:** | 指标 | 5月数据 | 定义 | |------|---------|------| | 当日进线→当天行课 | 3.0% (4/135) | 进线当天有 chapter settlement | | 7天线索→首课 | 28.6% (10/35) | 过去7天进线中 小溪阶段≥5 | **按销售拆解:** | 销售 | 当日行课率 | 7天首课率 | |------|-----------|----------| | Bob | 7.4% (最高) | 28.6% | | Tom | 3.7% | 28.6% | | 吴迪 | 0% | 28.6% | | 小龙 | 0% | 14.3% (最低) | **改动方案6处待陈逸鸫确认后执行** 1. **2aNzzy 每日线索分配** — 加 2 列(首课日期 V、当日行课 W 2. **3PRySY 行课情况** — 加 4 列当日行课数、当日行课率、7天线索数、7天首课率 3. **C1HVN2 日报** — 新增「五、行课转化」段 4. **Base 多维表格** — 3 张表加字段tbl9HgnKU2qgj4gE / tblB27fjK7mDnxjY / tblxjCeGOPNoLHl6 5. **funnel-daily 看板 HTML** — 新增「当日转化」+「7天首课」指标 6. **build_pipeline 脚本** — 新增 `scripts/compute_l", "snippet": "**需求:行课记录新增当日进线→当天行课 + 7天首课率 + 销售排名 + 日报展示** **数据摸底结果:** | 指标 | 5月数据 | 定义 | |------|---------|------| | 当日进线→当天行课 | 3.0% (4/135) | 进线当天有 chapter settlement | | 7天线索→首课 | 28.6% (10/35) | 过去7天进线中 小溪阶段≥5 | **按销售拆解:** | 销售 | 当日行课率 | 7天首课率 | |------|-----------|----------| | Bob | 7.4% (最高) | 28.6% | | Tom | 3.7% | 28.6% | | 吴迪 | 0% | 28.6% | | 小龙 | 0% | 14.3% (最低) | **改动方案6处待陈逸鸫确认后执行** 1. **2aNzzy 每日线索分配** — 加 2 列(首课日期 V、当日行课 W 2. **3PRySY 行课情况** — 加 4 列当日行课数、当日行课率、7天线索数、7天首课率 3. **C1HVN2 日报** — 新增「五、行课转化」段 4. **Base 多维表格** — 3 张表加字段tbl9HgnKU2qgj4gE / tblB27fjK7mDnxjY / tblxjCeGOPNoLHl6 5. **funnel-daily 看板 HTML** — 新增「当日转化」+「7天首课」指标 6. **build_pipeline 脚本** — 新增 `scripts/compute_l",
"recallCount": 4, "recallCount": 5,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 4, "totalScore": 5,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-29T06:12:52.521Z", "firstRecalledAt": "2026-05-29T06:12:52.521Z",
"lastRecalledAt": "2026-06-16T06:22:11.809Z", "lastRecalledAt": "2026-06-18T03:21:04.151Z",
"queryHashes": [ "queryHashes": [
"2aa08c6652fb", "2aa08c6652fb",
"6d1afbed352e", "6d1afbed352e",
"ff112f97114e", "ff112f97114e",
"d7be4ba41be4" "d7be4ba41be4",
"872ac2ac6438"
], ],
"recallDays": [ "recallDays": [
"2026-05-29", "2026-05-29",
"2026-06-12", "2026-06-12",
"2026-06-16" "2026-06-16",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"3.0", "3.0",
@ -1611,20 +1626,22 @@
"endLine": 624, "endLine": 624,
"source": "memory", "source": "memory",
"snippet": "6. **build_pipeline 脚本** — 新增 `scripts/compute_lesson_activation.py`PG→2aNzzy V/W **关键数据源映射:** 进线=2aNzzy C列日期 → 用户ID=2aNzzy → PG user_course_detail 首课日期 → 比对同天 → 写回 2aNzzy V/W ### 待办汇总 1. 📋 陈逸鸫确认行课转化改动方案 → 一口气改 6 处 2. 📋 王虹茗 user_id 获取(需她发消息或陈逸鸫截图) 3. 📋 数据转发王虹茗 + 写入大麦查询输出表 fd42b8 4. 📋 销售看板 build 挂住问题排查 5. 📋 Image2 生图任务执行 6. ⏳ 全量 pipeline 聚光验证(子进程) ### 20:52 行课转化全量改动完成 [陈逸鸫确认] 行课记录新增指标:当日进线→当天行课 + 7天首课6处改动已完成4处 | # | 位置 | 改动 | 状态 | |---|------|------|------| | 1 | 2aNzzy | V/W/X 三列(首课日期/当日行课/7日内行课 | ✅ | | 2 | 3PRySY | AE-AH 四列(当日行课/当日行课率/7日内首课/7日内首课率| ✅ | | 3 | C1HVN2 | 合并 三+五 →「线索→行课转化」| ✅ | | 4 | Base | 行课销售月(4)/5月漏斗(3)/销转销售月(2) 加字段 | ⚠️ bot权限不足需手动 | | 5 | funnel-daily 看板 |", "snippet": "6. **build_pipeline 脚本** — 新增 `scripts/compute_lesson_activation.py`PG→2aNzzy V/W **关键数据源映射:** 进线=2aNzzy C列日期 → 用户ID=2aNzzy → PG user_course_detail 首课日期 → 比对同天 → 写回 2aNzzy V/W ### 待办汇总 1. 📋 陈逸鸫确认行课转化改动方案 → 一口气改 6 处 2. 📋 王虹茗 user_id 获取(需她发消息或陈逸鸫截图) 3. 📋 数据转发王虹茗 + 写入大麦查询输出表 fd42b8 4. 📋 销售看板 build 挂住问题排查 5. 📋 Image2 生图任务执行 6. ⏳ 全量 pipeline 聚光验证(子进程) ### 20:52 行课转化全量改动完成 [陈逸鸫确认] 行课记录新增指标:当日进线→当天行课 + 7天首课6处改动已完成4处 | # | 位置 | 改动 | 状态 | |---|------|------|------| | 1 | 2aNzzy | V/W/X 三列(首课日期/当日行课/7日内行课 | ✅ | | 2 | 3PRySY | AE-AH 四列(当日行课/当日行课率/7日内首课/7日内首课率| ✅ | | 3 | C1HVN2 | 合并 三+五 →「线索→行课转化」| ✅ | | 4 | Base | 行课销售月(4)/5月漏斗(3)/销转销售月(2) 加字段 | ⚠️ bot权限不足需手动 | | 5 | funnel-daily 看板 |",
"recallCount": 2, "recallCount": 3,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 2, "totalScore": 3,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-05-31T23:25:36.480Z", "firstRecalledAt": "2026-05-31T23:25:36.480Z",
"lastRecalledAt": "2026-06-12T07:16:32.881Z", "lastRecalledAt": "2026-06-18T03:21:04.151Z",
"queryHashes": [ "queryHashes": [
"679cdd7bd3a8", "679cdd7bd3a8",
"6d1afbed352e" "6d1afbed352e",
"872ac2ac6438"
], ],
"recallDays": [ "recallDays": [
"2026-06-01", "2026-06-01",
"2026-06-12" "2026-06-12",
"2026-06-18"
], ],
"conceptTags": [ "conceptTags": [
"build-pipeline", "build-pipeline",
@ -2358,15 +2375,16 @@
"endLine": 30, "endLine": 30,
"source": "memory", "source": "memory",
"snippet": "- 发现核心 bug`pick_valid_order()` 只取最新一笔有效订单,未做 GSV 聚合 - **根因:** 18621578529account_id=13147有 2 笔有效订单P785... GSV=1,999 + 3734... GSV=1,599汇总只收了最新那笔 1,599丢了 1,999 - **影响范围:** 13 个账户各 2 笔有效订单,漏 GSV ¥23,185 - **修复v2.1** - 新增 `aggregate_valid_orders()` 函数:同一账户多笔有效订单 GSV/GMV/退款累加 - 订单号取未退款那笔(多笔未退款取最新),产品列多单用 `+` 拼接 - Step 4 线索绑单仍用 `pick_valid_order()` 不变 - 已更新 `sales_leads_full_refresh.py` + `skills/full-data-refresh/SKILL.md` - **数据源确认:** 大麦和小溪查的是同一个 PG `vala_bi.bi_vala_order`,数据一致 - **MySQL Makee 交易系统:** 大麦有 read_only 权限但 vala/vala_user/vala_order 库中无订单表,无法直接对比交易系统后台", "snippet": "- 发现核心 bug`pick_valid_order()` 只取最新一笔有效订单,未做 GSV 聚合 - **根因:** 18621578529account_id=13147有 2 笔有效订单P785... GSV=1,999 + 3734... GSV=1,599汇总只收了最新那笔 1,599丢了 1,999 - **影响范围:** 13 个账户各 2 笔有效订单,漏 GSV ¥23,185 - **修复v2.1** - 新增 `aggregate_valid_orders()` 函数:同一账户多笔有效订单 GSV/GMV/退款累加 - 订单号取未退款那笔(多笔未退款取最新),产品列多单用 `+` 拼接 - Step 4 线索绑单仍用 `pick_valid_order()` 不变 - 已更新 `sales_leads_full_refresh.py` + `skills/full-data-refresh/SKILL.md` - **数据源确认:** 大麦和小溪查的是同一个 PG `vala_bi.bi_vala_order`,数据一致 - **MySQL Makee 交易系统:** 大麦有 read_only 权限但 vala/vala_user/vala_order 库中无订单表,无法直接对比交易系统后台",
"recallCount": 1, "recallCount": 2,
"dailyCount": 0, "dailyCount": 0,
"groundedCount": 0, "groundedCount": 0,
"totalScore": 1, "totalScore": 2,
"maxScore": 1, "maxScore": 1,
"firstRecalledAt": "2026-06-18T00:09:26.923Z", "firstRecalledAt": "2026-06-18T00:09:26.923Z",
"lastRecalledAt": "2026-06-18T00:09:26.923Z", "lastRecalledAt": "2026-06-18T10:17:37.951Z",
"queryHashes": [ "queryHashes": [
"ee468f64688e" "ee468f64688e",
"d83437ba9cad"
], ],
"recallDays": [ "recallDays": [
"2026-06-18" "2026-06-18"
@ -2381,6 +2399,37 @@
"vala-bi.bi-vala-order", "vala-bi.bi-vala-order",
"read-only" "read-only"
] ]
},
"memory:memory/2026-06-17.md:1:23": {
"key": "memory:memory/2026-06-17.md:1:23",
"path": "memory/2026-06-17.md",
"startLine": 1,
"endLine": 23,
"source": "memory",
"snippet": "# 2026-06-17 工作日志 ## 数据查询审批 - **16:43** 刘亚伟user_id: 5f96bf7e在「麦动乾坤💰」群 @大麦请求导出角色ID 35012 的学习数据 - 刘亚伟不在 USER.md 权限列表中,属于第三级用户 - 已通知陈逸鸫8315a98e审批等待回复 - 消息ID: om_x100b6c11a0f1e8a0b3c5738760130d7 - **16:46** 陈逸鸫确认批准 - **16:47** 导出完成音频768条、互动组件514条、课程巩固19条、单元挑战14条、单元总结6条总计1321条 - **16:49** 文件已发送至麦动乾坤群oc_55cb96a8f6c7fa4020253fb2854371c5 - 文件路径: output/角色id_35012_导出时间_20260617.xlsx ## 财务核对群 — GSV 差异排查与修复 [陈逸鸫] - **问题:** 细水入海订单汇总 GSV 与李玉老师从系统拉出的 GSV 差异大 - **排查过程:** - 审计 E1E9 全 0 ✅,绑单逻辑无问题 - 同一订单号集合404个汇总表 GSV=952,805 vs DB GSV=951,105差异仅 ¥1,700 - 发现核心 bug`pick_valid_order()` 只取最新一笔有效订单,未做 GSV 聚合 - **根因:** 18621578529account_id=13147有 2 笔有效订单P785... GSV=1,999 + 3734... GS",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-06-18T04:44:32.687Z",
"lastRecalledAt": "2026-06-18T04:44:32.687Z",
"queryHashes": [
"f4b72dd59b18"
],
"recallDays": [
"2026-06-18"
],
"conceptTags": [
"user-id",
"user.md",
"pick-valid-order",
"account-id",
"工作",
"日志",
"数据",
"查询"
]
} }
} }
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,16 +1,18 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Bot 销转看板 Step2 刷新 XXTEA 精确匹配版 (v3) Bot 销转看板 Step2 刷新 XXTEA 精确匹配版 (v4 · UID 口径)
E列11位明文手机号 XXTEA加密 bi_vala_app_account.tel_encrypt精确匹配 H列UID E列11位明文手机号 XXTEA加密 bi_vala_app_account.tel_encrypt精确匹配 H列UID
S2 规则: S2 规则 (2026-06-18 列契约):
EH: phone_encrypt.py XXTEA 精确匹配, 查不到留空 EH: phone_encrypt.py XXTEA 精确匹配, 查不到留空
HD/I/J: 只补空, 不覆盖已有值 HD/I/J: 只补空, 不覆盖已有值
Y=1: 仅当 K(下单日) >= C(线索日期) X=1: GSV>0 且非全额退且 KC
全额退清: 所有订单都退费 N/O/P 全部清空 全额退清: 所有订单都退费 X=0, K-P 清空
N/O/P 0留空, O整元 N/O/P 0留空, O整元
G列不动, 订单汇总不动 G列不动, 订单汇总不动
覆盖列: D/H/I/J + K-U + X/Y/Z V/W 列不覆盖Cursor 维护
X=有效0/1, Y=渠道归属, 不写订单号
覆盖列: D/H/I/J + K-U + X/Y
""" """
import json, re, time, sys, os, requests, psycopg2 import json, re, time, sys, os, requests, psycopg2
from datetime import datetime from datetime import datetime
@ -27,9 +29,9 @@ from phone_encrypt import encrypt_phone
SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug" SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug"
SALES_SHEETS = [ SALES_SHEETS = [
("qJF4I", "小龙", "A1:Z1200"), ("qJF4I", "小龙", "A1:Y1200"),
("f975f0", "吴迪", "A1:Z700"), ("f975f0", "吴迪", "A1:Y700"),
("qJF4J", "成都", "A1:Z2500"), ("qJF4J", "成都", "A1:Y2500"),
] ]
CS_MAP = {"吴迪": "吴迪", "小龙": "小龙", "Tom": "Tom", "Bob": "Bob"} CS_MAP = {"吴迪": "吴迪", "小龙": "小龙", "Tom": "Tom", "Bob": "Bob"}
@ -496,7 +498,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
k_vals, l_vals, m_vals, n_vals = [], [], [], [] k_vals, l_vals, m_vals, n_vals = [], [], [], []
o_vals, p_vals, q_vals, r_vals = [], [], [], [] o_vals, p_vals, q_vals, r_vals = [], [], [], []
s_vals, t_vals, u_vals = [], [], [] s_vals, t_vals, u_vals = [], [], []
x_vals, y_vals, z_vals = [], [], [] x_vals, y_vals = [], []
for item in g: for item in g:
phone = item["phone"] phone = item["phone"]
@ -553,7 +555,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
valid_order, is_valid = pick_valid_order(orders, clue_date) valid_order, is_valid = pick_valid_order(orders, clue_date)
if is_valid and valid_order: if is_valid and valid_order:
# Y=1: K/L/X/N/O/P/Z 全写该有效单真实值 # X=1: K/L/M/N/O/P 全写该有效单真实值
pay_dt = valid_order["pay_dt"] pay_dt = valid_order["pay_dt"]
order_date = f"{pay_dt.month}{pay_dt.day}{pay_dt.strftime('%H:%M:%S')}" if pay_dt else "" order_date = f"{pay_dt.month}{pay_dt.day}{pay_dt.strftime('%H:%M:%S')}" if pay_dt else ""
k_vals.append([order_date]) k_vals.append([order_date])
@ -562,22 +564,19 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
n_vals.append([int(valid_order["pay_amount"]) if valid_order["pay_amount"] > 0 else ""]) n_vals.append([int(valid_order["pay_amount"]) if valid_order["pay_amount"] > 0 else ""])
o_vals.append([int(valid_order["refund_amount"]) if valid_order["refund_amount"] > 0 else ""]) o_vals.append([int(valid_order["refund_amount"]) if valid_order["refund_amount"] > 0 else ""])
p_vals.append([int(valid_order["gsv"]) if valid_order["gsv"] > 0 else ""]) p_vals.append([int(valid_order["gsv"]) if valid_order["gsv"] > 0 else ""])
x_vals.append([valid_order["trade_no"]]) x_vals.append([1]) # X=有效0/1
y_vals.append([1]) y_vals.append([classify_channel(valid_order["key_from"])]) # Y=渠道
z_vals.append([classify_channel(valid_order["key_from"])])
elif di["has_order"]: elif di["has_order"]:
# 有订单但无有效单 → Y=0, K/L/X 留空, N/O/P 不写 # 有订单但无有效单 → X=0, K/L 留空
k_vals.append([""]) k_vals.append([""])
l_vals.append([""]) l_vals.append([""])
m_vals.append([""]) m_vals.append([""])
n_vals.append([""]) n_vals.append([""])
o_vals.append([""]) o_vals.append([""])
p_vals.append([""]) p_vals.append([""])
x_vals.append([""]) x_vals.append([0])
y_vals.append([""]) y_vals.append([""])
z_vals.append([""])
else: else:
# 无订单
k_vals.append([""]) k_vals.append([""])
l_vals.append([""]) l_vals.append([""])
m_vals.append([""]) m_vals.append([""])
@ -586,7 +585,6 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
p_vals.append([""]) p_vals.append([""])
x_vals.append([""]) x_vals.append([""])
y_vals.append([""]) y_vals.append([""])
z_vals.append([""])
# Q: 激活课程 # Q: 激活课程
act = di["activation"] act = di["activation"]
@ -606,7 +604,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
else: else:
for arr in [d_vals, i_vals, j_vals, k_vals, l_vals, m_vals, n_vals, for arr in [d_vals, i_vals, j_vals, k_vals, l_vals, m_vals, n_vals,
o_vals, p_vals, q_vals, r_vals, s_vals, t_vals, o_vals, p_vals, q_vals, r_vals, s_vals, t_vals,
x_vals, y_vals, z_vals]: x_vals, y_vals]:
arr.append([""]) arr.append([""])
# U: 更新时间 # U: 更新时间
@ -617,7 +615,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
("K", k_vals), ("L", l_vals), ("M", m_vals), ("N", n_vals), ("K", k_vals), ("L", l_vals), ("M", m_vals), ("N", n_vals),
("O", o_vals), ("P", p_vals), ("Q", q_vals), ("R", r_vals), ("O", o_vals), ("P", p_vals), ("Q", q_vals), ("R", r_vals),
("S", s_vals), ("T", t_vals), ("U", u_vals), ("S", s_vals), ("T", t_vals), ("U", u_vals),
("X", x_vals), ("Y", y_vals), ("Z", z_vals), ("X", x_vals), ("Y", y_vals),
] ]
for col_letter, vals in cols: for col_letter, vals in cols:
put_values(token, sid, f"{col_letter}{sr}:{col_letter}{er}", vals) put_values(token, sid, f"{col_letter}{sr}:{col_letter}{er}", vals)

View File

@ -1,21 +1,23 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
销售线索全量刷新脚本 XXTEA 精确匹配版 销售线索全量刷新脚本 XXTEA 精确匹配版 · UID 口径 v2
功能: 功能:
1. 读取小龙吴迪成都三个 sheet E 列手机号 1. 读取小龙吴迪成都三个 sheet E 列手机号
2. XXTEA 加密 bi_vala_app_account.tel_encrypt 精确匹配 获取 account_id 2. XXTEA 加密 bi_vala_app_account.tel_encrypt 精确匹配 获取 account_id
3. 查询 PostgreSQL 获取用户订单/学习数据 3. 查询 PostgreSQL 获取用户订单/学习数据
4. 填写 D/H/I/J/K~U/X/Y/Z 自动U 列为操作更新时间 4. 填写 D/H/I/J/K~U/X/Y A-Y 共25U 列为操作更新时间
5. 将三个 sheet Y=1有效订单的用户汇总到订单汇总sheet 5. 将三个 sheet X=1有效订单的用户UID 聚合汇总到订单汇总sheet
规则沿用 S2 规则: 规则2026-06-18 列契约 v2:
EH: XXTEA 精确匹配, 查不到留空 EH: XXTEA 精确匹配, 查不到留空
HD/I/J: 只补空, 不覆盖已有值 HD/I/J: 只补空, 不覆盖已有值
Y=1: 仅当 K(下单日) >= C(线索日期) X=1: GSV>0 且非全额退且 KC
全额退清: 所有订单都退费 N/O/P 全部清空 全额退清: 所有订单都退费 X=0, K-P 清空
N/O/P 0 留空, O 整元 N/O/P 0 留空, O 整元
G 列不动 G 列不动
V/W 列不覆盖Cursor 维护
X=有效0/1, Y=渠道归属, 不写订单号
用法: 用法:
python3 scripts/sales_leads_full_refresh.py python3 scripts/sales_leads_full_refresh.py
@ -36,9 +38,9 @@ from phone_encrypt import encrypt_phone
SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug" SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug"
SALES_SHEETS = [ SALES_SHEETS = [
("qJF4I", "小龙", "A3:Z2607"), ("qJF4I", "小龙", "A3:Y2607"),
("f975f0", "吴迪", "A3:Z8149"), ("f975f0", "吴迪", "A3:Y8149"),
("qJF4J", "成都", "A3:Z2500"), ("qJF4J", "成都", "A3:Y2500"),
] ]
SUMMARY_SHEET_ID = "2smjwA" SUMMARY_SHEET_ID = "2smjwA"
@ -226,7 +228,6 @@ def parse_sales_sheets(token):
"U": safe_cell(row, 20), "U": safe_cell(row, 20),
"X": safe_cell(row, 23), "X": safe_cell(row, 23),
"Y": safe_cell(row, 24), "Y": safe_cell(row, 24),
"Z": safe_cell(row, 25),
}, },
}) })
@ -624,7 +625,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
k_vals, l_vals, m_vals, n_vals = [], [], [], [] k_vals, l_vals, m_vals, n_vals = [], [], [], []
o_vals, p_vals, q_vals, r_vals = [], [], [], [] o_vals, p_vals, q_vals, r_vals = [], [], [], []
s_vals, t_vals, u_vals = [], [], [] s_vals, t_vals, u_vals = [], [], []
x_vals, y_vals, z_vals = [], [], [] x_vals, y_vals = [], []
for e in g: for e in g:
phone = e["phone"] phone = e["phone"]
@ -678,7 +679,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
valid_order, is_valid = pick_valid_order(orders, clue_date) valid_order, is_valid = pick_valid_order(orders, clue_date)
if is_valid and valid_order: if is_valid and valid_order:
# Y=1: K/L/X/N/O/P/Z 全写该有效单真实值 # Y=1: K/L/M/N/O/P 全写该有效单真实值
pay_dt = valid_order["pay_dt"] pay_dt = valid_order["pay_dt"]
order_date = f"{pay_dt.month}{pay_dt.day}{pay_dt.strftime('%H:%M:%S')}" if pay_dt else "" order_date = f"{pay_dt.month}{pay_dt.day}{pay_dt.strftime('%H:%M:%S')}" if pay_dt else ""
k_vals.append([order_date]) k_vals.append([order_date])
@ -687,20 +688,18 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
n_vals.append([int(valid_order["pay_amount"]) if valid_order["pay_amount"] > 0 else ""]) n_vals.append([int(valid_order["pay_amount"]) if valid_order["pay_amount"] > 0 else ""])
o_vals.append([int(valid_order["refund_amount"]) if valid_order["refund_amount"] > 0 else ""]) o_vals.append([int(valid_order["refund_amount"]) if valid_order["refund_amount"] > 0 else ""])
p_vals.append([int(valid_order["gsv"]) if valid_order["gsv"] > 0 else ""]) p_vals.append([int(valid_order["gsv"]) if valid_order["gsv"] > 0 else ""])
x_vals.append([valid_order["trade_no"]]) x_vals.append([1]) # X=有效0/1
y_vals.append([1]) y_vals.append([classify_channel(valid_order["key_from"])]) # Y=渠道
z_vals.append([classify_channel(valid_order["key_from"])])
elif di["has_order"]: elif di["has_order"]:
# 有订单但无有效单 → Y=0, K/L/X 留空 # 有订单但无有效单 → X=0, K/L 留空
k_vals.append([""]) k_vals.append([""])
l_vals.append([""]) l_vals.append([""])
m_vals.append([""]) m_vals.append([""])
n_vals.append([""]) n_vals.append([""])
o_vals.append([""]) o_vals.append([""])
p_vals.append([""]) p_vals.append([""])
x_vals.append([""]) x_vals.append([0])
y_vals.append([""]) y_vals.append([""])
z_vals.append([""])
else: else:
k_vals.append([""]) k_vals.append([""])
l_vals.append([""]) l_vals.append([""])
@ -710,7 +709,6 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
p_vals.append([""]) p_vals.append([""])
x_vals.append([""]) x_vals.append([""])
y_vals.append([""]) y_vals.append([""])
z_vals.append([""])
# Q: 激活课程 # Q: 激活课程
act = di["activation"] act = di["activation"]
@ -727,7 +725,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
else: else:
for arr in [d_vals, i_vals, j_vals, k_vals, l_vals, m_vals, n_vals, for arr in [d_vals, i_vals, j_vals, k_vals, l_vals, m_vals, n_vals,
o_vals, p_vals, q_vals, r_vals, s_vals, t_vals, o_vals, p_vals, q_vals, r_vals, s_vals, t_vals,
x_vals, y_vals, z_vals]: x_vals, y_vals]:
arr.append([""]) arr.append([""])
# U: 更新时间 # U: 更新时间
@ -738,7 +736,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info):
("K", k_vals), ("L", l_vals), ("M", m_vals), ("N", n_vals), ("K", k_vals), ("L", l_vals), ("M", m_vals), ("N", n_vals),
("O", o_vals), ("P", p_vals), ("Q", q_vals), ("R", r_vals), ("O", o_vals), ("P", p_vals), ("Q", q_vals), ("R", r_vals),
("S", s_vals), ("T", t_vals), ("U", u_vals), ("S", s_vals), ("T", t_vals), ("U", u_vals),
("X", x_vals), ("Y", y_vals), ("Z", z_vals), ("X", x_vals), ("Y", y_vals),
] ]
for col_letter, vals in cols: for col_letter, vals in cols:
put_values(token, sid, f"{col_letter}{sr}:{col_letter}{er}", vals) put_values(token, sid, f"{col_letter}{sr}:{col_letter}{er}", vals)
@ -773,24 +771,23 @@ def clear_summary_sheet(token):
def write_summary_sheet(token, all_entries, phone_map, db_info): def write_summary_sheet(token, all_entries, phone_map, db_info):
""" """
订单汇总: 唯一真源 = 三表 Y=1 gate unique X 订单汇总: 唯一真源 = 三表 X=1 gate unique UID
gate 行全量重建A-U 镜像 gate V=Z(或classify L)W=X gate 行全量重建A-U 镜像 gate V=渠道W 留空
X 多进线 只保留 1 行号最小 1 UID = 1 UID 聚合 N/O/P
UID 多进线 只保留 1 行号最小
""" """
clear_summary_sheet(token) clear_summary_sheet(token)
log(" 汇总订单数据(gate 全量重建)...") log(" 汇总订单数据(UID gate 全量重建)...")
# 从三表收集 Y=1 行 # 从三表收集 X=1 行gate 门禁)
gate_rows = [] gate_rows = []
for sid, sname, _ in SALES_SHEETS: for sid, sname, _ in SALES_SHEETS:
entries = all_entries[sid] entries = all_entries[sid]
for e in entries: for e in entries:
# 读取当前行的 Y 和 X写入后的值
existing = e["existing"]
# Y 值已在上一步写入,这里用 phone_map + db_info 重新判断
phone = e["phone"] phone = e["phone"]
clue_date = e["clue_date_parsed"] clue_date = e["clue_date_parsed"]
existing = e["existing"]
aid = 0 aid = 0
if re.match(r'^\d{11}$', phone) and phone in phone_map: if re.match(r'^\d{11}$', phone) and phone in phone_map:
@ -808,7 +805,6 @@ def write_summary_sheet(token, all_entries, phone_map, db_info):
if not is_valid or not agg_result: if not is_valid or not agg_result:
continue continue
trade_no = agg_result["best_trade_no"]
latest = agg_result["latest_order"] latest = agg_result["latest_order"]
pay_dt = latest["pay_dt"] pay_dt = latest["pay_dt"]
order_date = f"{pay_dt.month}{pay_dt.day}{pay_dt.strftime('%H:%M:%S')}" if pay_dt else "" order_date = f"{pay_dt.month}{pay_dt.day}{pay_dt.strftime('%H:%M:%S')}" if pay_dt else ""
@ -836,21 +832,20 @@ def write_summary_sheet(token, all_entries, phone_map, db_info):
di.get("lesson_minutes", 0) or "", # T: 学习时长 di.get("lesson_minutes", 0) or "", # T: 学习时长
datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # U: 更新时间 datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # U: 更新时间
classify_channel(latest["key_from"]), # V: 渠道归属 classify_channel(latest["key_from"]), # V: 渠道归属
trade_no, # W: 订单号(取未退款那笔 "", # W: 留空(不再写 trade_no
] ]
gate_rows.append((trade_no, e["row"], row_data)) gate_rows.append((aid, e["row"], row_data))
# 同 X 多进线 → 只保留行号最小的 1 行 # 同 UID 多进线 → 只保留行号最小的 1 行
seen_trade = {} seen_uid = {}
deduped = [] deduped = []
for trade_no, row_num, row_data in sorted(gate_rows, key=lambda x: x[1]): for uid, row_num, row_data in sorted(gate_rows, key=lambda x: x[1]):
if trade_no and trade_no in seen_trade: if uid in seen_uid:
continue continue
if trade_no: seen_uid[uid] = True
seen_trade[trade_no] = True
deduped.append(row_data) deduped.append(row_data)
log(f"{len(gate_rows)} 条 gate 行, 去重后 {len(deduped)} 条, 唯一订单号 {len(seen_trade)}") log(f"{len(gate_rows)} 条 gate 行, 去重后 {len(deduped)} 行, 唯一 UID {len(seen_uid)}")
if not deduped: if not deduped:
log(" 无有效订单,跳过汇总") log(" 无有效订单,跳过汇总")
@ -859,7 +854,6 @@ def write_summary_sheet(token, all_entries, phone_map, db_info):
# 写入订单汇总 sheet从第3行开始A~W 共23列 # 写入订单汇总 sheet从第3行开始A~W 共23列
writer = FeishuSheetWriter(SPREADSHEET_TOKEN, token) writer = FeishuSheetWriter(SPREADSHEET_TOKEN, token)
# 构建 A~W 的值数组23列确保每行长度一致
values = [] values = []
for row_data in deduped: for row_data in deduped:
padded = row_data[:23] padded = row_data[:23]

View File

@ -13,16 +13,15 @@ metadata:
# 细水入海 — 销售数据全量刷新 # 细水入海 — 销售数据全量刷新
> **版本:** v2.12026-06-17 · GSV 聚合修复 > **版本:** v3.02026-06-18 · UID 口径 · 删 X 列订单号
> **协作契约:** `xhs-ark-dashboard/docs/bot-full-refresh-v2.md` > **协作契约:** `xhs-ark-dashboard/docs/bot-uid-centric-orders-v1.md`
> **大麦侧主文档:** `xhs-ark-dashboard/docs/damai-full-refresh-skill.md` > **大麦侧主文档:** `xhs-ark-dashboard/docs/damai-full-refresh-skill.md`
> >
> ### v2.1 变更2026-06-17 > ### v3.0 变更2026-06-18 · 列契约更新)
> - **GSV 聚合修复:** 订单汇总 Step 5 改用 `aggregate_valid_orders()` 替代 `pick_valid_order()` > - **三表 AY25列** 物理删除 X 列订单号X→有效0/1Y→渠道归属
> - 同一账户多笔有效订单 → GSV/GMV/退款 全部累加(不再只取最新一笔) > - **汇总 1 UID = 1 行:** 按 UID 去重聚合 N/O/PW 留空(不再写 trade_no
> - 订单号取未退款那笔(多笔未退款取最新) > - **gate 门禁:** X=1GSV>0 且非全额退且 K≥C
> - 产品列多单用 `+` 拼接 > - **线索绑单Step 4仍用 `pick_valid_order()` 不变**
> - 线索绑单Step 4仍用 `pick_valid_order()` 不变
## 核心架构规则(写死,不可漂移) ## 核心架构规则(写死,不可漂移)
@ -31,16 +30,16 @@ metadata:
- 共用 `pick_valid_order()` 函数 + 同一份 `db_info` 数据 - 共用 `pick_valid_order()` 函数 + 同一份 `db_info` 数据
- 禁止分两次 run 或使用不同数据源 - 禁止分两次 run 或使用不同数据源
### 2. 汇总 W = 三表 Xgate 同源 ### 2. 汇总 W 留空(不再写 trade_no
- 订单汇总 W 列取的是 `valid_order["trade_no"]`,与三表 X 列写入的值**完全一致** - 订单汇总 W 列留空,不再写订单号
- **不是** merge 时再查 DB 写 W - 汇总唯一真源 = 三表 X=1 gate 的 unique UID
- 唯一真源 = 三表 Y=1 gate 的 unique X - 1 UID = 1 行,按 UID 聚合 N/O/P
### 3. 2smjwAclear → gate 全量覆盖 ### 3. 2smjwAclear → UID gate 全量覆盖
- 先 `clear_summary_sheet()` 清空旧数据区 - 先 `clear_summary_sheet()` 清空旧数据区
- 再 gate 全量重建:从三表 Y=1 行收集 unique X → 每 X 一行 - 再 gate 全量重建:从三表 X=1 行收集 unique UID → 每 UID 一行
- **不保留旧 W**,不 append - **不保留旧 W**,不 append
- 同 X 多进线 → 只保留行号最小的 1 行 - 同 UID 多进线 → 只保留行号最小的 1 行
### 4. 「保留 X/Y」只三表 mirror不含汇总 ### 4. 「保留 X/Y」只三表 mirror不含汇总
- 三表 D/I/J 只补空、G 列不动 → 这些是 mirror 规则 - 三表 D/I/J 只补空、G 列不动 → 这些是 mirror 规则
@ -48,13 +47,13 @@ metadata:
### 5. 线索 1进线=1行 · 只绑有效单 ### 5. 线索 1进线=1行 · 只绑有效单
- 三表永远 1 次进线 = 1 行,不因多单拆行 - 三表永远 1 次进线 = 1 行,不因多单拆行
- Y=1 时 K/L/X/N/O/P/Z 全写有效主单真实值 - X=1 时 K/L/M/N/O/P 全写有效主单真实值
- 已退单不写旧 X/L`pick_valid_order` 自动跳过全额退 + K<C 的订单 - 已退单不写旧 K/L`pick_valid_order` 自动跳过全额退 + K<C 的订单
- 无有效单 → Y=0K/L/X 留空 - 无有效单 → X=0K/L 留空
### 6. 完成后群回「full_refresh 完成」 ### 6. 完成后群回「full_refresh 完成」
- 在数据更新群(`oc_4687e8f9f38e4f5c819238c78f97ae44`)回复 - 在数据更新群(`oc_4687e8f9f38e4f5c819238c78f97ae44`)回复
- 附带验证结果gate X 数 = 汇总 W - 附带验证结果gate UID 数 = 汇总 UID
## 验收标准 ## 验收标准
@ -63,9 +62,9 @@ Cursor 侧跑(大麦可自测):
- `audit_lead_primary_order_bind.py` - `audit_lead_primary_order_bind.py`
PASS 条件: PASS 条件:
- unique X 三表 = 汇总(当前 406=406 - unique UID 三表 = 汇总
- 绑单审计 E1E9 全部 0 - 绑单审计 E1E9 全部 0
- 孤儿 X有 X 但 Y≠1= 0 - 孤儿 UID有 UID 但 X≠1= 0
## 脚本位置 ## 脚本位置
@ -91,7 +90,7 @@ PASS 条件:
- **过程数据:** `3aOvV6` - **过程数据:** `3aOvV6`
- **凭据目录:** `/root/.openclaw/credentials/xiaoxi` - **凭据目录:** `/root/.openclaw/credentials/xiaoxi`
## 销售表列结构 (A-Z) ## 销售表列结构 (A-Y, 25列)
| 列 | 字段 | 说明 | | 列 | 字段 | 说明 |
|----|------|------| |----|------|------|
@ -118,9 +117,8 @@ PASS 条件:
| U | 更新时间 | | | U | 更新时间 | |
| V | 微伴 | Cursor 维护,勿覆盖 | | V | 微伴 | Cursor 维护,勿覆盖 |
| W | 时序公式 | Cursor 维护,勿覆盖 | | W | 时序公式 | Cursor 维护,勿覆盖 |
| X | 订单号 | 仅 Y=1 时写入有效主单号 | | X | 有效订单 | 1=是, 0=否, 空=无订单 |
| Y | 有效订单 | 1=是, 空=否 | | Y | 渠道归属 | 端内/销转/达人/直购 |
| Z | 渠道归属 | 端内/销转/达人/直购 |
## 数据规则 ## 数据规则
@ -130,7 +128,7 @@ PASS 条件:
3. **G 列:** 不动 3. **G 列:** 不动
4. **V/W 列:** 不覆盖Cursor 维护) 4. **V/W 列:** 不覆盖Cursor 维护)
### 有效订单判定 (Y=1) ### 有效订单判定 (X=1)
- `pick_valid_order()`: GSV>0 · 非全额退 · K≥C - `pick_valid_order()`: GSV>0 · 非全额退 · K≥C
- 一手机多单 → 取最新一笔满足门禁的有效单 - 一手机多单 → 取最新一笔满足门禁的有效单
- 已退单不出现在线索行 - 已退单不出现在线索行
@ -139,10 +137,10 @@ PASS 条件:
- 所有订单都退费 (GMV == 退款) → 该单不参与有效单选取 - 所有订单都退费 (GMV == 退款) → 该单不参与有效单选取
### 订单汇总进表条件 ### 订单汇总进表条件
- Y=1已在三表筛选汇总默认全是有效单 - X=1已在三表筛选汇总默认全是有效单
- GSV>0 · 非全额退 · K≥C - GSV>0 · 非全额退 · K≥C
- **同一账户多笔有效订单 → GSV/GMV/退款 累加,订单号取未退款那笔**v2.1 修复) - **同一 UID 多笔有效订单 → GSV/GMV/退款 累加**v2.1 修复)
- 同 X 多进线 → 汇总只保留 1 行 - 同 UID 多进线 → 汇总只保留 1 行
### 渠道归属分类 (Z列) [王虹茗确认 2026-06-15] ### 渠道归属分类 (Z列) [王虹茗确认 2026-06-15]
@ -205,9 +203,9 @@ cd /root/.openclaw/workspace-xiaoban && python3 scripts/refresh_order_summary.py
|----|------|------| |----|------|------|
| A-U | 镜像三表 | 与销售三表 A-U 列一致 | | A-U | 镜像三表 | 与销售三表 A-U 列一致 |
| V | 渠道归属 | 端内/销转/达人/直购 | | V | 渠道归属 | 端内/销转/达人/直购 |
| W | 订单号 | = 三表 Xgate 同源) | | W | 留空 | 不再写 trade_no |
> 2026-06-16 新契约:去掉原 W「有效成单」列订单号从 X 左移到 W。汇总唯一真源 = 三表 Y=1 gate 的 unique X。全量清空重写,不保留旧行。 > 2026-06-18 新契约:物理删除 X 列订单号W 留空。汇总唯一真源 = 三表 X=1 gate 的 unique UID。1 UID = 1 行,按 UID 聚合 N/O/P。全量清空重写,不保留旧行。
## 常见问题 ## 常见问题