diff --git a/logs/backup.log b/logs/backup.log index 997c608..045fe61 100644 --- a/logs/backup.log +++ b/logs/backup.log @@ -630,3 +630,11 @@ To https://git.valavala.com/ai_member_only/ai_member_xiaoban 3703b73..2b86823 master -> master [2026-06-17 08:10:02] 工作区备份成功:自动备份 2026-06-17 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 diff --git a/memory/.dreams/events.jsonl b/memory/.dreams/events.jsonl index 039aab2..4cedfb7 100644 --- a/memory/.dreams/events.jsonl +++ b/memory/.dreams/events.jsonl @@ -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: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-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}]} diff --git a/memory/.dreams/short-term-recall.json b/memory/.dreams/short-term-recall.json index 01e796c..27efdf7 100644 --- a/memory/.dreams/short-term-recall.json +++ b/memory/.dreams/short-term-recall.json @@ -1,6 +1,6 @@ { "version": 1, - "updatedAt": "2026-06-18T00:09:26.923Z", + "updatedAt": "2026-06-18T10:17:37.951Z", "entries": { "memory:memory/2026-05-24.md:1:30": { "key": "memory:memory/2026-05-24.md:1:30", @@ -176,13 +176,13 @@ "endLine": 71, "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_", - "recallCount": 27, + "recallCount": 31, "dailyCount": 0, "groundedCount": 0, - "totalScore": 27, + "totalScore": 31, "maxScore": 1, "firstRecalledAt": "2026-05-25T05:47:41.388Z", - "lastRecalledAt": "2026-06-18T00:09:26.923Z", + "lastRecalledAt": "2026-06-18T10:17:37.951Z", "queryHashes": [ "9aff8ec9594a", "566b5958861e", @@ -210,7 +210,11 @@ "a87866c0fa75", "54487377b5d1", "ee73b9da86b6", - "ee468f64688e" + "ee468f64688e", + "872ac2ac6438", + "f4b72dd59b18", + "f536bf691608", + "d83437ba9cad" ], "recallDays": [ "2026-05-25", @@ -244,13 +248,13 @@ "endLine": 110, "source": "memory", "snippet": "- `skills/studytime-analysis/scripts/studytime_analysis.py` — 重写 `fetch_chapter_info_map()`,新增全局 unit_index 计算;HTML 模板更新为 Level/Unit/Lesson 三列 - 已为角色 32009(zyl)重新生成 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, "groundedCount": 0, - "totalScore": 19, + "totalScore": 21, "maxScore": 1, "firstRecalledAt": "2026-05-25T05:47:41.388Z", - "lastRecalledAt": "2026-06-18T00:09:26.923Z", + "lastRecalledAt": "2026-06-18T10:17:37.951Z", "queryHashes": [ "9aff8ec9594a", "566b5958861e", @@ -270,7 +274,9 @@ "cf2a036061cf", "b2c23ece6608", "206acd60d69d", - "ee468f64688e" + "ee468f64688e", + "f536bf691608", + "d83437ba9cad" ], "recallDays": [ "2026-05-25", @@ -337,19 +343,20 @@ "endLine": 126, "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", - "recallCount": 5, + "recallCount": 6, "dailyCount": 0, "groundedCount": 0, - "totalScore": 5, + "totalScore": 6, "maxScore": 1, "firstRecalledAt": "2026-05-27T13:30:03.421Z", - "lastRecalledAt": "2026-06-18T00:09:26.923Z", + "lastRecalledAt": "2026-06-18T10:17:37.951Z", "queryHashes": [ "71463fe40be2", "c6c7ff4ed75d", "2d6e2b982050", "c4fd4a35d234", - "ee468f64688e" + "ee468f64688e", + "d83437ba9cad" ], "recallDays": [ "2026-05-27", @@ -376,25 +383,27 @@ "endLine": 16, "source": "memory", "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, "groundedCount": 0, - "totalScore": 5, + "totalScore": 6, "maxScore": 1, "firstRecalledAt": "2026-05-28T07:37:09.223Z", - "lastRecalledAt": "2026-06-03T03:03:56.621Z", + "lastRecalledAt": "2026-06-18T03:21:04.151Z", "queryHashes": [ "7031af54381b", "f22544a8757c", "a556c36dcd13", "9acf19355c6a", - "1382c5611b17" + "1382c5611b17", + "872ac2ac6438" ], "recallDays": [ "2026-05-28", "2026-05-29", "2026-05-30", - "2026-06-03" + "2026-06-03", + "2026-06-18" ], "conceptTags": [ "agents.md", @@ -414,13 +423,13 @@ "endLine": 92, "source": "memory", "snippet": "**根因分析**: - `vala_game_chapter`(MySQL)无 `unit_index` 字段 - `big_map_chapter`(PostgreSQL)有 `unit_index` 字段,但仅包含 A1 数据,且与 `vala_game_chapter` 无直接关联键 - 两者 ID 空间不重叠(big_map: ~1720-2070,game_chapter: ~55-399),UUID 也不匹配 **映射方案**: - 每个 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-48(49 个单元),与 big_map_chapter 的 unit_index 范围一致 - A2: Unit 0-49(50 个单元,比 A1 多 1 个) *", - "recallCount": 14, + "recallCount": 17, "dailyCount": 0, "groundedCount": 0, - "totalScore": 14, + "totalScore": 17, "maxScore": 1, "firstRecalledAt": "2026-05-28T09:07:57.953Z", - "lastRecalledAt": "2026-06-17T09:59:49.133Z", + "lastRecalledAt": "2026-06-18T10:17:31.215Z", "queryHashes": [ "c6c7ff4ed75d", "c59410788b42", @@ -435,7 +444,10 @@ "02e468d377f4", "a87866c0fa75", "54487377b5d1", - "ee73b9da86b6" + "ee73b9da86b6", + "872ac2ac6438", + "f4b72dd59b18", + "f536bf691608" ], "recallDays": [ "2026-05-28", @@ -445,7 +457,8 @@ "2026-06-09", "2026-06-12", "2026-06-16", - "2026-06-17" + "2026-06-17", + "2026-06-18" ], "conceptTags": [ "vala-game-chapter", @@ -1386,23 +1399,25 @@ "endLine": 602, "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", - "recallCount": 4, + "recallCount": 5, "dailyCount": 0, "groundedCount": 0, - "totalScore": 4, + "totalScore": 5, "maxScore": 1, "firstRecalledAt": "2026-05-29T06:12:52.521Z", - "lastRecalledAt": "2026-06-16T06:22:11.809Z", + "lastRecalledAt": "2026-06-18T03:21:04.151Z", "queryHashes": [ "2aa08c6652fb", "6d1afbed352e", "ff112f97114e", - "d7be4ba41be4" + "d7be4ba41be4", + "872ac2ac6438" ], "recallDays": [ "2026-05-29", "2026-06-12", - "2026-06-16" + "2026-06-16", + "2026-06-18" ], "conceptTags": [ "3.0", @@ -1611,20 +1626,22 @@ "endLine": 624, "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 看板 |", - "recallCount": 2, + "recallCount": 3, "dailyCount": 0, "groundedCount": 0, - "totalScore": 2, + "totalScore": 3, "maxScore": 1, "firstRecalledAt": "2026-05-31T23:25:36.480Z", - "lastRecalledAt": "2026-06-12T07:16:32.881Z", + "lastRecalledAt": "2026-06-18T03:21:04.151Z", "queryHashes": [ "679cdd7bd3a8", - "6d1afbed352e" + "6d1afbed352e", + "872ac2ac6438" ], "recallDays": [ "2026-06-01", - "2026-06-12" + "2026-06-12", + "2026-06-18" ], "conceptTags": [ "build-pipeline", @@ -2358,15 +2375,16 @@ "endLine": 30, "source": "memory", "snippet": "- 发现核心 bug:`pick_valid_order()` 只取最新一笔有效订单,未做 GSV 聚合 - **根因:** 18621578529(account_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, "groundedCount": 0, - "totalScore": 1, + "totalScore": 2, "maxScore": 1, "firstRecalledAt": "2026-06-18T00:09:26.923Z", - "lastRecalledAt": "2026-06-18T00:09:26.923Z", + "lastRecalledAt": "2026-06-18T10:17:37.951Z", "queryHashes": [ - "ee468f64688e" + "ee468f64688e", + "d83437ba9cad" ], "recallDays": [ "2026-06-18" @@ -2381,6 +2399,37 @@ "vala-bi.bi-vala-order", "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 差异大 - **排查过程:** - 审计 E1–E9 全 0 ✅,绑单逻辑无问题 - 同一订单号集合(404个),汇总表 GSV=952,805 vs DB GSV=951,105,差异仅 ¥1,700 - 发现核心 bug:`pick_valid_order()` 只取最新一笔有效订单,未做 GSV 聚合 - **根因:** 18621578529(account_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", + "工作", + "日志", + "数据", + "查询" + ] } } } diff --git a/output/角色id_17995_导出时间_20260618.xlsx b/output/角色id_17995_导出时间_20260618.xlsx new file mode 100644 index 0000000..2aba862 Binary files /dev/null and b/output/角色id_17995_导出时间_20260618.xlsx differ diff --git a/output/角色id_38709_导出时间_20260618.xlsx b/output/角色id_38709_导出时间_20260618.xlsx new file mode 100644 index 0000000..e6132d7 Binary files /dev/null and b/output/角色id_38709_导出时间_20260618.xlsx differ diff --git a/output/角色id_38918_导出时间_20260618.xlsx b/output/角色id_38918_导出时间_20260618.xlsx new file mode 100644 index 0000000..ca4d1c2 Binary files /dev/null and b/output/角色id_38918_导出时间_20260618.xlsx differ diff --git a/scripts/bot_sales_step2_refresh.py b/scripts/bot_sales_step2_refresh.py index d449b9f..8df6da3 100644 --- a/scripts/bot_sales_step2_refresh.py +++ b/scripts/bot_sales_step2_refresh.py @@ -1,16 +1,18 @@ #!/usr/bin/env python3 """ -Bot 销转看板 Step2 刷新 — XXTEA 精确匹配版 (v3) +Bot 销转看板 Step2 刷新 — XXTEA 精确匹配版 (v4 · UID 口径) E列11位明文手机号 → XXTEA加密 → bi_vala_app_account.tel_encrypt精确匹配 → H列UID -S2 规则: +S2 规则 (2026-06-18 列契约): ① E→H: phone_encrypt.py XXTEA 精确匹配, 查不到留空 ② H→D/I/J: 只补空, 不覆盖已有值 - ③ Y=1: 仅当 K(下单日) >= C(线索日期) - ④ 全额退清: 所有订单都退费 → N/O/P 全部清空 + ③ X=1: GSV>0 且非全额退且 K≥C + ④ 全额退清: 所有订单都退费 → X=0, K-P 清空 ⑤ N/O/P 0留空, O整元 ⑥ 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 from datetime import datetime @@ -27,9 +29,9 @@ from phone_encrypt import encrypt_phone SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug" SALES_SHEETS = [ - ("qJF4I", "小龙", "A1:Z1200"), - ("f975f0", "吴迪", "A1:Z700"), - ("qJF4J", "成都", "A1:Z2500"), + ("qJF4I", "小龙", "A1:Y1200"), + ("f975f0", "吴迪", "A1:Y700"), + ("qJF4J", "成都", "A1:Y2500"), ] 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 = [], [], [], [] o_vals, p_vals, q_vals, r_vals = [], [], [], [] s_vals, t_vals, u_vals = [], [], [] - x_vals, y_vals, z_vals = [], [], [] + x_vals, y_vals = [], [] for item in g: 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) 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"] order_date = f"{pay_dt.month}月{pay_dt.day}日 {pay_dt.strftime('%H:%M:%S')}" if pay_dt else "" 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 ""]) 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 ""]) - x_vals.append([valid_order["trade_no"]]) - y_vals.append([1]) - z_vals.append([classify_channel(valid_order["key_from"])]) + x_vals.append([1]) # X=有效0/1 + y_vals.append([classify_channel(valid_order["key_from"])]) # Y=渠道 elif di["has_order"]: - # 有订单但无有效单 → Y=0, K/L/X 留空, N/O/P 不写 + # 有订单但无有效单 → X=0, K/L 留空 k_vals.append([""]) l_vals.append([""]) m_vals.append([""]) n_vals.append([""]) o_vals.append([""]) p_vals.append([""]) - x_vals.append([""]) + x_vals.append([0]) y_vals.append([""]) - z_vals.append([""]) else: - # 无订单 k_vals.append([""]) l_vals.append([""]) m_vals.append([""]) @@ -586,7 +585,6 @@ def write_sales_sheets(token, all_entries, phone_map, db_info): p_vals.append([""]) x_vals.append([""]) y_vals.append([""]) - z_vals.append([""]) # Q: 激活课程 act = di["activation"] @@ -606,7 +604,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info): else: 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, - x_vals, y_vals, z_vals]: + x_vals, y_vals]: arr.append([""]) # 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), ("O", o_vals), ("P", p_vals), ("Q", q_vals), ("R", r_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: put_values(token, sid, f"{col_letter}{sr}:{col_letter}{er}", vals) diff --git a/scripts/sales_leads_full_refresh.py b/scripts/sales_leads_full_refresh.py index 52361b4..367808e 100644 --- a/scripts/sales_leads_full_refresh.py +++ b/scripts/sales_leads_full_refresh.py @@ -1,21 +1,23 @@ #!/usr/bin/env python3 """ -销售线索全量刷新脚本 — XXTEA 精确匹配版 +销售线索全量刷新脚本 — XXTEA 精确匹配版 · UID 口径 v2 功能: 1. 读取「小龙」「吴迪」「成都」三个 sheet 的 E 列手机号 2. XXTEA 加密 → bi_vala_app_account.tel_encrypt 精确匹配 → 获取 account_id 3. 查询 PostgreSQL 获取用户订单/学习数据 - 4. 填写 D/H/I/J/K~U/X/Y/Z 列(自动列),U 列为操作更新时间 - 5. 将三个 sheet 中 Y=1(有效订单)的用户汇总到「订单汇总」sheet + 4. 填写 D/H/I/J/K~U/X/Y 列(A-Y 共25列),U 列为操作更新时间 + 5. 将三个 sheet 中 X=1(有效订单)的用户按 UID 聚合汇总到「订单汇总」sheet -规则(沿用 S2 规则): +规则(2026-06-18 列契约 v2): ① E→H: XXTEA 精确匹配, 查不到留空 ② H→D/I/J: 只补空, 不覆盖已有值 - ③ Y=1: 仅当 K(下单日) >= C(线索日期) - ④ 全额退清: 所有订单都退费 → N/O/P 全部清空 + ③ X=1: GSV>0 且非全额退且 K≥C + ④ 全额退清: 所有订单都退费 → X=0, K-P 清空 ⑤ N/O/P 0 留空, O 整元 ⑥ G 列不动 + ⑦ V/W 列不覆盖(Cursor 维护) + ⑧ X=有效0/1, Y=渠道归属, 不写订单号 用法: python3 scripts/sales_leads_full_refresh.py @@ -36,9 +38,9 @@ from phone_encrypt import encrypt_phone SPREADSHEET_TOKEN = "NoZqsFi47hIOHEt9j8WcfRtbnug" SALES_SHEETS = [ - ("qJF4I", "小龙", "A3:Z2607"), - ("f975f0", "吴迪", "A3:Z8149"), - ("qJF4J", "成都", "A3:Z2500"), + ("qJF4I", "小龙", "A3:Y2607"), + ("f975f0", "吴迪", "A3:Y8149"), + ("qJF4J", "成都", "A3:Y2500"), ] SUMMARY_SHEET_ID = "2smjwA" @@ -226,7 +228,6 @@ def parse_sales_sheets(token): "U": safe_cell(row, 20), "X": safe_cell(row, 23), "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 = [], [], [], [] o_vals, p_vals, q_vals, r_vals = [], [], [], [] s_vals, t_vals, u_vals = [], [], [] - x_vals, y_vals, z_vals = [], [], [] + x_vals, y_vals = [], [] for e in g: 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) 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"] order_date = f"{pay_dt.month}月{pay_dt.day}日 {pay_dt.strftime('%H:%M:%S')}" if pay_dt else "" 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 ""]) 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 ""]) - x_vals.append([valid_order["trade_no"]]) - y_vals.append([1]) - z_vals.append([classify_channel(valid_order["key_from"])]) + x_vals.append([1]) # X=有效0/1 + y_vals.append([classify_channel(valid_order["key_from"])]) # Y=渠道 elif di["has_order"]: - # 有订单但无有效单 → Y=0, K/L/X 留空 + # 有订单但无有效单 → X=0, K/L 留空 k_vals.append([""]) l_vals.append([""]) m_vals.append([""]) n_vals.append([""]) o_vals.append([""]) p_vals.append([""]) - x_vals.append([""]) + x_vals.append([0]) y_vals.append([""]) - z_vals.append([""]) else: k_vals.append([""]) l_vals.append([""]) @@ -710,7 +709,6 @@ def write_sales_sheets(token, all_entries, phone_map, db_info): p_vals.append([""]) x_vals.append([""]) y_vals.append([""]) - z_vals.append([""]) # Q: 激活课程 act = di["activation"] @@ -727,7 +725,7 @@ def write_sales_sheets(token, all_entries, phone_map, db_info): else: 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, - x_vals, y_vals, z_vals]: + x_vals, y_vals]: arr.append([""]) # 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), ("O", o_vals), ("P", p_vals), ("Q", q_vals), ("R", r_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: 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): """ - 订单汇总: 唯一真源 = 三表 Y=1 gate 的 unique X。 - 从 gate 行全量重建,A-U 镜像 gate 行,V=Z(或classify L),W=X。 - 同 X 多进线 → 只保留 1 行(行号最小)。 + 订单汇总: 唯一真源 = 三表 X=1 gate 的 unique UID。 + 从 gate 行全量重建,A-U 镜像 gate 行,V=渠道,W 留空。 + 1 UID = 1 行,按 UID 聚合 N/O/P。 + 同 UID 多进线 → 只保留 1 行(行号最小)。 """ clear_summary_sheet(token) - log(" 汇总订单数据(gate 全量重建)...") + log(" 汇总订单数据(UID gate 全量重建)...") - # 从三表收集 Y=1 行 + # 从三表收集 X=1 行(gate 门禁) gate_rows = [] for sid, sname, _ in SALES_SHEETS: entries = all_entries[sid] for e in entries: - # 读取当前行的 Y 和 X(写入后的值) - existing = e["existing"] - # Y 值已在上一步写入,这里用 phone_map + db_info 重新判断 phone = e["phone"] clue_date = e["clue_date_parsed"] + existing = e["existing"] aid = 0 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: continue - trade_no = agg_result["best_trade_no"] latest = agg_result["latest_order"] pay_dt = latest["pay_dt"] 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: 学习时长 datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # U: 更新时间 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 行 - seen_trade = {} + # 同 UID 多进线 → 只保留行号最小的 1 行 + seen_uid = {} deduped = [] - for trade_no, row_num, row_data in sorted(gate_rows, key=lambda x: x[1]): - if trade_no and trade_no in seen_trade: + for uid, row_num, row_data in sorted(gate_rows, key=lambda x: x[1]): + if uid in seen_uid: continue - if trade_no: - seen_trade[trade_no] = True + seen_uid[uid] = True 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: log(" 无有效订单,跳过汇总") @@ -859,7 +854,6 @@ def write_summary_sheet(token, all_entries, phone_map, db_info): # 写入订单汇总 sheet(从第3行开始,A~W 共23列) writer = FeishuSheetWriter(SPREADSHEET_TOKEN, token) - # 构建 A~W 的值数组(23列),确保每行长度一致 values = [] for row_data in deduped: padded = row_data[:23] diff --git a/skills/full-data-refresh/SKILL.md b/skills/full-data-refresh/SKILL.md index 5e97315..d7962d7 100644 --- a/skills/full-data-refresh/SKILL.md +++ b/skills/full-data-refresh/SKILL.md @@ -13,16 +13,15 @@ metadata: # 细水入海 — 销售数据全量刷新 -> **版本:** v2.1(2026-06-17 · GSV 聚合修复) -> **协作契约:** `xhs-ark-dashboard/docs/bot-full-refresh-v2.md` +> **版本:** v3.0(2026-06-18 · UID 口径 · 删 X 列订单号) +> **协作契约:** `xhs-ark-dashboard/docs/bot-uid-centric-orders-v1.md` > **大麦侧主文档:** `xhs-ark-dashboard/docs/damai-full-refresh-skill.md` > -> ### v2.1 变更(2026-06-17) -> - **GSV 聚合修复:** 订单汇总 Step 5 改用 `aggregate_valid_orders()` 替代 `pick_valid_order()` -> - 同一账户多笔有效订单 → GSV/GMV/退款 全部累加(不再只取最新一笔) -> - 订单号取未退款那笔(多笔未退款取最新) -> - 产品列多单用 `+` 拼接 -> - 线索绑单(Step 4)仍用 `pick_valid_order()` 不变 +> ### v3.0 变更(2026-06-18 · 列契约更新) +> - **三表 A–Y(25列):** 物理删除 X 列(订单号),X→有效0/1,Y→渠道归属 +> - **汇总 1 UID = 1 行:** 按 UID 去重聚合 N/O/P,W 留空(不再写 trade_no) +> - **gate 门禁:** X=1(GSV>0 且非全额退且 K≥C) +> - **线索绑单(Step 4)仍用 `pick_valid_order()` 不变** ## 核心架构规则(写死,不可漂移) @@ -31,16 +30,16 @@ metadata: - 共用 `pick_valid_order()` 函数 + 同一份 `db_info` 数据 - 禁止分两次 run 或使用不同数据源 -### 2. 汇总 W = 三表 X(gate 同源) -- 订单汇总 W 列取的是 `valid_order["trade_no"]`,与三表 X 列写入的值**完全一致** -- **不是** merge 时再查 DB 写 W -- 唯一真源 = 三表 Y=1 gate 的 unique X +### 2. 汇总 W 留空(不再写 trade_no) +- 订单汇总 W 列留空,不再写订单号 +- 汇总唯一真源 = 三表 X=1 gate 的 unique UID +- 1 UID = 1 行,按 UID 聚合 N/O/P -### 3. 2smjwA:clear → gate 全量覆盖 +### 3. 2smjwA:clear → UID gate 全量覆盖 - 先 `clear_summary_sheet()` 清空旧数据区 -- 再 gate 全量重建:从三表 Y=1 行收集 unique X → 每 X 一行 +- 再 gate 全量重建:从三表 X=1 行收集 unique UID → 每 UID 一行 - **不保留旧 W**,不 append -- 同 X 多进线 → 只保留行号最小的 1 行 +- 同 UID 多进线 → 只保留行号最小的 1 行 ### 4. 「保留 X/Y」只三表 mirror,不含汇总 - 三表 D/I/J 只补空、G 列不动 → 这些是 mirror 规则 @@ -48,13 +47,13 @@ metadata: ### 5. 线索 1进线=1行 · 只绑有效单 - 三表永远 1 次进线 = 1 行,不因多单拆行 -- Y=1 时 K/L/X/N/O/P/Z 全写有效主单真实值 -- 已退单不写旧 X/L(`pick_valid_order` 自动跳过全额退 + K0 · 非全额退 · K≥C - 一手机多单 → 取最新一笔满足门禁的有效单 - 已退单不出现在线索行 @@ -139,10 +137,10 @@ PASS 条件: - 所有订单都退费 (GMV == 退款) → 该单不参与有效单选取 ### 订单汇总进表条件 -- Y=1(已在三表筛选,汇总默认全是有效单) +- X=1(已在三表筛选,汇总默认全是有效单) - GSV>0 · 非全额退 · K≥C -- **同一账户多笔有效订单 → GSV/GMV/退款 累加,订单号取未退款那笔**(v2.1 修复) -- 同 X 多进线 → 汇总只保留 1 行 +- **同一 UID 多笔有效订单 → GSV/GMV/退款 累加**(v2.1 修复) +- 同 UID 多进线 → 汇总只保留 1 行 ### 渠道归属分类 (Z列) [王虹茗确认 2026-06-15] @@ -205,9 +203,9 @@ cd /root/.openclaw/workspace-xiaoban && python3 scripts/refresh_order_summary.py |----|------|------| | A-U | 镜像三表 | 与销售三表 A-U 列一致 | | V | 渠道归属 | 端内/销转/达人/直购 | -| W | 订单号 | = 三表 X(gate 同源) | +| 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。全量清空重写,不保留旧行。 ## 常见问题 diff --git a/tmp_daily_summary.md b/tmp_daily_summary.md new file mode 100644 index 0000000..7755e03 --- /dev/null +++ b/tmp_daily_summary.md @@ -0,0 +1,3 @@ +=== 每日总结 20260619 === +## 昨日关键进展 +无昨日记忆记录