15 KiB
15 KiB
小程序后端接口输出规范
文档编号:DS-API-OUTPUT-001
版本:v1.0.0
适用范围:NeoZQYY 小程序所有后端接口(HTTP JSON 响应体)
最后更新:2026-03-18
关联文档:
- DISPLAY-STANDARDS.md — 前端展示规范第 1~6 章
- DISPLAY-STANDARDS-2.md — 第 7~9 章(截止日期 / 评分 / Mock)
- DATETIME-DISPLAY-STANDARD.md — 时间展示规范
目录
1. 总体约定
| 项目 | 规范 |
|---|---|
| 协议 | HTTPS REST JSON |
| 编码 | UTF-8 |
| Content-Type | application/json |
| 时区 | 后端统一输出 UTC,前端负责本地化展示 |
| 数值精度 | 金额为整数(元),课时为 0.5 步长浮点 |
| 空值 | 字段不存在时输出 null,不得省略字段 |
| 布尔值 | true / false,不用 0/1 |
| 字符串编码格式 | 纯数据,不含展示单位(¥、h、%、笔等) |
2. 响应体结构
2.1 成功响应
{
"code": 0,
"message": "success",
"data": { ... }
}
2.2 失败响应
{
"code": 40001,
"message": "参数错误:缺少 customerId",
"data": null
}
2.3 分页列表响应
{
"code": 0,
"message": "success",
"data": {
"list": [ ... ],
"total": 32,
"page": 1,
"pageSize": 20,
"hasMore": true
}
}
3. 字段类型规范(核心规则)
核心原则:后端输出原始语义数值,前端负责格式化展示。 后端不拼接
¥、h、%、笔等展示字符,也不做千分位格式化。
3.1 类型对照表
| 字段类型 | 后端输出类型 | 示例 | 前端处理函数 | 禁止输出 |
|---|---|---|---|---|
| 金额 | number(元,整数) |
12680 |
formatMoney() |
"¥12,680" "12680.00" |
| 课时 | number(小时,0.5步长) |
2.5 |
formatHours() |
"2.5h" "2h30min" |
| 计数 | number(整数) |
32 |
formatCount() |
"32笔" "32次" |
| 百分比 | number(0~100,整数或1位小数) |
85.5 |
formatPercent() |
"85.5%" "0.855" |
| 日期 | string(YYYY-MM-DD) |
"2026-03-18" |
formatDeadline() |
"2026/03/18" 1742256000000 |
| 时间戳 | string(ISO 8601,含时区) |
"2026-03-18T08:30:00+08:00" |
formatRelativeTime() |
Unix 毫秒整数 |
| 等级 key | string(英文 key) |
"star" |
查 LEVEL_MAP |
"星级" "gold" |
| 状态 key | string(英文 key) |
"pending" |
查枚举映射 | "待处理" |
| 评分 | number(0~10,0.5步长) |
8.5 |
scoreToHalfStar() |
"8.5分" 4 (5分制) |
| 布尔 | boolean |
true |
直接使用 | 1 "true" |
| 空值 | null |
null |
展示 -- |
"" 0(有语义时除外) |
4. 各业务字段细则
4.1 金额字段
// 正确
{ "balance": 2000, "income": 510, "salary": 12680 }
// 错误
{ "balance": "¥2,000", "income": "¥510", "salary": "¥12,680" }
- 统一以「元」为单位,不含分
- 负数直接输出负整数:
-368 - 零值输出
0,不输出null - 前端调用
formatMoney(value)展示
4.2 课时字段
// 正确
{ "hours": 2.5, "hoursRaw": 3.0 }
// 错误
{ "hours": "2.5h", "deduct": "(折0.5h)" }
| 字段 | 类型 | 说明 |
|---|---|---|
hours |
number |
折算后实际计入课时(小时) |
hoursRaw |
number | null |
折算前原始小时数;无折算时输出 null |
- 前端仅在
hoursRaw !== null && hoursRaw !== hours时展示折算备注 - 步长为 0.5,如
1.0、1.5、2.0、2.5
4.3 计数字段
// 正确
{ "totalCount": 32, "serviceCount": 18 }
// 错误
{ "totalCount": "32笔", "serviceCount": "18次" }
- 前端调用
formatCount(value, '笔')展示,单位由页面层决定
4.4 百分比字段
// 正确(进度/完成率)
{ "filledPct": 85, "completionRate": 72.5 }
// 错误
{ "filledPct": "85%", "completionRate": 0.725 }
- 统一 0~100 整数或1位小数,不用小数形式
- 允许超过 100(如完成率 120%)
4.5 日期与时间
| 场景 | 格式 | 示例 |
|---|---|---|
| 纯日期(截止日、生日等) | YYYY-MM-DD |
"2026-03-18" |
| 精确时间(备注时间、服务记录) | ISO 8601 含时区 | "2026-03-18T08:30:00+08:00" |
| 时间区间(service timeRange) | 直接拼接字符串 | "20:00-22:00" |
- 禁止 输出 Unix 毫秒时间戳整数
- 禁止 输出
YYYY/MM/DD格式 - 前端截止日期调用
formatDeadline(date)语义化 - 前端相对时间调用
formatRelativeTime(iso)展示
4.6 评分字段
// 正确
{ "heartScore": 8.5, "noteScore": 7.0 }
// 错误
{ "heartScore": 4, "noteScore": "7.5分" }
- 统一使用 0~10 分制,0.5 步长
- 0 表示「未评分」,前端展示
-- - 前端调用
scoreToHalfStar(score)转换为 0~5 星展示
4.7 等级字段
// 正确
{ "level": "star" }
// 错误
{ "level": "星级" }
| 后端 key | 前端展示 |
|---|---|
star |
星级助教 |
senior |
高级助教 |
middle |
中级助教 |
junior |
初级助教 |
4.8 天数字段
// 正确
{ "lastVisitDays": 23, "daysAbsent": 23 }
// 错误
{ "lastVisitDays": "23天前", "daysAbsent": "23天" }
- 统一输出整数天数,不含「天」「天前」等汉字
- 前端拼接文案时自行添加单位
5. 枚举值规范
所有枚举字段统一使用英文下划线 key,前端维护映射表。
5.1 任务类型 taskType
| key | 展示文案 |
|---|---|
callback |
回访 |
priority_recall |
优先召回 |
high_priority |
高优先召回 |
relationship |
关系构建 |
5.2 任务状态 status
| key | 展示文案 |
|---|---|
pending |
待处理 |
completed |
已完成 |
abandoned |
已放弃 |
5.3 助教等级 level
| key | 展示文案 |
|---|---|
star |
星级助教 |
senior |
高级助教 |
middle |
中级助教 |
junior |
初级助教 |
5.4 课程类型 courseType
| key | 展示文案 | 样式 key |
|---|---|---|
basic |
基础课 | tag-basic |
vip |
包厢课 | tag-vip |
tip |
打赏课 | tag-tip |
recharge |
充值 | tag-recharge |
incentive |
激励 | tag-incentive |
5.5 线索来源 source
| key | 展示文案 |
|---|---|
manual |
助教手动录入 |
ai_consumption |
系统自动(消费分析) |
ai_note |
系统自动(备注分析) |
5.6 线索分类 category
| key | 展示文案 |
|---|---|
customer_basic |
客户基础 |
consumption |
消费习惯 |
play_pref |
玩法偏好 |
promo_pref |
促销偏好 |
social |
社交偏好 |
feedback |
重要反馈 |
5.7 截止日期语义化(前端计算,非接口字段)
后端只输出 deadline: "YYYY-MM-DD",前端调用 formatDeadline() 计算:
| diff | 展示文案 | 样式 |
|---|---|---|
| < 0 | 逾期 N 天 |
danger(红) |
| = 0 | 今天到期 |
warning(橙) |
| 1~7 | 还剩 N 天 |
normal |
| > 7 | MM-DD |
muted(灰) |
| null | -- |
muted |
6. 分页规范
{
"list": [],
"total": 100,
"page": 1,
"pageSize": 20,
"hasMore": true
}
page从 1 开始计数hasMore由后端根据total和当前page * pageSize计算total为全量数据总条数(不是当前页条数)
7. 接口端点命名规范
GET /api/xcx/tasks 任务列表
GET /api/xcx/tasks/:id 任务详情
GET /api/xcx/tasks/:id/notes 任务备注列表
POST /api/xcx/tasks/:id/notes 新增备注
GET /api/xcx/tasks/:id/service-records 近期服务记录
GET /api/xcx/coaches 助教看板列表
GET /api/xcx/coaches/:id 助教详情
GET /api/xcx/performance 绩效概览
GET /api/xcx/performance/records 绩效记录列表(支持月份分页)
GET /api/xcx/retention-clues/:customerId 维客线索
- 资源名用复数小写连字符
- 路径参数用
:id,不用查询参数代替 - 月份筛选用
?year=2026&month=2
8. 各页面接口字段对照表
8.1 任务列表页 GET /api/xcx/tasks
{
"id": "task-001",
"customerName": "王先生",
"taskType": "high_priority",
"taskTypeLabel": "高优先召回",
"deadline": "2026-03-20",
"heartScore": 8.5,
"isPinned": true,
"hasNote": true,
"status": "pending",
"lastVisitDays": 23,
"balance": 2000,
"filledPct": 85,
"aiSuggestion": "建议本周内回访,余额即将到期"
}
说明:
lastVisitDays:integer,距上次到店天数,null 表示从未到店balance:integer(元),余额;null 表示无储值filledPct:integer(0~100),关系进度百分比deadline:YYYY-MM-DD,前端调用formatDeadline()语义化aiSuggestion:string,AI 摘要文案,后端生成,前端直接展示
8.2 任务详情页 GET /api/xcx/tasks/:id
{
"id": "task-001",
"customerName": "王先生",
"taskType": "high_priority",
"taskTypeLabel": "高优先召回",
"status": "pending",
"deadline": "2026-03-20",
"heartScore": 8.5,
"phone": "138****5678",
"lastVisitDate": "2026-03-01",
"lastSpendAmount": 380,
"daysAbsent": 23,
"callbackReason": "上次体验课后未续费,需跟进意向",
"churnRisk": "high",
"spendTrend": "down",
"aiAnalysis": {
"summary": "最近 3 个月每周均有 1-2 次课程互动",
"suggestions": ["询问近期是否有空", "告知会员专属活动"]
},
"talkingPoints": ["王哥好久不见..."],
"notes": [
{
"id": "note-001",
"content": "已通过微信联系王先生...",
"tagType": "customer",
"tagLabel": "客户:王先生",
"createdAt": "2026-03-10T16:30:00+08:00",
"score": 8.5
}
],
"serviceRecords": [
{
"table": "A12号台",
"type": "基础课",
"typeClass": "basic",
"recordType": "course",
"hours": 2.5,
"hoursRaw": 3.0,
"income": 200,
"isEstimate": true,
"drinks": "百威x2 红牛x1",
"date": "2026-02-07T21:30:00+08:00"
}
],
"serviceSummary": {
"totalHours": 6.0,
"totalIncome": 510,
"avgIncome": 170
}
}
说明:
phone:后端已做脱敏处理(138****5678),或根据权限返回明文score:0~10 分制,0 表示未评分serviceRecords.hours、hoursRaw:number(小时),前端调用formatHours()serviceRecords.income、serviceSummary.*:integer(元),前端调用formatMoney()isEstimate:boolean,true 时前端展示「预估」标注
8.3 助教看板页 GET /api/xcx/coaches
{
"id": "coach-001",
"name": "小燕",
"level": "star",
"storeName": "朗朗桌球",
"customerCount": 28,
"monthHours": 86.0,
"monthIncome": 18600,
"svAmount": 5000,
"filledPct": 92,
"taskCount": 6,
"urgentTaskCount": 2,
"aiSuggestion": "本月表现优秀,建议重点跟进 2 位高风险流失客户"
}
说明:
level:英文 key,前端查LEVEL_MAP展示中文monthHours:number(小时),前端调用formatHours()monthIncome、svAmount:integer(元),前端调用formatMoney()filledPct:integer(0~100),前端调用formatPercent()或toProgressWidth()customerCount、taskCount、urgentTaskCount:integer,前端调用formatCount()
8.4 绩效记录页 GET /api/xcx/performance/records
请求参数:?year=2026&month=2&page=1&pageSize=20
{
"summary": {
"totalCount": 32,
"totalHours": 59.0,
"totalIncome": 4720
},
"dateGroups": [
{
"date": "2026-02-07",
"totalHours": 6.0,
"totalIncome": 510,
"records": [
{
"id": "r1",
"customerName": "王先生",
"timeRange": "20:00-22:00",
"hours": 2.0,
"hoursRaw": null,
"courseType": "basic",
"location": "3号台",
"income": 160
}
]
}
],
"hasMore": false,
"page": 1,
"pageSize": 20
}
说明:
date:YYYY-MM-DD,前端格式化为「2月7日」summary.*、dateGroups.totalIncome、records.income:integer(元)summary.totalHours、dateGroups.totalHours、records.hours:number(小时)hoursRaw:null 表示无折算,有值时前端展示折算备注courseType:英文 key(basic/vip/tip/recharge/incentive)
8.5 备注接口 GET /api/xcx/tasks/:id/notes
[
{
"id": "note-001",
"content": "已通过微信联系王先生...",
"tagType": "customer",
"tagLabel": "客户:王先生",
"createdAt": "2026-03-10T16:30:00+08:00",
"score": 8.5
}
]
tagType:customer/coach/systemscore:0 表示未评分,0.5 步长,前端调用scoreToHalfStar()转 5 星制createdAt:ISO 8601,前端调用formatRelativeTime()展示相对时间
9. 禁止事项速查
| 禁止行为 | 正确做法 |
|---|---|
输出 "¥12,680" |
输出 12680 |
输出 "2.5h" |
输出 2.5 |
输出 "32笔" |
输出 32 |
输出 "85%" |
输出 85 |
输出 "星级" 作为等级 |
输出 "star" |
输出 "待处理" 作为状态 |
输出 "pending" |
| 省略值为 null 的字段 | 显式输出 null |
用 0 代替 null 表示「无」 |
用 null(0 保留给有意义的零值) |
| 输出 Unix 毫秒时间戳 | 输出 ISO 8601 字符串 |
输出 YYYY/MM/DD 日期格式 |
输出 YYYY-MM-DD |
后端做 toLocaleString() 格式化 |
后端输出原始数值,前端格式化 |
hoursRaw 输出 "(折0.5h)" |
输出 3.0(原始小时数) |
关联文档
- DISPLAY-STANDARDS.md — 前端格式化规范
- DISPLAY-STANDARDS-2.md — 截止日期 / 评分 / Mock 规范
- DATETIME-DISPLAY-STANDARD.md — 时间展示规范
utils/money.ts—formatMoney/formatCount/formatPercent/toProgressWidthutils/time.ts—formatHours/formatDeadline/formatRelativeTimeutils/rating.ts—scoreToHalfStar/isUnratedutils/mock-data.ts— Mock 数据(字段结构与接口保持一致)