18 KiB
18 KiB
需求文档 — RNS1.1:任务与绩效接口
简介
RNS1.1 是 NS1 小程序后端 API 补全项目的第二个子 spec,负责实现助教日常使用频率最高的 4 个核心接口(任务列表扩展、任务详情、绩效概览、绩效明细)、pin/unpin 端点、以及对应的前端适配。本 spec 覆盖助教视角的核心工作流,是助教登录后最先接触的功能集合。
依赖
- RNS1.0(基础设施与契约重写)必须先完成:全局响应包装中间件、camelCase 转换、重写后的 API 契约
- 前端已有 13 个页面(P5.2 交付),当前使用 mock 数据
- 后端已有
xcx_tasks.py(需扩展)、xcx_notes.py、xcx_auth.py
来源文档
docs/prd/Neo_Specs/RNS1-split-plan.md— 拆分计划主文档docs/miniprogram-dev/API-contract.md— API 契约(RNS1.0 T0-5 重写后版本)docs/prd/Neo_Specs/storyboard-walkthrough-assistant-view.md— 助教视角走查报告(GAP-02~22)docs/reports/DWD-DOC/— 金额口径与字段语义权威标杆文档
术语表
- Backend:FastAPI 后端应用,位于
apps/backend/ - Miniprogram:微信小程序前端应用,位于
apps/miniprogram/ - TASK_1_API:任务列表接口
GET /api/xcx/tasks,返回任务列表 + 绩效概览 - TASK_2_API:任务详情接口
GET /api/xcx/tasks/{taskId},返回单个任务的完整详情 - PERF_1_API:绩效概览接口
GET /api/xcx/performance,返回助教当月绩效汇总 - PERF_2_API:绩效明细接口
GET /api/xcx/performance/records,返回按日期分组的服务记录 - PIN_API:任务置顶/取消置顶接口
POST /api/xcx/tasks/{id}/pin和POST /api/xcx/tasks/{id}/unpin - PerformanceSummary:任务列表响应中附带的绩效概览数据结构(15+ 字段)
- DateGroup:按日期分组的数据结构,包含日期标签、当日汇总、记录列表
- FDW:PostgreSQL Foreign Data Wrapper,用于从业务库
zqyy_app访问 ETL 库etl_feiqiu的数据 - items_sum:DWD-DOC 强制使用的消费金额口径,=
table_charge_money + goods_money + assistant_pd_money + assistant_cx_money + electricity_money - assistant_pd_money:助教陪打费用(基础课),DWD-DOC 强制规则 2 要求的拆分字段
- assistant_cx_money:助教超休费用(激励课),DWD-DOC 强制规则 2 要求的拆分字段
- enrichTask:前端
task-list页面中对原始任务数据进行扩展的函数,补充lastVisitDays/balance/aiSuggestion等字段 - buildPerfData:前端
task-list页面中构建绩效进度条数据的函数,消费PerformanceSummary的 15+ 字段 - courseTypeClass:服务记录中课程类型的样式标识,统一使用
basic/vip/tip枚举(不带tag-前缀) - user_assistant_binding:业务库中用户与助教身份的绑定关系表,用于数据隔离
- ai_cache:业务库中 AI 分析结果的缓存表,按
cache_type区分不同类型的 AI 输出
需求
需求 1:扩展 TASK-1 任务列表绩效概览(T1-1)
用户故事: 作为助教,我希望在任务列表页面看到完整的绩效进度条(含档位节点、基础/激励课时、升档奖金、收入趋势),以便快速了解本月绩效状态和距升档的差距。
验收标准
- THE TASK_1_API SHALL 在响应的
performance字段中返回以下扩展字段:tierNodes(档位节点数组,如[0, 100, 130, 160, 190, 220])、basicHours(基础课时)、bonusHours(激励课时)、currentTier(当前档位索引,0-based)、nextTierHours(下一档位工时阈值)、tierCompleted(是否已达最高档)、bonusMoney(升档奖金,元)、incomeTrend(收入趋势描述,如"↓368")、incomeTrendDir(up或down)、prevMonth(上月标签,如"1月")、currentTierLabel(当前档位名称,如"初级") - THE TASK_1_API SHALL 从
fdw_etl.v_dws_assistant_salary_calc查询当前助教的绩效和档位数据,通过user_assistant_binding获取assistant_id进行数据隔离 - THE TASK_1_API SHALL 使用
items_sum口径计算所有收入金额(DWD-DOC 强制规则 1),使用assistant_pd_money(基础课)和assistant_cx_money(激励课)拆分助教费用(DWD-DOC 强制规则 2) - THE TASK_1_API SHALL 通过对比当月和上月的收入数据计算
incomeTrend和incomeTrendDir字段 - WHEN
tierCompleted为true时,THE TASK_1_API SHALL 将bonusMoney设为 0,nextTierHours设为当前档位工时阈值
1.2 任务项扩展字段(GAP-03)
- THE TASK_1_API SHALL 为每个任务 item 返回以下可选扩展字段:
lastVisitDays(距上次到店天数,integer)、balance(客户余额,number,元)、aiSuggestion(AI 建议摘要,string) - THE TASK_1_API SHALL 从
fdw_etl.dwd.dwd_settlement_head查询客户最后到店日期,计算lastVisitDays(当前日期与MAX(settle_time)的天数差) - THE TASK_1_API SHALL 从
fdw_etl.dwd.dim_member_card_account查询客户储值卡余额作为balance字段值 - THE TASK_1_API SHALL 从
biz.ai_cache查询cache_type对应的 AI 建议摘要作为aiSuggestion字段值 - IF 某个扩展字段的数据源查询失败或无数据,THEN THE TASK_1_API SHALL 对该字段返回
null,不影响其他字段和整体响应
需求 2:实现 TASK-2 任务详情完整版(T1-2)
用户故事: 作为助教,我希望点击任务后能看到完整的任务详情(包括服务记录、维客线索、AI 分析、备注),以便全面了解客户情况并制定跟进策略。
验收标准
- THE TASK_2_API SHALL 返回完整的任务详情响应,包含基础信息、维客线索(
retentionClues)、话术参考(talkingPoints)、服务记录摘要(serviceSummary)、服务记录列表(serviceRecords)、AI 分析(aiAnalysis)、备注列表(notes) - THE TASK_2_API SHALL 在响应中包含
customerId字段(客户唯一 ID),供前端跳转 chat 和 customer-service-records 页面使用 - WHEN 请求任务详情时,THE TASK_2_API SHALL 对服务记录(
serviceRecords)和备注(notes)各返回最多 20 条,按时间倒序排列,支持前端懒加载
2.2 维客线索格式统一(GAP-06~07)
- THE TASK_2_API SHALL 返回维客线索的
tag字段为纯文本字符串(不含换行符\n),多行标签使用空格分隔 - THE TASK_2_API SHALL 返回维客线索的
source字段为以下枚举值之一:manual(手动创建)、ai_consumption(AI 消费分析生成)、ai_note(AI 备注分析生成) - THE TASK_2_API SHALL 从
public.member_retention_clue查询维客线索数据,按created_at倒序排列
2.3 AI 分析 cache_type 映射(GAP-08)
- THE TASK_2_API SHALL 从
biz.ai_cache查询 AI 分析数据,使用以下cache_type映射:aiAnalysis.summary来自app4_analysis,talkingPoints来自app5_talking_points - IF
biz.ai_cache中无对应cache_type的缓存记录,THEN THE TASK_2_API SHALL 对aiAnalysis返回{ summary: "", suggestions: [] },对talkingPoints返回空数组
2.4 服务记录字段(GAP-06)
- THE TASK_2_API SHALL 为每条服务记录返回
courseTypeClass字段,使用统一枚举值:basic(基础课)、vip(包厢课)、tip(激励课)、recharge(充值)、incentive(激励),不带tag-前缀 - THE TASK_2_API SHALL 为每条服务记录返回可选字段
recordType(course或recharge)和isEstimate(是否预估数据,boolean) - THE TASK_2_API SHALL 使用
items_sum口径计算服务记录中的income字段(DWD-DOC 强制规则 1) - THE TASK_2_API SHALL 使用
dwd_assistant_service_log_ex.is_trash排除废单记录
2.5 权限与数据隔离
- THE TASK_2_API SHALL 验证请求的
taskId属于当前登录助教(通过user_assistant_binding获取assistant_id,校验coach_tasks.assistant_id匹配) - IF 请求的
taskId不属于当前助教,THEN THE TASK_2_API SHALL 返回 HTTP 403{ code: 403, message: "无权访问该任务" }
需求 3:实现 PERF-1 绩效概览(T1-3)
用户故事: 作为助教,我希望查看本月绩效概览(包括收入明细、档位进度、服务记录按日期分组、新客和常客列表),以便了解本月工作成果和收入构成。
验收标准
- THE PERF_1_API SHALL 接受
year和month查询参数,返回指定月份的绩效概览数据 - THE PERF_1_API SHALL 通过
user_assistant_binding获取当前助教的assistant_id,仅查询该助教自己的绩效数据
3.2 本月服务记录 DateGroup 结构(GAP-12)
- THE PERF_1_API SHALL 将
thisMonthRecords以 DateGroup 结构返回:每组包含date(日期标签,如"2月7日")、totalHours(当日总工时,格式化字符串)、totalIncome(当日总收入,格式化字符串)、records(记录列表) - THE PERF_1_API SHALL 为 DateGroup 中每条记录返回以下字段:
customerName、avatarChar(姓氏首字)、avatarColor(头像渐变色)、timeRange(时间段,如"20:00-22:00")、hours(工时,格式化字符串)、courseType(课程类型,如"基础课")、courseTypeClass(样式标识:basic/vip/tip,不带tag-前缀)、location(台桌/包厢名)、income(收入,格式化字符串) - THE PERF_1_API SHALL 从
fdw_etl.v_dwd_assistant_service_log查询服务记录,按settle_time日期分组,每组内按时间倒序排列
3.3 收入档位数据(GAP-13)
- THE PERF_1_API SHALL 返回收入档位数据:
currentTier(当前档,含basicRate和incentiveRate)、nextTier(下一档,含basicRate和incentiveRate)、upgradeHoursNeeded(距升档所需工时,number)、upgradeBonus(升档奖金,number,元) - THE PERF_1_API SHALL 从
fdw_etl.v_dws_assistant_salary_calc查询档位和费率数据
3.4 上月收入与收入明细(GAP-14~15)
- THE PERF_1_API SHALL 返回
lastMonthIncome字段(上月收入,格式化字符串,如"¥16,880") - THE PERF_1_API SHALL 为
incomeItems每项返回desc字段(费率×工时的拆分描述,如"80元/h × 75h"),由后端根据费率和工时数据计算生成 - THE PERF_1_API SHALL 使用
items_sum口径计算所有收入金额(DWD-DOC 强制规则 1),使用assistant_pd_money和assistant_cx_money拆分助教费用(DWD-DOC 强制规则 2)
3.5 新客与常客列表(GAP-16)
- THE PERF_1_API SHALL 为
newCustomers每项返回lastService(最后服务日期,如"2月7日")和count(服务次数,number)字段 - THE PERF_1_API SHALL 为
regularCustomers每项返回hours(总工时,number)和income(总收入,格式化字符串)字段 - THE PERF_1_API SHALL 通过
member_idJOINfdw_etl.dwd.dim_member(取scd2_is_current=1)获取客户姓名(DWD-DOC 强制规则 DQ-6),禁止直接使用member_phone或member_name
需求 4:实现 PERF-2 绩效明细(T1-4)
用户故事: 作为助教,我希望查看指定月份的绩效明细(按日期分组的服务记录列表),以便回顾每天的工作详情。
验收标准
- THE PERF_2_API SHALL 接受
year、month、page、pageSize查询参数,返回指定月份的绩效明细数据 - THE PERF_2_API SHALL 每页返回最多 20 条记录(默认
pageSize=20),按日期分组为dateGroups结构,并返回hasMore标记指示是否有更多数据
4.2 按日期分组(GAP-19~20)
- THE PERF_2_API SHALL 将服务记录按日期分组,每组包含
date(日期标签)、totalHours(当日总工时)、totalIncome(当日总收入)、records(记录列表) - THE PERF_2_API SHALL 为每条记录返回
courseTypeClass字段,使用统一枚举值basic/vip/tip(不带tag-前缀) - THE PERF_2_API SHALL 不返回
avatarChar和avatarColor字段(前端通过nameToAvatarColor()工具函数从customerName自行计算)
4.3 月度汇总
- THE PERF_2_API SHALL 返回月度汇总数据
summary:totalCount(总记录数)、totalHours(总工时)、totalHoursRaw(原始工时,未折算)、totalIncome(总收入) - THE PERF_2_API SHALL 使用
items_sum口径计算totalIncome和每条记录的income(DWD-DOC 强制规则 1) - THE PERF_2_API SHALL 通过
member_idJOINfdw_etl.dwd.dim_member(取scd2_is_current=1)获取客户姓名(DWD-DOC 强制规则 DQ-6)
需求 5:实现 pin/unpin API 端点(T1-5)
用户故事: 作为助教,我希望将重要任务置顶或取消置顶,以便优先处理关键客户的跟进任务。
验收标准
- THE Backend SHALL 实现
POST /api/xcx/tasks/{taskId}/pin端点,将指定任务的is_pinned字段设为true - THE Backend SHALL 实现
POST /api/xcx/tasks/{taskId}/unpin端点,将指定任务的is_pinned字段设为false - WHEN pin 或 unpin 操作成功时,THE PIN_API SHALL 返回
{ isPinned: true }或{ isPinned: false } - THE PIN_API SHALL 验证请求的
taskId属于当前登录助教(通过user_assistant_binding校验),不属于时返回 HTTP 403 - IF 请求的
taskId不存在,THEN THE PIN_API SHALL 返回 HTTP 404{ code: 404, message: "任务不存在" } - THE Miniprogram SHALL 在
services/api.ts中新增pinTask(taskId: string)和unpinTask(taskId: string)函数,分别调用 pin 和 unpin 端点 - WHEN pin/unpin API 调用成功后,THE Miniprogram SHALL 更新本地任务列表状态(将任务移入/移出置顶分组),无需重新请求完整任务列表
需求 6:前端适配 — 任务页面(T1-6 任务部分)
用户故事: 作为助教,我希望任务列表和任务详情页面能正确展示后端返回的真实数据(替代当前的 mock 数据),以便看到真实的客户信息和绩效状态。
验收标准
6.1 createNote 补充用户手动评分参数(GAP-05)
- THE Miniprogram SHALL 修改
services/api.ts中createNote函数的签名,增加可选参数manualScore?: number(用户手动评分,1-5 星) - WHEN 用户在备注弹窗中提交备注时,THE Miniprogram SHALL 将
manualScore字段一并传递给POST /api/xcx/notes端点 - THE Backend SHALL 修改
POST /api/xcx/notes端点,接受请求体中的可选manualScore字段(number,1-5),并存入biz.notes.score列。注意:此字段为用户手动评分(再次服务意愿 + 再来店可能性),与 AI 应用 6 的aiScore(1-10 分,展示用)语义不同
6.2 storageLevel/relationLevel 前端计算(GAP-11)
- THE Miniprogram SHALL 在 task-detail 页面根据后端返回的
balance字段值,在前端本地计算storageLevel(储值等级,如 "非常多"/"较多"/"一般"/"较少") - THE Miniprogram SHALL 在 task-detail 页面根据后端返回的
heartScore字段值(0-10 范围),在前端本地计算relationLevel、relationLevelText、relationColor,阈值遵循 P6 AC3 四级映射(>8.5 / >7 / >5 / ≤5)
需求 7:前端适配 — 绩效页面(T1-6 绩效部分)
用户故事: 作为助教,我希望绩效概览和绩效明细页面支持月份切换,以便查看历史月份的绩效数据。
验收标准
7.1 绩效概览月份切换(F8, GAP-18)
- THE Miniprogram SHALL 在 performance 页面添加月份切换控件(左右箭头 + 月份标签),允许用户在当前月和历史月份之间切换
- WHEN 用户切换月份时,THE Miniprogram SHALL 使用新的
year/month参数重新调用fetchPerformanceOverview接口,加载对应月份的绩效数据 - THE Miniprogram SHALL 在月份切换期间显示加载状态,防止用户重复操作
7.2 绩效明细月份切换重置分页(F9, GAP-21)
- WHEN 用户在 performance-records 页面切换月份时,THE Miniprogram SHALL 将
page重置为 1,清空已加载的记录列表,重新从第一页加载 - THE Miniprogram SHALL 修复
switchMonth()函数中page未重置的 Bug
7.3 avatarChar/avatarColor 前端计算(GAP-19 决策)
- THE Miniprogram SHALL 在 performance 和 performance-records 页面,使用
nameToAvatarColor()工具函数从customerName计算avatarChar(姓氏首字)和avatarColor(头像渐变色),不依赖后端返回这两个字段
需求 8:全局约束与数据隔离
用户故事: 作为系统管理员,我希望所有任务和绩效接口都遵循统一的权限控制和数据隔离规则,以确保每位助教只能访问自己的数据。
验收标准
- THE Backend SHALL 对所有 RNS1.1 接口(TASK-1、TASK-2、PERF-1、PERF-2、PIN/UNPIN)执行
require_approved()权限检查,确保用户状态为approved - THE Backend SHALL 对所有 RNS1.1 接口验证用户具有
view_tasks权限 - THE Backend SHALL 通过
user_assistant_binding表获取当前用户对应的assistant_id,所有数据查询均以该assistant_id作为过滤条件 - IF 当前用户在
user_assistant_binding中无绑定记录,THEN THE Backend SHALL 返回 HTTP 403{ code: 403, message: "未绑定助教身份" } - THE Backend SHALL 对所有涉及金额的字段统一使用
items_sum口径(DWD-DOC 强制规则 1),禁止使用consume_money - THE Backend SHALL 对所有涉及助教费用的字段使用
assistant_pd_money(陪打/基础课)+assistant_cx_money(超休/激励课)拆分(DWD-DOC 强制规则 2),禁止使用service_fee - THE Backend SHALL 对所有涉及会员信息的查询通过
member_idLEFT JOINfdw_etl.dwd.dim_member(取scd2_is_current=1)获取姓名和手机号(DWD-DOC 强制规则 DQ-6),禁止直接使用settlement_head.member_phone或member_name - THE Backend SHALL 使用
dwd_assistant_service_log_ex.is_trash排除废单记录,禁止使用已废弃的dwd_assistant_trash_event表