Files
Neo-ZQYY/.kiro/specs/rns1-task-performance-api/tasks.md

13 KiB
Raw Blame History

Implementation Plan: RNS1.1 任务与绩效接口

Overview

基于 design.md 的 7 个组件结构,增量扩展现有后端路由和服务层,新增 FDW 查询封装、绩效服务、Pydantic Schema并完成前端适配。所有 FDW 查询集中在 fdw_queries.py,服务层分为 task_manager.py(扩展)和 performance_service.py(新增)。

Tasks

  • 1. Pydantic Schema 定义(组件 6

    • 1.1 扩展 apps/backend/app/schemas/xcx_tasks.py,新增 PerformanceSummary15+ 字段tierNodes, basicHours, bonusHours, currentTier, nextTierHours, tierCompleted, bonusMoney, incomeTrend, incomeTrendDir, prevMonth, currentTierLabel 等)、TaskItem(扩展版,含 lastVisitDays, balance, aiSuggestion 可选字段)、TaskListResponseitems + total + page + pageSize + performance
      • 新增 RetentionClueServiceRecord(含 courseTypeClass 枚举)、AiAnalysisNoteItem(含 score 可选字段)、ServiceSummaryTaskDetailResponse 模型
      • Requirements: 1.1, 1.6, 2.1, 2.2, 2.4, 2.9
    • 1.2 新建 apps/backend/app/schemas/xcx_performance.py,定义 DateGroupRecord(含可选 avatarChar/avatarColorDateGroupTierInfoIncomeItem(含 descCustomerSummaryNewCustomerRegularCustomerPerformanceOverviewResponse 模型
      • 定义 RecordsSummarytotalCount, totalHours, totalHoursRaw, totalIncomePerformanceRecordsResponsesummary + dateGroups + hasMore模型
      • Requirements: 3.1, 3.3, 3.4, 3.5, 4.1, 4.2, 4.3
  • 2. FDW 查询封装服务(组件 3 — 新增 fdw_queries.py

    • 2.1 新建 apps/backend/app/services/fdw_queries.py,实现 _fdw_context(conn, site_id) 上下文管理器BEGIN + SET LOCAL app.current_site_idget_member_info(conn, site_id, member_ids) 批量查询会员信息
      • ⚠️ DQ-6通过 member_id JOIN fdw_etl.v_dim_member取 scd2_is_current=1
      • Requirements: 8.7
    • 2.2 实现 get_member_balance(conn, site_id, member_ids) 批量查询会员储值卡余额
      • ⚠️ DQ-7通过 member_id JOIN fdw_etl.v_dim_member_card_account取 scd2_is_current=1
      • Requirements: 1.8, 8.7
    • 2.3 实现 get_last_visit_days(conn, site_id, member_ids) 批量查询客户距上次到店天数
      • 来源fdw_etl.v_dwd_assistant_service_logWHERE is_trash = false
      • Requirements: 1.7
    • 2.4 实现 get_salary_calc(conn, site_id, assistant_id, year, month) 查询助教绩效/档位/收入数据
      • ⚠️ DWD-DOC 规则 1收入使用 items_sum 口径
      • ⚠️ DWD-DOC 规则 2费用使用 assistant_pd_money + assistant_cx_money
      • Requirements: 1.2, 1.3, 3.7, 8.5, 8.6
    • 2.5 实现 get_service_records(conn, site_id, assistant_id, year, month, limit, offset) 查询助教服务记录明细
      • ⚠️ 废单排除WHERE is_trash = falseDQ-6客户姓名通过 member_id JOIN dim_member
      • Requirements: 2.11, 2.12, 3.5, 4.7, 4.8, 8.8
    • 2.6 实现 get_service_records_for_task(conn, site_id, assistant_id, member_id, limit) 查询特定客户的服务记录TASK-2 用)
      • Requirements: 2.1, 2.3
  • 3. Checkpoint — Schema 与 FDW 查询层验证

    • Ensure all tests pass, ask the user if questions arise.
  • 4. task_manager 服务扩展(组件 4 — 扩展现有 task_manager.py

    • 4.1 在 apps/backend/app/services/task_manager.py 中实现 get_task_list_v2(user_id, site_id, status, page, page_size)
      • 逻辑_get_assistant_id() → 查询 coach_tasks 带分页 → fdw_queries 批量获取会员信息/余额/lastVisitDays → fdw_queries.get_salary_calc() 获取绩效概览 → 查询 ai_cache 获取 aiSuggestion → 组装 TaskListResponse
      • 扩展字段lastVisitDays/balance/aiSuggestion采用优雅降级单个查询失败返回 null不影响整体响应
      • Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10
    • 4.2 在 apps/backend/app/services/task_manager.py 中实现 get_task_detail(task_id, user_id, site_id)
      • 逻辑_get_assistant_id() + _verify_task_ownership() 权限校验 → 查询 coach_tasks 基础信息 → 查询 member_retention_clue 维客线索 → 查询 ai_cacheapp5_talking_points → talkingPoints, app4_analysis → aiAnalysis→ fdw_queries.get_service_records_for_task() 服务记录(最多 20 条)→ 查询 notes最多 20 条)→ 组装 TaskDetailResponse
      • tag 字段净化:去除换行符 \n多行标签使用空格分隔
      • Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.10, 2.11, 2.12, 2.13, 2.14
    • 4.3 Write property test: 收入趋势计算正确性
      • Property 1: 收入趋势计算正确性
      • 生成器st.floats(min_value=0, max_value=1e6) × 2
      • 验证incomeTrendDir 方向正确、差值正确、前缀符号一致
      • Validates: Requirements 1.4
    • 4.4 Write property test: lastVisitDays 计算正确性
      • Property 2: lastVisitDays 计算正确性
      • 生成器st.dates(max_value=date.today())
      • 验证:天数差 = (today - date).days非负
      • Validates: Requirements 1.7
    • 4.5 Write property test: 维客线索 tag 净化与 source 枚举
      • Property 3: 维客线索 tag 净化与 source 枚举
      • 生成器st.text() 生成含 \n 的 tag + st.sampled_from source
      • 验证tag 无换行、source 在枚举内
      • Validates: Requirements 2.4, 2.5
    • 4.6 Write property test: courseTypeClass 枚举映射
      • Property 4: courseTypeClass 枚举映射
      • 生成器st.sampled_from(ALL_COURSE_TYPES)
      • 验证:结果在 {basic, vip, tip, recharge, incentive} 内、无 tag- 前缀
      • Validates: Requirements 2.9, 4.4
  • 5. performance_service 服务(组件 5 — 新增 performance_service.py

    • 5.1 新建 apps/backend/app/services/performance_service.py,实现 get_overview(user_id, site_id, year, month)
      • 逻辑:获取 assistant_id → fdw_queries.get_salary_calc() 档位/收入/费率 → fdw_queries.get_service_records() 按日期分组为 DateGroup → 聚合新客/常客列表 → 计算 incomeItems含 desc 费率描述)→ 查询上月收入 lastMonthIncome
      • Requirements: 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13
    • 5.2 实现 get_records(user_id, site_id, year, month, page, page_size)
      • 逻辑:获取 assistant_id → fdw_queries.get_service_records() 带分页 → 按日期分组为 dateGroups → 计算 summary 汇总 → 返回 { summary, dateGroups, hasMore }
      • PERF-2 不返回 avatarChar/avatarColor前端自行计算
      • Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8
    • 5.3 Write property test: 分页与排序
      • Property 5: 列表分页与排序
      • 生成器st.lists(st.fixed_dictionaries(...)) + st.integers(1,10) page/pageSize
      • 验证:记录数 ≤ pageSize、hasMore 正确、排序正确
      • Validates: Requirements 2.3, 4.2
    • 5.4 Write property test: DateGroup 分组正确性
      • Property 6: DateGroup 分组正确性
      • 生成器st.lists(st.fixed_dictionaries({date, hours, income}))
      • 验证:日期唯一、组内日期一致、汇总正确、按日期倒序
      • Validates: Requirements 3.3, 4.3
    • 5.5 Write property test: incomeItems desc 格式化
      • Property 7: incomeItems desc 格式化
      • 生成器st.floats(min_value=0.01) rate × st.floats(min_value=0) hours
      • 验证desc 包含费率值和工时值,格式为 "{rate}元/h × {hours}h"
      • Validates: Requirements 3.9
    • 5.6 Write property test: 月度汇总聚合正确性
      • Property 8: 月度汇总聚合正确性
      • 生成器st.lists(st.fixed_dictionaries({hours, hours_raw, income}))
      • 验证totalCount/totalHours/totalHoursRaw/totalIncome 聚合正确
      • Validates: Requirements 4.6
  • 6. Checkpoint — 服务层验证

    • Ensure all tests pass, ask the user if questions arise.
  • 7. xcx_tasks Router 扩展(组件 1

    • 7.1 修改 apps/backend/app/routers/xcx_tasks.py:将 GET /api/xcx/tasks 响应从 list[TaskListItem] 改为 TaskListResponse(含 items + performance + 分页),新增 status/page/pageSize 查询参数,调用 task_manager.get_task_list_v2()
      • Requirements: 1.1, 1.2
    • 7.2 在 routers/xcx_tasks.py 中新增 GET /api/xcx/tasks/{task_id} 端点,调用 task_manager.get_task_detail(),含 require_approved() 权限校验
      • Requirements: 2.1, 2.13, 2.14
    • 7.3 修改 routers/xcx_tasks.pyPOST .../pinPOST .../unpin 端点,响应对齐契约格式 { isPinned: bool }
      • Requirements: 5.1, 5.2, 5.3, 5.4, 5.5
    • 7.4 修改 POST /api/xcx/notes 端点(xcx_notes.py),接受请求体中的可选 score 字段number, 1-5存入 biz.coach_notes.score 列;超出 1-5 范围返回 422
      • Requirements: 6.3
    • 7.5 Write property test: Pin/Unpin 状态往返
      • Property 9: Pin/Unpin 状态往返
      • 生成器st.booleans() 初始状态
      • 验证pin→true、unpin→false、往返恢复
      • Validates: Requirements 5.1, 5.2, 5.3
    • 7.6 Write property test: 权限与数据隔离
      • Property 10: 权限与数据隔离
      • 生成器st.sampled_from(INVALID_USER_SCENARIOS)
      • 验证:未审核/无绑定/无权限/非本人任务 → 所有端点返回 403
      • Validates: Requirements 2.13, 8.1, 8.2, 8.4
    • 7.7 Write property test: 备注 score 输入验证
      • Property 12: 备注 score 输入验证
      • 生成器st.integers()
      • 验证1-5 接受、超范围拒绝 422、null 接受
      • Validates: Requirements 6.3
  • 8. xcx_performance Router组件 2 — 新增)

    • 8.1 新建 apps/backend/app/routers/xcx_performance.py,实现 GET /api/xcx/performance 端点(接受 year/month 参数),调用 performance_service.get_overview(),含 require_approved() 权限校验
      • Requirements: 3.1, 3.2
    • 8.2 在 routers/xcx_performance.py 中实现 GET /api/xcx/performance/records 端点(接受 year/month/page/pageSize 参数),调用 performance_service.get_records()
      • Requirements: 4.1, 4.2
    • 8.3 修改 apps/backend/app/main.py,导入并注册 xcx_performance.router
      • Requirements: 3.1, 4.1
  • 9. Checkpoint — 后端路由层验证

    • Ensure all tests pass, ask the user if questions arise.
  • 10. 前端适配(组件 7

    • 10.1 修改 apps/miniprogram/miniprogram/services/api.ts:新增 pinTask()unpinTask()fetchTaskDetail()fetchPerformanceOverview(year, month)fetchPerformanceRecords(year, month, page) 函数;createNote() 增加可选 score 参数
      • Requirements: 5.6, 6.1, 6.2, 7.1
    • 10.2 修改 apps/miniprogram/miniprogram/pages/task-list/task-list.ts:消费 TaskListResponse 新结构items + performancebuildPerfData() 使用 15+ 字段绩效数据,移除 mock 数据
      • Requirements: 6.4, 6.5
    • 10.3 修改 task-detail 页面:调用 fetchTaskDetail();根据 balance 前端本地计算 storageLevel,根据 heartScore 计算 relationLevel/relationLevelText/relationColor
      • Requirements: 6.4, 6.5
    • 10.4 修改 apps/miniprogram/miniprogram/pages/performance/performance.ts:添加月份切换控件(左右箭头 + 月份标签),实现 switchMonth() 调用 fetchPerformanceOverview,含加载状态管理
      • Requirements: 7.1, 7.2, 7.3
    • 10.5 修改 apps/miniprogram/miniprogram/pages/performance-records/performance-records.ts:修复 switchMonth() 中 page 未重置的 Bug切换月份时清空记录列表并重新加载page 重置为 1
      • Requirements: 7.4, 7.5
    • 10.6 在 performance 和 performance-records 页面中,使用 nameToAvatarColor()customerName 计算 avatarChar/avatarColor,不依赖后端
      • Requirements: 7.6
    • 10.7 Write property test: 前端派生字段计算
      • Property 11: 前端派生字段计算
      • 生成器st.text(min_size=1) name + st.floats(0, 1e6) balance + st.floats(0, 10) heartScore
      • 验证avatarChar=name[0]、确定性、storageLevel/relationLevel 单调性
      • Validates: Requirements 6.4, 6.5, 7.6
  • 11. Final checkpoint — 全量验证

    • Ensure all tests pass, ask the user if questions arise.

Notes

  • Tasks marked with * are optional and can be skipped for faster MVP
  • 组件 3fdw_queries.py是所有 FDW 查询的集中封装,组件 4/5 通过调用它访问 ETL 数据
  • 组件 4 扩展现有 task_manager.py不新建 task_perf_service.py组件 5 新建 performance_service.py
  • Schema 文件命名:xcx_tasks.py(扩展)+ xcx_performance.py(新增),与 design.md 一致
  • 所有 12 个正确性属性P1-P12均有对应的属性测试任务
  • DWD-DOC 强制规则在 fdw_queries.py 中统一实施items_sum 口径、费用拆分、DQ-6/DQ-7 JOIN、废单排除