Files
juwan-frontend/接口文档.md
T
2026-02-28 10:33:50 +08:00

767 lines
37 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.
# 聚玩 (Juwan) API 设计文档
## 1. 文档概述
本文档为“聚玩”游戏陪玩平台的后端 API 设计规范,用于前后端联调与上线部署。
- **基础路径 (Base URL)**: `/api/v1`
- **数据格式**: `application/json`
## 2. 全局约定
### 2.1 认证与授权 (Auth)
- 采用 Cookie `JToken` 进行认证(Phase 2 接入后端时实现)。
- 当前前端仍以本地数据实现为主,不涉及真实后端交互;接入后端后会删除本地数据实现。
- 接口权限标识:
- 🔒:需要登录认证。
- 🛡️:需要管理员权限。
### 2.2 错误响应格式
所有失败的请求均返回统一的 JSON 结构,并附带 HTTP 状态码(如 400, 401, 403, 404, 500)。
```json
{
"code": 401,
"msg": "请先登录"
}
```
**常见错误码 (code)**
- `401`: 未登录或 Token 失效
- `403`: 角色权限不足或非参与者
- `404`: 资源不存在
- `400`: 参数校验失败、状态不合法、重复请求等
- `500`: 服务器内部错误
### 2.3 分页规范
采用 `offset``limit` 进行分页(与前端 `SearchResponse` 保持一致)。
**请求参数**`?offset=0&limit=20`
**响应格式**
```json
{
"items": [...],
"meta": {
"total": 100,
"offset": 0,
"limit": 20
}
}
```
### 2.4 文件上传与访问
- **上传端点**: `POST /api/v1/upload`
- **Content-Type**: `multipart/form-data`
- **参数**: `file` (文件), `type` (枚举: `avatar`, `chat`, `post`, `verification`, `dispute`)
- **响应**: 返回文件的 CDN URL 或文件 ID。
- **访问端点**: `GET /api/v1/files/:fileId` (获取文件内容)
### 2.5 时间戳格式
所有时间字段均采用 ISO 8601 格式的 UTC 时间字符串,例如:`2024-03-20T12:00:00.000Z`
### 2.6 角色系统 (UserRole)
- `consumer`: 普通消费者(老板)
- `player`: 陪玩打手
- `owner`: 店铺店长
- `admin`: 平台管理员(隐藏角色,用于后台管理)
### 2.7 ID 规范
所有 ID 均由后端使用 Snowflake 算法生成,类型为 `int64`。在前端交互和 JSON 序列化时,统一作为 `string` 处理,以避免精度丢失。
---
## 3. 数据模型
### 3.1 User (用户)
| 字段 | 类型 | 说明 |
| ------------------ | ---------- | ---------------------------------------------------- |
| id | string | 用户唯一标识 |
| username | string | 登录用户名 |
| email | string | 邮箱地址 (可选) |
| nickname | string | 昵称 |
| avatar | string | 头像 URL |
| role | UserRole | 当前激活的角色 |
| verifiedRoles | UserRole[] | 已认证的角色列表 |
| verificationStatus | object | 各角色的认证状态 (`pending`, `approved`, `rejected`) |
| bio | string | 个人简介 (可选) |
| createdAt | string | 注册时间 |
### 3.2 Game (游戏)
| 字段 | 类型 | 说明 |
| -------- | ------ | ----------------------------------- |
| id | string | 游戏 ID |
| name | string | 游戏名称 |
| icon | string | 游戏图标 URL |
| category | string | 分类 (`MOBA`, `FPS`, `动作`, `RPG`) |
### 3.3 Player & PlayerService (打手与服务)
**PlayerService**:
| 字段 | 类型 | 说明 |
| ------------ | -------- | --------------------------- |
| id | string | 服务 ID |
| playerId | string | 打手 ID |
| gameId | string | 游戏 ID |
| gameName | string | 游戏名称 |
| title | string | 服务标题 |
| description | string | 服务描述 |
| price | number | 价格 |
| unit | string | 计价单位 (`局`, `星`, `次`) |
| rankRange | string | 段位范围 (可选) |
| availability | string[] | 可接单时间段 |
**Player**:
| 字段 | 类型 | 说明 |
| -------------- | --------------- | ------------------------------------- |
| id | string | 打手 ID |
| user | User | 关联的用户信息 |
| rating | number | 综合评分 |
| totalOrders | number | 总接单数 |
| completionRate | number | 完单率 (0-1) |
| status | string | 状态 (`available`, `busy`, `offline`) |
| games | string[] | 擅长游戏 ID 列表 |
| services | PlayerService[] | 提供的服务列表 |
| shopId | string | 所属店铺 ID (可选) |
| shopName | string | 所属店铺名称 (可选) |
| tags | string[] | 个人标签 |
### 3.4 Shop (店铺)
| 字段 | 类型 | 说明 |
| ---------------------- | -------- | -------------------------------- |
| id | string | 店铺 ID |
| owner | User | 店长信息 |
| name | string | 店铺名称 |
| banner | string | 店铺招牌图 (可选) |
| description | string | 店铺简介 |
| rating | number | 综合评分 |
| totalOrders | number | 总单量 |
| playerCount | number | 打手数量 |
| commissionType | string | 抽成方式 (`fixed`, `percentage`) |
| commissionValue | number | 抽成数值 |
| allowMultiShop | boolean | 是否允许打手兼职 |
| allowIndependentOrders | boolean | 是否允许打手私下接单 |
| dispatchMode | string | 派单模式 (`manual`, `auto`) |
| announcements | string[] | 店铺公告列表 |
| templateConfig | object | 店铺主页模板配置 |
### 3.5 Order (订单)
| 字段 | 类型 | 说明 |
| ------------ | ------------- | ------------------- |
| id | string | 订单 ID |
| consumerId | string | 消费者 ID |
| consumerName | string | 消费者昵称 |
| playerId | string | 打手 ID |
| playerName | string | 打手昵称 |
| shopId | string | 店铺 ID (可选) |
| shopName | string | 店铺名称 (可选) |
| service | PlayerService | 购买的服务快照 |
| status | OrderStatus | 订单状态 |
| totalPrice | number | 订单总价 |
| note | string | 备注 (可选) |
| createdAt | string | 创建时间 |
| acceptedAt | string | 接单时间 (可选) |
| closedAt | string | 申请结算时间 (可选) |
| completedAt | string | 完成时间 (可选) |
**OrderStatus 枚举**: `pending_payment`, `pending_accept`, `in_progress`, `pending_close`, `pending_review`, `disputed`, `completed`, `cancelled`
### 3.6 Review (评价)
| 字段 | 类型 | 说明 |
| -------------- | ------- | -------------------------------------- |
| id | string | 评价 ID |
| orderId | string | 关联订单 ID |
| fromUserId | string | 评价人 ID |
| fromUserName | string | 评价人昵称 |
| fromUserAvatar | string | 评价人头像 |
| toUserId | string | 被评价人 ID |
| rating | number | 评分 (1-5) |
| content | string | 评价内容 (可选) |
| sealed | boolean | 是否处于密封状态(双方未互评前不可见) |
| createdAt | string | 评价时间 |
### 3.7 Dispute & DisputeRecord (争议)
| 字段 | 类型 | 说明 |
| ------------------ | -------- | ---------------------------------------------------------- |
| id | string | 争议 ID |
| orderId | string | 关联订单 ID |
| initiatorId | string | 发起人 ID |
| initiatorName | string | 发起人昵称 |
| reason | string | 争议原因 |
| evidence | string[] | 证据图片 URL 列表 |
| status | string | 状态 (`open`, `reviewing`, `resolved`, `appealed`) |
| result | string | 仲裁结果 (`full_refund`, `full_payment`, `partial_refund`) |
| respondentReason | string | 被诉方回应理由 (可选) |
| respondentEvidence | string[] | 被诉方证据 (可选) |
| appealReason | string | 申诉理由 (可选) |
| appealedAt | string | 申诉时间 (可选) |
| timeline | object[] | 争议处理时间线 |
| createdAt | string | 创建时间 |
### 3.8 ChatSession & ChatMessage (聊天)
**ChatSession**:
| 字段 | 类型 | 说明 |
| ------------- | -------- | ---------------------------------- |
| id | string | 会话 ID |
| type | string | 会话类型 (`order`, `consultation`) |
| orderId | string | 关联订单 ID (仅 order 类型) |
| participants | object[] | 参与者列表 `{id, name, avatar}` |
| lastMessage | string | 最后一条消息内容 |
| lastMessageAt | string | 最后一条消息时间 |
| unreadCount | number | 未读消息数 |
| readonly | boolean | 是否只读(如订单完成/咨询超时后) |
**ChatMessage**:
| 字段 | 类型 | 说明 |
| ------------ | ------ | ------------------------------------ |
| id | string | 消息 ID |
| sessionId | string | 会话 ID |
| senderId | string | 发送者 ID |
| senderName | string | 发送者昵称 |
| senderAvatar | string | 发送者头像 |
| type | string | 消息类型 (`text`, `image`, `system`) |
| content | string | 消息内容 |
| createdAt | string | 发送时间 |
### 3.9 Post & Comment (社区)
**Post**:
| 字段 | 类型 | 说明 |
| ------------- | -------- | ---------------------- |
| id | string | 帖子 ID |
| author | User | 作者信息 |
| authorRole | UserRole | 作者发帖时的角色 |
| title | string | 标题 |
| content | string | 内容 |
| images | string[] | 图片列表 |
| tags | string[] | 标签列表 |
| linkedOrderId | string | 关联的订单 ID (秀单帖) |
| quotedPostId | string | 引用的帖子 ID (引用帖) |
| likeCount | number | 点赞数 |
| commentCount | number | 评论数 |
| liked | boolean | 当前用户是否已赞 |
| pinned | boolean | 是否被作者置顶 |
| createdAt | string | 发布时间 |
**Comment**:
| 字段 | 类型 | 说明 |
| --------- | ------- | ---------------- |
| id | string | 评论 ID |
| postId | string | 关联帖子 ID |
| author | User | 评论者信息 |
| content | string | 评论内容 |
| likeCount | number | 点赞数 |
| liked | boolean | 当前用户是否已赞 |
| createdAt | string | 评论时间 |
### 3.10 WalletTransaction (钱包流水)
| 字段 | 类型 | 说明 |
| ----------- | ------ | ----------------------------------------------------------- |
| id | string | 流水 ID |
| type | string | 类型 (`topup`, `payment`, `income`, `withdrawal`, `refund`) |
| amount | number | 金额 (正数为收入/充值/退款,负数为支出/提现) |
| description | string | 描述 |
| orderId | string | 关联订单 ID (可选,用于结构化统计,替代前端正则匹配) |
| createdAt | string | 发生时间 |
### 3.11 Favorite (收藏)
| 字段 | 类型 | 说明 |
| ---------- | ------ | ------------------------------- |
| id | string | 收藏 ID |
| userId | string | 用户 ID |
| targetType | string | 收藏目标类型 (`player`, `shop`) |
| targetId | string | 收藏目标 ID |
| createdAt | string | 收藏时间 |
### 3.12 Notification (通知)
| 字段 | 类型 | 说明 |
| --------- | ------- | ----------------------------------------- |
| id | string | 通知 ID |
| type | string | 通知类型 (`order`, `community`, `system`) |
| title | string | 通知标题 |
| content | string | 通知内容 |
| read | boolean | 是否已读 |
| link | string | 关联跳转链接 (可选) |
| createdAt | string | 通知时间 |
---
## 4. 认证与用户
| 方法 | 路径 | 权限 | 说明 |
| ------ | ------------------------------------- | ---- | --------------------------------- |
| POST | `/auth/register` | | 用户注册 (username + email + password + vcode) |
| POST | `/auth/login` | | 用户登录 (username + password) |
| POST | `/auth/logout` | 🔒 | 退出登录,清除 Cookie |
| POST | `/auth/forgot-password/send` | | 忘记密码(发送验证码到邮箱) |
| POST | `/auth/reset-password` | | 重置密码 (email + vcode + newPassword) |
| POST | `/email/verification-code/send` | | 发送邮箱验证码 |
| GET | `/users/me` | 🔒 | 获取当前登录用户信息 |
| PUT | `/users/me` | 🔒 | 更新个人资料 (昵称, 头像, 简介等) |
| POST | `/users/me/switch-role` | 🔒 | 切换当前激活角色 |
| POST | `/users/me/verification` | 🔒 | 提交角色认证材料 |
| GET | `/users/me/verification` | 🔒 | 获取认证状态 |
| PUT | `/users/me/preferences/notifications` | 🔒 | 更新通知偏好设置 |
| PUT | `/users/me/preferences/theme` | 🔒 | 更新主题偏好设置 |
| GET | `/users/:id` | | 获取指定用户信息 |
| POST | `/users/:id/follow` | 🔒 | 关注用户 |
| DELETE | `/users/:id/follow` | 🔒 | 取消关注用户 |
**请求示例:登录**
```json
// POST /api/v1/auth/login
{
"username": "zhangsan",
"password": "..."
}
```
**响应示例:登录成功**
```json
{
"user": {
"id": "u1",
"username": "zhangsan",
"email": "zhangsan@example.com",
"nickname": "张三",
"avatar": "https://cdn.juwan.com/avatars/u1.jpg",
"role": "consumer",
"verifiedRoles": ["consumer", "player"],
"verificationStatus": { "consumer": "approved", "player": "approved" },
"createdAt": "2024-01-15T08:00:00.000Z"
}
}
```
**请求示例:提交认证材料**
```json
// POST /api/v1/users/me/verification
{
"role": "player",
"materials": {
"idCardFront": "https://cdn.juwan.com/uploads/xxx.jpg",
"idCardBack": "https://cdn.juwan.com/uploads/yyy.jpg",
"gameScreenshot": "https://cdn.juwan.com/uploads/zzz.jpg"
}
}
```
**请求示例:切换角色**
```json
// POST /api/v1/users/me/switch-role
{ "role": "player" }
```
**请求示例:更新通知偏好**
```json
// PUT /api/v1/users/me/preferences/notifications
{ "order": true, "community": true, "system": false }
```
---
## 5. 游戏数据
| 方法 | 路径 | 权限 | 说明 |
| ---- | ------------ | ---- | ----------------------- |
| GET | `/games` | | 获取游戏列表 (支持分页) |
| GET | `/games/:id` | | 获取指定游戏详情 |
---
## 6. 打手与服务
| 方法 | 路径 | 权限 | 说明 |
| ------ | ----------------------- | ---- | ------------------------------------------------- |
| GET | `/players` | | 获取打手列表 (支持分页、筛选) |
| GET | `/players/:id` | | 获取打手公开主页详情 |
| PUT | `/players/me/status` | 🔒 | 更新打手接单状态 (`available`, `busy`, `offline`) |
| GET | `/services` | | 获取所有服务列表 |
| GET | `/services/:id` | | 获取服务详情 |
| GET | `/players/:id/services` | | 获取指定打手的服务列表 |
| POST | `/services` | 🔒 | 创建服务 (仅 player) |
| PUT | `/services/:id` | 🔒 | 更新服务 (仅 player) |
| DELETE | `/services/:id` | 🔒 | 删除服务 (仅 player) |
---
## 7. 店铺系统
| 方法 | 路径 | 权限 | 说明 |
| ------ | ------------------------------- | ---- | --------------------------- |
| GET | `/shops` | | 获取店铺列表 |
| GET | `/shops/:id` | | 获取店铺公开主页详情 |
| GET | `/users/:id/shop` | | 获取指定店长的店铺 |
| POST | `/shops` | 🔒 | 创建店铺 (仅 owner) |
| PUT | `/shops/:id` | 🔒 | 更新店铺基础信息及规则 |
| PUT | `/shops/:id/template` | 🔒 | 更新店铺主页模板配置 |
| PUT | `/shops/:id/announcements` | 🔒 | 更新店铺公告 |
| POST | `/shops/:id/invitations` | 🔒 | 邀请打手加入店铺 |
| POST | `/shops/invitations/:id/accept` | 🔒 | 打手接受店铺邀请 |
| DELETE | `/shops/:id/players/:playerId` | 🔒 | 将打手移出店铺 |
| GET | `/shops/:id/income-stats` | 🔒 | 获取店铺收入统计 (仅 owner) |
| GET | `/shops/mine` | 🔒 | 获取当前登录店主的店铺详情 |
| GET | `/shops/:id/players` | | 获取店铺下的打手列表 |
| POST | `/shops/:id/announcements` | 🔒 | 新增店铺公告 |
| DELETE | `/shops/:id/announcements/:index` | 🔒 | 删除店铺公告 |
| DELETE | `/shops/invitations/:id` | 🔒 | 拒绝店铺邀请 (打手调用) |
**请求示例:更新店铺规则**
```json
// PUT /api/v1/shops/:id
{
"name": "星耀电竞工作室",
"description": "专业英雄联盟代练工作室",
"commissionType": "percentage",
"commissionValue": 15,
"allowMultiShop": false,
"allowIndependentOrders": true,
"dispatchMode": "auto"
}
```
**请求示例:更新店铺模板**
```json
// PUT /api/v1/shops/:id/template
{
"sections": [
{ "type": "banner", "enabled": true, "order": 0 },
{ "type": "intro", "enabled": true, "order": 1 },
{ "type": "services", "enabled": true, "order": 2 },
{ "type": "players", "enabled": true, "order": 3 },
{ "type": "announcements", "enabled": false, "order": 4 },
{ "type": "reviews", "enabled": true, "order": 5 }
]
}
```
**响应示例:店铺收入统计**
```json
// GET /api/v1/shops/:id/income-stats
{
"monthlyIncome": 12800.00,
"pendingSettlement": 3200.00,
"totalWithdrawn": 54000.00,
"totalOrders": 156,
"completedOrders": 142
}
```
---
## 8. 订单系统
### 8.1 订单状态机 (Order State Machine)
| 当前状态 | 触发动作 | 下一状态 | 允许的角色 | 副作用 |
| ----------------- | ----------------------------- | ---------------- | ---------------- | -------------------------------------------------- |
| `pending_payment` | `PAY` | `pending_accept` | consumer | CLEAR_TIMEOUT, SCHEDULE_TIMEOUT |
| `pending_accept` | `ACCEPT` | `in_progress` | player, owner | CLEAR_TIMEOUT, SYNC_CHAT_SESSION |
| `pending_accept` | `CANCEL_PRE_ACCEPT` | `cancelled` | consumer | CLEAR_TIMEOUT |
| `pending_accept` | `AUTO_TIMEOUT_PENDING_ACCEPT` | `cancelled` | system | CLEAR_TIMEOUT |
| `in_progress` | `REQUEST_CLOSE` | `pending_close` | consumer, player | CLEAR_TIMEOUT, SCHEDULE_TIMEOUT, SYNC_CHAT_SESSION |
| `in_progress` | `OPEN_DISPUTE` | `disputed` | consumer, player | CLEAR_TIMEOUT, SYNC_CHAT_SESSION |
| `pending_close` | `CONFIRM_CLOSE` | `pending_review` | consumer, player | CLEAR_TIMEOUT, SCHEDULE_TIMEOUT, SYNC_CHAT_SESSION |
| `pending_close` | `OPEN_DISPUTE` | `disputed` | consumer, player | CLEAR_TIMEOUT, SYNC_CHAT_SESSION |
| `pending_close` | `AUTO_TIMEOUT_PENDING_CLOSE` | `pending_review` | system | CLEAR_TIMEOUT, SCHEDULE_TIMEOUT, SYNC_CHAT_SESSION |
| `pending_review` | `SUBMIT_REVIEW` | `completed` | consumer, player | CLEAR_TIMEOUT, PAYOUT_INCOME, SYNC_CHAT_SESSION |
| `pending_review` | `AUTO_TIMEOUT_PENDING_REVIEW` | `completed` | system | CLEAR_TIMEOUT, PAYOUT_INCOME, SYNC_CHAT_SESSION |
| `disputed` | `RESOLVE_DISPUTE` | `pending_review` | owner, admin | CLEAR_TIMEOUT, SCHEDULE_TIMEOUT, SYNC_CHAT_SESSION |
### 8.2 超时配置 (Timeout Configs)
后端需实现定时任务(如 Redis 延迟队列)来处理以下超时逻辑:
- `ORDER_ACCEPT_TIMEOUT_MS`: 待接单超时自动取消(默认 5 分钟)。
- `ORDER_CLOSE_TIMEOUT_MS`: 申请结算后对方未确认,超时自动进入待评价(默认 24 小时)。
- `ORDER_REVIEW_TIMEOUT_MS`: 待评价超时自动好评并完成订单(默认 72 小时)。
### 8.3 订单接口
| 方法 | 路径 | 权限 | 说明 |
| ---- | --------------------------- | ---- | ----------------------------------- |
| GET | `/orders` | 🔒 | 获取当前用户的订单列表 |
| GET | `/orders/:id` | 🔒 | 获取订单详情 |
| POST | `/orders` | 🔒 | 创建订单 (状态: `pending_payment`) |
| POST | `/orders/paid` | 🔒 | 创建并直接支付订单 (快捷下单) |
| POST | `/orders/:id/pay` | 🔒 | 支付订单 (`PAY`) |
| POST | `/orders/:id/accept` | 🔒 | 接单 (`ACCEPT`) |
| POST | `/orders/:id/request-close` | 🔒 | 申请结算 (`REQUEST_CLOSE`) |
| POST | `/orders/:id/confirm-close` | 🔒 | 确认结算 (`CONFIRM_CLOSE`) |
| POST | `/orders/:id/cancel` | 🔒 | 接单前取消 (`CANCEL_PRE_ACCEPT`) |
| POST | `/orders/:id/reorder` | 🔒 | 再来一单 (基于原订单快速创建新订单) |
`GET /orders` 支持查询参数:`role` (consumer/player/owner)、`status` (状态过滤)、`offset``limit`。后端根据 Token 中的 userId 和 role 参数自动过滤,不允许查看他人订单。
**请求示例:创建并支付订单 (快捷下单)**
```json
// POST /api/v1/orders/paid
{
"playerId": "p1",
"shopId": "shop1",
"serviceId": "svc1",
"quantity": 3,
"note": "希望晚上8点后开始"
}
```
**响应示例:订单创建成功**
```json
{
"order": {
"id": "ord-20240320-001",
"consumerId": "u1",
"consumerName": "张三",
"playerId": "p1",
"playerName": "小明",
"shopId": "shop1",
"shopName": "星耀电竞",
"service": { "id": "svc1", "title": "英雄联盟代练", "price": 50, "unit": "局" },
"status": "pending_accept",
"totalPrice": 150,
"createdAt": "2024-03-20T12:00:00.000Z"
}
}
```
**请求示例:再来一单**
```json
// POST /api/v1/orders/:id/reorder
// 无请求体,后端基于原订单的 playerId、serviceId、shopId 创建新订单
```
---
## 9. 争议仲裁
| 方法 | 路径 | 权限 | 说明 |
| ---- | ------------------------ | ---- | ------------------------- |
| GET | `/disputes` | 🔒 | 获取当前用户的争议列表 |
| GET | `/orders/:id/dispute` | 🔒 | 获取指定订单的争议详情 |
| POST | `/orders/:id/dispute` | 🔒 | 发起争议 (`OPEN_DISPUTE`) |
| POST | `/disputes/:id/response` | 🔒 | 被诉方提交回应及证据 |
| POST | `/disputes/:id/appeal` | 🔒 | 对仲裁结果发起申诉 |
**争议处理时间线 (Timeline)**:
- `created`: 争议发起
- `response`: 被诉方回应
- `reviewing`: 店长/平台介入审查
- `resolved`: 给出仲裁结果
- `appealed`: 发起申诉,转交平台管理员
**请求示例:发起争议**
```json
// POST /api/v1/orders/:id/dispute
{
"reason": "打手未按约定时间上线",
"evidence": [
"https://cdn.juwan.com/uploads/evidence1.jpg",
"https://cdn.juwan.com/uploads/evidence2.jpg"
]
}
```
**请求示例:被诉方回应**
```json
// POST /api/v1/disputes/:id/response
{
"reason": "当时网络故障,已与客户沟通并补时",
"evidence": ["https://cdn.juwan.com/uploads/response1.jpg"]
}
```
**请求示例:申诉**
```json
// POST /api/v1/disputes/:id/appeal
{
"reason": "仲裁结果不合理,请求平台复核"
}
```
---
## 10. 评价系统
**密封机制 (Sealed Mechanics)**:
评价提交后默认为 `sealed: true`。只有当双方都完成评价,或者评价超时(`ORDER_REVIEW_TIMEOUT_MS`)后,评价才会解封并公开显示。
| 方法 | 路径 | 权限 | 说明 |
| ---- | --------------------- | ---- | ------------------------------------ |
| POST | `/orders/:id/review` | 🔒 | 提交评价 (`SUBMIT_REVIEW`) |
| GET | `/reviews` | | 获取公开评价列表 |
| GET | `/orders/:id/reviews` | 🔒 | 获取指定订单的评价(受密封机制限制) |
| GET | `/users/:id/reviews` | | 获取指定用户收到的评价 |
---
## 11. 聊天系统
### 11.1 会话类型
- **`order`**: 订单会话。随订单创建而建立,订单完成后变为只读。
- **`consultation`**: 咨询会话。用户在下单前与打手沟通。24小时无回复自动关闭。可升级为订单会话。
| 方法 | 路径 | 权限 | 说明 |
| ---- | ----------------------------- | ---- | ----------------------------------- |
| GET | `/chat/sessions` | 🔒 | 获取当前用户的会话列表 |
| GET | `/chat/sessions/:id` | 🔒 | 获取会话详情 |
| GET | `/chat/sessions/:id/messages` | 🔒 | 获取会话历史消息 (分页) |
| POST | `/chat/sessions/order` | 🔒 | 确保订单会话存在 (不存在则创建) |
| POST | `/chat/sessions/consultation` | 🔒 | 创建咨询会话 |
| POST | `/chat/sessions/:id/upgrade` | 🔒 | 将咨询会话升级为订单会话 |
| POST | `/chat/sessions/:id/messages` | 🔒 | 发送消息 (文本/图片) |
| GET | `/shops/:id/chat-sessions` | 🔒 | 店长查看员工的业务会话 (需员工同意) |
---
## 12. 社区系统
| 方法 | 路径 | 权限 | 说明 |
| ------ | --------------------- | ---- | ------------------------------------- |
| GET | `/posts` | | 获取帖子列表 (支持分页、标签筛选) |
| GET | `/posts/:id` | | 获取帖子详情 |
| POST | `/posts` | 🔒 | 发布帖子 (支持普通帖、秀单帖、引用帖) |
| POST | `/posts/:id/like` | 🔒 | 点赞帖子 |
| DELETE | `/posts/:id/like` | 🔒 | 取消点赞帖子 |
| POST | `/posts/:id/pin` | 🔒 | 作者置顶帖子 (最多 N 条) |
| DELETE | `/posts/:id/pin` | 🔒 | 取消置顶 |
| GET | `/posts/:id/comments` | | 获取帖子评论列表 |
| POST | `/posts/:id/comments` | 🔒 | 发表评论 |
| POST | `/comments/:id/like` | 🔒 | 点赞评论 |
| DELETE | `/comments/:id/like` | 🔒 | 取消点赞评论 |
| GET | `/users/:id/posts` | | 获取指定用户的帖子列表 |
`GET /posts` 支持查询参数:`tags` (标签过滤)、`gameId` (游戏过滤)、`sortBy` (new/hot)、`offset``limit`
**请求示例:发布秀单帖**
```json
// POST /api/v1/posts
{
"title": "超棒的代练体验",
"content": "从银到铂金,只用了三天!",
"images": ["https://cdn.juwan.com/uploads/post1.jpg"],
"tags": ["英雄联盟", "代练"],
"linkedOrderId": "ord-20240320-001"
}
```
---
## 13. 收藏与关注
| 方法 | 路径 | 权限 | 说明 |
| ------ | ---------------------------- | ---- | ---------------------------------- |
| GET | `/favorites` | 🔒 | 获取当前用户的收藏列表 (打手/店铺) |
| POST | `/favorites` | 🔒 | 添加收藏 |
| DELETE | `/favorites/:id` | 🔒 | 取消收藏 |
| GET | `/users/:id/favorites/check` | 🔒 | 检查是否已收藏指定目标 |
**请求示例:添加收藏**
```json
// POST /api/v1/favorites
{ "targetType": "player", "targetId": "p1" }
```
**检查收藏状态**
```
GET /api/v1/users/u1/favorites/check?targetType=player&targetId=p1
→ { "favorited": true }
```
---
## 14. 搜索与发现
| 方法 | 路径 | 权限 | 说明 |
| ---- | --------- | ---- | ------------ |
| GET | `/search` | | 统一搜索接口 |
**请求参数**:
- `q`: 搜索关键词
- `selectedGames`: 游戏 ID 数组
- `min`, `max`: 价格区间
- `onlyOnline`: 是否仅看在线 (`true`/`false`)
- `minRating`: 最低评分
- `sort`: 排序方式 (`composite`, `rating`, `orders`, `price_asc`, `price_desc`)
- `offset`, `limit`: 分页参数
| GET | `/recommendations/home` | | 首页推荐信息流 (混合打手与店铺卡片) |
**响应示例:搜索结果**
```json
{
"items": [
{
"type": "player",
"player": { "id": "p1", "user": {...}, "rating": 4.8, "status": "available", ... },
"minPrice": 30,
"unit": "局",
"rating": 4.8,
"orders": 256
},
{
"type": "shop",
"shop": { "id": "shop1", "name": "星耀电竞", ... },
"minPrice": 25,
"unit": "局",
"rating": 4.6,
"orders": 1024,
"games": ["英雄联盟", "CS2"],
"hasAvailable": true
}
],
"meta": { "total": 42, "offset": 0, "limit": 12 }
}
```
---
## 15. 钱包与资金
### 15.1 收入计算公式 (Income Calculation)
订单完成后,系统根据店铺规则计算打手实际收入:
- **无店铺 (独立接单)**: `income = totalPrice`
- **比例抽成 (percentage)**: `income = totalPrice * (1 - commissionValue / 100)`
- **固定抽成 (fixed)**: `income = Math.max(0, totalPrice - commissionValue)`
剩余部分作为店铺收入(若有店铺)。
### 15.2 钱包接口
| 方法 | 路径 | 权限 | 说明 |
| ---- | ---------------------- | ---- | ------------------------------------- |
| GET | `/wallet/balance` | 🔒 | 获取当前余额 |
| GET | `/wallet/transactions` | 🔒 | 获取资金流水 (包含结构化的 `orderId`) |
| POST | `/wallet/topup` | 🔒 | 充值 |
| POST | `/wallet/withdraw` | 🔒 | 提现 |
---
## 16. 通知系统
| 方法 | 路径 | 权限 | 说明 |
| ---- | ---------------------------------- | ---- | ------------------ |
| GET | `/notifications` | 🔒 | 获取通知列表 |
| PUT | `/notifications/:id/read` | 🔒 | 标记单条通知为已读 |
| PUT | `/notifications/read-all` | 🔒 | 标记所有通知为已读 |
| POST | `/notifications/push-subscription` | 🔒 | 订阅 Web Push 推送 |
---
## 17. 管理后台 (Admin)
| 方法 | 路径 | 权限 | 说明 |
| ---- | ---------------------------------- | ---- | -------------------------- |
| GET | `/admin/verifications` | 🛡️ | 获取待审核的认证申请 |
| POST | `/admin/verifications/:id/approve` | 🛡️ | 批准认证申请 |
| POST | `/admin/verifications/:id/reject` | 🛡️ | 拒绝认证申请 |
| GET | `/admin/disputes` | 🛡️ | 获取需要平台介入的争议列表 |
| POST | `/admin/disputes/:id/resolve` | 🛡️ | 平台管理员给出最终仲裁结果 |
---
## 18. WebSocket 事件
客户端连接到 `wss://api.juwan.com/api/v1/ws`,通过 JWT 鉴权。
**下发事件类型**:
- `chat:message`: 收到新聊天消息。
- `order:status_changed`: 订单状态变更(触发前端重新拉取订单详情)。
- `notification:new`: 收到新系统通知。
- `dispute:updated`: 争议状态或时间线更新。
- `wallet:balance_changed`: 余额变动通知。
---
## 19. 安全与校验清单
1. **数据隔离 (Data Isolation)**:
- 用户只能查询自己的订单、钱包流水、私聊会话。
- 店长只能查询本店铺的订单和员工数据。
2. **并发控制 (Concurrency Control)**:
- 订单状态流转必须使用乐观锁或数据库事务,防止并发导致状态机错乱。
- 钱包扣款必须保证原子性,防止超扣。
3. **权限校验 (Authorization)**:
- 严格校验 `Actor``role`。例如,只有 `player` 才能创建服务,只有 `owner` 才能修改店铺规则。
- 订单操作必须校验操作者是否为该订单的 `consumerId``playerId` 或关联的 `shopId` 的店长。
4. **幂等性 (Idempotency)**:
- 支付、接单、结算等核心操作必须保证幂等性,重复请求返回 `IDEMPOTENT_NOOP`