feat(api): 实现三端统一的JSON API响应契约

- 新增`api_response.py`统一响应封装工具类,提供标准成功/错误响应构造方法
- 重构WonderQ-Admin全局异常处理器,将所有异常转换为标准响应格式
- 修改所有公共和管理端接口的返回逻辑,统一使用`code`(与HTTP状态码一致)、`msg`和`data`的三层结构
- 新增`api-response-contract.md`文档,定义完整的三端统一JSON响应规范
- 更新所有领域API文档,明确业务数据需位于`data`字段内,补充响应格式说明
- 为WonderQ-MiniAPP和WonderQ-Admin-UI新增响应解析逻辑和类型定义,自动完成协议校验和错误处理
- 更新所有测试用例,适配新的响应结构确保接口符合契约要求
- 新增`module-config-api.md`模块配置API文档,补充站点模块配置的接口约定
- 更新项目README文档,调整文档分类顺序将响应契约置于首位
This commit is contained in:
duanshuwen
2026-08-19 22:02:20 +08:00
parent d16924584c
commit e082bd2d98
28 changed files with 993 additions and 383 deletions

View File

@@ -22,6 +22,8 @@
`key` 固定使用玩法路线 ID`WanfaRoute.id`,例如 `family-water`),但 `DetailRecord` 不建立数据库外键。详情页通过 `/pages/detail/index?routeId={key}` 定位内容;详情记录删除不会跨领域级联删除路线或其他数据。
所有 JSON 响应遵循 [三端统一 API 响应契约](./api-response-contract.md),成功业务对象位于 `data`,失败时 `data``null`
## 与 `detailPresentation.ts` 的关系
`detailPresentation.ts` 是前台展示适配器,不是持久化模型:
@@ -54,7 +56,7 @@ API 前缀为 `/api/admin`,除登录接口外均需要后台 JWT。
- 创建和编辑返回最新详情对象;排序接口返回排序后的 `items`
- ID 由后端生成并作为非空字符串返回;`key` 由调用方提供并保持稳定。
- 空列表返回 `[]`,不能返回 `null` 或省略字段。
- 失败响应沿用 Admin API 约定,包含 `message``code`可选的 `details`
- 成功结果放入 `data`;失败返回数字 `code``msg``data: null`,可选 `errorCode``details`
## 数据类型
@@ -141,26 +143,30 @@ Authorization: Bearer <admin-jwt>
```json
{
"details": [
{
"id": "detail-001",
"key": "classic-panorama",
"eyebrow": "玩法推荐",
"duration": "5天4晚",
"title": "经典贵州全景",
"subtitle": "贵州·瀑布、苗寨、古城与山地风光",
"intro": "沿着贵州山地的自然纹理深入探索。",
"highlights": ["核心景观串联", "小团出行,按同行人节奏调整"],
"included": ["行程内用车与接送服务"],
"excluded": ["往返大交通及个人消费"],
"notes": ["贵州多山多雨,请准备防滑鞋和轻便雨具。"],
"gallery": ["https://example.test/assets/detail-01.jpg"],
"isActive": true,
"sortOrder": 0,
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z"
}
]
"code": 200,
"msg": "success",
"data": {
"details": [
{
"id": "detail-001",
"key": "classic-panorama",
"eyebrow": "玩法推荐",
"duration": "5天4晚",
"title": "经典贵州全景",
"subtitle": "贵州·瀑布、苗寨、古城与山地风光",
"intro": "沿着贵州山地的自然纹理深入探索。",
"highlights": ["核心景观串联", "小团出行,按同行人节奏调整"],
"included": ["行程内用车与接送服务"],
"excluded": ["往返大交通及个人消费"],
"notes": ["贵州多山多雨,请准备防滑鞋和轻便雨具。"],
"gallery": ["https://example.test/assets/detail-01.jpg"],
"isActive": true,
"sortOrder": 0,
"createdAt": "2026-01-01T00:00:00Z",
"updatedAt": "2026-01-01T00:00:00Z"
}
]
}
}
```
@@ -171,7 +177,7 @@ GET /api/admin/details/{detailId}
Authorization: Bearer <admin-jwt>
```
成功返回单个 `DetailRecord`。记录不存在返回 `404 DETAIL_NOT_FOUND`
成功返回 `data` 内的单个 `DetailRecord`。记录不存在返回 `404`,业务码为 `DETAIL_NOT_FOUND`
### 新增详情
@@ -181,7 +187,7 @@ Authorization: Bearer <admin-jwt>
Content-Type: application/json
```
请求体为 `DetailCreate`。成功返回 `201` 和新建的 `DetailRecord`;未传 `sortOrder` 时追加到当前列表末尾。
请求体为 `DetailCreate`。成功返回 `201` `data`新建的 `DetailRecord`;未传 `sortOrder` 时追加到当前列表末尾。
### 编辑详情
@@ -191,7 +197,7 @@ Authorization: Bearer <admin-jwt>
Content-Type: application/json
```
请求体为 `DetailPatch`,只更新提交的字段。修改 `key` 时仍须保证全局唯一。成功返回更新后的 `DetailRecord`;记录不存在返回 `404 DETAIL_NOT_FOUND``key` 冲突返回 `409 DETAIL_KEY_EXISTS`
请求体为 `DetailPatch`,只更新提交的字段。修改 `key` 时仍须保证全局唯一。成功返回 `data`更新后的 `DetailRecord`;记录不存在返回 `404`,业务码为 `DETAIL_NOT_FOUND``key` 冲突返回 `409`,业务码为 `DETAIL_KEY_EXISTS`
### 删除详情
@@ -203,7 +209,11 @@ Authorization: Bearer <admin-jwt>
成功返回:
```json
{ "id": "detail-001" }
{
"code": 200,
"msg": "success",
"data": { "id": "detail-001" }
}
```
删除后应重新规范化剩余记录的 `sortOrder`,从 `0` 开始连续编号。详情记录没有 Product、订单或线索外键因此删除不触发跨领域级联操作。
@@ -225,7 +235,11 @@ Content-Type: application/json
成功返回:
```json
{ "items": [] }
{
"code": 200,
"msg": "success",
"data": { "items": [] }
}
```
其中 `items` 为更新 `sortOrder` 后的 `DetailRecord[]`。缺少 ID、包含未知 ID 或出现重复 ID 时返回 `400 DETAIL_REORDER_INVALID`