Files
Neo-ZQYY/docs/miniprogram-dev/API-OUTPUT-SPEC.md

546 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 小程序后端接口输出规范
> **文档编号**DS-API-OUTPUT-001
> **版本**v1.0.0
> **适用范围**NeoZQYY 小程序所有后端接口HTTP JSON 响应体)
> **最后更新**2026-03-18
> **关联文档**
> - [DISPLAY-STANDARDS.md](./design-system/DISPLAY-STANDARDS.md) — 前端展示规范第 16 章
> - [DISPLAY-STANDARDS-2.md](./design-system/DISPLAY-STANDARDS-2.md) — 第 79 章(截止日期 / 评分 / Mock
> - [DATETIME-DISPLAY-STANDARD.md](./design-system/DATETIME-DISPLAY-STANDARD.md) — 时间展示规范
---
## 目录
1. [总体约定](#1-总体约定)
2. [响应体结构](#2-响应体结构)
3. [字段类型规范(核心规则)](#3-字段类型规范核心规则)
4. [各业务字段细则](#4-各业务字段细则)
5. [枚举值规范](#5-枚举值规范)
6. [分页规范](#6-分页规范)
7. [接口端点命名规范](#7-接口端点命名规范)
8. [各页面接口字段对照表](#8-各页面接口字段对照表)
9. [禁止事项速查](#9-禁止事项速查)
---
## 1. 总体约定
| 项目 | 规范 |
|------|------|
| 协议 | HTTPS REST JSON |
| 编码 | UTF-8 |
| Content-Type | `application/json` |
| 时区 | **后端统一输出 UTC前端负责本地化展示** |
| 数值精度 | 金额为整数(元),课时为 0.5 步长浮点 |
| 空值 | 字段不存在时输出 `null`**不得省略字段** |
| 布尔值 | `true` / `false`,不用 `0/1` |
| 字符串编码格式 | 纯数据,**不含展示单位**¥、h、%、笔等) |
---
## 2. 响应体结构
### 2.1 成功响应
```json
{
"code": 0,
"message": "success",
"data": { ... }
}
```
### 2.2 失败响应
```json
{
"code": 40001,
"message": "参数错误:缺少 customerId",
"data": null
}
```
### 2.3 分页列表响应
```json
{
"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`0100整数或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`0100.5步长) | `8.5` | `scoreToHalfStar()` | `"8.5分"` `4` (5分制) |
| **布尔** | `boolean` | `true` | 直接使用 | `1` `"true"` |
| **空值** | `null` | `null` | 展示 `--` | `""` `0`(有语义时除外) |
---
## 4. 各业务字段细则
### 4.1 金额字段
```json
// 正确
{ "balance": 2000, "income": 510, "salary": 12680 }
// 错误
{ "balance": "¥2,000", "income": "¥510", "salary": "¥12,680" }
```
- 统一以「元」为单位,**不含分**
- 负数直接输出负整数:`-368`
- 零值输出 `0`,不输出 `null`
- 前端调用 `formatMoney(value)` 展示
### 4.2 课时字段
```json
// 正确
{ "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 计数字段
```json
// 正确
{ "totalCount": 32, "serviceCount": 18 }
// 错误
{ "totalCount": "32笔", "serviceCount": "18次" }
```
- 前端调用 `formatCount(value, '笔')` 展示,单位由页面层决定
### 4.4 百分比字段
```json
// 正确(进度/完成率)
{ "filledPct": 85, "completionRate": 72.5 }
// 错误
{ "filledPct": "85%", "completionRate": 0.725 }
```
- 统一 0100 整数或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 评分字段
```json
// 正确
{ "heartScore": 8.5, "noteScore": 7.0 }
// 错误
{ "heartScore": 4, "noteScore": "7.5分" }
```
- 统一使用 **010 分制**0.5 步长
- 0 表示「未评分」,前端展示 `--`
- 前端调用 `scoreToHalfStar(score)` 转换为 05 星展示
### 4.7 等级字段
```json
// 正确
{ "level": "star" }
// 错误
{ "level": "星级" }
```
| 后端 key | 前端展示 |
|----------|----------|
| `star` | 星级助教 |
| `senior` | 高级助教 |
| `middle` | 中级助教 |
| `junior` | 初级助教 |
### 4.8 天数字段
```json
// 正确
{ "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`(橙) |
| 17 | `还剩 N 天` | `normal` |
| > 7 | `MM-DD` | `muted`(灰) |
| null | `--` | `muted` |
---
## 6. 分页规范
```json
{
"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`
```json
{
"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`integer0100关系进度百分比
- `deadline``YYYY-MM-DD`,前端调用 `formatDeadline()` 语义化
- `aiSuggestion`stringAI 摘要文案,后端生成,前端直接展示
### 8.2 任务详情页 `GET /api/xcx/tasks/:id`
```json
{
"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`010 分制0 表示未评分
- `serviceRecords.hours``hoursRaw`number小时前端调用 `formatHours()`
- `serviceRecords.income``serviceSummary.*`integer前端调用 `formatMoney()`
- `isEstimate`booleantrue 时前端展示「预估」标注
### 8.3 助教看板页 `GET /api/xcx/coaches`
```json
{
"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`integer0100前端调用 `formatPercent()``toProgressWidth()`
- `customerCount``taskCount``urgentTaskCount`integer前端调用 `formatCount()`
### 8.4 绩效记录页 `GET /api/xcx/performance/records`
请求参数:`?year=2026&month=2&page=1&pageSize=20`
```json
{
"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`
```json
[
{
"id": "note-001",
"content": "已通过微信联系王先生...",
"tagType": "customer",
"tagLabel": "客户:王先生",
"createdAt": "2026-03-10T16:30:00+08:00",
"score": 8.5
}
]
```
- `tagType``customer` / `coach` / `system`
- `score`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](./design-system/DISPLAY-STANDARDS.md) — 前端格式化规范
- [DISPLAY-STANDARDS-2.md](./design-system/DISPLAY-STANDARDS-2.md) — 截止日期 / 评分 / Mock 规范
- [DATETIME-DISPLAY-STANDARD.md](./design-system/DATETIME-DISPLAY-STANDARD.md) — 时间展示规范
- `utils/money.ts``formatMoney` / `formatCount` / `formatPercent` / `toProgressWidth`
- `utils/time.ts``formatHours` / `formatDeadline` / `formatRelativeTime`
- `utils/rating.ts``scoreToHalfStar` / `isUnrated`
- `utils/mock-data.ts` — Mock 数据(字段结构与接口保持一致)