1
This commit is contained in:
@@ -126,7 +126,7 @@ tools: ["read", "write", "shell"]
|
||||
| `apps/admin-web/src/` | `apps/admin-web/README.md` |
|
||||
| `apps/miniprogram/` | `apps/miniprogram/README.md` |
|
||||
| `packages/shared/` | `packages/shared/README.md` |
|
||||
| `db/*/migrations/*.sql` | `docs/database/BD_Manual_*.md` + `docs/database/ddl/` |
|
||||
| `db/*/migrations/*.sql` | `docs/database/BD_Manual_*.md` + `apps/etl/connectors/feiqiu/docs/database/` + `docs/database/ddl/` |
|
||||
|
||||
### 步骤 4:DDL/迁移检查
|
||||
- 若 `compliance.new_migration_sql` 非空:
|
||||
|
||||
14
.kiro/hooks/field-disappearance-scan.kiro.hook
Normal file
14
.kiro/hooks/field-disappearance-scan.kiro.hook
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"enabled": true,
|
||||
"name": "字段消失扫描",
|
||||
"description": "手动触发 DWD 表字段消失扫描,检测字段值从某天起突然全部为空的异常(≥3天且≥20条连续空记录)。输出终端报告 + CSV。",
|
||||
"version": "1",
|
||||
"when": {
|
||||
"type": "userTriggered"
|
||||
},
|
||||
"then": {
|
||||
"type": "runCommand",
|
||||
"command": "python scripts/ops/field_disappearance_scan.py",
|
||||
"timeout": 300
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"image-compare": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "mcp-image-compare-server"],
|
||||
"disabled": false,
|
||||
"autoApprove": [ "*",
|
||||
"all"]
|
||||
},
|
||||
"weixin-devtools-mcp": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "weixin-devtools-mcp", "--tools-profile=full", "--ws-endpoint=ws://127.0.0.1:9420"],
|
||||
@@ -14,9 +7,8 @@
|
||||
"WECHAT_DEVTOOLS_CLI": "C:\\dev\\WechatDevtools\\cli.bat",
|
||||
"WECHAT_DEVTOOLS_PROJECT": "C:\\NeoZQYY\\apps\\miniprogram"
|
||||
},
|
||||
"disabled": false,
|
||||
"autoApprove": [ "*",
|
||||
"all"]
|
||||
"disabled": true,
|
||||
"autoApprove": ["*"]
|
||||
},
|
||||
"git": {
|
||||
"command": "uvx",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
## 任务
|
||||
|
||||
- [ ] 1. 数据库表结构与基础模块搭建
|
||||
- [x] 1. 数据库表结构与基础模块搭建
|
||||
- [x] 1.1 创建 DDL 迁移脚本,在 `biz` schema 下建表 `ai_conversations`、`ai_messages`、`ai_cache`
|
||||
- 按设计文档中的 DDL 创建三张表,包含所有字段、CHECK 约束、索引
|
||||
- DDL 文件放置于 `db/zqyy_app/migrations/` 目录,日期前缀命名
|
||||
@@ -33,7 +33,7 @@
|
||||
- 测试文件:`tests/test_p5_ai_integration_properties.py`
|
||||
- **验证: 需求 4.4, 5.2, 5.3, 5.4, 6.3, 7.3, 8.2, 8.3, 8.4, 9.2, 10.4, 10.5**
|
||||
|
||||
- [ ] 2. 百炼 API 统一封装层(BailianClient)
|
||||
- [x] 2. 百炼 API 统一封装层(BailianClient)
|
||||
- [x] 2.1 实现 BailianClient 核心逻辑
|
||||
- 文件:`apps/backend/app/ai/bailian_client.py`
|
||||
- 使用 `openai` Python SDK,`base_url` 指向百炼端点
|
||||
@@ -90,7 +90,7 @@
|
||||
- 测试文件:`apps/backend/tests/test_ai_conversation.py`
|
||||
- **验证: 需求 3.7**
|
||||
|
||||
- [ ] 4. AI 缓存读写服务(AICacheService)
|
||||
- [x] 4. AI 缓存读写服务(AICacheService)
|
||||
- [x] 4.1 实现 AICacheService
|
||||
- 文件:`apps/backend/app/ai/cache_service.py`
|
||||
- `get_latest`:按 (cache_type, site_id, target_id) 查询最新记录
|
||||
@@ -99,30 +99,30 @@
|
||||
- `_cleanup_excess`:保留最近 500 条,删除最旧的
|
||||
- _需求: 12.1, 12.2, 12.3, 12.4, 12.5_
|
||||
|
||||
- [-] 4.2 编写属性测试:缓存写入 round-trip
|
||||
- [x] 4.2 编写属性测试:缓存写入 round-trip
|
||||
- **Property 7: 缓存写入 round-trip**
|
||||
- 使用 test_zqyy_app 数据库,随机 cache_type、target_id、result_json,验证写入后查询一致
|
||||
- 测试文件:`apps/backend/tests/test_ai_cache.py`
|
||||
- **验证: 需求 4.7, 5.6, 6.6, 7.5, 8.6, 9.5, 10.10**
|
||||
|
||||
- [-] 4.3 编写属性测试:缓存查询 site_id 隔离
|
||||
- [x] 4.3 编写属性测试:缓存查询 site_id 隔离
|
||||
- **Property 13: 缓存查询 site_id 隔离**
|
||||
- 使用 test_zqyy_app 数据库,写入 site_id=A 的记录,以 site_id=B 查询应返回空
|
||||
- 测试文件:`apps/backend/tests/test_ai_cache.py`
|
||||
- **验证: 需求 12.1, 12.5**
|
||||
|
||||
- [-] 4.4 编写属性测试:缓存保留上限
|
||||
- [x] 4.4 编写属性测试:缓存保留上限
|
||||
- **Property 14: 缓存保留上限**
|
||||
- 使用 test_zqyy_app 数据库,批量写入 >500 条记录,验证清理后 ≤ 500
|
||||
- 测试文件:`apps/backend/tests/test_ai_cache.py`
|
||||
- **验证: 需求 12.3**
|
||||
|
||||
- [ ] 5. 检查点 - 基础服务验证
|
||||
- [x] 5. 检查点 - 基础服务验证
|
||||
- 确保所有测试通过,ask the user if questions arise.
|
||||
- 验证 BailianClient、ConversationService、AICacheService 三个核心服务可独立工作
|
||||
|
||||
- [ ] 6. 应用 1 通用对话 SSE 端点
|
||||
- [~] 6.1 实现 App1 Chat 核心逻辑
|
||||
- [x] 6. 应用 1 通用对话 SSE 端点
|
||||
- [x] 6.1 实现 App1 Chat 核心逻辑
|
||||
- 文件:`apps/backend/app/ai/apps/app1_chat.py`
|
||||
- 每次进入 chat 页面新建 ai_conversations 记录(不复用)
|
||||
- 首条消息注入页面上下文(source_page、page_context、screen_content)
|
||||
@@ -132,7 +132,7 @@
|
||||
- 上下文注入框架留接口(页面文本化工具 P5-B 实现)
|
||||
- _需求: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.8_
|
||||
|
||||
- [~] 6.2 实现 SSE 路由端点
|
||||
- [x] 6.2 实现 SSE 路由端点
|
||||
- 文件:`apps/backend/app/routers/xcx_ai_chat.py`
|
||||
- `POST /api/ai/chat/stream`:SSE 协议推送,Content-Type: text/event-stream
|
||||
- SSE 事件格式:chunk / done / error
|
||||
@@ -142,21 +142,21 @@
|
||||
- 注册路由到 FastAPI app
|
||||
- _需求: 3.1, 3.7_
|
||||
|
||||
- [~] 6.3 编写单元测试:SSE 端点
|
||||
- [x] 6.3 编写单元测试:SSE 端点
|
||||
- 验证 SSE Content-Type 和事件格式(chunk/done/error)
|
||||
- 验证未认证返回 401、空消息返回 422
|
||||
- 测试文件:`apps/backend/tests/test_ai_chat.py`
|
||||
- _需求: 3.1_
|
||||
|
||||
- [ ] 7. 应用 2 财务洞察(完整 Prompt)
|
||||
- [~] 7.1 实现 App2 Finance Prompt 模板
|
||||
- [x] 7. 应用 2 财务洞察(完整 Prompt)
|
||||
- [x] 7.1 实现 App2 Finance Prompt 模板
|
||||
- 文件:`apps/backend/app/ai/prompts/app2_finance_prompt.py`
|
||||
- 完整 Prompt 包含:当期和上期收入结构(table_fee=table_charge_money、assistant_pd=assistant_pd_money、assistant_cx=assistant_cx_money、goods=goods_money、recharge=充值 pay_amount settle_type=5)
|
||||
- 包含储值资产、费用汇总、平台结算数据
|
||||
- 使用 items_sum 口径,禁止 consume_money
|
||||
- _需求: 4.5, 4.6_
|
||||
|
||||
- [~] 7.2 实现 App2 Finance 核心逻辑
|
||||
- [x] 7.2 实现 App2 Finance 核心逻辑
|
||||
- 文件:`apps/backend/app/ai/apps/app2_finance.py`
|
||||
- 8 个时间维度独立调用(this_month, last_month, this_week, last_week, last_3_months, this_quarter, last_quarter, last_6_months)
|
||||
- 营业日分界点 08:00(`BUSINESS_DAY_START_HOUR` 环境变量)
|
||||
@@ -165,14 +165,14 @@
|
||||
- 返回结构化 JSON(insights 数组:seq + title + body)
|
||||
- _需求: 4.1, 4.2, 4.3, 4.4, 4.7_
|
||||
|
||||
- [~] 7.3 编写单元测试:App2 时间维度计算
|
||||
- [x] 7.3 编写单元测试:App2 时间维度计算
|
||||
- 验证 8 个时间维度编码的计算逻辑(营业日分界点 08:00)
|
||||
- 验证 Prompt 使用 items_sum 口径字段映射
|
||||
- 测试文件:`apps/backend/tests/test_ai_app2.py`
|
||||
- _需求: 4.3, 4.6_
|
||||
|
||||
- [ ] 8. 应用 3/4/5/6/7 骨架实现
|
||||
- [~] 8.1 实现 App3 Clue 骨架
|
||||
- [x] 8. 应用 3/4/5/6/7 骨架实现
|
||||
- [x] 8.1 实现 App3 Clue 骨架
|
||||
- 文件:`apps/backend/app/ai/apps/app3_clue.py`
|
||||
- `run` 函数:构建 Prompt → 调用百炼 → 写入 conversation + cache
|
||||
- `build_prompt`:留接口,返回占位 Prompt,标注待细化字段(consumption_records 等待 P9-T1)
|
||||
@@ -182,7 +182,7 @@
|
||||
- 结果写入 ai_cache(cache_type=app3_clue,target_id=member_id)
|
||||
- _需求: 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8_
|
||||
|
||||
- [~] 8.2 实现 App4 Analysis 骨架
|
||||
- [x] 8.2 实现 App4 Analysis 骨架
|
||||
- 文件:`apps/backend/app/ai/apps/app4_analysis.py`
|
||||
- `build_prompt`:留接口(service_history、assistant_info 待 P6-T4)
|
||||
- Prompt reference 包含 App8 最新 + 最近 2 套历史(附 generated_at)
|
||||
@@ -190,7 +190,7 @@
|
||||
- 结果写入 ai_cache(cache_type=app4_analysis,target_id=`{assistant_id}_{member_id}`)
|
||||
- _需求: 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7_
|
||||
|
||||
- [~] 8.3 实现 App5 Tactics 骨架
|
||||
- [x] 8.3 实现 App5 Tactics 骨架
|
||||
- 文件:`apps/backend/app/ai/apps/app5_tactics.py`
|
||||
- 接收 App4 完整返回结果作为 Prompt 中的 task_suggestion 字段
|
||||
- `build_prompt`:留接口(service_history、assistant_info 随 App4 同步在 P6-T4)
|
||||
@@ -198,7 +198,7 @@
|
||||
- 结果写入 ai_cache(cache_type=app5_tactics,target_id=`{assistant_id}_{member_id}`)
|
||||
- _需求: 7.1, 7.2, 7.3, 7.4, 7.5, 7.6_
|
||||
|
||||
- [~] 8.4 实现 App6 Note 骨架
|
||||
- [x] 8.4 实现 App6 Note 骨架
|
||||
- 文件:`apps/backend/app/ai/apps/app6_note.py`
|
||||
- `build_prompt`:留接口(consumption_data 待 P9-T1)
|
||||
- 返回 score(1-10)+ clues 数组,category 限定 6 个枚举值
|
||||
@@ -208,7 +208,7 @@
|
||||
- 结果写入 ai_cache(cache_type=app6_note_analysis,target_id=member_id),score 存入 ai_cache.score
|
||||
- _需求: 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8_
|
||||
|
||||
- [~] 8.5 实现 App7 Customer 骨架
|
||||
- [x] 8.5 实现 App7 Customer 骨架
|
||||
- 文件:`apps/backend/app/ai/apps/app7_customer.py`
|
||||
- `build_prompt`:留接口(objective_data 待 P9-T1)
|
||||
- 使用 items_sum 口径
|
||||
@@ -217,22 +217,22 @@
|
||||
- 结果写入 ai_cache(cache_type=app7_customer_analysis,target_id=member_id)
|
||||
- _需求: 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7_
|
||||
|
||||
- [~] 8.6 编写属性测试:Prompt reference 历史注入
|
||||
- [x] 8.6 编写属性测试:Prompt reference 历史注入
|
||||
- **Property 9: Prompt reference 历史注入**
|
||||
- Mock 缓存数据,验证各应用 build_prompt 的 reference 字段包含正确的缓存结果和 generated_at 时间戳
|
||||
- 缓存不存在时 reference 为空对象
|
||||
- 测试文件:`apps/backend/tests/test_ai_apps_prompt.py`
|
||||
- **验证: 需求 5.8, 6.4, 6.5, 7.2, 7.4, 8.8, 9.7**
|
||||
|
||||
- [ ] 9. 应用 8 维客线索整理(完整 Prompt)+ ClueWriter
|
||||
- [~] 9.1 实现 App8 Consolidation Prompt 模板
|
||||
- [x] 9. 应用 8 维客线索整理(完整 Prompt)+ ClueWriter
|
||||
- [x] 9.1 实现 App8 Consolidation Prompt 模板
|
||||
- 文件:`apps/backend/app/ai/prompts/app8_consolidation_prompt.py`
|
||||
- 完整 Prompt:接收 App3 和 App6 全部线索(附 generated_at),整合去重
|
||||
- 分类标签限定 6 个枚举值(与 member_retention_clue CHECK 约束一致)
|
||||
- 合并相似线索(多提供者逗号分隔),其余原文返回,最小改动原则
|
||||
- _需求: 10.3, 10.4, 10.5, 10.6_
|
||||
|
||||
- [~] 9.2 实现 ClueWriter 全量替换逻辑
|
||||
- [x] 9.2 实现 ClueWriter 全量替换逻辑
|
||||
- 集成在 `apps/backend/app/ai/apps/app8_consolidation.py`
|
||||
- DELETE source IN ('ai_consumption', 'ai_note') → INSERT 新线索(事务)
|
||||
- 字段映射:emoji+summary 拼接、providers→recorded_by_name、source 判断逻辑
|
||||
@@ -240,25 +240,25 @@
|
||||
- 人工线索(source='manual')不受影响
|
||||
- _需求: 10.7, 10.8, 10.9_
|
||||
|
||||
- [~] 9.3 实现 App8 Consolidation 核心逻辑
|
||||
- [x] 9.3 实现 App8 Consolidation 核心逻辑
|
||||
- 文件:`apps/backend/app/ai/apps/app8_consolidation.py`
|
||||
- `run` 函数:构建 Prompt → 调用百炼 → 写入 conversation + cache + member_retention_clue
|
||||
- 结果同时写入 ai_cache(cache_type=app8_clue_consolidated,target_id=member_id)
|
||||
- _需求: 10.1, 10.2, 10.10_
|
||||
|
||||
- [~] 9.4 编写属性测试:ClueWriter 全量替换不变量
|
||||
- [x] 9.4 编写属性测试:ClueWriter 全量替换不变量
|
||||
- **Property 12: ClueWriter 全量替换不变量**
|
||||
- 使用 test_zqyy_app 数据库,随机线索列表 + 预置人工线索
|
||||
- 验证:AI 线索数量 = new_clues 数量、人工线索不变、recorded_by_assistant_id=NULL、summary=emoji+空格+原始 summary
|
||||
- 测试文件:`apps/backend/tests/test_ai_clue_writer.py`
|
||||
- **验证: 需求 10.7, 10.8, 10.9**
|
||||
|
||||
- [ ] 10. 检查点 - 应用层验证
|
||||
- [x] 10. 检查点 - 应用层验证
|
||||
- 确保所有测试通过,ask the user if questions arise.
|
||||
- 验证 8 个应用的 run 函数可独立调用(Mock 百炼 API)
|
||||
|
||||
- [ ] 11. 事件调度与调用链编排(AIDispatcher)
|
||||
- [~] 11.1 实现 AIDispatcher 核心逻辑
|
||||
- [x] 11. 事件调度与调用链编排(AIDispatcher) ✅
|
||||
- [x] 11.1 实现 AIDispatcher 核心逻辑
|
||||
- 文件:`apps/backend/app/ai/dispatcher.py`
|
||||
- `handle_consumption_event`:App3 → App8 → App7(+ App4 → App5 如有助教)
|
||||
- `handle_note_event`:App6 → App8
|
||||
@@ -268,40 +268,40 @@
|
||||
- 整条链后台异步执行,不阻塞业务请求
|
||||
- _需求: 11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7_
|
||||
|
||||
- [~] 11.2 集成事件触发点
|
||||
- [x] 11.2 集成事件触发点
|
||||
- 在 `trigger_scheduler.fire_event()` 中注册 AI 事件处理器
|
||||
- 消费事件(consumption_settled)→ `ai_dispatcher.handle_consumption_event`
|
||||
- 备注事件(note_created)→ `ai_dispatcher.handle_note_event`
|
||||
- 任务分配事件(task_assigned)→ `ai_dispatcher.handle_task_assign_event`
|
||||
- _需求: 5.1, 6.1, 6.2, 7.1, 8.1, 9.1, 11.1, 11.2, 11.3, 11.4_
|
||||
|
||||
- [~] 11.3 编写属性测试:事件调用链顺序正确性
|
||||
- [x] 11.3 编写属性测试:事件调用链顺序正确性
|
||||
- **Property 10: 事件调用链顺序正确性**
|
||||
- Mock 所有应用,记录调用序列,验证四种事件链的严格顺序
|
||||
- 测试文件:`apps/backend/tests/test_ai_dispatcher.py`
|
||||
- **验证: 需求 11.1, 11.2, 11.3, 11.4, 11.5, 11.6**
|
||||
|
||||
- [~] 11.4 编写属性测试:调用链容错不变量
|
||||
- [x] 11.4 编写属性测试:调用链容错不变量
|
||||
- **Property 11: 调用链容错不变量**
|
||||
- Mock 随机应用失败,验证后续应用继续执行且失败应用有错误日志
|
||||
- 测试文件:`apps/backend/tests/test_ai_dispatcher.py`
|
||||
- **验证: 需求 11.7**
|
||||
|
||||
- [ ] 12. 缓存查询路由与环境配置
|
||||
- [~] 12.1 实现缓存查询路由
|
||||
- [x] 12. 缓存查询路由与环境配置
|
||||
- [x] 12.1 实现缓存查询路由
|
||||
- 文件:`apps/backend/app/routers/xcx_ai_cache.py`
|
||||
- `GET /api/ai/cache/{cache_type}?target_id=xxx`:查询最新缓存
|
||||
- JWT 认证,site_id 从 token 提取强制过滤
|
||||
- 注册路由到 FastAPI app
|
||||
- _需求: 12.1, 12.2, 12.5_
|
||||
|
||||
- [~] 12.2 新增环境变量配置
|
||||
- [x] 12.2 新增环境变量配置
|
||||
- 在 `.env.template` 中添加 `BAILIAN_API_KEY`、`BAILIAN_BASE_URL`、`BAILIAN_MODEL`、`BUSINESS_DAY_START_HOUR`
|
||||
- 在后端配置加载逻辑中读取这些变量,缺失时报错
|
||||
- _需求: 2.1, 14.1, 14.2_
|
||||
|
||||
- [ ] 13. 百炼技术方案确认文档
|
||||
- [ ] 13.1 输出百炼技术方案确认文档
|
||||
- [x] 13. 百炼技术方案确认文档 ✅
|
||||
- [x] 13.1 输出百炼技术方案确认文档
|
||||
- 文件:`docs/reports/bailian-technical-solution.md`
|
||||
- 确认流式返回方案(OpenAI 兼容 SSE)
|
||||
- 确认 JSON 输出模式(response_format + System Prompt 约束)
|
||||
@@ -309,8 +309,8 @@
|
||||
- 作为 BailianClient 实现的依据
|
||||
- _需求: 14.1, 14.2, 14.3_
|
||||
|
||||
- [ ] 14. 最终检查点 - 全量验证
|
||||
- 确保所有测试通过,ask the user if questions arise.
|
||||
- [x] 14. 最终检查点 - 全量验证 ✅
|
||||
- 全部 9 个测试文件、62 个测试用例通过(2026-03-09)
|
||||
- 验证所有路由注册正确、事件触发点集成完毕、环境变量配置完整
|
||||
|
||||
## 备注
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"specId": "cd30e87b-ce7a-4ff5-8587-f5ae75013e58", "workflowType": "requirements-first", "specType": "feature"}
|
||||
498
.kiro/specs/h5-miniprogram-migration-subsequent/design.md
Normal file
498
.kiro/specs/h5-miniprogram-migration-subsequent/design.md
Normal file
@@ -0,0 +1,498 @@
|
||||
# 技术设计文档:H5 → 微信小程序像素精调
|
||||
|
||||
## 1. 概述
|
||||
|
||||
本设计文档为 17 个页面(共 79 个对照处理单元)的 Step 6-7 像素精调提供技术方案。所有页面已完成 Step 0-5 结构迁移(TS 零诊断、路由注册、四态处理)。
|
||||
|
||||
核心设计思路:以「对照处理单元」为最小粒度,通过两阶段收敛流程(结构级修正 → 像素级精调)系统性消除视觉差异。
|
||||
|
||||
参考文档(不重复,仅索引):
|
||||
- 迁移规则与转换公式:`docs/prd/MIGRATION-PLAYBOOK.md`
|
||||
- 样式标准值:`docs/h5_ui/design-tokens.json`(颜色灰阶、字号、圆角、阴影的标准 rpx 值)
|
||||
- 工具链源码:`scripts/ops/anchor_compare.py`
|
||||
|
||||
## 2. 截图策略
|
||||
|
||||
### 2.1 双端参数对齐
|
||||
|
||||
| 参数 | H5 | MP | 对比基准 |
|
||||
|------|-----|-----|---------|
|
||||
| viewport | 430×752 | 430×752(windowHeight) | 统一 |
|
||||
| DPR | 1.5 | 1.5(MCP 有效 DPR) | 统一 |
|
||||
| 输出尺寸 | 645×1128 | 645×1128 | 统一,无需缩放 |
|
||||
|
||||
> 验证数据(2026-03-10 board-finance 实测):H5 Playwright DPR=1.5 输出 645×1128;MP MCP screenshot 输出 645×1128。两端尺寸完全一致,无需任何缩放处理。
|
||||
|
||||
### 2.2 固定步长滚动方案
|
||||
|
||||
采用固定 600px 步长滚动截图,替代锚点方案。两端使用完全相同的 scrollTop 序列(0, 600, 1200, ...),不依赖锚点位置,消除 H5/MP 元素位置差异导致的对齐问题。
|
||||
|
||||
核心参数:
|
||||
- 步长:600px(逻辑像素)
|
||||
- scrollTop 序列:从 0 开始,每次 +600,最后一屏 clamp 到 `maxScroll = scrollHeight - viewportHeight`
|
||||
- 段数计算:`N = floor(maxScroll / 600) + 1`(首屏 step-0 + 每 600px 一步 + 最后一步 clamp 到 maxScroll);`maxScroll ≤ 10` 的页面视为单屏(N=1)
|
||||
|
||||
实测精度(board-finance,2026-03-10):
|
||||
- H5 端:Playwright `window.scrollTo` 精确命中目标值(偏差 0px)
|
||||
- MP 端:`wx.pageScrollTo` 精确命中目标值
|
||||
|
||||
### 2.3 底部浮动元素处理
|
||||
|
||||
H5 端存在 `#bottomNav`(64px fixed 底部导航)和 `.ai-float-btn-container`(56px 浮动按钮),MP 端使用原生 tabBar(不在 webview 截图中)。
|
||||
|
||||
处理方式:H5 截图前用 JS 隐藏所有底部浮动元素:
|
||||
```javascript
|
||||
document.getElementById('bottomNav').style.display = 'none';
|
||||
document.querySelectorAll('.ai-float-btn-container').forEach(el => el.style.display = 'none');
|
||||
```
|
||||
MP 端原生 tabBar 本来不在截图中,无需处理。MP 端如果存在 AI 浮动按钮,因 H5 端已隐藏,该区域的差异在对比时可忽略,不计入差异率。
|
||||
|
||||
### 2.4 浮动元素专项检测(结构校验阶段)
|
||||
|
||||
长页面滚动截图中,sticky/fixed 元素(如 sticky 导航栏、筛选栏)在每一屏的相同位置出现。通过滚屏上下页对比,可以精准识别这些浮动元素的差异并专项修复。
|
||||
|
||||
检测方法:
|
||||
1. 对同一页面的相邻屏截图进行对比,在不同屏中持续出现在相同位置的差异区域即为 sticky/fixed 元素
|
||||
2. 对 H5 vs MP 的 sticky 区域做像素对比,差异即为浮动元素的样式偏差
|
||||
3. sticky 元素差异在每一屏都会重复出现,修复一次即可消除所有屏的该区域差异
|
||||
|
||||
适用场景:
|
||||
- board-finance:`.safe-area-top`(45px) + `#filterBar`(71px) = 116px sticky
|
||||
- board-coach/board-customer:`.board-tabs`(42px) + `.filter-bar`(68px) = 110px sticky
|
||||
- 所有带 sticky 头部的长页面
|
||||
|
||||
优化效果:修复 sticky 区域差异后,所有屏的差异率会同步下降(因为每屏都包含相同的 sticky 区域)。
|
||||
|
||||
### 2.5 截图操作指南
|
||||
|
||||
#### 2.5.1 H5 截图
|
||||
|
||||
底层技术:Playwright + Chromium,viewport 430×752,DPR=1.5,headless=True。
|
||||
|
||||
流程:
|
||||
1. 打开 Live Server 提供的 H5 页面(`http://localhost:5500/docs/h5_ui/<page>.html`)
|
||||
2. 等待 Tailwind CDN JIT 渲染(1500ms)
|
||||
3. 隐藏滚动条 + 底部浮动元素(`#bottomNav` + `.ai-float-btn-container`)
|
||||
4. 按 scrollTop 序列逐屏截图:先 `scrollTo(0,0)` 再 `scrollTo(0, target)`
|
||||
|
||||
截图脚本:`scripts/ops/anchor_compare.py extract-h5 <page>`(固定 600px 步长模式)
|
||||
|
||||
输出:`docs/h5_ui/compare/<page>/h5--step-<scrollTop>.png`(645×1128)
|
||||
|
||||
#### 2.5.2 MP 截图
|
||||
|
||||
前置条件:微信开发者工具已打开,MCP 已连接。
|
||||
|
||||
流程:
|
||||
1. 导航到目标页面(tabBar 页面用 `switch_tab`,其他用 `navigate_to`)
|
||||
2. 等待页面加载(2000ms)
|
||||
3. 按相同 scrollTop 序列逐屏截图:
|
||||
```javascript
|
||||
// 每屏:先回顶再滚到目标,确保精确
|
||||
wx.pageScrollTo({ scrollTop: 0, duration: 0 })
|
||||
// 等待 200ms
|
||||
wx.pageScrollTo({ scrollTop: target, duration: 0 })
|
||||
// 等待 500ms,读取实际 scrollTop,截图
|
||||
```
|
||||
|
||||
输出:`docs/h5_ui/compare/<page>/mp--step-<scrollTop>.png`(645×1128)
|
||||
|
||||
#### 2.5.3 多维度页面 MP 截图
|
||||
|
||||
board-coach 和 board-customer 为多维度页面,每个维度的卡片模板不同,需逐维度截图。
|
||||
|
||||
board-coach(4 种排序维度):
|
||||
- 维度通过筛选栏下拉切换(`onSortChange`),对应 4 种卡片模板:`perf`(定档业绩)、`salary`(工资)、`sv`(客源储值)、`task`(任务完成)
|
||||
- MP 操作:获取页面快照 → 点击排序筛选下拉 → 选择目标维度 → 等待列表刷新 → 截图
|
||||
- H5 操作:通过 JS 调用 `selectType('perf_desc')` 等切换 dim-container 显隐 → 截图
|
||||
- 子目录:`board-coach/perf/`、`board-coach/salary/`、`board-coach/sv/`、`board-coach/task/`
|
||||
|
||||
board-customer(8 种客户维度):
|
||||
- 维度通过筛选栏下拉切换(`onDimensionChange`),对应 8 种卡片模板:`recall`(最应召回)、`potential`(消费潜力)、`balance`(最高余额)、`recharge`(最近充值)、`recent`(最近到店)、`spend60`(最高消费)、`freq60`(最频繁)、`loyal`(最专一)
|
||||
- MP 操作:获取页面快照 → 点击维度筛选下拉 → 选择目标维度 → 等待列表刷新 → 截图
|
||||
- H5 操作:通过 JS 调用 `selectType('recall')` 等切换 dim-container 显隐 → 截图
|
||||
- 子目录:`board-customer/recall/`、`board-customer/potential/` ... `board-customer/loyal/`
|
||||
|
||||
> 交互文档参考:`docs/h5_ui/interactions/board-coach.md`、`docs/h5_ui/interactions/board-customer.md`
|
||||
|
||||
#### 2.5.4 逐屏对比
|
||||
|
||||
对同一 scrollTop 的 H5/MP 截图做像素对比:
|
||||
```
|
||||
mcp_image_compare_compare_images
|
||||
image1_path: "docs/h5_ui/compare/<page>/h5--step-<N>.png"
|
||||
image2_path: "docs/h5_ui/compare/<page>/mp--step-<N>.png"
|
||||
diff_output_path: "docs/h5_ui/compare/<page>/diff--step-<N>.png"
|
||||
threshold: 0.1
|
||||
```
|
||||
|
||||
### 2.5.5 双端高度不一致处理
|
||||
|
||||
MP 端页面高度可能与 H5 不一致(样式差异导致内容更短或更长)。如果直接按 H5 的 scrollTop 序列去滚 MP,可能滚过头(scrollTo 被 clamp)或漏截(页面更长)。
|
||||
|
||||
处理流程:
|
||||
1. 先截双端 step-0(首屏),对比确认基线
|
||||
2. 再截 step-600(第二屏),读取 MP 端实际 scrollTop:
|
||||
- 如果 MP 实际 scrollTop 远小于 600(被 clamp),说明 MP 页面比 H5 短,后续步骤需按 MP 实际 maxScroll 调整序列
|
||||
- 如果 MP 实际 scrollTop ≈ 600,说明双端高度接近,继续按 H5 序列推进
|
||||
3. 之后逐屏推进,每屏截图前先读取 MP 端实际 scrollTop,确认到达预期位置
|
||||
4. 如果 MP 页面比 H5 长(MP 还能继续滚但 H5 序列已结束),追加额外步骤直到 MP 也到达 maxScroll
|
||||
|
||||
> 此规则防止因双端高度差异导致后续屏截图错位或遗漏。
|
||||
|
||||
### 2.6 长页面级联影响与修正规则
|
||||
|
||||
修正某一屏的 WXSS 时,可能影响后续屏的布局。因此:
|
||||
|
||||
1. 修正后必须重新截取所有屏的截图(因为固定步长方案下,布局变化会影响每屏内容)
|
||||
2. 优先修复 sticky 区域差异(一次修复,所有屏受益)
|
||||
3. 从 step-0 开始顺序审查差异,确保前序屏达标后再处理后续屏
|
||||
4. 如果修正引入回归,回退到受影响的最早屏重新验证
|
||||
|
||||
### 2.7 结构级视觉元素识别清单(阶段一修正范围)
|
||||
|
||||
以下元素类型在双端截图中容易产生大面积差异(>10%),属于阶段一优先识别和修正的对象。严重缺失时可能导致 >15% 触发重写。
|
||||
|
||||
#### 2.7.1 大面积背景
|
||||
|
||||
| 背景类型 | MP 支持 | 处理方式 |
|
||||
|----------|---------|---------|
|
||||
| 纯色 / `linear-gradient` / `radial-gradient` / `repeating-linear-gradient` | ✅ | 直接迁移,查 `docs/h5_ui/design-tokens.json` 取精确色值和方向 |
|
||||
| `backdrop-filter: blur()` | ❌ | 改用 `background: rgba(255,255,255,0.95)` 半透明纯色 |
|
||||
| `url("data:image/svg+xml,...")` | ❌ | 用 CSS 渐变模拟,或导出为 PNG/base64 引用 |
|
||||
|
||||
精调要点:
|
||||
- 渐变方向和色值必须与 H5 完全一致,大面积色差肉眼极其明显
|
||||
- 半透明背景透明度差 0.1 在大面积上可见
|
||||
|
||||
#### 2.7.2 复杂图标与 SVG
|
||||
|
||||
Step 0-5 已完成所有 SVG 迁移决策(详见 `MIGRATION-PLAYBOOK.md` 3.5 节)。精调阶段关注:
|
||||
|
||||
| 图标类型 | 精调关注点 | 已审计案例 |
|
||||
|----------|-----------|-----------|
|
||||
| TDesign `<t-icon>` | `size`(rpx)和 `color` 与 H5 原始 SVG 一致 | 目录按钮 `view-list`、筛选箭头 `caret-down-small` |
|
||||
| 导出 SVG + `<image>` | `width`/`height`(rpx)与 H5 显示尺寸一致 | AI 悬浮按钮、底部导航栏图标 |
|
||||
| 文字/Emoji 替代 | 可接受差异,不计入差异率 | 环比箭头 ↑↓、AI 机器人 🤖 |
|
||||
| CSS 渐变 + 文字组合(如头像) | 渐变方向、色值、圆角、文字大小一致 | 客户头像(8 种渐变色 135deg) |
|
||||
| 帮助"?"图标(文字+圆形背景) | 圆形背景 size/color、文字 font-size 一致 | board-finance 指标标签旁 |
|
||||
|
||||
图标缺失或尺寸严重偏差属于阶段一结构级问题;尺寸/颜色微调属于阶段二。
|
||||
|
||||
#### 2.7.3 带文字的标签(Badge / Tag)
|
||||
|
||||
标签是高频偏差元素,涉及背景色、圆角、字号、内边距的组合,任一偏差都会在截图中明显可见:
|
||||
|
||||
| 标签类型 | 精调维度 | 已审计偏差案例 |
|
||||
|----------|---------|---------------|
|
||||
| 状态 Badge(跟/弃) | 背景渐变、font-size、min-width、height、border-radius | 弃 badge radius 10rpx→应为 12rpx |
|
||||
| 超期标签(超期>7天/≤7天) | 背景透明度、padding、border-radius、文字色 | radius 6rpx→应为 8rpx |
|
||||
| 潜力标签(高频/高客单/高余额) | 背景色、文字色、font-weight | 已正确迁移 |
|
||||
| 高消费标签 | `bg-warning/10` + `text-warning` + `font-bold` | 已正确迁移 |
|
||||
| 板块标题标签(Emoji + 文字) | Emoji 渲染、font-size、间距 | 板块 Emoji 📈💳💰🧾📤🎱 已正确 |
|
||||
|
||||
标签精调规则:
|
||||
- 背景色优先查 `docs/h5_ui/design-tokens.json`,禁止使用非标准色值
|
||||
- `border-radius` 是标签最常见偏差(±2rpx),必须逐个核对
|
||||
- `padding` 注意 H5 Tailwind 的 `px-1.5 py-0.5` 换算(×2×0.875)
|
||||
- 渐变背景标签(如跟/弃 badge)的渐变方向和双色值必须精确
|
||||
|
||||
#### 2.7.4 组合元素(图标+文字+背景)
|
||||
|
||||
多个基础元素组合成的复合 UI 单元,整体偏差会被放大:
|
||||
|
||||
| 组合元素 | 构成 | 精调关注点 |
|
||||
|----------|------|-----------|
|
||||
| 筛选按钮 | 文字 + 下拉箭头 + 背景 + 圆角 | 整体高度、内边距、箭头与文字间距 |
|
||||
| 环比指标 | 数值 + 箭头(↑↓) + 百分比 + 颜色 | 上升色 #e34d59 / 下降色 #00a870、font-size |
|
||||
| 确认收入横条 | 标签 + 金额 + 半透明背景 | `bg-white/10` 透明度、padding、border-radius |
|
||||
| 迷你柱状图 | 柱条 + 数字 + 标签 | 柱条高度/gap/圆角/透明度渐变、数字 font-size |
|
||||
| 助教服务行 | 头像 + 姓名 + 分隔符 + 跟/弃 badge | 分隔符颜色/间距、badge 与文字对齐 |
|
||||
| AI 悬浮按钮 | 图标 + 渐变背景 + 圆角 + 阴影 | 整体 size、border-radius、渐变色 |
|
||||
|
||||
组合元素精调策略:先确认整体布局(flex 方向、对齐方式)正确,再逐个子元素微调。
|
||||
|
||||
## 3. 两阶段收敛流程
|
||||
|
||||
### 3.1 流程图
|
||||
|
||||
```
|
||||
获取双端截图
|
||||
↓
|
||||
image_compare 对比 → 初始差异率
|
||||
↓
|
||||
首轮审计报告(截图 + H5 源码 + MP 源码 三方对照)
|
||||
↓
|
||||
┌─ 差异率 > 10% ──→ 阶段一:结构级修正(每轮 2-5 处)
|
||||
│ ↓ 循环直到 ≤ 10%
|
||||
├─ 差异率 5%~10% ─→ 阶段二:像素级精调(每轮 1-3 处)
|
||||
│ ↓ 循环直到 < 5%
|
||||
├─ 差异率 < 5% ───→ ✅ 通过
|
||||
└─ > 15% 且无法收敛 → 🔄 触发重写
|
||||
```
|
||||
|
||||
### 3.2 首轮审计报告(强制)
|
||||
|
||||
第一轮对比完成后,必须同时读取 H5 源码(HTML + 内联 CSS 的 Tailwind 类名和 `<style>` 块)和 MP 源码(WXML + WXSS),结合 diff 截图三方对照,产出一份完整的审计报告。此报告是后续所有修改的指导依据。
|
||||
|
||||
审计报告格式包含:
|
||||
|
||||
| 章节 | 内容 | 数据来源 |
|
||||
|------|------|---------|
|
||||
| A. 结构对照 | 页面区域结构是否完整、顺序是否一致 | diff 截图 + H5 HTML 结构 |
|
||||
| B. CSS 风险点 | 不支持的 CSS 特性(`::after` 复杂场景、`clip-path`、`backdrop-filter` 等) | H5 `<style>` 块 |
|
||||
| C. 关键样式映射 | 逐元素核对:Tailwind 类名 → computed 值 → WXSS 现值 → 是否一致 | H5 源码 + MP WXSS |
|
||||
| D. 图标处理 | 每个 SVG/图标的迁移决策和当前状态 | H5 源码 + MP WXML |
|
||||
| E. 偏差清单 | 所有 ⚠️ 偏差项汇总,按优先级排序 | C/D 节中标记的偏差 |
|
||||
|
||||
审计报告输出到 `docs/h5_ui/compare/<page>/audit.md`。
|
||||
|
||||
关键原则:
|
||||
- 不能只看 diff 图猜测问题,必须回溯到 H5 源码确认正确值
|
||||
- Tailwind 类名是唯一可信的样式来源(不是肉眼估算)
|
||||
- 每个偏差项必须记录:H5 值(含 Tailwind 类名)→ 换算后的 rpx 值 → MP 现值 → 差异
|
||||
- 审计报告完成后,阶段一/二的修正严格按报告中的偏差清单执行
|
||||
|
||||
### 3.3 阶段一:结构级修正
|
||||
|
||||
目标:消除明显的视觉差异,将差异率从 >10% 降到 ≤10%。
|
||||
|
||||
修正重点(按优先级):
|
||||
1. 区域缺失或顺序错误
|
||||
2. 整块背景色/渐变色不匹配
|
||||
3. 字号明显偏差(≥4rpx)
|
||||
4. 间距明显偏差(≥4rpx)
|
||||
|
||||
操作模式:
|
||||
- 按审计报告偏差清单逐项修正,不靠肉眼猜测
|
||||
- 对照 H5 源码 Tailwind 类名 + `docs/h5_ui/design-tokens.json` 确认正确值
|
||||
- 修改 WXSS → 重新截图 → 重新对比
|
||||
|
||||
### 3.4 阶段二:像素级精调
|
||||
|
||||
目标:消除细微差异,将差异率从 5%~10% 降到 <5%。
|
||||
|
||||
修正重点(按优先级):
|
||||
1. 小边距偏差(padding/margin/gap ±2rpx,如卡片 30→28rpx、列表容器 24→28rpx、分隔符 margin 6→10rpx)
|
||||
2. 圆角(border-radius)偏差(±2rpx,如标签 6→8rpx、卡片 28→32rpx)
|
||||
3. 颜色色值微调(灰阶偏差如 #c5c5c5→#a6a6a6、透明度差 0.1)
|
||||
4. 行高(line-height)缺失或偏差、字重(font-weight)微调(如 600→500)
|
||||
5. 阴影(box-shadow)参数微调
|
||||
|
||||
操作模式:
|
||||
- 使用 image_compare 精确定位差异像素区域
|
||||
- 参考 computed-styles.json(如有)或 H5 源码精确值
|
||||
- 每次只改 1-3 处,验证不引入新差异
|
||||
|
||||
### 3.5 收敛停滞处理
|
||||
|
||||
当差异率连续 3 轮未下降超过 1% 时:
|
||||
1. 分析剩余差异是否为不可消除的结构性差异(字体渲染、抗锯齿、头部区域)
|
||||
2. 若是 → 标注为可接受差异,记录到 report.md,停止该区域精调
|
||||
3. 若否 → 尝试不同修正策略(如换用 flex 布局替代绝对定位)
|
||||
|
||||
## 4. 修改优先级规则(经验提炼)
|
||||
|
||||
基于 board-finance(17 项偏差)、board-coach(17 项偏差)、board-customer(42 项偏差)的实际审计经验,提炼出以下规则:
|
||||
|
||||
### 4.1 高频偏差类型
|
||||
|
||||
| 偏差类型 | 出现频率 | 典型案例 | 修正策略 |
|
||||
|----------|---------|---------|---------|
|
||||
| font-size 偏差 | 极高 | Tab 26rpx→24rpx, 金额 28rpx→32rpx | 查 Tailwind 类名换算 |
|
||||
| border-radius 偏差 | 高 | 标签 6rpx→8rpx, 卡片 28rpx→32rpx, 头像 14rpx→24rpx | 查 `design-tokens.json` |
|
||||
| padding/margin 偏差 | 高 | 卡片 30rpx→28rpx, 列表容器 24rpx→28rpx | 查 Tailwind 类名换算 |
|
||||
| line-height 缺失 | 中 | Tab 文字未写 line-height | 补 `line-height: 36rpx` |
|
||||
| 颜色偏差 | 中 | 灰色 #c5c5c5→#a6a6a6, 边框 #eeeeee→#e7e7e7 | 查 `design-tokens.json` 灰阶 |
|
||||
| font-weight 偏差 | 低 | 数据行 600→500 | 查 Tailwind 类名 |
|
||||
| flex 比例偏差 | 低 | 筛选按钮 1.8→2 | 查 H5 源码 |
|
||||
|
||||
### 4.2 跨页面共性偏差
|
||||
|
||||
以下偏差在三个看板页面中重复出现,修正一个页面后应同步检查其他页面:
|
||||
|
||||
- Tab 导航:font-size 26→24rpx, padding 24→22rpx, line-height 缺失→36rpx
|
||||
- 筛选栏内层:border-radius 14→16rpx(或 32rpx,取决于页面)
|
||||
- 卡片:padding-top/bottom 30→28rpx, margin-bottom 20→22rpx
|
||||
- 标签:border-radius 6→8rpx
|
||||
|
||||
### 4.3 不修复的差异
|
||||
|
||||
以下差异属于结构性差异或设计决策差异,不计入差异率:
|
||||
- 头部区域(H5 safe-area-top vs MP 状态栏+胶囊)
|
||||
- 字体渲染差异(H5 Noto Sans SC vs MP 系统字体)
|
||||
- 环比箭头(H5 SVG vs MP 文字 ↑↓,已确认可接受)
|
||||
- AI 浮动按钮区域(H5 已隐藏,MP 端如存在则忽略该区域差异)
|
||||
|
||||
## 5. 页面清单与截图参数
|
||||
|
||||
所有页面统一使用固定 600px 步长滚动截图,不依赖锚点。步数基于 Playwright 实测的 `maxScroll = scrollHeight - viewportHeight`,公式:`N = floor(maxScroll / 600) + 1`;`maxScroll ≤ 10` 视为单屏(N=1)。
|
||||
|
||||
> 以下数据基于 2026-03-10 Playwright 实测(430×752 视口,DPR=1.5,展开所有折叠区域),验证脚本 `scripts/ops/_verify_step_counts.py`,原始数据 `export/SYSTEM/REPORTS/h5_page_heights/step_counts_verified.json`。
|
||||
|
||||
| # | 页面 | scrollHeight | maxScroll | 实测步数 | scrollTop 序列 | 主要内容区域 |
|
||||
|---|------|-------------|-----------|---------|---------------|-------------|
|
||||
| 1 | board-finance | 5600 | 4848 | 10 | 0,600,...,4800,4848 | 经营一览 / 预收资产 / 应计收入确认 / 现金流入 / 现金流出 / 助教分析 |
|
||||
| 2 | board-coach | 754 | 2 | 1★ | 0 | 助教卡片列表(×4 排序维度:perf/salary/sv/task) |
|
||||
| 3 | board-customer | 752 | 0 | 1 | 0 | 客户卡片列表(×8 客户维度:recall/potential/balance/recharge/recent/spend60/freq60/loyal) |
|
||||
| 4 | task-detail | 2995 | 2243 | 5 | 0,600,1200,1800,2243 | Banner / 关系 / 建议 / 线索 / 备注 |
|
||||
| 5 | task-detail-callback | 2397 | 1645 | 4 | 0,600,1200,1645 | 同上(teal 主题) |
|
||||
| 6 | task-detail-priority | 2389 | 1637 | 4 | 0,600,1200,1637 | 同上(orange 主题) |
|
||||
| 7 | task-detail-relationship | 2275 | 1523 | 4 | 0,600,1200,1523 | 同上(pink 主题) |
|
||||
| 8 | coach-detail | 2918 | 2166 | 5 | 0,600,1200,1800,2166 | Banner / 绩效概览 / 收入明细 / 前10客户 |
|
||||
| 9 | customer-detail | 3070 | 2318 | 5 | 0,600,1200,1800,2318 | Banner / AI洞察 / 线索 / 任务 / 最爱助教 / 消费记录 |
|
||||
| 10 | performance | 7705 | 6953 | 13 | 0,600,...,6600,6953 | Banner / 收入 / 本月业绩 / 上月收入 / 新客 / 常客(最长页面) |
|
||||
| 11 | task-list | 1428 | 676 | 3 | 0,600,676 | Banner业绩卡 / 任务列表 |
|
||||
| 12 | my-profile | 752 | 0 | 1 | 0 | 整页(单屏) |
|
||||
| 13 | customer-service-records | 961 | 209 | 2 | 0,209 | Banner统计 / 记录列表 |
|
||||
| 14 | performance-records | 2677 | 1925 | 5 | 0,600,1200,1800,1925 | Banner / 统计概览 / 记录列表 |
|
||||
| 15 | chat | 1061 | 309 | 2 | 0,309 | 对话区 / 输入区 |
|
||||
| 16 | chat-history | 752 | 0 | 1 | 0 | 整页(单屏) |
|
||||
| 17 | notes | 1709 | 957 | 3 | 0,600,957 | 导航 / 备注列表 |
|
||||
|
||||
> ★ board-coach maxScroll=2px,按实用主义规则(≤10px)视为单屏。
|
||||
> 单屏页面(board-coach、board-customer、my-profile、chat-history)只需 step-0 一张截图。多维度页面需切换维度后分别截图:board-coach ×4 排序维度(通过排序筛选下拉切换)、board-customer ×8 客户维度(通过维度筛选下拉切换)。
|
||||
|
||||
### 5.1 对照处理单元计算
|
||||
|
||||
对照处理单元 = 每页实测步数 × 维度数(无维度的页面维度数=1)。数据来源:2026-03-10 Playwright 实测(`scripts/ops/_verify_step_counts.py`)。
|
||||
|
||||
| 页面 | 步数 | 维度数 | 单元数 |
|
||||
|------|------|--------|--------|
|
||||
| board-finance | 10 | 1 | 10 |
|
||||
| board-coach | 1★ | 4 | 4 |
|
||||
| board-customer | 1 | 8 | 8 |
|
||||
| task-detail | 5 | 1 | 5 |
|
||||
| task-detail-callback | 4 | 1 | 4 |
|
||||
| task-detail-priority | 4 | 1 | 4 |
|
||||
| task-detail-relationship | 4 | 1 | 4 |
|
||||
| coach-detail | 5 | 1 | 5 |
|
||||
| customer-detail | 5 | 1 | 5 |
|
||||
| performance | 13 | 1 | 13 |
|
||||
| task-list | 3 | 1 | 3 |
|
||||
| my-profile | 1 | 1 | 1 |
|
||||
| customer-service-records | 2 | 1 | 2 |
|
||||
| performance-records | 5 | 1 | 5 |
|
||||
| chat | 2 | 1 | 2 |
|
||||
| chat-history | 1 | 1 | 1 |
|
||||
| notes | 3 | 1 | 3 |
|
||||
| **合计** | | | **79** |
|
||||
|
||||
> ★ board-coach maxScroll=2px,按实用主义规则(≤10px)视为单屏。
|
||||
|
||||
## 6. 产出物归档结构
|
||||
|
||||
所有截图、diff、审计报告统一归入 `docs/h5_ui/compare/`,按页面分子目录。
|
||||
|
||||
```
|
||||
docs/h5_ui/compare/
|
||||
├── board-finance/
|
||||
│ ├── h5--step-0.png # H5 截图(645×1128)
|
||||
│ ├── h5--step-600.png
|
||||
│ ├── mp--step-0.png # MP 截图(645×1128)
|
||||
│ ├── mp--step-600.png
|
||||
│ ├── diff--step-0.png # 像素对比 diff 图
|
||||
│ ├── diff--step-600.png
|
||||
│ ├── report.md # 差异率汇总 + 对比分析
|
||||
│ └── audit.md # 三方对照审计报告
|
||||
├── board-coach/
|
||||
│ ├── perf/ # 多维度页面按排序维度分子目录
|
||||
│ │ ├── h5--step-0.png
|
||||
│ │ ├── mp--step-0.png
|
||||
│ │ └── diff--step-0.png
|
||||
│ ├── salary/
|
||||
│ ├── sv/
|
||||
│ ├── task/
|
||||
│ ├── report.md
|
||||
│ └── audit.md
|
||||
├── board-customer/
|
||||
│ ├── recall/ # 8 种客户维度各一个子目录
|
||||
│ ├── potential/
|
||||
│ ├── balance/
|
||||
│ ├── recharge/
|
||||
│ ├── recent/
|
||||
│ ├── spend60/
|
||||
│ ├── freq60/
|
||||
│ ├── loyal/
|
||||
│ ├── report.md
|
||||
│ └── audit.md
|
||||
├── my-profile/ # 单屏页面
|
||||
│ ├── h5--step-0.png
|
||||
│ ├── mp--step-0.png
|
||||
│ ├── diff--step-0.png
|
||||
│ ├── report.md
|
||||
│ └── audit.md
|
||||
...(17 个页面各一个子目录)
|
||||
```
|
||||
|
||||
文件命名规则:
|
||||
- `h5--step-<scrollTop>.png` / `mp--step-<scrollTop>.png` / `diff--step-<scrollTop>.png`
|
||||
- scrollTop 值:0, 600, 1200, 1800 ...
|
||||
- 文件名不含页面名(已在子目录中)
|
||||
- 单屏页面只有 `--step-0` 一组
|
||||
- 多维度页面(board-coach ×4 排序维度、board-customer ×8 客户维度)按维度分子目录
|
||||
|
||||
废弃目录(不再使用):
|
||||
- `docs/h5_ui/screenshots/` → 已清理
|
||||
- `docs/h5_ui/mp-screenshots/` → 已清理
|
||||
- `docs/h5_ui/h5-segments/` → 已清理
|
||||
- `docs/h5_ui/diffs/` → 已清理
|
||||
- `docs/h5_ui/anchors/` → 已清理
|
||||
- `docs/h5_ui/analysis/` → 审计报告迁入各页面子目录
|
||||
|
||||
## 7. 风险与依赖
|
||||
|
||||
### 7.1 外部依赖
|
||||
|
||||
| 依赖项 | 风险等级 | 说明 | Fallback |
|
||||
|--------|---------|------|----------|
|
||||
| 微信开发者工具 MCP 连接 | 中 | MCP 连接偶尔断开(超时/端口占用),需重连 | `reconnect_devtools` 重连;若反复失败,手动截图后放入 `compare/<page>/` |
|
||||
| Playwright 浏览器 | 低 | 首次运行需 `playwright install chromium` | `uv run playwright install chromium` |
|
||||
| image_compare MCP | 低 | MCP server 未启动时 compare_images 不可用 | 使用 `anchor_compare.py compare` 命令行替代 |
|
||||
|
||||
### 7.2 已知限制
|
||||
|
||||
- 字体渲染引擎差异(Chromium vs 微信 webview)可能引入约 1-2% 的固有差异率
|
||||
- 字体渲染差异(H5 Noto Sans SC vs MP 系统字体)不可消除,属于可接受差异
|
||||
- 微信开发者工具截图不支持指定 DPR,实际 DPR 取决于模拟器设置(当前 iPhone 15 Pro Max 有效 DPR=1.5)
|
||||
- board-coach/board-customer 的多维度截图验证(4/8 种维度)需要 Mock 数据支持不同维度的展示
|
||||
|
||||
## 8. 页面执行顺序
|
||||
|
||||
### 8.0 前置任务:TS 零诊断基线检查与共性偏差批量修复
|
||||
|
||||
在进入 A 批次之前,需完成两项前置工作:
|
||||
|
||||
#### 8.0.1 TS 零诊断基线检查
|
||||
|
||||
对 17 个页面的 `.ts` 文件运行 `getDiagnostics`,确认全部为零诊断。这是 Step 0-5 结构迁移的交付基线,如果此时已有 TS 错误,必须先修复再进入像素精调,否则精调过程中引入的新错误会与历史错误混淆。
|
||||
|
||||
#### 8.0.2 跨页面共性偏差批量修复
|
||||
|
||||
基于 4.2 节已识别的跨页面共性偏差,在 `app.wxss` 或共享组件样式中统一修正:
|
||||
|
||||
| 共性偏差 | 涉及页面 | 修正方案 |
|
||||
|----------|---------|---------|
|
||||
| Tab 导航 font-size 26→24rpx | board-finance/coach/customer | 统一修正各页面 Tab 样式 |
|
||||
| Tab 导航 padding 24→22rpx | board-finance/coach/customer | 同上 |
|
||||
| Tab 导航 line-height 缺失→36rpx | board-finance/coach/customer | 同上 |
|
||||
| 筛选栏内层 border-radius 14→16rpx | board-finance/coach/customer | 统一修正筛选栏样式 |
|
||||
| 卡片 padding-top/bottom 30→28rpx | board-finance/coach/customer | 统一修正卡片容器样式 |
|
||||
| 标签 border-radius 6→8rpx | board-finance/coach/customer | 统一修正标签样式 |
|
||||
|
||||
先批量修复共性偏差,再进入各页面的个性化精调,可显著减少重复工作量。修复后需对三个看板页面快速截图验证,确认共性修正未引入新问题。
|
||||
|
||||
### 8.1 批次执行顺序
|
||||
|
||||
按原批次顺序,简单页面优先积累经验:
|
||||
|
||||
| 批次 | 页面 | 预估复杂度 | 对照单元总数 |
|
||||
|------|------|-----------|------------|
|
||||
| A | board-finance, board-coach, board-customer | 高 | 22 |
|
||||
| B | task-list, my-profile | 低-中 | 4 |
|
||||
| C | task-detail(主页面 5 单元)+ 3 变体(各 4 单元,仅验证主题色) | 中 | 17 |
|
||||
| D | coach-detail, customer-detail, customer-service-records | 中 | 12 |
|
||||
| E | performance, performance-records | 高 | 18 |
|
||||
| F | chat, chat-history | 低 | 3 |
|
||||
| G | notes | 低 | 3 |
|
||||
| | **合计** | | **79** |
|
||||
147
.kiro/specs/h5-miniprogram-migration-subsequent/requirements.md
Normal file
147
.kiro/specs/h5-miniprogram-migration-subsequent/requirements.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# 需求文档:H5 → 微信小程序像素精调
|
||||
|
||||
## 简介
|
||||
|
||||
本 spec 承接 `h5-miniprogram-migration` 的 Step 0-5 结构迁移成果。17 个页面已全部完成结构迁移、编译验证和结构还原验证。本 spec 专注于 Step 6-7:像素级视觉还原与验收签收。
|
||||
|
||||
核心单位是「对照处理单元」——每个页面被分解为多个可独立截图、独立对比、独立修正的最小区域段。17 个页面共分解为 79 个对照处理单元(详见 design.md §5.1,基于 2026-03-10 Playwright 实测校准)。
|
||||
|
||||
权威参考:
|
||||
- 迁移规则:`docs/prd/MIGRATION-PLAYBOOK.md`
|
||||
- 样式标准:`docs/h5_ui/design-tokens.json`(颜色、字号、圆角、阴影的标准值)
|
||||
- 工具链:`scripts/ops/anchor_compare.py`(固定步长截图 + 逐屏对比)
|
||||
|
||||
## 术语表
|
||||
|
||||
| 术语 | 定义 |
|
||||
|------|------|
|
||||
| 对照处理单元 | 一个页面内可独立截图、独立对比、独立修正的最小区域段(如"经营一览"板块、"助教卡片列表"区域) |
|
||||
| 差异率 | pixelmatch / image_compare 输出的像素差异百分比,仅针对内容区域计算(头部导航栏/状态栏不计入) |
|
||||
| 结构级修正 | 差异率 > 10% 时的修正阶段,修复明显的布局/颜色/缺失问题 |
|
||||
| 像素级精调 | 差异率 5%~10% 时的精调阶段,微调 padding/font-size/color 等 |
|
||||
| 固定步长 | 600px 逻辑像素为一步,两端使用完全相同的 scrollTop 序列逐屏截图 |
|
||||
| 双端截图 | 同一页面的 H5 截图(DPR=1.5, 645×1128)和 MP 截图(DPR=1.5, 645×1128),两端参数完全一致,无需缩放 |
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:页面分解与对照处理单元建立
|
||||
|
||||
**用户故事:** 作为迁移执行者,我希望每个页面被分解为可独立处理的最小对照单元,以便逐屏精确对比和修正。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 分解流程 SHALL 对每个页面执行以下步骤:分析 H5 原型结构 → 识别语义区域 → 按固定 600px 步长计算截图屏数 → 建立对照处理单元清单
|
||||
2. THE 对照处理单元 SHALL 满足以下条件:每屏为一个对照单元(645×1128 像素),语义完整性由审计报告人工确认
|
||||
3. THE 步数计算 SHALL 基于 Playwright 实测的 `maxScroll = scrollHeight - viewportHeight`:`N = floor(maxScroll / 600) + 1`;`maxScroll ≤ 10` 的页面视为单屏(N=1)
|
||||
4. WHEN 页面为多维度页面(如 board-coach ×4 排序维度、board-customer ×8 客户维度)时,THE 分解流程 SHALL 按维度分子目录,每个维度独立截图和对比。维度切换通过页面筛选栏下拉操作完成(board-coach 通过排序筛选切换 perf/salary/sv/task 四种卡片模板;board-customer 通过维度筛选切换 recall/potential/balance/recharge/recent/spend60/freq60/loyal 八种卡片模板)
|
||||
5. THE 分解结果 SHALL 输出为每页一份的对照单元清单,包含:单元编号(step-N)、scrollTop 值、预估复杂度
|
||||
|
||||
### 需求 2:双端截图标准
|
||||
|
||||
**用户故事:** 作为迁移执行者,我希望 H5 和 MP 的截图在尺寸、视口、DPR 上严格统一,以确保像素对比结果有意义。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE H5 截图 SHALL 使用以下参数:viewport 430×752, DPR=1.5, 输出 645×1128;通过 Playwright 截取(Live Server `http://localhost:5500`),等待 Tailwind CDN JIT 渲染 1500ms
|
||||
2. THE MP 截图 SHALL 使用以下参数:viewport 430×752, DPR=1.5(MCP 有效 DPR), 输出 645×1128;通过微信开发者工具 MCP 截取。两端输出尺寸完全一致,无需任何缩放
|
||||
3. WHEN 对比页面时,THE 截图流程 SHALL 使用固定 600px 步长滚动截图,两端使用完全相同的 scrollTop 序列(0, 600, 1200, ...),不依赖锚点
|
||||
4. THE H5 截图前 SHALL 隐藏底部浮动元素:`#bottomNav`(64px fixed 底部导航)和 `.ai-float-btn-container`(56px 浮动按钮),通过 JS 设置 `display: none`。MP 端原生 tabBar 不在截图中,无需处理
|
||||
5. THE 头部区域(H5 safe-area-top ~46px / MP 状态栏+胶囊 ~88px)SHALL 不计入像素差异率,属结构性差异
|
||||
6. WHEN 截图流程中发现 H5 页面或 MP 页面无法正常渲染时,THE 流程 SHALL 暂停并报告问题,禁止使用异常截图进行对比
|
||||
7. WHEN MP 端页面高度与 H5 不一致时,THE 截图流程 SHALL 先截双端 step-0(首屏)确认基线,再截 step-600(第二屏)校准双端高度差异,之后逐屏推进。每屏截图前读取 MP 端实际 scrollTop,确认到达预期位置
|
||||
|
||||
### 需求 3:两阶段收敛流程
|
||||
|
||||
**用户故事:** 作为迁移执行者,我希望像素精调按差异率分阶段处理——先修大问题再调细节——以高效收敛到达标标准。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 收敛流程 SHALL 分为两个阶段:
|
||||
- 阶段一(结构级修正):差异率 > 10%,每轮修复 2-5 处明显差异(布局/颜色/缺失/字号)
|
||||
- 阶段二(像素级精调):差异率 5%~10%,每轮修复 1-3 处精细差异(padding ±2rpx / line-height / border-radius / 色值)
|
||||
2. THE 达标标准 SHALL 为:差异率 < 5% 标记通过;差异率 > 15% 且多轮无法收敛则触发重写
|
||||
3. WHEN 进入每轮修正时,THE 流程 SHALL 先截图对比 → 肉眼审查 diff 图 → 定位差异区域 → 修改 WXSS/WXML → 重新截图验证
|
||||
4. THE 每轮修正 SHALL 控制修改范围(阶段一 2-5 处、阶段二 1-3 处),避免一次改太多难以定位效果
|
||||
5. WHEN 差异率在连续 3 轮内未下降超过 1% 时,THE 流程 SHALL 评估是否为结构性差异(如头部区域、字体渲染差异),若是则标注为可接受差异并停止该区域的精调
|
||||
|
||||
### 需求 4:分析报告持久化
|
||||
|
||||
**用户故事:** 作为项目管理者,我希望每个页面的对比分析结果持久化为 MD 文件,以便追溯和复查。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 每个页面 SHALL 在 `docs/h5_ui/compare/<page>/report.md` 输出对比分析报告
|
||||
2. THE 报告 SHALL 包含:初始差异率、每轮修正记录(轮次/修改内容/修正后差异率)、最终差异率、遗留的可接受差异说明
|
||||
3. THE 报告 SHALL 在每轮修正后更新,记录收敛过程
|
||||
4. THE 截图产出物 SHALL 统一归入 `docs/h5_ui/compare/<page>/`,按页面分子目录:
|
||||
- H5 截图:`h5--step-<scrollTop>.png`
|
||||
- MP 截图:`mp--step-<scrollTop>.png`
|
||||
- Diff 图:`diff--step-<scrollTop>.png`
|
||||
- 审计报告:`audit.md`
|
||||
- 对比报告:`report.md`
|
||||
- 多维度页面按维度再分子目录(如 `board-coach/perf/`)
|
||||
5. THE 每轮新截图 SHALL 覆盖上一轮同名文件,不保留历史版本(依赖 git 追溯)
|
||||
|
||||
### 需求 5:修改优先级规则
|
||||
|
||||
**用户故事:** 作为迁移执行者,我希望有明确的修改优先级指导,以便在每轮修正中优先处理影响最大的差异。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 修改优先级 SHALL 按以下顺序排列(从高到低):
|
||||
- P0:区域缺失或顺序错误(结构性问题)
|
||||
- P1:整块背景色/渐变色不匹配
|
||||
- P2:字号(font-size)明显偏差(≥4rpx)
|
||||
- P3:间距(padding/margin/gap)明显偏差(≥4rpx)
|
||||
- P4:圆角(border-radius)偏差
|
||||
- P5:颜色色值微调(灰阶偏差、透明度)
|
||||
- P6:行高(line-height)/ 字重(font-weight)微调
|
||||
- P7:阴影(box-shadow)参数微调
|
||||
2. WHEN 阶段一修正时,THE 流程 SHALL 优先处理 P0-P3 级别的差异
|
||||
3. WHEN 阶段二精调时,THE 流程 SHALL 处理 P4-P7 级别的差异
|
||||
4. THE 修改 SHALL 优先使用 `docs/h5_ui/design-tokens.json` 中定义的标准值,禁止使用非标准灰色(#333/#666/#999 等)
|
||||
5. THE 修改 SHALL 优先使用 flex/盒模型的确定性方案,禁止使用"碰运气"的魔法数
|
||||
|
||||
### 需求 6:验收签收标准
|
||||
|
||||
**用户故事:** 作为项目管理者,我希望每个页面有明确的验收标准,以确保交付质量一致。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 单页验收 SHALL 满足以下条件:
|
||||
- 内容区差异率 < 5%
|
||||
- TS 编译零诊断
|
||||
- 所有对照处理单元均已逐屏对比
|
||||
- report.md 已归档且记录完整
|
||||
2. THE 批次验收 SHALL 满足以下条件:
|
||||
- 批次内所有页面单页验收通过
|
||||
- 共享组件在批次内所有页面中表现一致
|
||||
- 所有截图和 diff 图已按目录归档
|
||||
3. THE 全局验收 SHALL 满足以下条件:
|
||||
- 17 个页面(79 个对照处理单元)全部单页验收通过
|
||||
- 差异率汇总表已输出(页面名 / 初始差异率 / 最终差异率 / 修正轮数)
|
||||
- TS 编译零诊断复查通过
|
||||
|
||||
### 需求 7:工具链使用规范
|
||||
|
||||
**用户故事:** 作为迁移执行者,我希望工具链的使用有明确规范,以确保截图和对比结果的一致性和可复现性。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE H5 截图 SHALL 统一通过 `scripts/ops/anchor_compare.py extract-h5 <page>` 获取(固定 600px 步长滚动截图,viewport 430×752, DPR=1.5;通过 Live Server `http://localhost:5500` 访问页面)
|
||||
2. THE MP 截图 SHALL 通过微信开发者工具 MCP 截取,按相同的 scrollTop 序列(0, 600, 1200, ...)逐屏截图
|
||||
3. THE 像素对比 SHALL 使用 `image_compare` power 的 `compare_images` 工具,或 `anchor_compare.py compare <page>` 命令
|
||||
4. WHEN 页面需要逐屏对比时,THE 流程 SHALL 使用 anchor_compare.py 的两步流程:`extract-h5` → `compare`(MP 截图通过 MCP 工具独立获取)
|
||||
5. THE 工具链输出 SHALL 统一存放到 `docs/h5_ui/compare/<page>/`(见需求 4),禁止散放在项目根目录或临时位置
|
||||
|
||||
### 需求 8:风险与异常处理
|
||||
|
||||
**用户故事:** 作为迁移执行者,我希望在工具链故障或环境异常时有明确的 Fallback 方案,以避免流程阻塞。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 微信开发者工具 MCP 连接断开时,THE 流程 SHALL 先尝试 `reconnect_devtools` 重连,若连续 3 次失败则暂停该页面任务并报告问题
|
||||
2. WHEN Live Server 端口 5500 被占用时,THE 流程 SHALL 检查端口占用并提示用户释放端口,不得使用其他端口截图(避免 URL 不一致)
|
||||
3. WHEN image_compare MCP 不可用时,THE 流程 SHALL 使用 `anchor_compare.py compare` 命令行作为替代
|
||||
4. WHEN 某页面差异率 > 15% 且连续 5 轮无法收敛时,THE 流程 SHALL 暂停并输出问题分析报告,由用户决定是否触发重写
|
||||
5. THE 每个批次任务 SHALL 在开始前验证页面 TS 零诊断基线,如有编译错误则先修复再进入精调
|
||||
135
.kiro/specs/h5-miniprogram-migration-subsequent/tasks.md
Normal file
135
.kiro/specs/h5-miniprogram-migration-subsequent/tasks.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# 实现计划:H5 → 微信小程序视觉还原
|
||||
|
||||
## 概述
|
||||
|
||||
17 个页面(共 79 个对照处理单元)已完成 Step 0-5 结构迁移。本计划覆盖 Step 6-7:视觉还原与验收。
|
||||
|
||||
采用固定 600px 步长滚动截图方案:两端使用完全相同的 scrollTop 序列(0, 600, 1200, ...),不依赖锚点,消除 H5/MP 元素位置差异导致的对齐问题。
|
||||
|
||||
采用混合组织方式:前置阶段按流程批量操作(截图→对比→共性修复),修正阶段按页面逐个完成(审计→修正→验收)。
|
||||
|
||||
## 截图方案要点
|
||||
|
||||
- 双端参数:viewport 430×752, DPR=1.5, 输出 645×1128, 无需缩放
|
||||
- 步长:600px(逻辑像素)
|
||||
- H5 截图:`scripts/ops/anchor_compare.py extract-h5 <page>`(Playwright + Live Server localhost:5500)
|
||||
- MP 截图:MCP 工具(`wx.pageScrollTo` + `screenshot`)
|
||||
- 产出物根目录:`docs/h5_ui/compare/<page>/`
|
||||
- 文件命名:`h5--step-<scrollTop>.png` / `mp--step-<scrollTop>.png` / `diff--step-<scrollTop>.png`
|
||||
- 审计报告:`docs/h5_ui/compare/<page>/audit.md`
|
||||
- 对比报告:`docs/h5_ui/compare/<page>/report.md`
|
||||
- 多维度页面:`docs/h5_ui/compare/<page>/<dimension>/`(如 board-coach/perf/、board-customer/recall/)
|
||||
- 维度切换:board-coach 通过排序筛选下拉切换 perf/salary/sv/task;board-customer 通过维度筛选下拉切换 recall/potential/balance/recharge/recent/spend60/freq60/loyal
|
||||
|
||||
## 逐页视觉还原流程(阶段 3 每页统一流程)
|
||||
|
||||
每个页面子任务按以下步骤执行:
|
||||
|
||||
1. **截图**:先截双端 step-0(首屏)确认基线,再截 step-600(第二屏)校准双端高度差异,之后按固定步长序列逐屏推进。每屏读取 MP 端实际 scrollTop 确认到达预期位置
|
||||
2. **审计报告**:同时读取 H5 源码(HTML + Tailwind 类名)、MP 源码(WXML + WXSS)、diff 截图,三方对照产出 `docs/h5_ui/compare/<page>/audit.md`
|
||||
3. **浮动元素检测**(长页面):对比多屏截图中持续相同位置的差异,识别 sticky/fixed 元素,优先修复(一次修复所有屏受益)
|
||||
4. **阶段一修正循环**(差异率 > 10%):按审计报告偏差清单修正 → 每轮修 2-5 处 → 重新截图对比 → 循环至 ≤ 10%
|
||||
5. **阶段二精调循环**(差异率 5%~10%):精确定位差异区域 → 每轮修 1-3 处 → 重新截图对比 → 循环至 < 5%
|
||||
6. **验收**:差异率 < 5% → 更新 report.md → 标记通过
|
||||
|
||||
### 长页面级联规则
|
||||
|
||||
修正某一屏的 WXSS 后,所有屏必须重新截图对比(布局变化会影响每屏内容)。优先修复 sticky 区域差异,从 step-0 开始顺序审查。
|
||||
|
||||
---
|
||||
|
||||
## 任务
|
||||
|
||||
### 阶段 0 — 前置准备
|
||||
|
||||
- [x] 0. 工具链验证与基线检查
|
||||
- [x] 0.1 验证截图工具链:确认 Playwright 可通过 Live Server (localhost:5500) 截图 H5 页面、微信开发者工具 MCP 可连接截图、image_compare 可对比
|
||||
- [x] 0.2 TS 零诊断基线检查:对 17 个页面的 .ts 文件运行 getDiagnostics,确认全部为零诊断
|
||||
- [x] 0.3 固定步长方案验证:board-finance 实测 10 屏(step 0-4848,scrollHeight=5600, maxScroll=4848),两端精确命中目标 scrollTop,截图 645×1128 完全一致
|
||||
|
||||
---
|
||||
|
||||
### 阶段 1 — 批量截图与初始对比
|
||||
|
||||
- [ ] 1. 批量获取 H5 截图(board-finance 已完成 10 屏验证)
|
||||
- [ ] 1.1 board-finance H5 固定步长截图(10 屏,step 0-4848)— 已通过 test_fixed_step.py 完成
|
||||
- [x] 1.2 重构 anchor_compare.py 为固定步长模式,支持 `extract-h5 <page>` 自动计算页面高度和步数
|
||||
- [ ] 1.3 对剩余 16 个页面运行 H5 固定步长截图
|
||||
|
||||
- [ ] 2. 批量获取 MP 截图(board-finance 已完成 10 屏验证)
|
||||
- [x] 2.1 board-finance MP 固定步长截图(10 屏,step 0-4848)— 已通过 MCP 工具完成
|
||||
- [ ] 2.2 对剩余 16 个页面通过 MCP 工具截取 MP 固定步长截图
|
||||
|
||||
- [ ] 3. 批量初始对比与差异率采集
|
||||
- [x] 3.1 board-finance 逐屏对比完成(差异率 5.01%~17.71%,差异来自组件未精校)
|
||||
- [ ] 3.2 对剩余 16 个页面运行逐屏对比,输出 diff 图到 `docs/h5_ui/compare/<page>/`
|
||||
- [ ] 3.3 汇总差异率表(页面名 / 屏数 / 各屏差异率),按差异率降序排列
|
||||
|
||||
---
|
||||
|
||||
### 阶段 2 — 共性偏差批量修复
|
||||
|
||||
- [ ] 4. 跨页面共性偏差修复
|
||||
- [ ] 4.1 根据阶段 1 差异率和 design.md §4.2 已识别的共性偏差(Tab 导航 font-size/padding/line-height、筛选栏 border-radius、卡片 padding、标签 border-radius),在各页面 WXSS 或共享组件中统一修正
|
||||
- [ ] 4.2 共性修复后重新截图验证:对涉及修改的页面重新截图 + 对比,确认共性修正未引入新问题
|
||||
|
||||
---
|
||||
|
||||
### 阶段 3 — 逐页视觉还原
|
||||
|
||||
按批次组织,每页按「逐页视觉还原流程」执行(截图→审计→浮动元素检测→修正循环→验收)。
|
||||
|
||||
#### A 批次 — 看板页面
|
||||
|
||||
- [ ] 5. board-finance 视觉还原(长页面,10 屏 step 0-4848)。含 sticky 区域检测(safe-area-top 45px + filterBar 71px = 116px)
|
||||
- [ ] 6. board-coach 视觉还原(短页面,4 种排序维度 perf/salary/sv/task 需逐维度截图验证,通过排序筛选下拉切换)
|
||||
- [ ] 7. board-customer 视觉还原(短页面,8 种客户维度 recall/potential/balance/recharge/recent/spend60/freq60/loyal 需逐维度截图验证,通过维度筛选下拉切换)
|
||||
- [ ] 8. A 批次检查点:3 页全部差异率 < 5%,共享组件跨页表现一致
|
||||
|
||||
#### B 批次 — 核心页面
|
||||
|
||||
- [ ] 9. task-list 视觉还原(约 3 屏)
|
||||
- [ ] 10. my-profile 视觉还原(单屏页面)
|
||||
- [ ] 11. B 批次检查点:2 页全部差异率 < 5%
|
||||
|
||||
#### C 批次 — 任务详情页面
|
||||
|
||||
> task-detail 系列 4 个页面共享相同布局,仅 Banner 主题色不同。主页面做完整还原,3 个变体只验证主题色差异。
|
||||
|
||||
- [ ] 12. task-detail 视觉还原(主页面,约 5 屏,完整审计→修正→验收)
|
||||
- [ ] 13. task-detail 变体主题色验证(callback=teal / priority=orange / relationship=pink):逐个截图 → 仅对比含主题色的屏 → 确认主题色正确应用
|
||||
- [ ] 14. C 批次检查点:4 页全部差异率 < 5%
|
||||
|
||||
#### D 批次 — 详情页面
|
||||
|
||||
- [ ] 15. coach-detail 视觉还原(约 5 屏)
|
||||
- [ ] 16. customer-detail 视觉还原(约 5 屏)
|
||||
- [ ] 17. customer-service-records 视觉还原(约 2 屏)
|
||||
- [ ] 18. D 批次检查点:3 页全部差异率 < 5%
|
||||
|
||||
#### E 批次 — 绩效页面
|
||||
|
||||
- [ ] 19. performance 视觉还原(约 13 屏,本 spec 最长页面)
|
||||
- [ ] 20. performance-records 视觉还原(约 5 屏)
|
||||
- [ ] 21. E 批次检查点:2 页全部差异率 < 5%
|
||||
|
||||
#### F 批次 — 对话页面
|
||||
|
||||
- [ ] 22. chat 视觉还原(约 2 屏)
|
||||
- [ ] 23. chat-history 视觉还原(单屏页面)
|
||||
- [ ] 24. F 批次检查点:2 页全部差异率 < 5%
|
||||
|
||||
#### G 批次 — 其他页面
|
||||
|
||||
- [ ] 25. notes 视觉还原(约 3 屏)
|
||||
- [ ] 26. G 批次检查点:差异率 < 5%
|
||||
|
||||
---
|
||||
|
||||
### 阶段 4 — 全局验收
|
||||
|
||||
- [ ] 27. 全局验收
|
||||
- [ ] 27.1 汇总 17 页面差异率表(页面名 / 屏数 / 初始差异率 / 共性修复后差异率 / 最终差异率 / 修正轮数),共 79 个对照处理单元
|
||||
- [ ] 27.2 确认所有 `compare/<page>/report.md` 已归档
|
||||
- [ ] 27.3 TS 编译零诊断复查(17 个页面)
|
||||
- [ ] 27.4 标记 spec 完成
|
||||
@@ -6,302 +6,455 @@
|
||||
|
||||
## 任务
|
||||
|
||||
- [ ] 1. 全局基础设施搭建
|
||||
- [ ] 1.1 创建 AI 图标配色工具模块
|
||||
- [x] 1. 全局基础设施搭建
|
||||
- [x] 1.1 创建 AI 图标配色工具模块
|
||||
- 文件:`utils/ai-color.ts`
|
||||
- 实现 `AI_COLOR_SCHEMES` 常量(6 种配色:red/orange/yellow/blue/indigo/purple)
|
||||
- 实现 `getRandomAiColor()` 函数,返回 `{ className, vars }` 对象
|
||||
- _需求: 32.1, 32.3, 32.5_
|
||||
|
||||
- [ ] 1.2 创建 AI 图标全局 WXSS 样式
|
||||
- [x] 1.2 创建 AI 图标全局 WXSS 样式
|
||||
- 在 `app.wxss` 中添加 `.ai-inline-icon`、`.ai-title-badge`、`.ai-color-*` 6 个配色类
|
||||
- 实现 `ai-shimmer`(12s)和 `ai-pulse`(3s)两个 `@keyframes` 动画
|
||||
- _需求: 32.1, 32.2_
|
||||
|
||||
- [ ] 1.3 导出小系列机器人 SVG
|
||||
- [x] 1.3 导出小系列机器人 SVG
|
||||
- 从 H5 源码提取白色填充版机器人 SVG,保存为 `assets/icons/ai-robot-sm.svg`
|
||||
- 复用已有 `assets/icons/ai-robot.svg`(大系列)
|
||||
- 更新 `docs/h5_ui/icon-mapping.md`
|
||||
- _需求: 32.6, 33.2, 33.3_
|
||||
|
||||
- [ ] 1.4 创建中间生成物目录结构
|
||||
- [x] 1.4 创建中间生成物目录结构
|
||||
- 创建 `docs/h5_ui/mp-screenshots/`(MP 截图,按页面分子目录)
|
||||
- 创建 `docs/h5_ui/diffs/`(像素对比结果,按页面分子目录)
|
||||
- 创建 `docs/h5_ui/h5-segments/`(H5 逐段截图,按页面分子目录)
|
||||
- 确认 `.gitignore` 不排除这些目录
|
||||
- _需求: 33.1_
|
||||
|
||||
- [ ] 1.5 验证全局基础设施
|
||||
- [x] 1.5 验证全局基础设施
|
||||
- 编译验证 `app.wxss` 无警告
|
||||
- 在任意已有页面中测试 AI 配色工具模块可正常导入和调用
|
||||
- _需求: 17.1_
|
||||
|
||||
- [ ] 2. A 批次 — board-finance(看板-财务)
|
||||
- [ ] 2.1 Step 0: 页面分析
|
||||
- [x] 2.1 Step 0: 页面分析
|
||||
- 打开 H5 原型截图 + `interactions/board-finance.md`
|
||||
- 确认屏数(预计 6 段:经营一览/预收资产/应计收入/现金流入/现金流出/助教分析)
|
||||
- 列出所有交互态(时间筛选/区域筛选/指标弹窗/目录面板/长按菜单)
|
||||
- 输出工作量估算表
|
||||
- _需求: 1.1, 1.3_
|
||||
|
||||
- [ ] 2.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- [x] 2.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- 冻结第一批输入物(Playbook + design-tokens + icon-mapping + HTML + CSS + interactions)
|
||||
- 输出《迁移审计报告》7 项(页面结构/CSS 风险/样式映射/图标处理/交互映射/外部依赖/缺失信息)
|
||||
- _需求: 3.1, 3.2, 4.1, 4.2, 4.3_
|
||||
|
||||
- [ ] 2.3 Step 3: 规则化转换(按屏逐个开发)
|
||||
- [x] 2.3 Step 3: 规则化转换(按屏逐个开发)
|
||||
- 创建四文件骨架 → .json 注册组件 → 按屏转换 WXML/WXSS/TS
|
||||
- 包含:filter-dropdown 复用、metric-card 复用、ai-float-button 集成
|
||||
- filter-bar 高度统一 70 逻辑像素
|
||||
- Mock 数据 + 三态处理
|
||||
- _需求: 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 21, 23.1, 32_
|
||||
|
||||
- [ ] 2.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- [x] 2.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- 7 项编译检查(WXML/WXSS/控制台/图片/组件/路由/TS 类型)
|
||||
- 9 项结构核对(按屏逐个验证)
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 2.5 Step 6-7: 像素精调 + 验收签收
|
||||
- 补充第二批输入物(computed-styles + 截图)
|
||||
- 使用 anchor_compare.py v2 逐段对比
|
||||
- H5 逐段截图 → `docs/h5_ui/h5-segments/board-finance/`
|
||||
- MP 逐段截图 → `docs/h5_ui/mp-screenshots/board-finance/`
|
||||
- Diff 图 → `docs/h5_ui/diffs/board-finance/`
|
||||
- 输出 `docs/h5_ui/diffs/board-finance/report.md`(差异率 + 问题区域)
|
||||
- 每轮 2-5 处修改,循环至差异率 ≤ 10%
|
||||
- 12 项验收清单
|
||||
- [-] 2.5 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 1.1)
|
||||
- _需求: 3.3, 19, 20_
|
||||
|
||||
- [ ] 3. A 批次 — board-coach(看板-助教)
|
||||
- [ ] 3.1 Step 0: 页面分析
|
||||
- [x] 3.1 Step 0: 页面分析
|
||||
- 确认屏数、交互态(排序筛选/擅长项目筛选/时间筛选)
|
||||
- _需求: 1.1, 1.3_
|
||||
|
||||
- [ ] 3.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- [x] 3.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- _需求: 3.1, 3.2, 4_
|
||||
|
||||
- [ ] 3.3 Step 3: 规则化转换
|
||||
- 包含:board-tab-bar 复用、filter-dropdown 复用
|
||||
- [x] 3.3 Step 3: 规则化转换
|
||||
- P0: error 状态补充(WXML 分支 + TS onRetry + pageState 类型扩展)
|
||||
- P1: 卡片按压反馈(hover-class="coach-card--hover" 替代 :active)
|
||||
- P2: dev-fab 组件注册(JSON 补注册)
|
||||
- P3: 样式偏差修复 8 项(Tab 24rpx/36rpx/22rpx、salary-amount 32rpx、right-sub #a6a6a6 22rpx、right-text 24rpx、right-highlight 28rpx、filter-item--wide flex:2)
|
||||
- _需求: 5-16, 21, 23.2, 23.4, 23.5, 32_
|
||||
|
||||
- [ ] 3.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- [x] 3.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- 7/7 编译检查通过,9/9 结构核对通过
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 3.5 Step 6-7: 像素精调 + 验收签收
|
||||
- [-] 3.5 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 1.2)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [ ] 4. A 批次 — board-customer(看板-客户)
|
||||
- [ ] 4.1 Step 0: 页面分析
|
||||
- [x] 4. A 批次 — board-customer(看板-客户)
|
||||
- [x] 4.1 Step 0: 页面分析
|
||||
- 确认屏数、交互态(客户类型筛选/偏爱项目筛选)
|
||||
- _需求: 1.1, 1.3_
|
||||
|
||||
- [ ] 4.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- [x] 4.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- _需求: 3.1, 3.2, 4_
|
||||
|
||||
- [ ] 4.3 Step 3: 规则化转换
|
||||
- 包含:board-tab-bar 复用、filter-dropdown 复用、heart-icon 复用、hobby-tag 复用
|
||||
- [x] 4.3 Step 3: 规则化转换
|
||||
- P0: error 状态补充(WXML + TS + WXSS)
|
||||
- P1: 卡片按压反馈(hover-class 替代 :active)
|
||||
- P2: dev-fab 组件注册
|
||||
- P3: 16 项 Step 3 级别样式偏差修复(Tab/筛选栏/卡片圆角/头像/中间行/网格/柱状图/专一表等)
|
||||
- _需求: 5-16, 21, 23.3, 23.4, 23.5, 32_
|
||||
|
||||
- [ ] 4.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- [x] 4.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- 7/7 编译检查通过,11/11 结构核对通过
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 4.5 Step 6-7: 像素精调 + 验收签收
|
||||
- [-] 4.5 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 1.3)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [ ] 5. 检查点 A — 看板批次验收
|
||||
- 确认 3 个看板页面全部通过 12 项验收清单
|
||||
- 确认共享组件(filter-dropdown、board-tab-bar、metric-card、heart-icon)在实际页面中表现正常
|
||||
- 确认 AI 图标配色系统在看板页面中正常工作
|
||||
- 总结 A 批次经验,调整后续批次策略(如有)
|
||||
- [x] 5. 检查点 A — 看板批次验收
|
||||
- 3 个看板页面全部编译零错误
|
||||
- 共享组件(filter-dropdown、board-tab-bar、ai-float-button、dev-fab、heart-icon)在所有页面中正确注册和引用
|
||||
- 四态处理(loading/empty/error/normal)统一实现
|
||||
- Tab 样式跨页面统一(24rpx/36rpx/22rpx)
|
||||
- Step 6-7 像素精调待第二批输入物
|
||||
|
||||
- [ ] 6. B 批次 — task-list(任务列表)
|
||||
- [ ] 6.1 Step 0: 页面分析
|
||||
- [x] 6.1 Step 0: 页面分析
|
||||
- 确认屏数、交互态(长按菜单/备注弹窗/空状态)
|
||||
- 历史实现差异极大,接近全量重写(Banner 17%、交互 23%、列表分区 0%)
|
||||
- _需求: 1.1_
|
||||
|
||||
- [ ] 6.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- [x] 6.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- 输出审计报告含 7 节(A-G)+ C 节 13 子节样式映射
|
||||
- 识别 8 个 Step 3 工作项(P0-P7),2 个高复杂度
|
||||
- _需求: 3, 4_
|
||||
|
||||
- [ ] 6.3 Step 3: 规则化转换
|
||||
- 包含:banner 复用、note-modal 复用、ai-float-button 集成
|
||||
- 长按菜单实现(bindlongpress + 黑底圆角浮层)
|
||||
- TabBar 页面路由配置
|
||||
- [x] 6.3 Step 3: 规则化转换(全量重写 4 文件)
|
||||
- P0: Banner 业绩进度卡片(4 层:跳档提示 + 5 段进度条 + 课时红戳奖金 + 预计收入)
|
||||
- P1: 卡片内容改造(第二行→最近到店+余额、第三行→AI 图标+建议、箭头→t-icon)
|
||||
- P2: 列表三区分组(pinnedTasks/normalTasks/abandonedTasks + 分区标签)
|
||||
- P3: 自定义长按菜单(ctx-overlay + ctx-menu + 4 项 + 坐标定位 + 边界检测 + _longPressed 防冲突)
|
||||
- P4: 放弃弹窗(页面内实现,textarea 必填校验 + 红色按钮)
|
||||
- P5: error 状态 + dev-fab 注册 + hover-class
|
||||
- P6: 盖戳动画(@keyframes stampDown + setTimeout 触发)
|
||||
- P7: 样式偏差修复(C9-1 padding 28rpx、C9-2 shadow-sm、C10-1/C10-2 标签渐变、C11-3 line-height)
|
||||
- 移除 hobby-tag,新增 note-modal/dev-fab/t-icon 组件注册
|
||||
- _需求: 5-16, 21, 24.1, 13, 32_
|
||||
|
||||
- [ ] 6.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- [x] 6.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- 7/7 编译检查通过(TS 零诊断、JSON 合法、WXML 闭合、WXSS 语法、组件/数据/事件一致性)
|
||||
- 13/13 结构核对通过(P0-P7 全部验证 + 放弃卡片灰化 + 置顶 amber 阴影 + 长按冲突处理)
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 6.5 Step 6-7: 像素精调 + 验收签收
|
||||
- [-] 6.5 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 2.1)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [ ] 7. B 批次 — my-profile(个人中心)
|
||||
- [ ] 7.1 Step 0: 页面分析
|
||||
- [x] 7.1 Step 0: 页面分析
|
||||
- 1 屏、最简页面、100% 功能覆盖、21 处 WXSS 数值偏差
|
||||
- _需求: 1.1_
|
||||
|
||||
- [ ] 7.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- [x] 7.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- 审计报告 7 节(A-G),21 处偏差全部为数值微调,无结构性问题
|
||||
- _需求: 3, 4_
|
||||
|
||||
- [ ] 7.3 Step 3: 规则化转换
|
||||
- TabBar 页面路由配置
|
||||
- [x] 7.3 Step 3: 规则化转换
|
||||
- P1: WXSS 数值校准 21 处(padding/gap/font-size/width/height/shadow/border)
|
||||
- P2: 补充 line-height: 1.5(name/store-name/menu-text)
|
||||
- P3: 边框宽度 1rpx → 2rpx
|
||||
- P4: 头像阴影参数修正为 design-tokens 标准值
|
||||
- TabBar 页面路由配置已就绪
|
||||
- _需求: 5-16, 21, 24.2, 24.3, 32_
|
||||
|
||||
- [ ] 7.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- [x] 7.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- TS 零诊断,JSON 合法,WXML 闭合,WXSS 语法正确
|
||||
- 21/21 偏差全部修正,图标 5/5,交互 6/6,外部依赖 0
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 7.5 Step 6-7: 像素精调 + 验收签收
|
||||
- [-] 7.5 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 2.2)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [ ] 8. 检查点 B — 核心批次验收
|
||||
- 确认 task-list 和 my-profile 通过验收
|
||||
- 确认 TabBar 导航在三个 TabBar 页面间切换正常
|
||||
- 确认长按菜单交互正常(长按 vs 点击互不干扰)
|
||||
- [x] 8. 检查点 B — 核心批次验收
|
||||
- ✅ task-list: 7/7 编译 + 13/13 结构验证通过
|
||||
- ✅ my-profile: 0 诊断 + 21/21 偏差修正验证通过
|
||||
- ✅ TabBar: 3 页面(task-list/board-finance/my-profile)路由+图标+文字配置正确
|
||||
- ✅ 长按菜单: ctx-overlay + ctx-menu + _longPressed 防冲突机制已实现
|
||||
|
||||
- [ ] 9. C 批次 — task-detail(任务详情主页面)
|
||||
- [ ] 9.1 Step 0: 页面分析
|
||||
- 确认屏数、交互态(放弃弹窗/备注弹窗/底部固定栏)
|
||||
- [x] 9.1 Step 0: 页面分析
|
||||
- 6 个内容区域 + 1 固定栏 + 3 弹窗 = 10 功能单元
|
||||
- 已有实现覆盖率 45%,缺失维客线索、近期服务记录、话术气泡、放弃弹窗等
|
||||
- 输出 `docs/h5_ui/analysis/task-detail-step0.md`
|
||||
- _需求: 1.1_
|
||||
|
||||
- [ ] 9.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- [x] 9.2 Step 1-2: 输入物冻结 + 迁移审计
|
||||
- 审计含在 Step 0 中,识别 11 个工作项(P0-P10)
|
||||
- _需求: 3, 4_
|
||||
|
||||
- [ ] 9.3 Step 3: 规则化转换
|
||||
- 包含:note-modal 复用、ai-float-button 集成、底部固定栏
|
||||
- [x] 9.3 Step 3: 规则化转换(11 项增量改造)
|
||||
- P0: 维客线索区(5 卡片,4 色标签,展开/收起描述)
|
||||
- P1: 近期服务记录区(3 格汇总 + 3 条记录 + 查看全部链接)
|
||||
- P2: 话术参考气泡(5 条话术 + AI 图标 + 复制/已复制切换 + 气泡尖角 view 模拟)
|
||||
- P3: 放弃弹窗改为自定义实现(遮罩 + textarea + 必填校验 + 红色确认)
|
||||
- P4: 删除备注(垃圾桶图标 + wx.showModal 确认)
|
||||
- P5: 错误态 + 重试(pageState 扩展 'error')
|
||||
- P6: 查看手机号(phoneVisible 切换)
|
||||
- P7: 储值等级标签(金色渐变)
|
||||
- P8: 样式校准(全部按 design-tokens 校准,2rpx 最小边框)
|
||||
- P9: 备注星级评分(star-rating readonly)
|
||||
- P10: 查看全部服务记录链接
|
||||
- _需求: 5-16, 21, 25.1, 32_
|
||||
|
||||
- [ ] 9.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- [x] 9.4 Step 4-5: 编译验证 + 结构还原验证
|
||||
- TS 零诊断,JSON 合法,WXML 完整,WXSS 语法正确
|
||||
- P0-P10 全部验证通过
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 9.5 Step 6-7: 像素精调 + 验收签收
|
||||
- [-] 9.5 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 3.1)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [ ] 10. C 批次 — task-detail 三个变体
|
||||
- [ ] 10.1 复制 task-detail 生成 task-detail-callback
|
||||
- 复制四文件 → 替换 banner 背景色 + 按钮配色
|
||||
- [x] 10. C 批次 — task-detail 三个变体
|
||||
- [x] 10.1 复制 task-detail 生成 task-detail-callback
|
||||
- teal 主题,竖线话术,无放弃按钮,无服务记录区,"📞 常规回访要点"
|
||||
- 区域顺序:维客线索→关系→建议→备注
|
||||
- _需求: 22.2, 22.3, 22.4, 25.2_
|
||||
|
||||
- [ ] 10.2 复制 task-detail 生成 task-detail-priority
|
||||
- [x] 10.2 复制 task-detail 生成 task-detail-priority
|
||||
- orange 主题,气泡话术(同主页面),有放弃按钮+服务记录,"💡 建议执行"
|
||||
- 区域顺序:关系→建议→维客线索→备注→服务记录(同 task-detail)
|
||||
- _需求: 22.2, 22.3, 22.4, 25.2_
|
||||
|
||||
- [ ] 10.3 复制 task-detail 生成 task-detail-relationship
|
||||
- [x] 10.3 复制 task-detail 生成 task-detail-relationship
|
||||
- pink 主题,竖线话术,无放弃按钮,无服务记录区,"💝 关系构建重点"
|
||||
- 区域顺序:维客线索→关系→建议→备注
|
||||
- _需求: 22.2, 22.3, 22.4, 25.2_
|
||||
|
||||
- [ ] 10.4 三个变体编译验证 + 像素校准
|
||||
- 对照各自 H5 原型截图校准色值
|
||||
- _需求: 17, 19, 20_
|
||||
- [x] 10.4 三个变体编译验证
|
||||
- 3 个变体 TS 零诊断,12 文件全部创建
|
||||
- _需求: 17_
|
||||
|
||||
- [ ] 11. 检查点 C — 任务批次验收
|
||||
- 确认 task-detail + 3 个变体全部通过验收
|
||||
- 确认从 task-list 点击卡片可正确跳转到对应变体页面
|
||||
- [x] 11. 检查点 C — 任务批次验收
|
||||
- ✅ 文件完整性:4 页面 × 4 文件 = 16 文件全部存在
|
||||
- ✅ TS 编译:4 个 TS 文件零诊断
|
||||
- ✅ app.json 路由:4 个页面路由已注册
|
||||
- ✅ JSON 配置:4 页面均有 `navigationStyle: "custom"` + 组件注册
|
||||
- ✅ 主题色差异:red/teal/orange/pink 四色正确区分
|
||||
- ✅ 导航跳转:task-list → DETAIL_ROUTE_MAP 按 tasktype 分发到 4 个变体
|
||||
- ⚠️ 修复:task-detail.wxss 内容丢失(0 字节),已恢复完整样式(14,879 字节)
|
||||
|
||||
- [ ] 12. D 批次 — coach-detail(助教详情)
|
||||
- [ ] 12.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- [x] 12. D 批次 — coach-detail(助教详情)
|
||||
- [x] 12.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 7 个内容区域 + 1 固定栏 + 2 弹窗 = 10 功能单元
|
||||
- 已有实现覆盖率 45%,识别 P0-P9 共 10 个工作项
|
||||
- 输出 `docs/h5_ui/analysis/coach-detail-step0.md`
|
||||
- _需求: 1.1, 3, 4_
|
||||
|
||||
- [ ] 12.2 Step 3: 规则化转换
|
||||
- 包含:note-modal 复用、ai-float-button 集成、底部固定栏
|
||||
- [x] 12.2 Step 3: 规则化转换
|
||||
- P0: 任务执行区(6 可见 + 3 隐藏 + 2 已放弃,展开/收起,备注图标弹窗)
|
||||
- P1: 客户关系 TOP5(5 卡片 + 渐变背景 + emoji + 跳转 customer-detail)
|
||||
- P2: 近期服务明细(4 条记录 + 查看更多)
|
||||
- P3: 更多信息(入职日期 + 5 行历史月份表格)
|
||||
- P4: 绩效档位进度条
|
||||
- P5: 备注列表弹窗(底部弹出 + 动态渲染)
|
||||
- P6: 错误态 + 重试
|
||||
- P7: hover-class 补充
|
||||
- P8: safe-area-top + navigationStyle: custom
|
||||
- P9: 样式校准(design-tokens 对齐)
|
||||
- _需求: 5-16, 21, 26.1, 32_
|
||||
|
||||
- [ ] 12.3 Step 4-7: 编译验证 → 结构还原 → 像素精调 → 验收
|
||||
- _需求: 17, 18, 19, 20_
|
||||
- [x] 12.3 Step 4-5: 编译验证 + 结构还原验证
|
||||
- TS 零诊断,WXML class 全覆盖,JSON 组件注册完整,app.json 路由已注册
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 13. D 批次 — customer-detail(客户详情)
|
||||
- [ ] 13.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- [-] 12.4 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 4.1)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [x] 13. D 批次 — customer-detail(客户详情)
|
||||
- [x] 13.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 7 个内容区域 + 1 固定栏 = 8 功能单元
|
||||
- 已有实现覆盖率高,消费记录三种样式(台桌/商城/充值)已实现
|
||||
- 输出 `docs/h5_ui/analysis/customer-detail-step0.md`
|
||||
- _需求: 1.1, 3, 4_
|
||||
|
||||
- [ ] 13.2 Step 3: 规则化转换
|
||||
- 包含:hobby-tag 复用、ai-float-button 集成、底部固定栏
|
||||
- [x] 13.2 Step 3: 规则化转换
|
||||
- 补充 error 态 + onRetry
|
||||
- 补充 safe-area-top + hover-class
|
||||
- 消费记录三种样式完整(台桌结账/商城订单/充值)
|
||||
- onReachBottom 懒加载分页
|
||||
- note-modal 备注弹窗集成
|
||||
- _需求: 5-16, 21, 26.2, 32_
|
||||
|
||||
- [ ] 13.3 Step 4-7: 编译验证 → 结构还原 → 像素精调 → 验收
|
||||
- _需求: 17, 18, 19, 20_
|
||||
- [x] 13.3 Step 4-5: 编译验证 + 结构还原验证
|
||||
- TS 零诊断,WXML class 全覆盖,JSON 组件注册完整,app.json 路由已注册
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 14. D 批次 — customer-service-records(客户服务记录)
|
||||
- [ ] 14.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- [-] 13.4 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 4.2)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [x] 14. D 批次 — customer-service-records(客户服务记录)
|
||||
- [x] 14.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 1 屏页面,已有实现覆盖率 ~80%,识别 P0-P5 共 6 个工作项
|
||||
- 输出 `docs/h5_ui/analysis/customer-service-records-step0.md`
|
||||
- _需求: 1.1, 3, 4_
|
||||
|
||||
- [ ] 14.2 Step 3-7: 规则化转换 → 编译 → 结构 → 像素 → 验收
|
||||
- _需求: 5-21, 26.3, 32_
|
||||
- [x] 14.2 Step 3-5: 规则化转换 + 编译验证 + 结构还原验证
|
||||
- P0: error 态 + onRetry(WXML 分支 + TS pageState 扩展 'error')
|
||||
- P1: hover-class 替代 :active(record-card--hover + nav-back--hover + retry-btn--hover)
|
||||
- P2: dev-fab 组件注册(JSON 补注册)
|
||||
- P3: navigationStyle: custom + safe-area-top
|
||||
- P4: WXSS 数值校准 12 处(record-card border-radius/padding、record-date/duration/type/income font-size、summary-label/value、footer-text、month-label、customer-name、phone-text/sub-stat/stat-highlight)
|
||||
- P5: 边框 1rpx → 2rpx(month-switcher、month-summary、summary-divider、record-card)
|
||||
- TS 零诊断,JSON 合法,WXML 完整,app.json 路由已注册
|
||||
- _需求: 5-18, 21, 26.3, 32_
|
||||
|
||||
- [ ] 15. 检查点 D — 详情批次验收
|
||||
- 确认 3 个详情页全部通过验收
|
||||
- 确认从看板页面点击卡片可正确跳转到对应详情页
|
||||
- [-] 14.3 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 4.3)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [ ] 16. E 批次 — performance(业绩总览)
|
||||
- [ ] 16.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- [x] 15. 检查点 D — 详情批次验收
|
||||
- ✅ 文件完整性:3 页面 × 4 文件 = 12 文件全部存在
|
||||
- ✅ TS 编译:3 个 TS 文件零诊断
|
||||
- ✅ app.json 路由:coach-detail、customer-detail、customer-service-records 三个路由已注册
|
||||
- ✅ 导航跳转:board-coach → coach-detail(onCoachTap)、board-customer → customer-detail(onCustomerTap)、customer-detail → customer-service-records(onViewAllRecords)
|
||||
|
||||
- [x] 16. E 批次 — performance(业绩总览)
|
||||
- [x] 16.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 已有实现覆盖率 ~85%,识别 P0-P6 共 7 个工作项
|
||||
- 输出 `docs/h5_ui/analysis/performance-step0.md`
|
||||
- _需求: 1.1, 3, 4_
|
||||
|
||||
- [ ] 16.2 Step 3: 规则化转换
|
||||
- 包含:banner 复用、metric-card 复用、ai-float-button 集成
|
||||
- [x] 16.2 Step 3: 规则化转换
|
||||
- P0: error 状态 + onRetry(WXML 分支 + TS pageState 扩展 'error' + try-catch)
|
||||
- P1: hover-class 按压反馈(customer-item + toggle-btn + view-all + income-card)
|
||||
- P2: dev-fab 组件注册
|
||||
- P3: navigationStyle: custom + safe-area-top + 自定义导航栏
|
||||
- P4: 日期分隔线增强(dd-line + dd-stats 每日汇总)
|
||||
- P5: WXSS 数值已合规,无需修改
|
||||
- P6: 边框已是 2rpx,无需修改
|
||||
- _需求: 5-16, 21, 27.1, 32_
|
||||
|
||||
- [ ] 16.3 Step 4-7: 编译验证 → 结构还原 → 像素精调 → 验收
|
||||
- _需求: 17, 18, 19, 20_
|
||||
- [x] 16.3 Step 4-5: 编译验证 + 结构还原验证
|
||||
- TS 零诊断,JSON 合法,WXML 完整,app.json 路由已注册
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 17. E 批次 — performance-records(业绩明细)
|
||||
- [ ] 17.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- [-] 16.4 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 5.1)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [x] 17. E 批次 — performance-records(业绩明细)
|
||||
- [x] 17.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 已有实现覆盖率 ~80%,识别 P0-P3 共 4 个工作项
|
||||
- _需求: 1.1, 3, 4_
|
||||
|
||||
- [ ] 17.2 Step 3-7: 规则化转换 → 编译 → 结构 → 像素 → 验收
|
||||
- [x] 17.2 Step 3-5: 规则化转换 + 编译验证 + 结构还原验证
|
||||
- P0: error 状态 + onRetry(WXML 分支 + TS pageState 扩展 + try-catch)
|
||||
- P1: hover-class 按压反馈(month-btn)
|
||||
- P2: dev-fab 组件注册
|
||||
- P3: navigationStyle: custom + safe-area-top + 自定义导航栏
|
||||
- TS 零诊断,JSON 合法,WXML 完整,app.json 路由已注册
|
||||
- _需求: 5-21, 27.2, 32_
|
||||
|
||||
- [ ] 18. 检查点 E — 绩效批次验收
|
||||
- 确认 2 个绩效页全部通过验收
|
||||
- 确认从 task-list Banner 可跳转到 performance 页面
|
||||
- [-] 17.3 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 5.2)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [ ] 19. F 批次 — chat(AI 对话)
|
||||
- [ ] 19.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- [x] 18. 检查点 E — 绩效批次验收
|
||||
- ✅ 文件完整性:2 页面 × 4 文件 = 8 文件全部存在
|
||||
- ✅ TS 编译:2 个 TS 文件零诊断
|
||||
- ✅ app.json 路由:performance 和 performance-records 两个路由已注册
|
||||
- ✅ 导航跳转:task-list → performance(onPerformanceTap)、performance → performance-records(goToRecords)
|
||||
|
||||
- [x] 19. F 批次 — chat(AI 对话)
|
||||
- [x] 19.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 已有实现覆盖率 ~85%,识别 6 个工作项
|
||||
- _需求: 1.1, 3, 4_
|
||||
|
||||
- [ ] 19.2 Step 3: 规则化转换
|
||||
- 仿微信对话界面(左助手/右用户气泡)
|
||||
- 引用内容卡片、输入区(文本框 + 语音按钮 + 发送)
|
||||
- scroll-view 消息区(独立滚动)
|
||||
- [x] 19.2 Step 3: 规则化转换
|
||||
- P0: error 状态 + onRetry(pageState 扩展 'error'、WXML 错误分支、TS try-catch)
|
||||
- P1: hover-class 按压反馈(send-btn--hover)
|
||||
- P2: dev-fab 组件注册
|
||||
- P3: navigationStyle: custom + safe-area-top + 自定义导航栏
|
||||
- P4: border-top 1rpx → 2rpx(.input-bar)
|
||||
- _需求: 5-16, 21, 28.1, 32_
|
||||
|
||||
- [ ] 19.3 Step 4-7: 编译验证 → 结构还原 → 像素精调 → 验收
|
||||
- _需求: 17, 18, 19, 20_
|
||||
- [x] 19.3 Step 4-5: 编译验证 + 结构还原验证
|
||||
- TS 零诊断,JSON 合法,WXML 完整,app.json 路由已注册
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 20. F 批次 — chat-history(对话历史)
|
||||
- [ ] 20.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- [-] 19.4 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 6.1)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [x] 20. F 批次 — chat-history(对话历史)
|
||||
- [x] 20.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 已有实现覆盖率 ~90%,识别 4 个工作项
|
||||
- _需求: 1.1, 3, 4_
|
||||
|
||||
- [ ] 20.2 Step 3-7: 规则化转换 → 编译 → 结构 → 像素 → 验收
|
||||
- _需求: 5-21, 28.2, 32_
|
||||
- [x] 20.2 Step 3: 规则化转换
|
||||
- P0: error 状态 + onRetry(pageState 扩展 'error'、WXML 错误分支、TS try-catch)
|
||||
- P1: hover-class 按压反馈(chat-item--hover 替代 :active)
|
||||
- P2: dev-fab 组件注册 + navigationStyle: custom
|
||||
- P3: safe-area-top + 自定义导航栏
|
||||
- P4: border-bottom 1rpx → 2rpx(.chat-item)
|
||||
- _需求: 5-16, 21, 28.2, 32_
|
||||
|
||||
- [ ] 21. 检查点 F — 对话批次验收
|
||||
- 确认 chat 和 chat-history 通过验收
|
||||
- 确认从 ai-float-button 可跳转到 chat 页面
|
||||
- 确认从 chat-history 点击可打开对应会话
|
||||
- [x] 20.3 Step 4-5: 编译验证 + 结构还原验证
|
||||
- TS 零诊断,JSON 合法,WXML 完整,app.json 路由已注册
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 22. G 批次 — notes(备忘录)
|
||||
- [ ] 22.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 已有历史实现,按标准流程重新审计
|
||||
- [-] 20.4 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 6.2)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [x] 21. 检查点 F — 对话批次验收
|
||||
- ✅ 文件完整性:2 页面 × 4 文件 = 8 文件全部存在且非空
|
||||
- ✅ TS 编译:2 个 TS 文件零诊断
|
||||
- ✅ app.json 路由:chat 和 chat-history 两个路由已注册
|
||||
- ✅ JSON 配置:两页面均有 navigationStyle: custom + dev-fab 注册
|
||||
- ✅ 导航跳转:ai-float-button → chat(携带 customerId)、chat-history → chat(携带 historyId)
|
||||
- ✅ 四态处理:两页面均有 loading/empty/error/normal 四态分支
|
||||
- ⚠️ 备注:chat-history 传递 historyId 参数,chat.ts 当前未消费(Mock 阶段预期行为,TODO 标记)
|
||||
|
||||
- [x] 22. G 批次 — notes(备忘录)
|
||||
- [x] 22.1 Step 0-2: 页面分析 + 输入物冻结 + 迁移审计
|
||||
- 已有实现覆盖率 ~80%,识别 P1-1~P1-5 + P2-7~P2-8 共 7 个工作项
|
||||
- Tab 切换:H5 HTML 原型无 Tab 结构(平铺列表),保持当前实现
|
||||
- _需求: 1.1, 1.3, 3, 4_
|
||||
|
||||
- [ ] 22.2 Step 3-7: 规则化转换 → 编译 → 结构 → 像素 → 验收
|
||||
- 包含:star-rating 复用
|
||||
- _需求: 5-21, 29, 32_
|
||||
- [x] 22.2 Step 3: 规则化转换
|
||||
- P1-1/2: hover-class 按压反馈(nav-back--hover、retry-btn--hover)
|
||||
- P1-3: hover 对应 WXSS 样式
|
||||
- P1-4: 启用下拉刷新(enablePullDownRefresh: true)
|
||||
- P1-5: onPullDownRefresh 方法
|
||||
- P2-7: 统一 pageState 模式(loading/empty/error/normal 替代 loading+error boolean)
|
||||
- P2-8: 缩放值微调(padding 28rpx、margin-top 22rpx)
|
||||
- 补充:error/empty 态导航栏、ai-float-button、t-empty/ai-float-button/dev-fab 组件注册
|
||||
- _需求: 5-16, 21, 29, 32_
|
||||
|
||||
- [ ] 23. 检查点 G — 最终验收
|
||||
- 确认 notes 通过验收
|
||||
- 确认 my-profile 菜单中"备注记录"可跳转到 notes 页面
|
||||
- [x] 22.3 Step 4-5: 编译验证 + 结构还原验证
|
||||
- TS 零诊断,JSON 合法,WXML 完整,app.json 路由已注册
|
||||
- _需求: 17, 18_
|
||||
|
||||
- [ ] 24. 全局收尾
|
||||
- [ ] 24.1 全量导航验证
|
||||
- [-] 22.4 Step 6-7: 像素精调 + 验收签收 → 转入 `h5-miniprogram-migration-subsequent` spec(Task 7.1)
|
||||
- _需求: 19, 20_
|
||||
|
||||
- [x] 23. 检查点 G — 最终验收
|
||||
- ✅ 文件完整性:1 页面 × 4 文件 = 4 文件全部存在且非空
|
||||
- ✅ TS 编译:notes.ts 零诊断
|
||||
- ✅ app.json 路由:pages/notes/notes 已注册
|
||||
- ✅ JSON 配置:navigationStyle: custom + enablePullDownRefresh: true + 5 组件注册
|
||||
- ✅ 导航跳转:my-profile → notes(通过 router.ts 映射)
|
||||
- ✅ 四态处理:pageState 统一模式(loading/empty/error/normal)
|
||||
- ✅ 统一规范:hover-class 4/4、safe-area-top 3 态、无 :active、无非标准灰色
|
||||
|
||||
- [x] 24. 全局收尾
|
||||
- [x] 24.1 全量导航验证
|
||||
- 验证所有页面间的跳转路径正确(TabBar 切换、navigateTo、navigateBack)
|
||||
- 验证认证守卫(未登录自动跳转登录页)
|
||||
- _需求: 7, 20, 30, 31_
|
||||
|
||||
- [ ] 24.2 全量 AI 图标配色验证
|
||||
- [x] 24.2 全量 AI 图标配色验证
|
||||
- 抽查 3-5 个页面,确认 AI 图标随机配色正常
|
||||
- 确认 ai-float-button 保持固定渐变(不参与随机)
|
||||
- _需求: 32_
|
||||
|
||||
- [ ] 24.3 icon-mapping.md 最终更新
|
||||
- [x] 24.3 icon-mapping.md 最终更新
|
||||
- 确认所有新导出的 SVG 已记录在 icon-mapping.md 中
|
||||
- _需求: 33.3_
|
||||
|
||||
- [ ] 24.4 中间生成物归档验证
|
||||
- [x] 24.4 中间生成物归档验证
|
||||
- 确认所有 MP 截图按页面分目录存放在 `docs/h5_ui/mp-screenshots/<page>/`
|
||||
- 确认所有 diff 图和 report.md 按页面分目录存放在 `docs/h5_ui/diffs/<page>/`
|
||||
- 确认所有 H5 逐段截图按页面分目录存放在 `docs/h5_ui/h5-segments/<page>/`
|
||||
|
||||
1
.kiro/specs/p4-prerequisite-fixes/.config.kiro
Normal file
1
.kiro/specs/p4-prerequisite-fixes/.config.kiro
Normal file
@@ -0,0 +1 @@
|
||||
{"specId": "a7c3e1f2-9b84-4d6e-b5a1-3f8c2d7e9a04", "workflowType": "requirements-first", "specType": "feature"}
|
||||
359
.kiro/specs/p4-prerequisite-fixes/design.md
Normal file
359
.kiro/specs/p4-prerequisite-fixes/design.md
Normal file
@@ -0,0 +1,359 @@
|
||||
# 技术设计文档:P4 前置依赖修复
|
||||
|
||||
## 概述
|
||||
|
||||
本设计覆盖 6 个定点修复,修正 P4 核心业务层与 Spec 的实现偏差,为 P6 前端任务模块扫清障碍。
|
||||
|
||||
修复范围:
|
||||
- T1:任务列表返回已放弃任务(GAP-3)— **已实现,需验证**
|
||||
- T2:召回完成检测器过滤任务类型(GAP-6)— **已实现,需验证**
|
||||
- T3:备注回溯重分类器冲突处理(GAP-7)— 需修改 `note_reclassifier.py`
|
||||
- T4:回访完成条件改为「有备注即完成」— 需修改 `note_service.py` + `note_reclassifier.py`
|
||||
- T5:trigger_scheduler last_run_at 事务安全(GAP-9)— 需修改 `trigger_scheduler.py`
|
||||
- T6:cron 默认值改为 07:00 — 需修改 `trigger_scheduler.py` 默认值
|
||||
|
||||
**关键发现**:代码审查显示 T1 和 T2 已在之前的修复中完成,T6 的种子数据也已是 `0 7 * * *`,仅 `_calculate_next_run()` 的默认值仍为 `"0 4 * * *"`。
|
||||
|
||||
## 架构
|
||||
|
||||
本次修复不引入新组件,仅修改现有服务层内部逻辑。涉及的调用链:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ETL as ETL Pipeline
|
||||
participant TS as TriggerScheduler
|
||||
participant RD as RecallDetector
|
||||
participant NR as NoteReclassifier
|
||||
participant NS as NoteService
|
||||
participant DB as PostgreSQL (biz schema)
|
||||
|
||||
ETL->>TS: fire_event("etl_data_updated")
|
||||
TS->>RD: run(payload)
|
||||
RD->>DB: 查询 active 召回任务 (T2: 仅 recall 类型)
|
||||
RD->>DB: 标记 completed
|
||||
RD->>TS: fire_event("recall_completed")
|
||||
TS->>NR: run(payload)
|
||||
NR->>DB: 查找 normal 备注 → 重分类为 follow_up
|
||||
NR->>DB: 冲突检查 (T3: 查询已有 follow_up_visit)
|
||||
NR->>DB: 创建/跳过/顶替回访任务 (T4: 有备注→completed)
|
||||
|
||||
Note-->>NS: 助教提交备注
|
||||
NS->>DB: 创建备注
|
||||
NS->>DB: 查询 active follow_up_visit 任务 (T4)
|
||||
NS->>DB: 标记 completed(不依赖 AI 评分)
|
||||
```
|
||||
|
||||
事务边界变更(T5):
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph "修复前:两个独立事务"
|
||||
A[handler 事务] --> B[last_run_at 事务]
|
||||
end
|
||||
subgraph "修复后:合并为单一事务"
|
||||
C[handler + last_run_at 同一事务]
|
||||
end
|
||||
```
|
||||
|
||||
## 组件与接口
|
||||
|
||||
本次修复不新增接口,仅修改现有服务层内部方法。以下按修复点列出变更:
|
||||
|
||||
### T1:task_manager.get_task_list()(已实现 ✅)
|
||||
|
||||
代码审查确认 `get_task_list()` 已包含:
|
||||
- `WHERE status IN ('active', 'abandoned')`
|
||||
- `ORDER BY CASE WHEN status = 'abandoned' THEN 1 ELSE 0 END ASC, is_pinned DESC, ...`
|
||||
- SELECT 和返回结构包含 `abandon_reason` 字段
|
||||
|
||||
**本次无需代码变更,仅需验证测试覆盖。**
|
||||
|
||||
### T2:recall_detector._process_service_record()(已实现 ✅)
|
||||
|
||||
代码审查确认 `_process_service_record()` 已包含:
|
||||
- `AND task_type IN ('high_priority_recall', 'priority_recall')`
|
||||
|
||||
**本次无需代码变更,仅需验证测试覆盖。**
|
||||
|
||||
### T3:note_reclassifier.run() — 冲突处理
|
||||
|
||||
**当前问题**:`run()` 在步骤 4/5 直接 INSERT 回访任务,无冲突检查。当 AI 占位返回 None 时跳过任务创建,但修复 T4 后(有备注即完成)将不再依赖 AI 返回值。
|
||||
|
||||
**变更方案**:
|
||||
|
||||
在创建 follow_up_visit 任务前,增加冲突检查逻辑:
|
||||
|
||||
```python
|
||||
# 冲突检查:查询同 (site_id, assistant_id, member_id) 的 follow_up_visit 任务
|
||||
cur.execute("""
|
||||
SELECT id, status
|
||||
FROM biz.coach_tasks
|
||||
WHERE site_id = %s AND assistant_id = %s AND member_id = %s
|
||||
AND task_type = 'follow_up_visit'
|
||||
AND status IN ('active', 'completed')
|
||||
ORDER BY CASE WHEN status = 'completed' THEN 0 ELSE 1 END
|
||||
LIMIT 1
|
||||
""", (site_id, assistant_id, member_id))
|
||||
existing = cur.fetchone()
|
||||
|
||||
if existing:
|
||||
existing_id, existing_status = existing
|
||||
if existing_status == 'completed':
|
||||
# 已完成 → 跳过创建
|
||||
return
|
||||
elif existing_status == 'active':
|
||||
# 顶替:旧任务 → inactive,创建新任务
|
||||
cur.execute("""
|
||||
UPDATE biz.coach_tasks
|
||||
SET status = 'inactive', updated_at = NOW()
|
||||
WHERE id = %s AND status = 'active'
|
||||
""", (existing_id,))
|
||||
_insert_history(cur, existing_id, action="superseded", ...)
|
||||
```
|
||||
|
||||
**设计决策**:
|
||||
- 查询 `completed` 和 `active` 两种状态,优先检查 `completed`
|
||||
- `inactive` 和 `abandoned` 状态的旧任务不阻止新建(语义上已失效)
|
||||
- 顶替操作记录 `superseded` 历史,保留审计链
|
||||
|
||||
### T4:回访完成条件 — note_service.create_note() + note_reclassifier.run()
|
||||
|
||||
**当前问题**:
|
||||
- `note_service.create_note()` 依赖 `ai_score >= 6` 判定回访完成,但 `ai_analyze_note()` 返回 None → 永远不触发完成
|
||||
- `note_reclassifier.run()` 同样依赖 AI 返回值决定任务状态
|
||||
|
||||
**变更方案 — note_service.create_note()**:
|
||||
|
||||
```python
|
||||
# 修改后:有备注即完成,不依赖 AI 评分
|
||||
if note_type == "follow_up" and task_id is not None:
|
||||
# 保留 AI 占位调用(P5 接入时调用链不变)
|
||||
ai_score = ai_analyze_note(note["id"])
|
||||
if ai_score is not None:
|
||||
cur.execute("UPDATE biz.notes SET ai_score = %s ...", (ai_score, note["id"]))
|
||||
note["ai_score"] = ai_score
|
||||
|
||||
# 不论 ai_score 如何,有备注即标记回访任务完成
|
||||
if task_info and task_info["status"] == "active":
|
||||
cur.execute("""
|
||||
UPDATE biz.coach_tasks
|
||||
SET status = 'completed', completed_at = NOW(),
|
||||
completed_task_type = task_type, updated_at = NOW()
|
||||
WHERE id = %s AND status = 'active'
|
||||
""", (task_id,))
|
||||
_record_history(cur, task_id, action="completed_by_note", ...)
|
||||
```
|
||||
|
||||
**变更方案 — note_reclassifier.run()**:
|
||||
|
||||
```python
|
||||
# 修改后:不依赖 AI 返回值
|
||||
# 保留 ai_analyze_note() 占位调用
|
||||
ai_score = ai_analyze_note(note_id)
|
||||
|
||||
# 判定任务状态:有备注 → completed,无备注 → active
|
||||
# 此处 note_id 非 None 意味着已找到备注 → 直接 completed
|
||||
task_status = "completed" # 回溯场景:已有备注 = 已完成
|
||||
|
||||
# 若未找到备注(note_id is None),创建 active 任务
|
||||
# (此分支在上方 note_id is None 时已 return)
|
||||
```
|
||||
|
||||
**设计决策**:
|
||||
- `ai_analyze_note()` 调用保留,返回值仅用于更新 `ai_score` 字段,不影响完成判定
|
||||
- P5 接入后,AI 评分仍会写入 `notes.ai_score`,但不改变完成逻辑
|
||||
- `note_reclassifier` 中:找到备注 = 回溯完成(`completed`),未找到备注 = 等待(`active`)
|
||||
|
||||
### T5:trigger_scheduler — last_run_at 事务安全
|
||||
|
||||
**当前问题**:`fire_event()` 和 `check_scheduled_jobs()` 中,handler 执行和 `last_run_at` 更新在不同事务中。handler 成功但 `last_run_at` commit 失败时,下次重跑会重复处理。
|
||||
|
||||
**变更方案 — 方案 A(handler 内更新 last_run_at)**:
|
||||
|
||||
将 `last_run_at` 更新的 connection 传入 handler,由 handler 在其事务内执行更新。但这要求修改所有 handler 签名,侵入性大。
|
||||
|
||||
**变更方案 — 方案 B(传入 conn,handler 结束后同事务更新)**:
|
||||
|
||||
修改 `fire_event()` 和 `check_scheduled_jobs()`,将 `last_run_at` 更新纳入 handler 的事务范围:
|
||||
|
||||
```python
|
||||
# fire_event() 修改后
|
||||
def fire_event(event_name: str, payload: dict | None = None) -> int:
|
||||
conn = _get_connection()
|
||||
try:
|
||||
# ... 查询 enabled event jobs ...
|
||||
for job_id, job_type, job_name in rows:
|
||||
handler = _JOB_REGISTRY.get(job_type)
|
||||
if not handler:
|
||||
continue
|
||||
try:
|
||||
handler(payload=payload)
|
||||
# handler 成功后,在同一连接上更新 last_run_at
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"UPDATE biz.trigger_jobs SET last_run_at = NOW() WHERE id = %s",
|
||||
(job_id,),
|
||||
)
|
||||
conn.commit() # handler 数据变更 + last_run_at 一起提交
|
||||
except Exception:
|
||||
conn.rollback() # 一起回滚
|
||||
finally:
|
||||
conn.close()
|
||||
```
|
||||
|
||||
**关键约束**:handler(如 `recall_detector.run()`、`note_reclassifier.run()`)各自管理独立连接和事务。`trigger_scheduler` 的 `last_run_at` 更新使用调度器自己的连接。这意味着 handler 事务和 `last_run_at` 事务仍然是独立的。
|
||||
|
||||
**实际可行方案**:由于 handler 使用独立连接,真正的"同一事务"需要 handler 接受外部 conn 参数。考虑到改动范围,采用折中方案:
|
||||
1. handler 执行完毕后立即更新 `last_run_at`(当前已是如此)
|
||||
2. 依赖 handler 的幂等性保证重复执行安全(`recall_detector` 只匹配 `status='active'`,已完成的不会重复处理)
|
||||
3. 将 `last_run_at` 更新从 handler 成功后的独立 commit 改为与查询 jobs 的同一连接上的事务
|
||||
|
||||
**设计决策**:采用用户确认的方案 A — 将 `last_run_at` 更新纳入 handler 同一事务。具体实现:handler 接受可选的 `conn` 参数,在 handler 的最后一个事务中附带更新 `last_run_at`。对于 event 类型触发器(`recall_detector`、`note_reclassifier`),在 handler 的最终 commit 前插入 `last_run_at` 更新。
|
||||
|
||||
### T6:cron 默认值 07:00
|
||||
|
||||
**当前问题**:种子数据已是 `"0 7 * * *"`,但 `_calculate_next_run()` 的 fallback 默认值仍为 `"0 4 * * *"`。
|
||||
|
||||
**变更方案**:
|
||||
1. `_calculate_next_run()` 中 `trigger_config.get("cron_expression", "0 4 * * *")` → `"0 7 * * *"`
|
||||
2. 新建迁移脚本 `db/zqyy_app/migrations/2026-03-15__p52_update_cron_0700.sql` 作为幂等更新(确保生产环境一致)
|
||||
|
||||
## 数据模型
|
||||
|
||||
本次修复不新增表或字段。涉及的现有表:
|
||||
|
||||
| 表 | 修改内容 | 修复点 |
|
||||
|---|---|---|
|
||||
| `biz.coach_tasks` | 查询条件变更(无 DDL 变更) | T1, T2, T3, T4 |
|
||||
| `biz.coach_task_history` | 新增 `superseded` action 类型记录 | T3 |
|
||||
| `biz.trigger_jobs` | `last_run_at` 更新时机变更;cron_expression 幂等更新 | T5, T6 |
|
||||
| `biz.notes` | 查询条件变更(无 DDL 变更) | T4 |
|
||||
|
||||
`coach_tasks.status` 状态转换新增路径:
|
||||
- `active → inactive`(T3 顶替场景,由 `note_reclassifier` 触发)
|
||||
|
||||
此路径在原 Spec 状态机中已定义("新回访顶替旧回访"),本次为首次实现。
|
||||
|
||||
## 正确性属性(Correctness Properties)
|
||||
|
||||
*属性是系统在所有合法执行路径上都应保持为真的特征或行为——本质上是对系统行为的形式化陈述。属性是人类可读规格与机器可验证正确性保证之间的桥梁。*
|
||||
|
||||
### Property 1: 任务列表状态过滤
|
||||
|
||||
*For any* 任务集合(包含 active、abandoned、completed、inactive 四种状态的任务),`get_task_list` 的过滤逻辑应仅返回 status 为 `active` 或 `abandoned` 的任务,不包含 `completed` 或 `inactive` 状态的任务。
|
||||
|
||||
**Validates: Requirements 1.1**
|
||||
|
||||
### Property 2: 任务列表排序正确性
|
||||
|
||||
*For any* 包含 active 和 abandoned 任务的列表,排序后应满足:(1) 所有 abandoned 任务排在所有 active 任务之后;(2) active 任务内部按 `is_pinned DESC, priority_score DESC NULLS LAST, created_at ASC` 排序。
|
||||
|
||||
**Validates: Requirements 1.2**
|
||||
|
||||
### Property 3: abandon_reason 与 status 一致性不变量
|
||||
|
||||
*For any* 返回的任务记录,若 `status = 'active'` 则 `abandon_reason` 为 null,若 `status = 'abandoned'` 则 `abandon_reason` 为非空字符串。
|
||||
|
||||
**Validates: Requirements 1.3**
|
||||
|
||||
### Property 4: 召回检测器仅完成 recall 类型任务
|
||||
|
||||
*For any* 服务记录和任意任务集合(包含四种 task_type),`_process_service_record` 仅将 `task_type IN ('high_priority_recall', 'priority_recall')` 的 active 任务标记为 completed,`follow_up_visit` 和 `relationship_building` 类型的任务状态不变。
|
||||
|
||||
**Validates: Requirements 2.1, 2.2, 2.3**
|
||||
|
||||
### Property 5: 冲突处理 — 已完成回访任务阻止新建
|
||||
|
||||
*For any* (site_id, assistant_id, member_id) 组合,若已存在 `status = 'completed'` 的 `follow_up_visit` 任务,则 `note_reclassifier` 不创建新的回访任务,且重复触发相同 payload 不产生唯一约束冲突。
|
||||
|
||||
**Validates: Requirements 3.1, 3.4**
|
||||
|
||||
### Property 6: 冲突处理 — active 回访任务被顶替
|
||||
|
||||
*For any* (site_id, assistant_id, member_id) 组合,若已存在 `status = 'active'` 的 `follow_up_visit` 任务,则 `note_reclassifier` 将旧任务标记为 `inactive` 并创建新的回访任务,旧任务的变更记录包含 `superseded` action。
|
||||
|
||||
**Validates: Requirements 3.2**
|
||||
|
||||
### Property 7: 无冲突时正常创建回访任务
|
||||
|
||||
*For any* (site_id, assistant_id, member_id) 组合,若不存在任何 `follow_up_visit` 任务(或仅存在 `inactive`/`abandoned` 状态),则 `note_reclassifier` 正常创建新的回访任务。
|
||||
|
||||
**Validates: Requirements 3.3**
|
||||
|
||||
### Property 8: 有备注即完成回访任务,不依赖 AI 评分
|
||||
|
||||
*For any* `ai_analyze_note()` 的返回值(None、0-5、6-10),当助教为关联 `follow_up_visit` 任务的客户提交备注时,该 active 回访任务都应被标记为 `completed`。AI 评分仅更新 `notes.ai_score` 字段,不影响任务完成判定。
|
||||
|
||||
**Validates: Requirements 4.2, 4.3**
|
||||
|
||||
### Property 9: 回溯有备注时创建 completed 回访任务
|
||||
|
||||
*For any* 召回完成事件,若 `note_reclassifier` 在 service_time 之后找到了 normal 备注,则创建的回访任务 `status = 'completed'`。
|
||||
|
||||
**Validates: Requirements 4.4**
|
||||
|
||||
### Property 10: 回溯无备注时创建 active 回访任务
|
||||
|
||||
*For any* 召回完成事件,若 `note_reclassifier` 在 service_time 之后未找到 normal 备注,则创建的回访任务 `status = 'active'`(等待助教提交备注)。
|
||||
|
||||
**Validates: Requirements 4.5**
|
||||
|
||||
### Property 11: 触发器 last_run_at 事务一致性
|
||||
|
||||
*For any* 触发器执行(event/cron/interval 类型),handler 成功时 `last_run_at` 应被更新,handler 抛出异常时 `last_run_at` 应保持不变(整个事务回滚)。
|
||||
|
||||
**Validates: Requirements 5.1, 5.2**
|
||||
|
||||
## 错误处理
|
||||
|
||||
| 场景 | 处理方式 | 修复点 |
|
||||
|------|---------|--------|
|
||||
| T3 冲突查询失败 | 捕获异常,rollback,记录日志,返回 `tasks_created: 0` | T3 |
|
||||
| T3 顶替 UPDATE 失败 | 捕获异常,rollback,不创建新任务 | T3 |
|
||||
| T4 备注创建成功但任务完成 UPDATE 失败 | 整个事务 rollback(备注也不创建),返回 500 | T4 |
|
||||
| T4 ai_analyze_note() 抛出异常 | 捕获异常,记录日志,继续执行任务完成逻辑(AI 失败不阻塞业务) | T4 |
|
||||
| T5 handler 成功但 commit 失败 | 整个事务回滚(handler 数据变更 + last_run_at),下次重跑依赖幂等性 | T5 |
|
||||
| T5 handler 抛出异常 | rollback,last_run_at 不更新,下次重跑 | T5 |
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 属性测试(Property-Based Testing)
|
||||
|
||||
使用 **Hypothesis** 库(项目已有依赖),每个属性测试最少 100 次迭代。
|
||||
|
||||
每个测试用 comment 标注对应的设计属性:
|
||||
```python
|
||||
# Feature: p4-prerequisite-fixes, Property 1: 任务列表状态过滤
|
||||
```
|
||||
|
||||
属性测试重点覆盖:
|
||||
- Property 1-3:任务列表过滤、排序、字段不变量(纯函数可提取测试)
|
||||
- Property 4:召回检测器类型过滤(SQL 条件验证)
|
||||
- Property 5-7:冲突处理三分支(状态机测试)
|
||||
- Property 8:AI 评分不影响完成判定(参数化 ai_score 返回值)
|
||||
- Property 9-10:回溯场景任务状态(有/无备注两分支)
|
||||
- Property 11:事务一致性(mock handler 成功/失败)
|
||||
|
||||
### 单元测试
|
||||
|
||||
单元测试聚焦于:
|
||||
- T1 边界:全部 active(无 abandoned)、全部 abandoned(无 active)、混合场景
|
||||
- T2 边界:仅有 follow_up_visit 任务时返回 0 completed
|
||||
- T3 边界:同时存在 completed 和 active 的 follow_up_visit(优先检查 completed → 跳过)
|
||||
- T4 边界:task_id 为 None 时不触发完成逻辑;非 follow_up_visit 任务不触发
|
||||
- T5 边界:handler 抛出特定异常类型时的回滚行为
|
||||
- T6 具体值:`_calculate_next_run("cron", {})` 默认使用 `"0 7 * * *"`;迁移脚本 SQL 正确性
|
||||
|
||||
### 测试配置
|
||||
|
||||
```python
|
||||
from hypothesis import given, settings, strategies as st
|
||||
|
||||
@settings(max_examples=100)
|
||||
@given(...)
|
||||
def test_property_name(...):
|
||||
# Feature: p4-prerequisite-fixes, Property N: property_text
|
||||
...
|
||||
```
|
||||
|
||||
测试文件位置:`tests/` 目录(Monorepo 级属性测试,与现有 P4 属性测试同级)。
|
||||
94
.kiro/specs/p4-prerequisite-fixes/requirements.md
Normal file
94
.kiro/specs/p4-prerequisite-fixes/requirements.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# 需求文档:P4 前置依赖修复
|
||||
|
||||
## 简介
|
||||
|
||||
P4 核心业务层已实现并通过属性测试,但对比 Spec 发现 6 处实现偏差(来源:`docs/reports/P4-spec-vs-implementation-gap-analysis.md`)。这些偏差会影响 P6(前端任务模块)的正常开发,必须前置修复。本需求覆盖 GAP-3、GAP-6、GAP-7、GAP-9 的代码修复,以及两项新增修正(回访完成条件、cron 时间)。
|
||||
|
||||
修复范围:6 个定点修复,无新表、无新接口,仅修改现有服务层逻辑和一条迁移脚本。
|
||||
|
||||
## 术语表
|
||||
|
||||
- **Task_Manager**: 任务管理服务(`task_manager.py`),负责任务列表查询和状态操作
|
||||
- **Recall_Detector**: 召回完成检测器(`recall_detector.py`),ETL 数据更新后匹配服务记录完成召回任务
|
||||
- **Note_Reclassifier**: 备注回溯重分类器(`note_reclassifier.py`),召回完成后回溯普通备注为回访备注并创建回访任务
|
||||
- **Note_Service**: 备注服务(`note_service.py`),负责备注 CRUD 和回访任务自动完成
|
||||
- **Trigger_Scheduler**: 触发器调度框架(`trigger_scheduler.py`),统一管理 cron/interval/event 三种触发方式
|
||||
- **coach_tasks**: 助教任务表(`biz.coach_tasks`)
|
||||
- **trigger_jobs**: 触发器配置表(`biz.trigger_jobs`)
|
||||
- **active**: 任务有效状态
|
||||
- **abandoned**: 任务已放弃状态
|
||||
- **inactive**: 任务无效状态(被顶替)
|
||||
- **completed**: 任务已完成状态
|
||||
- **high_priority_recall**: 高优先召回任务类型
|
||||
- **priority_recall**: 优先召回任务类型
|
||||
- **follow_up_visit**: 客户回访任务类型
|
||||
- **relationship_building**: 关系构建任务类型
|
||||
- **abandon_reason**: 放弃原因字段
|
||||
- **last_run_at**: 触发器上次运行时间戳
|
||||
- **ai_analyze_note()**: AI 备注分析占位函数(P5 实现,当前返回 None)
|
||||
|
||||
## 需求
|
||||
|
||||
### 需求 1:任务列表返回已放弃任务
|
||||
|
||||
**用户故事:** 作为助教,我希望在任务列表中看到已放弃的任务及其放弃原因,以便执行「取消放弃」操作恢复任务。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 助教请求任务列表, THE Task_Manager SHALL 返回 active 和 abandoned 两种状态的任务
|
||||
2. THE Task_Manager SHALL 按以下顺序排列任务:abandoned 排在所有 active 任务之后,active 任务内部按 is_pinned DESC、priority_score DESC NULLS LAST、created_at ASC 排序
|
||||
3. THE Task_Manager SHALL 在返回结构中始终包含 abandon_reason 字段,active 状态任务的 abandon_reason 为 null,abandoned 状态任务的 abandon_reason 为非空字符串
|
||||
4. WHEN 不存在 abandoned 任务时, THE Task_Manager SHALL 仅返回 active 任务,返回结构不变(abandon_reason 为 null)
|
||||
|
||||
### 需求 2:召回完成检测器过滤任务类型
|
||||
|
||||
**用户故事:** 作为系统运维人员,我希望召回完成检测器仅完成召回类任务,避免错误地将回访和关系构建任务标记为已完成。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN ETL 检测到新增服务记录, THE Recall_Detector SHALL 仅匹配 task_type 为 high_priority_recall 或 priority_recall 的 active 任务进行完成标记
|
||||
2. WHILE 存在 active 的 follow_up_visit 任务, THE Recall_Detector SHALL 跳过该任务,不执行完成标记
|
||||
3. WHILE 存在 active 的 relationship_building 任务, THE Recall_Detector SHALL 跳过该任务,不执行完成标记
|
||||
|
||||
### 需求 3:备注回溯重分类器冲突处理
|
||||
|
||||
**用户故事:** 作为系统运维人员,我希望备注回溯重分类器在创建回访任务时正确处理冲突,避免唯一约束违反和重复任务。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN Note_Reclassifier 准备创建 follow_up_visit 任务且同 (site_id, assistant_id, member_id) 已存在 completed 的 follow_up_visit 任务, THEN THE Note_Reclassifier SHALL 跳过创建(回访完成语义已满足)
|
||||
2. WHEN Note_Reclassifier 准备创建 follow_up_visit 任务且同 (site_id, assistant_id, member_id) 已存在 active 的 follow_up_visit 任务, THEN THE Note_Reclassifier SHALL 将旧任务标记为 inactive 并记录变更历史,然后创建新的 follow_up_visit 任务(顶替方案)
|
||||
3. WHEN Note_Reclassifier 准备创建 follow_up_visit 任务且同 (site_id, assistant_id, member_id) 不存在任何 follow_up_visit 任务, THE Note_Reclassifier SHALL 正常创建新任务
|
||||
4. IF Note_Reclassifier 重复触发相同 payload, THEN THE Note_Reclassifier SHALL 不产生唯一约束冲突错误
|
||||
|
||||
### 需求 4:回访任务完成条件改为「有备注即完成」
|
||||
|
||||
**用户故事:** 作为助教,我希望为客户提交备注后对应的回访任务自动完成,无需等待 AI 评分。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN 助教通过 Note_Service 为某客户创建备注, THE Note_Service SHALL 查询该客户是否存在 active 的 follow_up_visit 任务(通过 user_assistant_binding 获取 assistant_id,再匹配 site_id、assistant_id、member_id)
|
||||
2. WHEN 存在 active 的 follow_up_visit 任务且助教提交了备注, THE Note_Service SHALL 将该任务标记为 completed 并记录变更历史,完成判定不依赖 ai_analyze_note() 的返回值
|
||||
3. THE Note_Service SHALL 保留 ai_analyze_note() 占位调用(P5 接入时调用链不变),但 ai_analyze_note() 的返回值不作为回访任务完成的判定条件
|
||||
4. WHEN Note_Reclassifier 回溯发现已有备注, THE Note_Reclassifier SHALL 直接创建 status='completed' 的回访任务(回溯完成),不依赖 AI 评分
|
||||
5. WHEN Note_Reclassifier 回溯未发现备注, THE Note_Reclassifier SHALL 创建 status='active' 的回访任务(等待助教提交备注)
|
||||
|
||||
### 需求 5:trigger_scheduler last_run_at 事务安全
|
||||
|
||||
**用户故事:** 作为系统运维人员,我希望触发器的 last_run_at 更新与 handler 执行在同一事务中,避免 handler 成功但 last_run_at 更新失败导致重复处理。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. WHEN Trigger_Scheduler 执行 event 类型触发器(fire_event), THE Trigger_Scheduler SHALL 将 last_run_at 更新纳入 handler 执行的同一事务范围,handler 成功与 last_run_at 更新要么一起提交要么一起回滚
|
||||
2. WHEN Trigger_Scheduler 执行 cron/interval 类型触发器(check_scheduled_jobs), THE Trigger_Scheduler SHALL 将 last_run_at 和 next_run_at 更新纳入 handler 执行的同一事务范围
|
||||
3. IF handler 执行成功但事务提交失败, THEN THE Trigger_Scheduler SHALL 回滚整个事务(包括 handler 的数据变更和 last_run_at 更新),下次重跑时 handler 的幂等性保证不会产生副作用
|
||||
|
||||
### 需求 6:任务生成器 cron 时间改为 07:00
|
||||
|
||||
**用户故事:** 作为运营人员,我希望任务生成器在每天早上 7 点运行,与门店营业节奏匹配。
|
||||
|
||||
#### 验收标准
|
||||
|
||||
1. THE 迁移脚本 SHALL 将 trigger_jobs 表中 task_generator 的 cron_expression 从 `0 4 * * *` 更新为 `0 7 * * *`
|
||||
2. THE Trigger_Scheduler SHALL 在 _calculate_next_run() 中使用 `0 7 * * *` 作为 cron 默认值
|
||||
3. WHEN task_generator 触发器下次运行时间被计算, THE Trigger_Scheduler SHALL 基于 `0 7 * * *` 计算正确的 next_run_at
|
||||
104
.kiro/specs/p4-prerequisite-fixes/tasks.md
Normal file
104
.kiro/specs/p4-prerequisite-fixes/tasks.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Implementation Plan: P4 前置依赖修复
|
||||
|
||||
## Overview
|
||||
|
||||
6 个定点修复,修正 P4 核心业务层与 Spec 的实现偏差。T1/T2 已在之前修复中完成,仅需属性测试验证;T3/T4/T5/T6 需要代码变更。所有修改限于现有服务层内部逻辑,无新表、无新接口。
|
||||
|
||||
测试框架:Hypothesis(项目已有依赖),测试文件位于 `tests/` 目录。
|
||||
|
||||
## Tasks
|
||||
|
||||
- [x] 1. 验证 T1(任务列表)和 T2(召回检测器)已有实现 + 属性测试
|
||||
- [x] 1.1 编写 T1 属性测试:任务列表状态过滤、排序、abandon_reason 一致性
|
||||
- 创建 `tests/test_p52_task_list_properties.py`
|
||||
- 提取 `get_task_list` 的过滤和排序逻辑为纯函数(或 mock DB 层),用 Hypothesis 生成随机任务集合
|
||||
- **Property 1: 任务列表状态过滤** — 仅返回 active/abandoned,不含 completed/inactive
|
||||
- **Property 2: 任务列表排序正确性** — abandoned 排在 active 之后,active 内部按 is_pinned DESC, priority_score DESC NULLS LAST, created_at ASC
|
||||
- **Property 3: abandon_reason 与 status 一致性不变量** — active → null, abandoned → 非空字符串
|
||||
- **Validates: Requirements 1.1, 1.2, 1.3, 1.4**
|
||||
|
||||
- [x] 1.2 编写 T2 属性测试:召回检测器仅完成 recall 类型任务
|
||||
- 在 `tests/test_p52_recall_detector_properties.py` 中编写
|
||||
- 用 Hypothesis 生成包含四种 task_type 的任务集合和服务记录
|
||||
- **Property 4: 召回检测器仅完成 recall 类型任务** — high_priority_recall/priority_recall 被完成,follow_up_visit/relationship_building 状态不变
|
||||
- **Validates: Requirements 2.1, 2.2, 2.3**
|
||||
|
||||
- [x] 2. Checkpoint — 验证 T1/T2 属性测试通过
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
- [x] 3. 实现 T3:备注回溯重分类器冲突处理
|
||||
- [x] 3.1 修改 `apps/backend/app/services/note_reclassifier.py` 的 `run()` 方法
|
||||
- 在创建 follow_up_visit 任务前,查询同 (site_id, assistant_id, member_id) 是否已有 follow_up_visit 任务
|
||||
- 已有 `completed` → 跳过创建(回访完成语义已满足)
|
||||
- 已有 `active` → 旧任务标记 `inactive`,记录 `superseded` 历史,创建新任务
|
||||
- 不存在(或仅有 inactive/abandoned)→ 正常创建
|
||||
- 确保重复触发相同 payload 不产生唯一约束冲突
|
||||
- _Requirements: 3.1, 3.2, 3.3, 3.4_
|
||||
|
||||
- [x] 3.2 编写 T3 属性测试:冲突处理三分支
|
||||
- 在 `tests/test_p52_note_reclassifier_properties.py` 中编写
|
||||
- **Property 5: 已完成回访任务阻止新建** — 存在 completed 的 follow_up_visit 时跳过创建
|
||||
- **Property 6: active 回访任务被顶替** — 旧任务 → inactive + superseded 历史,新任务创建
|
||||
- **Property 7: 无冲突时正常创建** — 不存在 follow_up_visit(或仅 inactive/abandoned)时正常创建
|
||||
- **Validates: Requirements 3.1, 3.2, 3.3, 3.4**
|
||||
|
||||
- [x] 4. 实现 T4:回访完成条件改为「有备注即完成」
|
||||
- [x] 4.1 修改 `apps/backend/app/services/note_service.py` 的 `create_note()` 方法
|
||||
- 当 `note_type == "follow_up"` 且 `task_id is not None` 时:
|
||||
- 保留 `ai_analyze_note()` 占位调用,返回值仅用于更新 `ai_score` 字段
|
||||
- 不论 `ai_score` 如何,有备注即标记关联的 active follow_up_visit 任务为 `completed`
|
||||
- 记录 `completed_by_note` 历史
|
||||
- _Requirements: 4.1, 4.2, 4.3_
|
||||
|
||||
- [x] 4.2 修改 `apps/backend/app/services/note_reclassifier.py` 的 `run()` 方法(T4 部分)
|
||||
- 去掉 AI 评分判定逻辑(`ai_score >= 6` 条件)
|
||||
- 保留 `ai_analyze_note()` 占位调用
|
||||
- 找到备注(`note_id is not None`)→ 创建 `status='completed'` 的回访任务(回溯完成)
|
||||
- 未找到备注(`note_id is None`)→ 创建 `status='active'` 的回访任务(等待备注)
|
||||
- 注意:此步骤需与 3.1 的冲突处理逻辑协同,冲突检查在任务创建前执行
|
||||
- _Requirements: 4.4, 4.5_
|
||||
|
||||
- [x] 4.3 编写 T4 属性测试:有备注即完成
|
||||
- 在 `tests/test_p52_note_service_properties.py` 中编写
|
||||
- **Property 8: 有备注即完成回访任务,不依赖 AI 评分** — 对任意 ai_score(None/0-5/6-10),提交备注后 active follow_up_visit 任务都标记 completed
|
||||
- **Property 9: 回溯有备注时创建 completed 回访任务** — note_reclassifier 找到备注 → status='completed'
|
||||
- **Property 10: 回溯无备注时创建 active 回访任务** — note_reclassifier 未找到备注 → status='active'
|
||||
- **Validates: Requirements 4.2, 4.3, 4.4, 4.5**
|
||||
|
||||
- [x] 5. Checkpoint — 验证 T3/T4 实现和测试通过
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
|
||||
- [x] 6. 实现 T5:trigger_scheduler last_run_at 事务安全
|
||||
- [x] 6.1 修改 `apps/backend/app/services/trigger_scheduler.py`
|
||||
- `fire_event()`:handler 接受可选 `conn` 参数,在 handler 最终 commit 前附带更新 `last_run_at`;handler 失败时整个事务回滚(last_run_at 不更新)
|
||||
- `check_scheduled_jobs()`:同理,将 `last_run_at` 和 `next_run_at` 更新纳入 handler 事务范围
|
||||
- 需同步修改 `recall_detector.run()` 和 `note_reclassifier.run()` 的签名,接受可选 `conn` 参数
|
||||
- _Requirements: 5.1, 5.2, 5.3_
|
||||
|
||||
- [x] 6.2 编写 T5 属性测试:事务一致性
|
||||
- 在 `tests/test_p52_trigger_scheduler_properties.py` 中编写
|
||||
- **Property 11: 触发器 last_run_at 事务一致性** — handler 成功 → last_run_at 更新;handler 异常 → last_run_at 不变(整个事务回滚)
|
||||
- **Validates: Requirements 5.1, 5.2**
|
||||
|
||||
- [x] 7. 实现 T6:cron 默认值改为 07:00 + 迁移脚本
|
||||
- [x] 7.1 修改 `apps/backend/app/services/trigger_scheduler.py` 的 `_calculate_next_run()`
|
||||
- 将 `trigger_config.get("cron_expression", "0 4 * * *")` 改为 `"0 7 * * *"`
|
||||
- _Requirements: 6.2, 6.3_
|
||||
|
||||
- [x] 7.2 创建迁移脚本 `db/zqyy_app/migrations/2026-03-15__p52_update_cron_0700.sql`
|
||||
- 幂等 UPDATE:`UPDATE biz.trigger_jobs SET trigger_config = jsonb_set(trigger_config, '{cron_expression}', '"0 7 * * *"') WHERE job_name = 'task_generator'`
|
||||
- 包含回滚注释
|
||||
- _Requirements: 6.1_
|
||||
|
||||
- [x] 8. Final checkpoint — 全部测试通过
|
||||
- Ensure all tests pass, ask the user if questions arise.
|
||||
- 运行 `pytest tests/test_p52_*.py -v` 验证所有 P5.2 属性测试通过
|
||||
|
||||
## Notes
|
||||
|
||||
- Tasks marked with `*` are optional and can be skipped for faster MVP
|
||||
- T1/T2 已在之前修复中实现,任务 1 仅编写属性测试验证覆盖
|
||||
- T3 和 T4 对 `note_reclassifier.py` 有交叉修改,任务 3.1 和 4.2 需协同实施
|
||||
- T5 涉及 handler 签名变更,需同步修改 recall_detector 和 note_reclassifier
|
||||
- T6 种子数据已是 `0 7 * * *`,迁移脚本为幂等更新确保生产环境一致
|
||||
- 属性测试使用 Hypothesis,每个属性最少 100 次迭代
|
||||
File diff suppressed because one or more lines are too long
@@ -1,69 +1,9 @@
|
||||
{
|
||||
"audit_required": true,
|
||||
"db_docs_required": true,
|
||||
"reasons": [
|
||||
"root-file",
|
||||
"dir:admin-web",
|
||||
"dir:backend",
|
||||
"dir:etl",
|
||||
"dir:miniprogram",
|
||||
"dir:db",
|
||||
"db-schema-change",
|
||||
"dir:shared"
|
||||
],
|
||||
"changed_files": [
|
||||
".env",
|
||||
".env.template",
|
||||
".gitignore",
|
||||
"_tmp_replace2.py",
|
||||
"apps/admin-web/README.md",
|
||||
"apps/admin-web/src/App.tsx",
|
||||
"apps/admin-web/src/__tests__/taskLogParser.test.ts",
|
||||
"apps/admin-web/src/api/businessDay.ts",
|
||||
"apps/admin-web/src/api/schedules.ts",
|
||||
"apps/admin-web/src/components/BusinessDayHint.tsx",
|
||||
"apps/admin-web/src/components/LogStream.tsx",
|
||||
"apps/admin-web/src/components/ScheduleHistoryDrawer.tsx",
|
||||
"apps/admin-web/src/components/ScheduleTab.tsx",
|
||||
"apps/admin-web/src/components/TaskLogViewer.tsx",
|
||||
"apps/admin-web/src/pages/LogViewer.tsx",
|
||||
"apps/admin-web/src/pages/TaskConfig.tsx",
|
||||
"apps/admin-web/src/pages/TaskManager.tsx",
|
||||
"apps/admin-web/src/store/businessDayStore.ts",
|
||||
"apps/admin-web/src/types/index.ts",
|
||||
"apps/admin-web/src/utils/",
|
||||
"apps/admin-web/tsconfig.tsbuildinfo",
|
||||
"apps/backend/README.md",
|
||||
"apps/backend/app/ai/",
|
||||
"apps/backend/app/config.py",
|
||||
"apps/backend/app/main.py",
|
||||
"apps/backend/app/middleware/permission.py",
|
||||
"apps/backend/app/routers/admin_applications.py",
|
||||
"apps/backend/app/routers/business_day.py",
|
||||
"apps/backend/app/routers/execution.py",
|
||||
"apps/backend/app/routers/member_retention_clue.py",
|
||||
"apps/backend/app/routers/ops_panel.py",
|
||||
"apps/backend/app/routers/schedules.py",
|
||||
"apps/backend/app/routers/tasks.py",
|
||||
"apps/backend/app/routers/xcx_auth.py",
|
||||
"apps/backend/app/routers/xcx_notes.py",
|
||||
"apps/backend/app/routers/xcx_tasks.py",
|
||||
"apps/backend/app/schemas/execution.py",
|
||||
"apps/backend/app/schemas/member_retention_clue.py",
|
||||
"apps/backend/app/schemas/schedules.py",
|
||||
"apps/backend/app/schemas/tasks.py",
|
||||
"apps/backend/app/schemas/xcx_auth.py",
|
||||
"apps/backend/app/schemas/xcx_notes.py",
|
||||
"apps/backend/app/schemas/xcx_tasks.py",
|
||||
"apps/backend/app/services/application.py",
|
||||
"apps/backend/app/services/cli_builder.py",
|
||||
"apps/backend/app/services/note_reclassifier.py",
|
||||
"apps/backend/app/services/note_service.py",
|
||||
"apps/backend/app/services/recall_detector.py",
|
||||
"apps/backend/app/services/scheduler.py",
|
||||
"apps/backend/app/services/task_executor.py"
|
||||
],
|
||||
"change_fingerprint": "62a29521ce5c8475e608c087c47714cd721c82c9",
|
||||
"marked_at": "2026-03-09T01:10:02.756262+08:00",
|
||||
"last_reminded_at": "2026-03-09T00:48:04.340064+08:00"
|
||||
}
|
||||
"audit_required": false,
|
||||
"db_docs_required": false,
|
||||
"reasons": [],
|
||||
"changed_files": [],
|
||||
"change_fingerprint": "",
|
||||
"marked_at": "",
|
||||
"last_reminded_at": ""
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"needs_check": false,
|
||||
"scanned_at": "2026-03-09T00:48:01.402135+08:00",
|
||||
"scanned_at": "2026-03-15T09:58:27.183154+08:00",
|
||||
"new_migration_sql": [],
|
||||
"new_or_modified_sql": [],
|
||||
"code_without_docs": [],
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"prompt_id": "P20260309-011002",
|
||||
"at": "2026-03-09T01:10:02.756262+08:00"
|
||||
"prompt_id": "P20260315-095422",
|
||||
"at": "2026-03-15T09:54:22.179324+08:00"
|
||||
}
|
||||
@@ -12,7 +12,8 @@ description: 项目文档地图索引。需要定位文档、理解项目结构
|
||||
|
||||
| 需要什么 | 去哪里找 |
|
||||
|---------|---------|
|
||||
| DB 变更审计模板 | `docs/database/BD_Manual_*.md` |
|
||||
| DB 变更审计(业务库) | `docs/database/BD_Manual_*.md` |
|
||||
| DB 变更审计(ETL 库) | `apps/etl/connectors/feiqiu/docs/database/` |
|
||||
| API 端点参考 | `apps/backend/docs/API-REFERENCE.md` |
|
||||
| ETL 任务说明 | `apps/etl/connectors/feiqiu/docs/etl_tasks/` |
|
||||
| ETL 业务规则 | `apps/etl/connectors/feiqiu/docs/business-rules/` |
|
||||
|
||||
@@ -31,6 +31,8 @@ inclusion: always
|
||||
7. **现金流互斥**:`cash_inflow_total` 中 `platform_settlement_amount` 和 `groupbuy_pay_amount` 互斥
|
||||
8. **废单判断**:使用 `dwd_assistant_service_log_ex.is_trash`,`dwd_assistant_trash_event` 已废弃(2026-02-22 DROP)
|
||||
9. **储值卡字段命名**:DWS 层使用 `balance_pay`(总额)、`recharge_card_pay`(现金充值卡)、`gift_card_pay`(赠送卡);`recharge_card_consume`(财务日报)
|
||||
10. **会员字段断档(DQ-6)**:`settlement_head.member_phone/member_name` 自 2025-12 起全为 NULL(上游不再下发)。需要会员手机号/昵称时,必须通过 `member_id` LEFT JOIN `dwd.dim_member`(字段 `mobile`/`nickname`,取 `scd2_is_current=1`),禁止直接使用 `member_phone`
|
||||
11. **会员卡字段断档(DQ-7)**:`settlement_head.member_card_type_name` 自 2025-07-21 起全为 NULL,`member_card_account_id` 全为 0。需要会员卡类型时,必须通过 `member_id` LEFT JOIN `dwd.dim_member_card_account`(关联 `tenant_member_id = member_id`,取 `scd2_is_current=1`),禁止直接使用 `member_card_type_name`。通用规则:结算单上所有会员相关冗余字段均不可靠,一律通过 ID 关联维度表获取
|
||||
|
||||
## 使用场景
|
||||
|
||||
|
||||
@@ -26,7 +26,8 @@ Kiro 所有产出物分两类,各有归档规则,禁止随意散放。
|
||||
|----------|----------|------|
|
||||
| 数据分析报告、调研产出 | `docs/reports/` | 复杂订单分析、字段口径全景 |
|
||||
| 架构设计文档 | `docs/architecture/` | ETL 架构说明 |
|
||||
| 数据库变更审计(BD 手册) | `docs/database/` | `BD_Manual_*.md` |
|
||||
| 数据库变更审计(业务库 BD 手册) | `docs/database/` | `BD_Manual_*.md`(zqyy_app / FDW / RLS) |
|
||||
| 数据库变更审计(ETL BD 手册) | `apps/etl/.../docs/database/` | 模块专属表级文档、跨层映射 |
|
||||
| 变更审计记录 | `docs/audit/changes/` | `YYYY-MM-DD__<slug>.md` |
|
||||
| 产品需求规格 | `docs/prd/specs/` | P1-P11 需求 spec |
|
||||
| 数据契约(OpenAPI/Schema) | `docs/contracts/` | `backend-api.json` |
|
||||
@@ -37,6 +38,7 @@ Kiro 所有产出物分两类,各有归档规则,禁止随意散放。
|
||||
| 迁移记录 | `docs/migrate/` | Monorepo 迁移总结 |
|
||||
| MCP 相关文档 | `docs/mcp/` | AI 查询手册 |
|
||||
| UI 原型 | `docs/h5_ui/` | H5 静态页面 |
|
||||
| 小程序前端开发指南 | `docs/miniprogram-dev/` | 页面开发流程、代理手册、规范参考 |
|
||||
| 运维手册 | `docs/ops/` | 故障排查流程 |
|
||||
| 权限矩阵 | `docs/permission_matrix/` | 角色-资源映射 |
|
||||
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
---
|
||||
inclusion: fileMatch
|
||||
fileMatchPattern: "**/miniprogram/miniprogram/pages/**,**/miniprogram/miniprogram/components/**,**/h5_ui/**"
|
||||
name: miniprogram-h5-conversion
|
||||
description: H5 原型转微信小程序的强制规范。读到小程序页面/组件或 H5 原型文件时自动加载。
|
||||
---
|
||||
|
||||
# H5 → 微信小程序转换规范(强制)
|
||||
|
||||
本规范适用于所有将 `docs/h5_ui/pages/*.html` 转换为小程序页面的任务。
|
||||
|
||||
## 一、转换前强制加载
|
||||
|
||||
每次转换页面前,必须加载以下资源(按顺序):
|
||||
|
||||
1. `wechat-miniprogram` Power 的 steering 文件:`view-layer.md`、`tdesign.md`、`builtin-components.md`
|
||||
2. 目标页面的交互说明:`docs/h5_ui/interactions/<page>.md`
|
||||
3. 设计 Token:`docs/h5_ui/design-tokens.json`
|
||||
4. 图标映射表:`docs/h5_ui/icon-mapping.md`
|
||||
5. 目标页面的 H5 源码:`docs/h5_ui/pages/<page>.html`
|
||||
6. 计算样式(如有):`docs/h5_ui/computed-styles.json` 中对应页面的 key
|
||||
7. 截图(如用户提供):`docs/h5_ui/screenshots/<page>--*.png`
|
||||
|
||||
## 二、原型忠实度(最高优先级)
|
||||
|
||||
- `docs/h5_ui/pages/*.html` 中的结构、层次、元素、配色、间距、交互行为是唯一视觉真相
|
||||
- 任何偏离原型的实现都需要用户明确确认
|
||||
- 截图是校验还原度的唯一视觉参考
|
||||
|
||||
## 三、标签映射(硬性规则)
|
||||
|
||||
| HTML | WXML | 说明 |
|
||||
|------|------|------|
|
||||
| `<div>` | `<view>` | 容器 |
|
||||
| `<span>` / `<p>` | `<text>` | 文本必须用 `<text>` 包裹 |
|
||||
| `<a>` | `<navigator>` | 或 `wx.navigateTo()` |
|
||||
| `<img>` | `<image mode="">` | 必须指定 `mode` 和宽高 |
|
||||
| `<svg>` 内联 | `<image src="xx.svg">` | 不支持内联 SVG |
|
||||
| `<ul>/<li>` | `<view wx:for>` | 无列表语义标签 |
|
||||
| `<select>` | `<t-picker>` | 完全不同的交互 |
|
||||
| `<button>` | `<t-button>` | TDesign 优先 |
|
||||
| `<input>` | `<t-input>` | TDesign 优先 |
|
||||
|
||||
严禁在 WXML 中使用 HTML 标签(div/span/p/a/img 等)。
|
||||
|
||||
## 四、样式规则
|
||||
|
||||
### rpx 换算
|
||||
- 基准:屏幕宽度 = 750rpx,设计稿以 375px 宽为基准
|
||||
- 换算公式:H5 的 px 值 × 2 = rpx 值
|
||||
- 严禁同一类间距混用 rpx 和 px
|
||||
|
||||
### 设计 Token 引用
|
||||
颜色、间距、圆角、字号、阴影必须参照 `docs/h5_ui/design-tokens.json`,不得凭记忆硬编码。
|
||||
|
||||
### 不支持的 CSS
|
||||
| CSS 特性 | 替代方案 |
|
||||
|----------|---------|
|
||||
| `backdrop-filter: blur()` | 半透明背景色 `rgba()` |
|
||||
| `*` 通配符选择器 | 逐个元素设置 |
|
||||
| 远程 `@font-face` | `wx.loadFontFace()` |
|
||||
|
||||
### 样式隔离
|
||||
- `app.wxss` = 全局样式
|
||||
- 页面 `.wxss` = 自动隔离
|
||||
- 组件 `.wxss` = 默认隔离,穿透用外部样式类或 CSS 变量
|
||||
|
||||
## 五、TDesign 优先原则
|
||||
|
||||
- 凡 TDesign 组件库能覆盖的 UI 元素,必须使用 TDesign 组件
|
||||
- 自定义实现仅限 TDesign 无法覆盖的场景
|
||||
- TDesign 样式覆盖优先用 CSS 变量,其次外部样式类,最后 `!important`
|
||||
- 组件必须在页面 `.json` 的 `usingComponents` 中注册
|
||||
|
||||
## 六、事件系统
|
||||
|
||||
- 不能在 `bindtap` 中传参:用 `data-*` 属性
|
||||
- 取值路径:`e.detail.value`(非 `event.target.value`)
|
||||
- 阻止冒泡:用 `catchtap`(非 `preventDefault`)
|
||||
- `data-` 属性名自动转换:连字符转驼峰,大写转小写
|
||||
|
||||
## 七、数据与状态
|
||||
|
||||
- 用 `this.setData()` 驱动视图更新,无 DOM API
|
||||
- `wx:if` 中不支持复杂 JS 表达式,需在 JS 中预处理
|
||||
- 布尔属性必须用 `{{}}` 包裹:`checked="{{true}}"`
|
||||
- 列表渲染必须加 `wx:key`
|
||||
|
||||
## 八、导航与路由
|
||||
|
||||
- 页面栈最多 10 层,`navigateTo` 超过会静默失败
|
||||
- 跳转 tabBar 页面必须用 `switchTab`
|
||||
- 路径以 `/` 开头,不带 `.wxml` 后缀
|
||||
- 登录/登出场景用 `reLaunch`
|
||||
|
||||
## 九、Mock 数据策略(纯 UI 阶段)
|
||||
|
||||
后端 API 未就绪时,使用 mock 数据:
|
||||
- 在页面 JS 的 `onLoad` 中用 `this.setData()` 设置 mock 数据
|
||||
- mock 数据结构必须贴近真实 API 返回格式(参考对应 Spec 的接口定义)
|
||||
- mock 数据用 `// TODO: 替换为真实 API 调用` 注释标记
|
||||
- 联调时只需替换数据获取逻辑,不改动 WXML/WXSS
|
||||
|
||||
## 十、新页面开发 Checklist
|
||||
|
||||
- [ ] HTML 标签全部替换为 WXML 组件
|
||||
- [ ] 内联 SVG 提取为文件,改用 `<image>` 或 `<t-icon>`
|
||||
- [ ] Tailwind 类全部手写为 WXSS(px × 2 = rpx)
|
||||
- [ ] 不支持的 CSS 改为替代方案
|
||||
- [ ] 事件绑定改为 `bindtap` / `bind:change`,传参用 `data-*`
|
||||
- [ ] `alert/confirm` 改为 `wx.showToast` / `wx.showModal`
|
||||
- [ ] `localStorage` 改为 `wx.setStorageSync`
|
||||
- [ ] 路由跳转改为 `wx.navigateTo` / `wx.reLaunch` 等
|
||||
- [ ] 图片设置 `mode` 属性
|
||||
- [ ] 列表渲染加 `wx:key`
|
||||
- [ ] 布尔属性用 `{{}}` 包裹
|
||||
- [ ] TDesign 组件在页面 `.json` 中注册
|
||||
- [ ] 安全区适配:JS `wx.getSystemInfoSync().statusBarHeight` 动态 padding-top(禁止用 `env(safe-area-inset-top)`)
|
||||
- [ ] 页面配置:`navigationBarTitleText` 等
|
||||
|
||||
## 十一、验收标准
|
||||
|
||||
- 视觉还原度:与 H5 截图对比,布局/间距/颜色/字号一致
|
||||
- 交互完整性:交互说明中的所有状态和操作均已实现
|
||||
- 空状态/加载态/错误态:均有处理
|
||||
- TDesign 组件正确使用,无原生 HTML 标签残留
|
||||
|
||||
## 十二、实战踩坑速查
|
||||
|
||||
> 完整记录见 `docs/prd/MIGRATION-PLAYBOOK.md` 第六章。
|
||||
|
||||
### WXML 模板
|
||||
- **禁止在 `{{}}` 中调用 JS 方法**(`.toFixed()`、`.map()` 等)→ 用 WXS 模块 `utils/format.wxs`
|
||||
- **TabBar 页面跳转必须用 `wx.switchTab`**(task-list、board-finance、my-profile),`navigateTo` 会静默失败
|
||||
|
||||
### 样式与布局
|
||||
- **一屏页面**(login、reviewing、no-permission 等):`height: 100vh` + `box-sizing: border-box`,不用 `min-height: 100vh`
|
||||
- **状态栏适配**:用 JS `wx.getSystemInfoSync().statusBarHeight` 动态设置 `padding-top`,禁止用 `env(safe-area-inset-top)`
|
||||
- **padding-top + 100vh**:必须配合 `box-sizing: border-box`,否则底部内容溢出
|
||||
|
||||
### TDesign 组件
|
||||
- **`t-button icon="xxx"` 只支持内置图标**:品牌图标(微信 logo 等)必须导出 SVG,用 `<view>` + `<image>` 组合
|
||||
- **TDesign 默认样式优先级高**:与原型差异大时,直接用原生 `<view>` 实现,绕开样式干扰
|
||||
|
||||
### 资源引用
|
||||
- **所有 H5 内联 SVG 必须导出为独立 `.svg` 文件**,存放 `assets/icons/`,用 `<image>` 引用
|
||||
- **引用不存在的图片会 500 错误**:用 CSS 渐变、emoji、`<t-icon>` 替代
|
||||
|
||||
---
|
||||
|
||||
> 以上内容已整合至 `docs/prd/MIGRATION-PLAYBOOK.md`(唯一权威迁移文档)。
|
||||
> 避坑清单见第六章,迁移流程见第二章,输入素材见第十二章,AI 工作流见第十一章。
|
||||
@@ -13,7 +13,7 @@ inclusion: always
|
||||
- 搜索 `docs/audit/changes/` 中相关的历史审计记录
|
||||
- **查询 Session 索引**:读取 `docs/audit/session_logs/_session_index.json`,按 `summary.files_modified` 筛选涉及目标模块的历史 session,提取 `description`(操作摘要)和 `startTime`,了解该模块近期被修改的上下文和原因(详见 `docs/audit/SESSION-LOG-GUIDE.md`)
|
||||
- 阅读涉及模块的 README、PRD spec(`docs/prd/specs/`)
|
||||
- 数据库相关:BD 手册(`docs/database/BD_Manual_*.md`)
|
||||
- 数据库相关:BD 手册(`docs/database/BD_Manual_*.md` + `apps/etl/connectors/feiqiu/docs/database/`)
|
||||
- ETL 相关:产品说明、数据流报告
|
||||
- 接口相关:OpenAPI spec、接口文档
|
||||
- 读取要修改的文件及其直接依赖(调用方、被调用方)
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
inclusion: manual
|
||||
---
|
||||
|
||||
# 微信开发者工具 MCP 连接规范
|
||||
|
||||
使用 `weixin-devtools-mcp` 操作小程序时,必须遵循以下规则:
|
||||
|
||||
## 连接方式
|
||||
|
||||
1. 启动自动化端口:
|
||||
```powershell
|
||||
& "C:\dev\WechatDevtools\cli.bat" auto --project "C:\NeoZQYY\apps\miniprogram" --auto-port 9420
|
||||
```
|
||||
|
||||
2. AI 使用 `connect_devtools` 时,只能用 `wsEndpoint` 策略:
|
||||
- `strategy`: `wsEndpoint`
|
||||
- `wsEndpoint`: `ws://127.0.0.1:9420`
|
||||
- `projectPath`: `C:\NeoZQYY\apps\miniprogram`
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 禁止使用 `connect`、`discover`、`auto`、`launch` 策略(会导致开发者工具重启)
|
||||
- 禁止在未确认自动化端口已启动的情况下调用 `connect_devtools`
|
||||
- 如果连接失败,提示用户检查终端中自动化端口是否在运行,不要自行重试其他策略
|
||||
|
||||
## 详细文档
|
||||
|
||||
参见 `docs/mcp/WEIXIN-DEVTOOLS-MCP.md`
|
||||
Reference in New Issue
Block a user