1222 lines
42 KiB
Markdown
1222 lines
42 KiB
Markdown
# 移动端任务与账户平台前后端对接文档
|
||
|
||
> 版本:V1.0
|
||
> 更新日期:2026-10-09
|
||
> 适用项目:`im_workbench`
|
||
> 数据源:MySQL `olons_admin` 中的 `hg_*` 业务表
|
||
|
||
## 1. 文档说明
|
||
|
||
本文档用于移动端与 Workbench 后端联调。内容依据《移动端任务与账户平台需求文档》、当前代码实现和现有数据库表结构整理。
|
||
|
||
接口分为两类:
|
||
|
||
- **已实现**:当前代码已经开放,可以直接联调。
|
||
- **待实现**:依据需求和现有数据模型定义的目标契约,不表示服务当前已经开放。
|
||
|
||
当前认证、个人中心、首页内容、任务订单和手工商城接口已实现。其余接口应按本文档契约逐步开发,实施时如果字段或状态发生调整,必须同步更新本文档后再联调。
|
||
|
||
## 2. 能力范围
|
||
|
||
| 领域 | 状态 | 说明 |
|
||
| --- | --- | --- |
|
||
| 注册、登录 | 已实现 | 创建会员、资料、CNY 钱包并签发登录会话 |
|
||
| 退出 | 已实现 | 撤销当前 Redis 会话 |
|
||
| 个人资料、密码 | 已实现 | 会员概要、头像、登录密码和交易密码 |
|
||
| 首页、内容、Banner、等级 | 已实现 | 只返回已发布且已生效的配置和内容 |
|
||
| 任务、订单、任务提交 | 已实现 | 大厅、资格预检、领单、查询和凭证提交;审核结算由后台负责 |
|
||
| 钱包、账户明细 | 已实现 | 钱包余额随会员资料返回;账户明细读取不可变流水表并支持分页、业务类型和收支方向筛选 |
|
||
| 收款账户、取出 | 已实现(沙箱) | 加密绑定、试算、申请、资金冻结和记录查询;上线前仍需支付与合规评审 |
|
||
| 储入 | 待实现 | 需在支付与合规评审后开放 |
|
||
| 手工商城 | 已实现 | 已发布商品列表、分类筛选和详情;当前只提供客服咨询动作 |
|
||
| 客服、通知、上传 | 待实现 | 部分数据表已存在 |
|
||
|
||
## 3. 公共协议
|
||
|
||
### 3.1 基础路径
|
||
|
||
```text
|
||
{BASE_URL}/v1
|
||
```
|
||
|
||
接口不再包含应用名路径段,旧前缀不再提供兼容路由。
|
||
|
||
生产和测试环境均应使用 HTTPS。
|
||
|
||
### 3.2 公共请求头
|
||
|
||
| Header | 必填 | 说明 |
|
||
| --- | --- | --- |
|
||
| `Content-Type: application/json` | JSON 请求必填 | 请求编码 |
|
||
| `Accept: application/json` | 建议 | 响应编码 |
|
||
| `X-Request-ID` | 建议 | 客户端生成 UUID,用于链路追踪 |
|
||
| `X-Device-ID` | 建议 | 安装级随机标识,不使用 IMEI 等硬件标识 |
|
||
| `Authorization: Bearer <token>` | 受保护接口必填 | 登录成功后取得的用户会话 |
|
||
| `Idempotency-Key` | 取出提交必填 | 8–80 位请求唯一键;相同业务重试必须复用,不同请求禁止复用 |
|
||
|
||
`tenant_id` 由后端部署配置确定。客户端不得在 Header、Query 或 Body 中传入租户身份。
|
||
|
||
### 3.3 登录会话
|
||
|
||
当前 Token 是 32 字节随机数的 Base64URL 编码,不是 JWT。前端不得解析 Token 或从中推断用户信息。
|
||
|
||
- App 使用系统安全存储;Web 不在普通 LocalStorage 中长期保存敏感会话。
|
||
- Token 不得进入 URL、埋点、普通日志或错误上报。
|
||
- HTTP `401`:清除本地会话,保存当前页面地址并跳转登录。
|
||
- HTTP `403`:展示无权限或账户访问受限,不直接按登录过期处理。
|
||
- “记住密码”只属于客户端安全存储策略,不作为接口字段上传,严禁明文保存密码。
|
||
|
||
### 3.4 时间、金额和比例
|
||
|
||
- 时间统一为 RFC 3339 UTC,例如 `2026-10-09T10:00:00.123Z`。
|
||
- 金额统一使用最小货币单位整数。CNY 的 `amount=29800` 表示 `298.00` 元。
|
||
- 比例统一使用万分比。`rate=500` 表示 `5%`。
|
||
- 前端不得使用浮点数参与资金计算,页面展示值不参与后端结算。
|
||
|
||
金额对象示例:
|
||
|
||
```json
|
||
{
|
||
"amount": 29800,
|
||
"currency": "CNY"
|
||
}
|
||
```
|
||
|
||
### 3.5 成功响应
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {},
|
||
"request_id": "29ece743-7474-4f32-8141-31f994da68e9",
|
||
"server_time": "2026-10-09T10:00:00.123Z"
|
||
}
|
||
```
|
||
|
||
`data` 可为对象、列表或 `null`。前端同时判断 HTTP 状态码和业务 `code`。
|
||
|
||
### 3.6 失败响应
|
||
|
||
```json
|
||
{
|
||
"code": 30000,
|
||
"reason": "PHONE_INVALID_FORMAT",
|
||
"message": "validation failed",
|
||
"details": {
|
||
"field": "phone"
|
||
},
|
||
"request_id": "29ece743-7474-4f32-8141-31f994da68e9",
|
||
"server_time": "2026-10-09T10:00:00.123Z"
|
||
}
|
||
```
|
||
|
||
| 字段 | 用途 |
|
||
| --- | --- |
|
||
| `code` | 稳定业务码,用于程序分支 |
|
||
| `reason` | 稳定英文原因,用于本地化文案映射 |
|
||
| `message` | 后端降级文案 |
|
||
| `details` | 错误字段、等待时间等结构化详情 |
|
||
| `request_id` | 客服和日志排查依据 |
|
||
|
||
### 3.7 分页
|
||
|
||
```http
|
||
GET /v1/task-orders?page=1&page_size=20&status=pending
|
||
```
|
||
|
||
- `page` 从 1 开始,默认 1。
|
||
- `page_size` 默认 20,最大 100。
|
||
- 默认按创建时间倒序。
|
||
- 排序字段必须使用后端白名单。
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"items": [],
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"total": 0,
|
||
"has_next": false
|
||
},
|
||
"request_id": "uuid",
|
||
"server_time": "2026-10-09T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
### 3.8 重复提交
|
||
|
||
- 注册接口不使用 `Idempotency-Key`,由账户名、手机号等数据库唯一约束最终防重。
|
||
- 任务领取、任务提交、储入和取出等高风险写操作必须由后端使用业务单号、状态机和账务约束防止重复执行。
|
||
- 前端在写请求执行中禁用按钮;发生超时后先查询业务单状态,不盲目再次提交。
|
||
- 钱包入账以业务单号及 `hg_wallet_ledger.idempotency_key` 等后端约束为准。
|
||
|
||
## 4. 认证接口
|
||
|
||
### 4.1 注册(已实现)
|
||
|
||
```http
|
||
POST /v1/auth/register
|
||
Content-Type: application/json
|
||
```
|
||
|
||
未登录可访问。
|
||
|
||
```json
|
||
{
|
||
"username": "alice01",
|
||
"phone": "13800138000",
|
||
"password": "Secret123",
|
||
"referral_code": "ABCD2345",
|
||
"privacy_accepted": true
|
||
}
|
||
```
|
||
|
||
| 字段 | 类型 | 必填 | 规则 |
|
||
| --- | --- | --- | --- |
|
||
| `username` | string | 是 | 1–10 位小写字母或数字;后端去空格并转小写 |
|
||
| `phone` | string | 是 | 中国大陆 11 位手机号,不带 `+86` |
|
||
| `password` | string | 是 | 6–72 字节,不做 MD5 |
|
||
| `referral_code` | string | 否 | 1–32 位字母或数字,必须匹配正常会员邀请码 |
|
||
| `privacy_accepted` | boolean | 是 | 必须为 `true` |
|
||
|
||
注册事务同时写入:
|
||
|
||
- `hg_app_member`:会员主档。
|
||
- `hg_app_member_profile`:会员资料。
|
||
- `hg_wallet_account`:CNY 零余额钱包。
|
||
|
||
成功响应:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"member_id": 9,
|
||
"member_no": "MABCDEFGHIJKLMNOPQRST",
|
||
"username": "alice01",
|
||
"phone": "13800138000",
|
||
"invite_code": "EFGH6789",
|
||
"token": "random-base64url-token",
|
||
"token_type": "Bearer",
|
||
"expires_at": "2026-10-23T10:00:00Z"
|
||
},
|
||
"request_id": "uuid",
|
||
"server_time": "2026-10-09T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
注册成功即自动登录。前端保存 Token 后直接进入首页,不再调用登录接口。
|
||
|
||
### 4.2 登录(已实现)
|
||
|
||
```http
|
||
POST /v1/auth/login
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"phone": "13800138000",
|
||
"password": "Secret123"
|
||
}
|
||
```
|
||
|
||
成功响应与注册相同。连续登录失败达到 10 次时,该账号在 15 分钟窗口内被限流。
|
||
|
||
### 4.3 退出(已实现)
|
||
|
||
```http
|
||
POST /v1/auth/logout
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
后端删除当前会话,响应 `data=null`。缺少、格式错误或已失效的 Token 返回 HTTP 401 和 `AUTH_REQUIRED`。前端无论请求是否成功都清除本地凭证。
|
||
|
||
### 4.4 认证错误
|
||
|
||
| HTTP | `reason` | 说明 |
|
||
| --- | --- | --- |
|
||
| 400 | `MALFORMED_REQUEST` | JSON 不合法、字段类型错误或存在未知字段 |
|
||
| 400 | `USERNAME_INVALID_FORMAT` | 账户名格式错误 |
|
||
| 400 | `PHONE_INVALID_FORMAT` | 手机号格式错误 |
|
||
| 400 | `PASSWORD_INVALID_FORMAT` | 密码格式错误 |
|
||
| 400 | `REFERRAL_CODE_INVALID` | 推荐码无效 |
|
||
| 400 | `PRIVACY_POLICY_NOT_ACCEPTED` | 未同意隐私政策 |
|
||
| 401 | `INVALID_CREDENTIALS` | 手机号或密码错误 |
|
||
| 409 | `ACCOUNT_ALREADY_REGISTERED` | 账户名、手机号或其他唯一字段冲突 |
|
||
| 429 | `RATE_LIMITED` | 登录失败次数过多 |
|
||
| 503 | `SERVICE_UNAVAILABLE` | Redis 或敏感数据密钥未正确配置 |
|
||
|
||
## 5. 个人中心(已实现)
|
||
|
||
### 5.1 当前会员概要(已实现)
|
||
|
||
```http
|
||
GET /v1/me
|
||
```
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"member_id": 9,
|
||
"member_no": "MABCDEFGHIJKLMNOPQRST",
|
||
"username": "alice01",
|
||
"phone": "13800138000",
|
||
"avatar_url": "",
|
||
"invite_code": "EFGH6789",
|
||
"level": {
|
||
"id": 1,
|
||
"code": "normal",
|
||
"name": "普通会员",
|
||
"icon_url": "",
|
||
"commission_rate": 180
|
||
},
|
||
"member_status": "active",
|
||
"member_category": "real",
|
||
"credit_score": 100,
|
||
"wallet": {
|
||
"available_amount": 0,
|
||
"frozen_amount": 0,
|
||
"total_income": 0,
|
||
"total_expense": 0,
|
||
"currency": "CNY",
|
||
"status": "active",
|
||
"version": 0
|
||
}
|
||
},
|
||
"request_id": "uuid",
|
||
"server_time": "2026-10-09T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
### 5.2 更换头像(已实现)
|
||
|
||
```http
|
||
PATCH /v1/me/avatar
|
||
```
|
||
|
||
```json
|
||
{
|
||
"attachment_id": 101
|
||
}
|
||
```
|
||
|
||
附件必须是 `app_id=workbench`、归属当前会员、状态有效且 MIME 类型为图片的 `hg_sys_attachment` 记录。上传接口未实现前,前端不能自行生成可用附件 ID。
|
||
|
||
成功响应 `data`:
|
||
|
||
```json
|
||
{
|
||
"attachment_id": 101,
|
||
"avatar_url": "https://cdn.example.com/avatar.png"
|
||
}
|
||
```
|
||
|
||
### 5.3 修改登录密码(已实现)
|
||
|
||
```http
|
||
PUT /v1/me/password
|
||
```
|
||
|
||
```json
|
||
{
|
||
"old_password": "OldSecret123",
|
||
"new_password": "NewSecret456"
|
||
}
|
||
```
|
||
|
||
新密码为 6–72 字节且不能与当前密码相同。修改成功后撤销该会员在密码修改前签发的所有会话,包括当前会话;前端收到成功响应后清理 Token 并返回登录页。
|
||
|
||
### 5.4 设置或修改交易密码(已实现)
|
||
|
||
```http
|
||
PUT /v1/me/trade-password
|
||
```
|
||
|
||
```json
|
||
{
|
||
"login_password": "Secret123",
|
||
"old_trade_password": "123456",
|
||
"new_trade_password": "654321"
|
||
}
|
||
```
|
||
|
||
交易密码固定为 6 位数字。首次设置时不传 `old_trade_password`;已设置时必须传入正确的旧交易密码。每次操作都需要 `login_password` 二次确认。
|
||
|
||
### 5.5 个人中心错误
|
||
|
||
| HTTP | `reason` | 说明 |
|
||
| --- | --- | --- |
|
||
| 400 | `AVATAR_ATTACHMENT_INVALID` | 附件无效、非图片或不属于当前会员 |
|
||
| 400 | `CURRENT_PASSWORD_INVALID` | 当前登录密码错误 |
|
||
| 400 | `LOGIN_PASSWORD_INVALID` | 设置交易密码时二次确认的登录密码错误 |
|
||
| 400 | `NEW_PASSWORD_INVALID` | 新登录密码格式错误或与原密码相同 |
|
||
| 400 | `OLD_TRADE_PASSWORD_REQUIRED` | 已设置交易密码但未传旧密码 |
|
||
| 400 | `OLD_TRADE_PASSWORD_INVALID` | 旧交易密码错误 |
|
||
| 400 | `TRADE_PASSWORD_INVALID` | 新交易密码不是 6 位数字或与原密码相同 |
|
||
| 404 | `ACCOUNT_NOT_FOUND` | 会员不存在或已停用 |
|
||
| 409 | `ACCOUNT_CHANGED` | 会员安全信息已被并发修改,需重新操作 |
|
||
|
||
## 6. 首页和内容(已实现)
|
||
|
||
### 6.1 首页聚合(已实现)
|
||
|
||
```http
|
||
GET /v1/home
|
||
```
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"profile": {
|
||
"username": "alice01",
|
||
"avatar_url": "",
|
||
"level_name": "普通会员"
|
||
},
|
||
"wallet": {
|
||
"available_amount": 100000,
|
||
"frozen_amount": 0,
|
||
"currency": "CNY"
|
||
},
|
||
"features": {
|
||
"task_enabled": true,
|
||
"recharge_enabled": false,
|
||
"withdrawal_enabled": false,
|
||
"manual_mall_enabled": true
|
||
},
|
||
"banners": [],
|
||
"notices": [],
|
||
"task_summary": {
|
||
"today_count": 0,
|
||
"today_commission_amount": 0,
|
||
"yesterday_commission_amount": 0
|
||
}
|
||
},
|
||
"request_id": "uuid",
|
||
"server_time": "2026-10-09T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
`features` 由当前已发布的 `hg_site_config_version.config_json` 生成,前端不得写死。关闭的功能入口应显示后端提供的原因。
|
||
|
||
功能开关支持位于 `features` 对象内或配置根节点。找不到已发布且已到生效时间的配置时,所有开关默认为 `false`。
|
||
|
||
`task_summary.today_count` 按当日创建的任务订单统计;今日和昨日佣金仅统计 `hg_task_submission.submission_status=4` 的已结算数据。
|
||
|
||
### 6.2 Banner(已实现)
|
||
|
||
```http
|
||
GET /v1/banners?position=home_top
|
||
```
|
||
|
||
`position` 默认为 `home_top`,只允许小写字母、数字、下划线和连字符。接口只返回已发布、处于投放时间内且未删除的 Banner。
|
||
|
||
Banner 跳转类型:
|
||
|
||
| 数据库值 | API `target_type` | 处理 |
|
||
| --- | --- | --- |
|
||
| 1 | `none` | 不跳转,不返回 `target_value` |
|
||
| 2 | `internal_route` | 只接受单斜线开头的站内路由 |
|
||
| 3 | `external_url` | 只接受带有有效域名的 HTTPS URL |
|
||
|
||
不安全或不识别的跳转值降级为 `none`。
|
||
|
||
### 6.3 内容详情(已实现)
|
||
|
||
```http
|
||
GET /v1/contents/{content_key}
|
||
```
|
||
|
||
`privacy_policy` 和 `user_agreement` 允许未登录访问,其他内容需要 Bearer Token。目前数据库中尚无这两个公开内容键,在后台发布前请求会返回 `404 RESOURCE_NOT_FOUND`。
|
||
|
||
内容详情建议字段:
|
||
|
||
```json
|
||
{
|
||
"content_key": "privacy_policy",
|
||
"content_type": "policy",
|
||
"title": "用户隐私政策",
|
||
"summary": "",
|
||
"body_html": "<p>...</p>",
|
||
"body_text": "...",
|
||
"version": 3,
|
||
"published_at": "2026-10-09T08:00:00Z"
|
||
}
|
||
```
|
||
|
||
`asset_ids` 始终返回数组。`body_html` 来自后台已清洗的发布版本;前端仍需禁止脚本、事件属性和危险 URL scheme。
|
||
|
||
### 6.4 会员等级(已实现)
|
||
|
||
```http
|
||
GET /v1/member-levels
|
||
```
|
||
|
||
只返回已启用等级及其当前已发布、已生效版本,按后台 `sort` 排序。
|
||
|
||
列表项:
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"code": "VIP1",
|
||
"name": "普通会员",
|
||
"icon_url": "",
|
||
"upgrade_amount": 50000,
|
||
"gift_amount": 2000,
|
||
"daily_order_limit": 10,
|
||
"commission_rate": 180,
|
||
"daily_withdraw_limit": 4,
|
||
"rules": {},
|
||
"version": 1
|
||
}
|
||
```
|
||
|
||
### 6.5 荣誉榜(已实现)
|
||
|
||
```http
|
||
GET /v1/leaderboard
|
||
```
|
||
|
||
接口要求登录,返回当前租户内已完成任务数量排名前 50 的有效会员。排名只统计
|
||
`hg_trade_order.order_type=2 AND order_status=4` 的真实任务订单;昵称由服务端脱敏,前端不得还原或展示手机号。
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": [
|
||
{
|
||
"rank": 1,
|
||
"username": "风***淡",
|
||
"avatar_url": "https://cdn.example.com/avatar.png",
|
||
"completed_count": 12580,
|
||
"status": "领取成功"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
没有已完成任务时返回空数组,不使用模拟排行数据填充页面。
|
||
|
||
### 6.6 首页和内容错误
|
||
|
||
| HTTP | `reason` | 说明 |
|
||
| --- | --- | --- |
|
||
| 400 | `BANNER_POSITION_INVALID` | Banner 位置参数格式错误 |
|
||
| 400 | `CONTENT_KEY_INVALID` | 内容键格式错误 |
|
||
| 404 | `RESOURCE_NOT_FOUND` | 内容不存在、未发布或未生效 |
|
||
|
||
## 7. 任务和订单(已实现)
|
||
|
||
### 7.1 接口清单
|
||
|
||
| 方法 | 接口 | 用途 |
|
||
| --- | --- | --- |
|
||
| GET | `/v1/task-halls` | 当前等级可访问的任务大厅 |
|
||
| GET | `/v1/tasks/eligibility?hall_id=1` | 领取资格预检 |
|
||
| GET | `/v1/tasks/stats` | 总资产、今日/昨日佣金、领取数量 |
|
||
| POST | `/v1/task-orders/claim` | 领取或匹配任务 |
|
||
| GET | `/v1/task-orders` | 订单分页 |
|
||
| GET | `/v1/task-orders/{order_id}` | 订单详情 |
|
||
| POST | `/v1/task-orders/{order_id}/submissions` | 提交任务证据 |
|
||
|
||
本章接口全部要求登录。数据来源为 `hg_task_hall`、`hg_task`、`hg_trade_order`、`hg_task_submission`、`hg_wallet_account` 和 `hg_wallet_ledger`,仅处理 `order_type=2` 的任务订单,不会混入手工商城订单。
|
||
|
||
任务开关和领单规则读取当前已发布且已生效的 `hg_site_config_version.config_json`。支持以下配置键(可放在根节点或嵌套对象中):
|
||
|
||
| 配置键 | 含义 | 未配置时 |
|
||
| --- | --- | --- |
|
||
| `task_enabled` | 任务功能开关 | `false`,关闭领单 |
|
||
| `task_minimum_amount` | 最低可用余额,单位分 | `0` |
|
||
| `task_business_start_at` | 营业开始时间,格式 `HH:mm` 或 `HH:mm:ss` | `00:00:00` |
|
||
| `task_business_end_at` | 营业结束时间,格式 `HH:mm` 或 `HH:mm:ss` | `23:59:59` |
|
||
| `task_deadline_minutes` | 订单完成时限,分钟 | `15` |
|
||
|
||
开关采用失败关闭策略:找不到有效配置或没有 `task_enabled=true` 时,可以读取大厅、统计及历史订单,但资格预检返回 `TASK_DISABLED`,领单被拒绝。
|
||
|
||
### 7.2 领取资格预检
|
||
|
||
```http
|
||
GET /v1/tasks/eligibility?hall_id=1
|
||
```
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"eligible": false,
|
||
"reason": "INSUFFICIENT_BALANCE",
|
||
"message": "可用余额不足",
|
||
"available_amount": 10000,
|
||
"minimum_amount": 50000,
|
||
"today_count": 2,
|
||
"daily_limit": 5,
|
||
"pending_order_id": 0,
|
||
"business_start_at": "09:00:00+08:00",
|
||
"business_end_at": "22:00:00+08:00"
|
||
},
|
||
"request_id": "uuid",
|
||
"server_time": "2026-10-09T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
预检包括营业时间、会员状态、钱包状态、最低余额、当日数量、未完成订单及等级范围。预检只供展示,领取时后端必须在事务内再次校验。
|
||
|
||
判断顺序为:任务开关、营业时间、钱包状态、最低余额、等级每日上限、未完成订单。`risk_status` 是会员类别(`1=真人`、`2=假人`),不是风控状态,不能据此拒绝领单。
|
||
|
||
### 7.3 领取任务
|
||
|
||
```http
|
||
POST /v1/task-orders/claim
|
||
```
|
||
|
||
```json
|
||
{
|
||
"hall_id": 1
|
||
}
|
||
```
|
||
|
||
成功返回订单摘要,包括 `id`、`order_no`、`status`、`product`、`total_amount`、`commission_amount`、`currency` 和 `deadline_at`。
|
||
|
||
领单事务会锁定当前会员和钱包记录,重新校验大厅等级、账户状态、最低余额、当日次数、未完成订单、任务发布与有效期、任务每日上限及单会员上限。当前版本在事务内直接选中可用任务,创建 `status=pending` 的订单并记录 `matched_at`,客户端收到成功响应后即可进入订单详情并提交凭证;不依赖额外匹配进程。领取不扣款、不冻结余额,也不生成钱包流水。当前表结构没有任务与商品的直接绑定字段,因此 `product.id`、`total_amount` 和 `unit_price_amount` 允许为 `0`,任务名称和封面取自 `hg_task`。
|
||
|
||
| HTTP | `reason` | 说明 |
|
||
| --- | --- | --- |
|
||
| 409 | `PENDING_ORDER_EXISTS` | 存在未完成订单 |
|
||
| 422 | `OUTSIDE_BUSINESS_HOURS` | 不在营业时间 |
|
||
| 422 | `INSUFFICIENT_BALANCE` | 可用余额不足 |
|
||
| 422 | `DAILY_LIMIT_REACHED` | 已达当日上限 |
|
||
| 422 | `LEVEL_NOT_ELIGIBLE` | 等级不符合 |
|
||
| 422 | `ACCOUNT_RESTRICTED` | 账户状态受限 |
|
||
| 422 | `TASK_DISABLED` | 任务开关未开启或没有已生效配置 |
|
||
| 503 | `NO_TASK_AVAILABLE` | 当前没有可匹配任务 |
|
||
|
||
### 7.4 订单列表
|
||
|
||
```http
|
||
GET /v1/task-orders?page=1&page_size=20&status=pending
|
||
```
|
||
|
||
`status` 可选:`all`、`matching`、`pending`、`processing`、`completed`、`expired`、`frozen`、`cancelled`、`failed`。
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"id": 101,
|
||
"order_no": "TO202610090001A1B2C3D4",
|
||
"task_id": 1,
|
||
"product": {
|
||
"id": 20,
|
||
"name": "示例商品",
|
||
"cover_url": "https://cdn.example.com/product.png"
|
||
},
|
||
"quantity": 1,
|
||
"unit_price_amount": 29800,
|
||
"total_amount": 29800,
|
||
"commission_amount": 1490,
|
||
"currency": "CNY",
|
||
"status": "pending",
|
||
"status_text": "待处理",
|
||
"message": "请在截止时间前完成",
|
||
"created_at": "2026-10-09T10:00:00Z",
|
||
"updated_at": "2026-10-09T10:01:00Z",
|
||
"deadline_at": "2026-10-09T10:15:00Z"
|
||
}
|
||
],
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"total": 1
|
||
}
|
||
```
|
||
|
||
### 7.5 订单详情与提交
|
||
|
||
订单详情额外返回任务说明、商品和规则快照、状态时间线、失败原因、关联账变及 `allowed_actions`。倒计时使用响应 `server_time` 与 `deadline_at` 的差值。
|
||
|
||
```http
|
||
POST /v1/task-orders/{order_id}/submissions
|
||
```
|
||
|
||
```json
|
||
{
|
||
"evidence_text": "已完成任务",
|
||
"evidence_attachment_ids": [1001, 1002]
|
||
}
|
||
```
|
||
|
||
成功返回 `submission_no`、`status=reviewing`、`submitted_at` 和最新订单状态。重复提交不得生成多笔审核记录或佣金流水。
|
||
|
||
仅 `pending` 订单允许提交。`evidence_text` 去除首尾空白后最长 2000 字符,附件最多 9 个,两者至少提供一项;附件必须属于当前租户和当前会员、`app_id=workbench`、状态有效,且类型为图片或 PDF。提交事务对订单加锁,超时订单自动置为 `expired`,有效提交创建唯一审核记录并把订单置为 `processing`。此步骤不生成佣金流水;审核通过并结算仍由后台流程负责。
|
||
|
||
订单详情返回:
|
||
|
||
- `task`:任务标题、说明和详情 HTML;
|
||
- `rule_snapshot`:领单时固化的佣金、等级和截止时间;
|
||
- `submission`:凭证、审核状态与驳回原因;
|
||
- `timeline`:创建、匹配、提交、审核、结算、完成时间点;
|
||
- `ledgers`:以订单号或提交号关联的钱包流水;
|
||
- `allowed_actions`:待处理为 `submit`、`contact_support`,审核中/超时/冻结/失败仅为 `contact_support`。
|
||
|
||
### 7.6 任务统计
|
||
|
||
```http
|
||
GET /v1/tasks/stats
|
||
```
|
||
|
||
```json
|
||
{
|
||
"available_amount": 100000,
|
||
"frozen_amount": 29800,
|
||
"total_asset_amount": 129800,
|
||
"today_commission_amount": 1490,
|
||
"yesterday_commission_amount": 1000,
|
||
"today_claim_count": 2,
|
||
"today_completed_count": 1
|
||
}
|
||
```
|
||
|
||
佣金只统计 `hg_task_submission.submission_status=4` 的已结算记录,今日领取和完成数量只统计任务订单。日期边界按数据库 UTC 日期计算。
|
||
|
||
### 7.7 通用校验错误
|
||
|
||
| HTTP | `reason` | 说明 |
|
||
| --- | --- | --- |
|
||
| 400 | `HALL_ID_INVALID` | 大厅 ID 缺失或格式错误 |
|
||
| 400 | `ORDER_ID_INVALID` | 订单 ID 格式错误 |
|
||
| 400 | `PAGE_INVALID` / `PAGE_SIZE_INVALID` | 分页参数错误,`page_size` 最大 100 |
|
||
| 400 | `ORDER_STATUS_INVALID` | 状态筛选值不在允许范围内 |
|
||
| 400 | `EVIDENCE_INVALID` | 凭证内容或附件不符合要求 |
|
||
| 404 | `ORDER_NOT_FOUND` | 订单不存在或不属于当前会员 |
|
||
| 409 | `ORDER_STATE_INVALID` | 当前状态不允许提交或已经提交过 |
|
||
| 409 | `ORDER_EXPIRED` | 提交时订单已超时 |
|
||
|
||
## 8. 手工商城(已实现)
|
||
|
||
| 方法 | 接口 | 说明 |
|
||
| --- | --- | --- |
|
||
| GET | `/v1/manual-products?page=1&page_size=20&category_id=0` | `product_type=2` 的已发布商品 |
|
||
| GET | `/v1/manual-products/{product_id}` | 商品详情和可执行动作 |
|
||
|
||
两个接口均要求登录,只返回同时满足以下条件的商品:
|
||
|
||
- `hg_product.product_type=2`;
|
||
- 商品 `publish_status=3`,未被软删除且在展示有效期内;
|
||
- 所属 `hg_product_category.status=1`,并且分类未被软删除。
|
||
|
||
### 8.1 商品列表
|
||
|
||
```http
|
||
GET /v1/manual-products?page=1&page_size=20&category_id=0
|
||
```
|
||
|
||
`category_id=0` 或不传表示全部启用分类,指定正整数时按分类筛选。推荐商品优先,再按后台 `sort` 和商品 ID 排序。响应示例:
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"id": 4,
|
||
"product_no": "DEMO-P-03",
|
||
"category": {
|
||
"id": 2,
|
||
"code": "DEMO_DAILY",
|
||
"name": "演示日用百货"
|
||
},
|
||
"name": "已发布演示商品",
|
||
"shop_name": "Olons 演示店",
|
||
"price_amount": 12900,
|
||
"currency": "CNY",
|
||
"cover_url": "https://cdn.example.com/product.png",
|
||
"summary": "商品说明摘要",
|
||
"claimed_count": 1,
|
||
"is_recommended": true,
|
||
"is_limited": true,
|
||
"start_at": "2026-10-01T00:00:00Z",
|
||
"end_at": "2026-10-31T23:59:59Z",
|
||
"available_actions": ["contact_support"]
|
||
}
|
||
],
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"total": 1
|
||
}
|
||
```
|
||
|
||
金额单位为分。现有 `hg_product` 没有独立摘要字段,`summary` 由商品详情转换为纯文本后截取前 120 个字符。`claimed_count` 统计该商品 `order_type=3` 且状态不是已取消或失败的订单。`is_limited` 在商品配置了 `end_at` 时为 `true`,客户端使用该字段区分限时商品,不根据分类名称推断;`start_at`、`end_at` 为商品展示有效期。
|
||
|
||
### 8.2 商品详情
|
||
|
||
```http
|
||
GET /v1/manual-products/4
|
||
```
|
||
|
||
详情在列表字段基础上增加:
|
||
|
||
```json
|
||
{
|
||
"payment_type": "balance",
|
||
"detail_text": "已发布演示商品,用于展示。",
|
||
"created_at": "2026-10-05T14:32:29Z",
|
||
"updated_at": "2026-10-08T14:32:29Z"
|
||
}
|
||
```
|
||
|
||
当前版本只支持用户主动咨询,不创建商城订单,也不扣款或冻结余额,因此 `available_actions` 固定返回 `["contact_support"]`。后续开放购买时必须另行增加下单接口、库存校验、幂等与资金事务,不能复用咨询动作直接扣款。
|
||
|
||
运营详情不会以原始 HTML 返回。后端移除标签、脚本和样式内容后输出 `detail_text`,避免持久型 XSS;`cover_url` 仅接受不包含用户凭据的 HTTPS 地址,不符合要求时返回空字符串。
|
||
|
||
### 8.3 错误码
|
||
|
||
| HTTP | `reason` | 说明 |
|
||
| --- | --- | --- |
|
||
| 400 | `CATEGORY_ID_INVALID` | 分类 ID 不是非负整数 |
|
||
| 400 | `PRODUCT_ID_INVALID` | 商品 ID 缺失或格式错误 |
|
||
| 400 | `PAGE_INVALID` / `PAGE_SIZE_INVALID` | 分页参数错误,`page_size` 最大 100 |
|
||
| 404 | `PRODUCT_NOT_FOUND` | 商品不存在、未发布、已过展示期、已删除或分类已停用 |
|
||
|
||
## 9. 钱包和明细(待实现)
|
||
|
||
### 9.1 钱包概要
|
||
|
||
```http
|
||
GET /v1/wallet
|
||
```
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": {
|
||
"available_amount": 100000,
|
||
"frozen_amount": 29800,
|
||
"total_income": 50000,
|
||
"total_expense": 10000,
|
||
"currency": "CNY",
|
||
"status": "active",
|
||
"version": 12
|
||
},
|
||
"request_id": "uuid",
|
||
"server_time": "2026-10-09T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
### 9.2 账户明细
|
||
|
||
```http
|
||
GET /v1/wallet/ledgers?page=1&page_size=20&biz_type=task&direction=income
|
||
```
|
||
|
||
```json
|
||
{
|
||
"id": 1001,
|
||
"ledger_no": "WL202610090001",
|
||
"biz_type": "task",
|
||
"biz_no": "TO202610090001",
|
||
"entry_type": "commission",
|
||
"direction": "income",
|
||
"amount": 1490,
|
||
"before_amount": 100000,
|
||
"after_amount": 101490,
|
||
"currency": "CNY",
|
||
"remark": "任务佣金",
|
||
"occurred_at": "2026-10-09T10:30:00Z",
|
||
"resource": {
|
||
"type": "task_order",
|
||
"id": 101
|
||
}
|
||
}
|
||
```
|
||
|
||
钱包流水只能由后端业务事务生成,移动端没有新增、修改或删除流水的接口。
|
||
|
||
## 10. 储入(待实现)
|
||
|
||
本组接口在支付通道、收款主体和合规评审完成前只允许沙箱联调。
|
||
|
||
| 方法 | 接口 | 用途 |
|
||
| --- | --- | --- |
|
||
| GET | `/v1/recharge/channels` | 可用通道、金额范围和手续费规则 |
|
||
| POST | `/v1/recharge-orders` | 创建储入订单 |
|
||
| GET | `/v1/recharge-orders` | 储入记录分页 |
|
||
| GET | `/v1/recharge-orders/{order_id}` | 储入详情 |
|
||
|
||
创建请求:
|
||
|
||
```json
|
||
{
|
||
"channel_id": 1,
|
||
"amount": 50000,
|
||
"currency": "CNY",
|
||
"voucher_attachment_ids": [],
|
||
"remark": ""
|
||
}
|
||
```
|
||
|
||
响应包含 `recharge_no`、`status`、`request_amount`、`payable_amount`、`currency`、`expire_at` 和经过校验的支付指引。不通过客服聊天发送临时个人收款账户。
|
||
|
||
公开状态:`pending_payment`、`reviewing`、`processing`、`succeeded`、`failed`、`expired`、`cancelled`。失败、驳回或过期必须返回 `reason_code` 和 `reason_text`。
|
||
|
||
## 11. 收款账户和取出(已实现,沙箱)
|
||
|
||
本组接口已完成代码和现有数据库的读接口联调。在支付通道、付款主体、实名要求、反洗钱策略和法务评审完成前,只允许沙箱使用,不得连接真实付款通道。
|
||
|
||
取出功能读取当前已发布且已生效的 `hg_site_config_version.config_json`。仅当根节点或嵌套对象中的 `withdrawal_enabled=true` 时允许试算和提交;没有有效配置时按失败关闭策略返回 `WITHDRAWAL_DISABLED`。收款账户查询与绑定不受该开关影响。
|
||
|
||
### 11.1 收款账户
|
||
|
||
```http
|
||
GET /v1/payment-accounts
|
||
POST /v1/payment-accounts
|
||
```
|
||
|
||
新增请求:
|
||
|
||
```json
|
||
{
|
||
"account_type": "bank_card",
|
||
"bank_code": "ICBC",
|
||
"bank_name": "中国工商银行",
|
||
"holder_name": "张三",
|
||
"account_no": "6222000000001234",
|
||
"reserved_phone": "13800138000",
|
||
"qr_attachment_id": 0,
|
||
"trade_password": "654321"
|
||
}
|
||
```
|
||
|
||
支持的账户类型:
|
||
|
||
| `account_type` | 必填字段 | 说明 |
|
||
| --- | --- | --- |
|
||
| `bank_card` | `bank_code`、`bank_name`、`holder_name`、`account_no` | 卡号只允许 8–32 位数字,空格和连字符会被移除 |
|
||
| `digital_wallet` | `holder_name`、`account_no` | 通用数字钱包 |
|
||
| `unionpay` | `holder_name`、`account_no` | 银联账户 |
|
||
| `alipay` | `holder_name`、`account_no` | 后端固定渠道名称和编码 |
|
||
| `wechat` | `holder_name`、`account_no` | 后端固定渠道名称和编码 |
|
||
|
||
`reserved_phone` 可选,传入时必须为 11 位中国大陆手机号;`qr_attachment_id` 可选,传入时必须是当前会员在 `workbench` 应用下有效的图片附件。绑定前必须校验 6 位数字交易密码,连续错误 5 次后锁定 15 分钟。
|
||
|
||
姓名、账号和手机号使用 AES-256-GCM 独立随机 nonce 加密,账号另存 HMAC-SHA256 检索哈希用于防重复。列表只返回脱敏信息,绝不返回明文或密文。新增账户初始 `verify_status=pending`,必须由后台核验为 `verified` 后才能用于取出。
|
||
|
||
列表项示例:
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"account_type": "bank_card",
|
||
"bank_code": "ICBC",
|
||
"bank_name": "中国工商银行",
|
||
"holder_mask": "张*",
|
||
"mobile_mask": "138****8000",
|
||
"account_no_mask": "6222********1234",
|
||
"qr_attachment_id": 0,
|
||
"verify_status": "pending",
|
||
"is_default": true,
|
||
"created_at": "2026-10-09T10:00:00Z",
|
||
"updated_at": "2026-10-09T10:00:00Z"
|
||
}
|
||
```
|
||
|
||
### 11.2 取出试算与提交
|
||
|
||
```http
|
||
POST /v1/withdrawal-orders/quote
|
||
POST /v1/withdrawal-orders
|
||
GET /v1/withdrawal-orders?page=1&page_size=20&status=all
|
||
GET /v1/withdrawal-orders/{order_id}
|
||
```
|
||
|
||
试算请求:
|
||
|
||
```json
|
||
{
|
||
"payment_account_id": 1,
|
||
"amount": 50000,
|
||
"currency": "CNY"
|
||
}
|
||
```
|
||
|
||
试算根据已核验收款账户选择启用且支持取出的 `hg_payment_channel`。优先匹配账户类型对应通道,不存在时使用人工通道。手续费支持固定金额、万分比和两者相加三种模式;比例手续费向上取整到分。
|
||
|
||
试算返回金额、渠道、可用余额、当日次数、额度范围和 5 分钟后的 `quote_expires_at`,但不冻结余额:
|
||
|
||
```json
|
||
{
|
||
"payment_account_id": 1,
|
||
"account_mask": "6222********1234",
|
||
"channel_id": 3,
|
||
"channel_code": "bank",
|
||
"channel_name": "银行卡",
|
||
"request_amount": 50000,
|
||
"fee_amount": 100,
|
||
"actual_amount": 49900,
|
||
"currency": "CNY",
|
||
"minimum_amount": 1,
|
||
"maximum_amount": 100000,
|
||
"available_amount": 100000,
|
||
"today_count": 0,
|
||
"daily_limit": 4,
|
||
"quote_expires_at": "2026-10-09T10:05:00Z"
|
||
}
|
||
```
|
||
|
||
提交请求:
|
||
|
||
```http
|
||
POST /v1/withdrawal-orders
|
||
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
|
||
Content-Type: application/json
|
||
```
|
||
|
||
```json
|
||
{
|
||
"payment_account_id": 1,
|
||
"amount": 50000,
|
||
"currency": "CNY",
|
||
"trade_password": "654321"
|
||
}
|
||
```
|
||
|
||
后端不信任试算结果,提交时重新读取通道并计算手续费和到账金额。`Idempotency-Key` 会结合租户和会员派生稳定业务单号;相同请求重试返回原订单并标记 `idempotent_replay=true`,同一个键用于不同账户、金额或币种时返回 `IDEMPOTENCY_CONFLICT`,不依赖额外幂等记录表。
|
||
|
||
提交事务执行以下操作:
|
||
|
||
1. 锁定会员,确认账户有效、交易密码未变化;
|
||
2. 校验收款账户属于当前会员且已核验;
|
||
3. 锁定并重新校验支付通道规则;
|
||
4. 锁定 CNY 钱包,检查钱包状态、可用余额及会员等级每日取出次数;
|
||
5. 创建 `pending_review` 取出订单和加密收款账户快照;
|
||
6. 可用余额减少申请金额,冻结余额增加申请金额;
|
||
7. 分别写入可用余额支出和冻结余额收入两条不可变流水。
|
||
|
||
订单、钱包和两条流水在同一数据库事务内提交,任一步失败全部回滚。提交阶段不增加 `total_expense`;后台付款成功时才把冻结金额转为最终支出,失败、驳回或取消时必须解冻退回。后台状态处理不属于本章客户端接口。
|
||
|
||
公开状态为 `pending_review`、`reviewing`、`processing`、`succeeded`、`failed`、`rejected`、`cancelled`。列表支持上述状态过滤和标准分页;详情、列表均返回脱敏收款快照、金额、手续费、状态、失败原因和各状态时间,不返回 `account_snapshot_cipher`。
|
||
|
||
### 11.3 错误码
|
||
|
||
| HTTP | `reason` | 说明 |
|
||
| --- | --- | --- |
|
||
| 400 | `ACCOUNT_TYPE_INVALID` | 收款账户类型不支持 |
|
||
| 400 | `PAYMENT_ACCOUNT_FIELDS_INVALID` | 动态必填字段或格式错误 |
|
||
| 400 | `TRADE_PASSWORD_INVALID` | 交易密码格式或内容错误 |
|
||
| 400 | `CURRENCY_INVALID` | 当前仅支持 CNY |
|
||
| 400 | `IDEMPOTENCY_KEY_INVALID` | 取出提交未提供合规的幂等键 |
|
||
| 400 | `WITHDRAWAL_STATUS_INVALID` | 列表状态筛选值错误 |
|
||
| 409 | `PAYMENT_ACCOUNT_EXISTS` | 相同类型和账号已经绑定 |
|
||
| 409 | `IDEMPOTENCY_CONFLICT` | 同一幂等键被用于不同请求 |
|
||
| 422 | `TRADE_PASSWORD_NOT_SET` | 尚未设置交易密码 |
|
||
| 422 | `PAYMENT_ACCOUNT_INVALID` | 收款账户不存在、已删除或未核验 |
|
||
| 422 | `WITHDRAWAL_DISABLED` | 取出功能未开启 |
|
||
| 422 | `WITHDRAWAL_AMOUNT_INVALID` | 金额不在通道范围、超过余额或手续费不合理 |
|
||
| 422 | `WITHDRAWAL_DAILY_LIMIT_REACHED` | 已达到会员等级每日次数上限 |
|
||
| 422 | `INSUFFICIENT_BALANCE` | 可用余额不足 |
|
||
| 422 | `ACCOUNT_RESTRICTED` | 会员或钱包状态受限 |
|
||
| 429 | `RATE_LIMITED` | 交易密码连续错误次数过多,15 分钟后重试 |
|
||
| 503 | `WITHDRAWAL_CHANNEL_UNAVAILABLE` | 没有可用的取出通道 |
|
||
|
||
## 12. 客服、通知和上传
|
||
|
||
### 12.1 客服(已实现)
|
||
|
||
```http
|
||
GET /v1/customer-services
|
||
```
|
||
|
||
响应字段包括 `id`、`service_code`、`name`、`avatar_url`、`work_time`、`online_status`、`service_url`、`backup_contact` 和 `privacy_notice`。
|
||
|
||
只返回 `hg_customer_service.status=1` 且未删除的客服,按 `sort`、`id` 排序。`online_status` 映射为 `online`、`offline` 或 `busy`。头像和客服地址仅返回不含用户凭据的 HTTPS URL,不符合要求时返回空字符串。
|
||
|
||
客服 URL 必须经服务端域名白名单校验。前端 WebView/iframe 只开启必要权限,并显示第三方服务来源和隐私提示。
|
||
|
||
### 12.2 通知
|
||
|
||
```http
|
||
GET /v1/notices?page=1&page_size=20
|
||
GET /v1/notices/{notice_id}
|
||
POST /v1/notices/{notice_id}/read
|
||
```
|
||
|
||
当前已实现通知列表接口。列表包含当前会员通知和 `member_id=0` 的全体通知,只返回有效期内且未撤回记录,按创建时间倒序排列。
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"id": 1,
|
||
"title": "系统维护通知",
|
||
"content": "通知内容",
|
||
"source_type": "real",
|
||
"start_at": "2026-10-13T00:00:00Z",
|
||
"end_at": "2026-10-20T00:00:00Z",
|
||
"created_at": "2026-10-13T00:00:00Z"
|
||
}
|
||
],
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"total": 1
|
||
}
|
||
```
|
||
|
||
`source_type` 为 `real`(系统通知)或 `operational_simulation`(活动通知)。详情和已读接口尚未实现;当前数据库没有会员通知已读关系表,如需精确已读状态,实现前应补充数据模型。
|
||
|
||
### 12.3 上传
|
||
|
||
```http
|
||
POST /v1/uploads
|
||
```
|
||
|
||
```json
|
||
{
|
||
"scene": "task_evidence",
|
||
"file_name": "evidence.jpg",
|
||
"mime_type": "image/jpeg",
|
||
"size": 102400
|
||
}
|
||
```
|
||
|
||
推荐流程为“申请凭证 → 上传隔离区 → 安全扫描 → 绑定业务”。业务接口只接受扫描通过且属于当前会员的附件 ID。
|
||
|
||
| 场景 | 类型 | 建议限制 |
|
||
| --- | --- | --- |
|
||
| `avatar` | JPEG、PNG、WebP | 5 MiB,校验像素尺寸 |
|
||
| `task_evidence` | JPEG、PNG、WebP、PDF | 单文件 10 MiB,最多 9 个 |
|
||
| `payment_qr` | JPEG、PNG、WebP | 5 MiB,内容校验 |
|
||
| `recharge_voucher` | JPEG、PNG、WebP、PDF | 单文件 10 MiB |
|
||
|
||
## 13. 状态枚举
|
||
|
||
数据库数字状态是内部实现。API 对前端返回稳定字符串和 `status_text`,前端不得依赖数据库数值。
|
||
|
||
`hg_app_member.risk_status` 字段名沿用现有数据库,实际业务含义是会员类别:`1` 真人、`2` 假人。API 统一使用 `member_category=real|fake`,不将该字段用于判断账户是否可登录。
|
||
|
||
| 领域 | API 状态 |
|
||
| --- | --- |
|
||
| 会员 | `active`、`disabled`、`cancelled` |
|
||
| 会员类别 | `real`、`fake` |
|
||
| 任务订单 | `matching`、`pending`、`processing`、`completed`、`expired`、`frozen`、`cancelled`、`failed` |
|
||
| 任务提交 | `reviewing`、`approved`、`rejected`、`settled`、`reversed` |
|
||
| 储入 | `pending_payment`、`reviewing`、`processing`、`succeeded`、`failed`、`expired`、`cancelled` |
|
||
| 取出 | `pending_review`、`reviewing`、`processing`、`succeeded`、`failed`、`rejected`、`cancelled` |
|
||
| 收款账户核验 | `pending`、`verified`、`rejected` |
|
||
| 客服 | `online`、`offline`、`busy` |
|
||
|
||
已实现领域按本表映射;待实现领域在开发前仍需与 HotGo 字典和正式状态流转确认。
|
||
|
||
## 14. 通用错误与重试
|
||
|
||
| HTTP | `reason` | 前端处理 |
|
||
| --- | --- | --- |
|
||
| 400 | `MALFORMED_REQUEST` | 根据 `details.field` 定位表单字段 |
|
||
| 401 | `AUTH_REQUIRED` | 清除会话并跳转登录 |
|
||
| 403 | `FORBIDDEN` | 显示无权限或账户访问受限 |
|
||
| 404 | `RESOURCE_NOT_FOUND` | 显示内容下线或记录不存在 |
|
||
| 405 | `METHOD_NOT_ALLOWED` | 作为开发错误记录,不重试 |
|
||
| 409 | `CONFLICT` | 刷新业务资源后让用户决定下一步 |
|
||
| 422 | 具体业务原因码 | 显示原因和恢复入口 |
|
||
| 429 | `RATE_LIMITED` | 按 `retry_after_seconds` 倒计时 |
|
||
| 500 | `INTERNAL` | 展示通用错误和 `request_id` |
|
||
| 503 | `SERVICE_UNAVAILABLE` | 安全读请求可限次重试 |
|
||
|
||
- GET 在网络错误或 503 时可指数退避,最多自动重试 2 次。
|
||
- POST、PUT、PATCH 默认不自动重试;超时后先查询业务资源。
|
||
- 400、401、403、404、409、422 不做网络层自动重试。
|
||
|
||
## 15. 页面与接口映射
|
||
|
||
| 页面 | 首屏接口 | 操作接口 |
|
||
| --- | --- | --- |
|
||
| `/login` | — | `POST /auth/login` |
|
||
| `/register` | `GET /contents/privacy_policy` | `POST /auth/register` |
|
||
| `/home` | `GET /home` | Banner、快捷入口、内容详情 |
|
||
| `/receive` | `GET /tasks/eligibility`、`GET /tasks/stats` | `POST /task-orders/claim` |
|
||
| 记录页 | `GET /task-orders` | 跳转订单详情 |
|
||
| `/orderDetail` | `GET /task-orders/{id}` | `POST /task-orders/{id}/submissions` |
|
||
| `/mall` | `GET /manual-products` | 查看详情或客服 |
|
||
| `/customerService` | `GET /customer-services` | 打开安全 WebView/iframe |
|
||
| `/mine` | `GET /me` | 钱包、收款账户、密码、通知、退出 |
|
||
| `/recharge` | `GET /recharge/channels`、`GET /member-levels` | `POST /recharge-orders` |
|
||
| `/withdrawal` | `GET /wallet`、`GET /payment-accounts` | 试算、提交取出 |
|
||
| `/depositRecord` | `GET /recharge-orders` | 查看详情 |
|
||
| `/withdrawalRecord` | `GET /withdrawal-orders` | 查看详情 |
|
||
| `/bill` | `GET /wallet/ledgers` | 跳转关联业务详情 |
|
||
|
||
表中省略公共前缀 `/v1`。
|
||
|
||
## 16. API 与数据表映射
|
||
|
||
| 领域 | 主表 | 关联表 |
|
||
| --- | --- | --- |
|
||
| 认证、会员资料 | `hg_app_member` | `hg_app_member_profile`、`hg_app_member_level` |
|
||
| 收款账户 | `hg_app_member_payment_account` | `hg_sys_attachment` |
|
||
| 钱包 | `hg_wallet_account` | `hg_wallet_ledger` |
|
||
| 首页配置 | `hg_site_config_version` | `hg_banner`、`hg_content`、`hg_content_version` |
|
||
| 会员等级 | `hg_app_member_level` | `hg_app_member_level_version` |
|
||
| 任务大厅 | `hg_task_hall` | `hg_task_hall_level` |
|
||
| 任务订单 | `hg_task`、`hg_trade_order` | `hg_task_level`、`hg_product`、`hg_task_submission`、`hg_wallet_ledger` |
|
||
| 手工商城 | `hg_product` | `hg_product_category`、`hg_sys_attachment` |
|
||
| 储入 | `hg_recharge_order` | `hg_payment_channel`、`hg_wallet_account`、`hg_wallet_ledger` |
|
||
| 取出 | `hg_withdrawal_order` | `hg_app_member_payment_account`、`hg_wallet_account`、`hg_wallet_ledger` |
|
||
| 客服 | `hg_customer_service` | 第三方会话映射 |
|
||
| 通知 | `hg_app_member_notice` | 已读关系待补充 |
|
||
|
||
## 17. 前端实现要求
|
||
|
||
### 17.1 请求层
|
||
|
||
- 集中注入 `BASE_URL`、`X-Request-ID`、`X-Device-ID` 和 `Authorization`。
|
||
- 集中处理统一响应、401、429、超时和断网。
|
||
- 搜索、分页和页签切换时取消过期请求,避免旧响应覆盖新状态。
|
||
- 日志不记录密码、交易密码、Token、完整手机号、银行卡和收款码。
|
||
|
||
### 17.2 页面状态
|
||
|
||
每个页面至少覆盖:
|
||
|
||
- 首次加载、下拉刷新、加载更多、空状态、可重试失败、不可重试业务失败。
|
||
- 写请求期间按钮 loading 和防重复点击。
|
||
- 服务端返回的状态文案、失败原因与恢复入口。
|
||
- 320–430 像素宽度可用;键盘弹出时表单按钮可达;触控区域至少 44×44 像素。
|
||
|
||
### 17.3 语言和文案
|
||
|
||
- `reason`、`status` 等枚举固定使用英文。
|
||
- 前端语言包映射用户文案,不把后端 `message` 作为唯一文案源。
|
||
- 本文档统一使用“储入”“取出”“领取”。如产品最终改为“充值”“提现”“接单”,前后端文档与语言包必须同时调整。
|
||
|
||
## 18. 联调顺序
|
||
|
||
1. **P0 认证**:注册、登录、退出、会话过期和错误映射。
|
||
2. **P0 账户首页**:`/me`、`/home`、Banner、内容、等级和钱包概要。
|
||
3. **P0 任务闭环**:预检、领取、订单列表、详情、提交、审核状态和账变。
|
||
4. **P1 内容服务**:手工商城、客服、通知和上传。
|
||
5. **P1 资金闭环**:收款账户、储入、取出、回调、审核和对账;开始前必须完成支付与法务评审。
|
||
|
||
## 19. 联调验收清单
|
||
|
||
- [ ] 未登录用户只能访问登录、注册和公开协议。
|
||
- [ ] 注册成功后自动进入登录态,不重复调用登录。
|
||
- [ ] 401 清理会话并返回登录;403 不误判为会话过期。
|
||
- [ ] 页签快速切换时旧请求不会覆盖新数据。
|
||
- [ ] 重复点击任务领取或提交不生成重复订单、提交或账变。
|
||
- [ ] 订单、钱包、账变和统计口径一致。
|
||
- [ ] 储入和取出失败、驳回、超时及取消均有原因和恢复路径。
|
||
- [ ] 手机号、密码、交易密码、银行卡和 Token 不进入日志或埋点。
|
||
- [ ] 富文本、商品名、公告和客服链接无可执行恶意内容。
|
||
- [ ] 金额均按最小货币单位传输,无浮点精度差异。
|
||
- [ ] 断网、超时、429 和 5xx 均有清晰恢复方式。
|
||
|
||
## 20. 待确认事项
|
||
|
||
1. 登录注册是否加入图片验证码、短信验证或设备风控挑战。
|
||
2. 是否新增刷新 Token、设备会话列表和“退出所有设备”。
|
||
3. 任务、储入和取出数据库状态值的最终字典与允许转换。
|
||
4. 任务领取是随机匹配、规则匹配还是用户选择,以及截止时间的正式存储位置。
|
||
5. 会员等级版本中储入、取出、任务数和佣金规则的正式 JSON Schema。
|
||
6. 支付通道、收款主体、实名要求、取出审核和适用地区的合规结论。
|
||
7. 客服使用自建系统还是第三方 WebView/iframe,以及允许传递的用户信息。
|
||
8. 通知是否要求逐会员已读记录;如需要,数据库应补充相应关系表。
|