|
|
@@ -0,0 +1,694 @@
|
|
|
+# Client API 前端联调文档
|
|
|
+
|
|
|
+文档版本:v1.0.0
|
|
|
+最后更新:2026-03-31
|
|
|
+状态:联调中
|
|
|
+
|
|
|
+## 1. 文档说明
|
|
|
+
|
|
|
+本文档面向前端联调,描述当前 `client-api` 在代码中真实可用的接口。
|
|
|
+
|
|
|
+约定:
|
|
|
+
|
|
|
+- 本文档优先级高于产品阶段的总草案;前端联调以本文档为准
|
|
|
+- 本文档只覆盖 `client-api`
|
|
|
+- 每个接口会标记当前状态:
|
|
|
+ - `已实现,已联调`
|
|
|
+ - `已实现,未联调`
|
|
|
+ - `预留未就绪`
|
|
|
+
|
|
|
+## 2. 通用约定
|
|
|
+
|
|
|
+### 2.1 Base Path
|
|
|
+
|
|
|
+- `client-api`:`/client/v1`
|
|
|
+
|
|
|
+### 2.2 成功响应
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "request_id": "req_xxx",
|
|
|
+ "data": {}
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 2.3 失败响应
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "request_id": "req_xxx",
|
|
|
+ "error": {
|
|
|
+ "code": "invalid_request",
|
|
|
+ "message": "xxx",
|
|
|
+ "details": {}
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 2.4 鉴权说明
|
|
|
+
|
|
|
+- 登录后接口使用:`Authorization: Bearer {access_token}`
|
|
|
+- `launch` 成功后会返回 `session_token`
|
|
|
+- 但当前版本下游 `session` 相关接口尚未开放,因此前端暂时只需要保存 `session_token`
|
|
|
+
|
|
|
+### 2.5 枚举说明
|
|
|
+
|
|
|
+`client_type`
|
|
|
+
|
|
|
+- `app`
|
|
|
+- `wechat`
|
|
|
+
|
|
|
+`body_profile_status`
|
|
|
+
|
|
|
+- `pending`
|
|
|
+- `completed`
|
|
|
+
|
|
|
+## 3. 已实现接口
|
|
|
+
|
|
|
+### 3.1 `POST /client/v1/auth/sms/send`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 发送短信验证码
|
|
|
+- 当前已接阿里云短信
|
|
|
+
|
|
|
+请求参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `scene` | `string` | 是 | 当前已使用 `client_login` |
|
|
|
+| `country_code` | `string` | 是 | 国家码,如 `86` |
|
|
|
+| `mobile` | `string` | 是 | 手机号 |
|
|
|
+| `client_type` | `string` | 是 | `app` / `wechat` |
|
|
|
+| `device_id` | `string` | 是 | 设备唯一标识 |
|
|
|
+
|
|
|
+请求示例:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "scene": "client_login",
|
|
|
+ "country_code": "86",
|
|
|
+ "mobile": "15168870729",
|
|
|
+ "client_type": "app",
|
|
|
+ "device_id": "dev_iphone_001"
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `cooldown_sec` | `int` | 重发冷却时间 |
|
|
|
+| `expires_in_sec` | `int` | 验证码有效期 |
|
|
|
+
|
|
|
+### 3.2 `POST /client/v1/auth/login/sms`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 短信登录
|
|
|
+- 如果手机号首次登录,后端会自动创建:
|
|
|
+ - `users`
|
|
|
+ - `login_identities`
|
|
|
+ - 默认 `user_body_profiles`
|
|
|
+ - 首条 `user_body_profile_versions`
|
|
|
+
|
|
|
+请求参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `login_request_id` | `string` | 是 | 登录幂等号 |
|
|
|
+| `country_code` | `string` | 是 | 国家码 |
|
|
|
+| `mobile` | `string` | 是 | 手机号 |
|
|
|
+| `sms_code` | `string` | 是 | 短信验证码 |
|
|
|
+| `client_type` | `string` | 是 | `app` / `wechat` |
|
|
|
+| `device_id` | `string` | 是 | 设备唯一标识 |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `user_id` | `string` | 用户公开 ID |
|
|
|
+| `access_token` | `string` | 登录态 token |
|
|
|
+| `refresh_token` | `string` | refresh token |
|
|
|
+| `login_method` | `string` | 当前为 `sms` |
|
|
|
+| `body_profile_status` | `string` | `pending` / `completed` |
|
|
|
+| `expires_in_sec` | `int` | `access_token` 有效期 |
|
|
|
+
|
|
|
+### 3.3 `POST /client/v1/auth/login/wechat`
|
|
|
+
|
|
|
+状态:`已实现,未联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 微信登录入口已预留
|
|
|
+- 当前仓库里 provider 仍以 mock 为主,尚未做真实联调
|
|
|
+
|
|
|
+请求参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `login_request_id` | `string` | 是 | 登录幂等号 |
|
|
|
+| `wechat_login_code` | `string` | 是 | 微信登录 code |
|
|
|
+| `client_type` | `string` | 是 | 建议传 `wechat` |
|
|
|
+| `device_id` | `string` | 是 | 设备唯一标识 |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `user_id` | `string` | 用户公开 ID |
|
|
|
+| `access_token` | `string` | 登录态 token |
|
|
|
+| `refresh_token` | `string` | refresh token |
|
|
|
+| `login_method` | `string` | 当前为 `wechat` |
|
|
|
+| `body_profile_status` | `string` | `pending` / `completed` |
|
|
|
+| `expires_in_sec` | `int` | `access_token` 有效期 |
|
|
|
+
|
|
|
+### 3.4 `POST /client/v1/auth/refresh`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 使用 refresh token 刷新 `access_token`
|
|
|
+
|
|
|
+请求参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `refresh_token` | `string` | 是 | refresh token |
|
|
|
+| `client_type` | `string` | 是 | `app` / `wechat` |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `access_token` | `string` | 新的登录态 token |
|
|
|
+| `expires_in_sec` | `int` | 有效期 |
|
|
|
+
|
|
|
+### 3.5 `PUT /client/v1/me/body-profile`
|
|
|
+
|
|
|
+状态:`已实现,未联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 更新身体数据
|
|
|
+- 成功后会更新当前档案,并追加历史版本
|
|
|
+
|
|
|
+认证:
|
|
|
+
|
|
|
+- 需要 `access_token`
|
|
|
+
|
|
|
+请求参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `gender` | `string` | 否 | `male` / `female` / `other` / `unknown` |
|
|
|
+| `birth_date` | `string` | 否 | `YYYY-MM-DD` |
|
|
|
+| `height_cm` | `number` | 否 | 身高,厘米 |
|
|
|
+| `weight_kg` | `number` | 否 | 体重,千克 |
|
|
|
+| `resting_heart_rate_bpm` | `int` | 否 | 静息心率 |
|
|
|
+| `max_heart_rate_bpm` | `int` | 否 | 最大心率 |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `user_id` | `string` | 用户公开 ID |
|
|
|
+| `body_profile_status` | `string` | `pending` / `completed` |
|
|
|
+| `completed_at` | `string` | 首次补全时间,未补全时可能为空 |
|
|
|
+
|
|
|
+### 3.6 `GET /client/v1/cards`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 首页卡片列表
|
|
|
+
|
|
|
+查询参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `region_code` | `string` | 否 | 地区编码,当前可空 |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+`data.items[]`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `card_id` | `string` | 卡片公开 ID |
|
|
|
+| `card_type` | `string` | 例如 `competition_card` |
|
|
|
+| `display_name` | `string` | 卡片展示名称 |
|
|
|
+| `competition_id` | `string` | 关联赛事 ID,非赛事卡可能为空 |
|
|
|
+| `html_url` | `string` | H5 地址,可空 |
|
|
|
+| `cover_url` | `string` | 封面地址,可空 |
|
|
|
+| `display_slot` | `string` | 展示槽位 |
|
|
|
+| `display_priority` | `int` | 展示优先级 |
|
|
|
+
|
|
|
+### 3.7 `GET /client/v1/competitions/{competition_id}`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 赛事详情页
|
|
|
+- 如果带 `access_token`,会返回当前用户的 `registration_status`
|
|
|
+
|
|
|
+认证:
|
|
|
+
|
|
|
+- 可匿名访问
|
|
|
+- 建议前端在登录后带上 `access_token`
|
|
|
+
|
|
|
+Path 参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `competition_id` | `string` | 赛事公开 ID |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `competition_id` | `string` | 赛事公开 ID |
|
|
|
+| `display_name` | `string` | 赛事名称 |
|
|
|
+| `competition_status` | `string` | 当前状态 |
|
|
|
+| `registration_enabled` | `bool` | 是否允许报名 |
|
|
|
+| `registration_status` | `string` | 当前用户报名状态,匿名访问时可能为空 |
|
|
|
+| `competition_start_at` | `string` | 赛事开始时间 |
|
|
|
+| `competition_end_at` | `string` | 赛事结束时间 |
|
|
|
+| `leaderboard_enabled` | `bool` | 是否展示排行榜 |
|
|
|
+| `realtime_board_enabled` | `bool` | 是否启用实时榜 |
|
|
|
+
|
|
|
+`data.events[]`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+| `display_name` | `string` | Event 名称 |
|
|
|
+| `is_default` | `bool` | 是否默认 Event |
|
|
|
+| `current_release_id` | `string` | 当前发布版 ID |
|
|
|
+| `manifest_url` | `string` | manifest 下载地址 |
|
|
|
+| `manifest_checksum_sha256` | `string` | manifest 校验值 |
|
|
|
+| `relation_status` | `string` | 关联状态 |
|
|
|
+
|
|
|
+### 3.8 `GET /client/v1/competitions/{competition_id}/events/{event_id}`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 赛事上下文下的 Event 详情
|
|
|
+- 前端应在这个页面预加载 manifest,并完成路线预览
|
|
|
+
|
|
|
+认证:
|
|
|
+
|
|
|
+- 可匿名访问
|
|
|
+- 建议前端在登录后带上 `access_token`
|
|
|
+
|
|
|
+Path 参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `competition_id` | `string` | 赛事公开 ID |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `competition_id` | `string` | 赛事公开 ID |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+| `display_name` | `string` | Event 名称 |
|
|
|
+| `current_release_id` | `string` | 当前发布版 ID |
|
|
|
+| `manifest_url` | `string` | manifest 下载地址 |
|
|
|
+| `manifest_checksum_sha256` | `string` | manifest 校验值 |
|
|
|
+| `direct_entry_enabled` | `bool` | 是否支持地图直入 |
|
|
|
+| `playfield_version_id` | `string` | 场地版本 ID |
|
|
|
+| `playfield_kind` | `string` | 如 `course` |
|
|
|
+
|
|
|
+`data.competition_context`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `competition_id` | `string` | 赛事公开 ID |
|
|
|
+| `display_name` | `string` | 赛事名称 |
|
|
|
+| `competition_status` | `string` | 赛事状态 |
|
|
|
+| `registration_status` | `string` | 当前用户报名状态 |
|
|
|
+| `leaderboard_enabled` | `bool` | 是否显示排行榜 |
|
|
|
+| `realtime_board_enabled` | `bool` | 是否启用实时榜 |
|
|
|
+
|
|
|
+`data.map_summary`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `map_id` | `string` | 地图公开 ID |
|
|
|
+| `display_name` | `string` | 地图名称 |
|
|
|
+| `cover_url` | `string` | 封面图,可空 |
|
|
|
+| `scale_text` | `string` | 比例尺,可空 |
|
|
|
+
|
|
|
+`data.preview_summary`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `control_count` | `int` | 控制点数量 |
|
|
|
+| `route_count` | `int` | 路线数量 |
|
|
|
+| `playfield_kind` | `string` | 场地类型 |
|
|
|
+
|
|
|
+### 3.9 `POST /client/v1/competitions/{competition_id}/registrations`
|
|
|
+
|
|
|
+状态:`已实现,未联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 赛事报名
|
|
|
+
|
|
|
+认证:
|
|
|
+
|
|
|
+- 需要 `access_token`
|
|
|
+
|
|
|
+Path 参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `competition_id` | `string` | 赛事公开 ID |
|
|
|
+
|
|
|
+请求参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `group_id` | `string` | 否 | 队伍或分组 ID |
|
|
|
+| `form_payload` | `object` | 否 | 附加报名表单 |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `registration_id` | `string` | 报名记录 ID |
|
|
|
+| `status` | `string` | 当前报名状态 |
|
|
|
+
|
|
|
+### 3.10 `GET /client/v1/maps`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 地图列表页
|
|
|
+
|
|
|
+查询参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `region_code` | `string` | 否 | 地区编码 |
|
|
|
+| `page` | `int` | 否 | 默认 `1` |
|
|
|
+| `page_size` | `int` | 否 | 默认 `20`,最大 `50` |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+`data.items[]`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `map_id` | `string` | 地图公开 ID |
|
|
|
+| `display_name` | `string` | 地图名称 |
|
|
|
+| `cover_url` | `string` | 封面图,可空 |
|
|
|
+| `scale_text` | `string` | 比例尺,可空 |
|
|
|
+| `distance_from_user_km` | `number` | 距离,可空 |
|
|
|
+
|
|
|
+说明:
|
|
|
+
|
|
|
+- 当前响应只返回 `items`,不回显 `page/page_size/total`
|
|
|
+
|
|
|
+### 3.11 `GET /client/v1/maps/{map_id}`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 地图详情页
|
|
|
+- 同时返回当前地图下允许直入的 Event 列表
|
|
|
+
|
|
|
+Path 参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `map_id` | `string` | 地图公开 ID |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `map_id` | `string` | 地图公开 ID |
|
|
|
+| `display_name` | `string` | 地图名称 |
|
|
|
+
|
|
|
+`data.map_summary`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `cover_url` | `string` | 封面图,可空 |
|
|
|
+| `scale_text` | `string` | 比例尺,可空 |
|
|
|
+| `updated_date` | `string` | 更新时间,可空 |
|
|
|
+
|
|
|
+`data.events[]`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+| `display_name` | `string` | Event 名称 |
|
|
|
+| `preview_image_url` | `string` | 预览图,可空 |
|
|
|
+| `control_count` | `int` | 控制点数量 |
|
|
|
+| `route_count` | `int` | 路线数量 |
|
|
|
+| `direct_entry_enabled` | `bool` | 是否允许地图直入 |
|
|
|
+| `current_release_id` | `string` | 当前发布版 ID |
|
|
|
+| `manifest_url` | `string` | manifest 下载地址 |
|
|
|
+| `manifest_checksum_sha256` | `string` | manifest 校验值 |
|
|
|
+| `playfield_kind` | `string` | 如 `course` |
|
|
|
+
|
|
|
+### 3.12 `GET /client/v1/events`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 地图直入链路下的 Event 列表
|
|
|
+
|
|
|
+查询参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `map_id` | `string` | 否 | 按地图筛选 |
|
|
|
+| `page` | `int` | 否 | 默认 `1` |
|
|
|
+| `page_size` | `int` | 否 | 默认 `20`,最大 `50` |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+`data.items[]`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+| `display_name` | `string` | Event 名称 |
|
|
|
+| `map_id` | `string` | 地图公开 ID |
|
|
|
+| `map_display_name` | `string` | 地图名称 |
|
|
|
+| `preview_image_url` | `string` | 预览图,可空 |
|
|
|
+| `control_count` | `int` | 控制点数量 |
|
|
|
+| `route_count` | `int` | 路线数量 |
|
|
|
+| `direct_entry_enabled` | `bool` | 是否允许地图直入 |
|
|
|
+| `current_release_id` | `string` | 当前发布版 ID |
|
|
|
+| `manifest_url` | `string` | manifest 下载地址 |
|
|
|
+| `manifest_checksum_sha256` | `string` | manifest 校验值 |
|
|
|
+| `playfield_kind` | `string` | 如 `course` |
|
|
|
+
|
|
|
+说明:
|
|
|
+
|
|
|
+- 当前响应只返回 `items`,不回显 `page/page_size/total`
|
|
|
+
|
|
|
+### 3.13 `GET /client/v1/events/{event_id}`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 地图直入上下文下的 Event 详情
|
|
|
+- 与赛事入口页共用同一套 Event 详情视图
|
|
|
+
|
|
|
+Path 参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+| `display_name` | `string` | Event 名称 |
|
|
|
+| `direct_entry_enabled` | `bool` | 是否允许地图直入 |
|
|
|
+| `current_release_id` | `string` | 当前发布版 ID |
|
|
|
+| `manifest_url` | `string` | manifest 下载地址 |
|
|
|
+| `manifest_checksum_sha256` | `string` | manifest 校验值 |
|
|
|
+| `playfield_version_id` | `string` | 场地版本 ID |
|
|
|
+| `playfield_kind` | `string` | 如 `course` |
|
|
|
+
|
|
|
+`data.map_summary`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `map_id` | `string` | 地图公开 ID |
|
|
|
+| `display_name` | `string` | 地图名称 |
|
|
|
+| `cover_url` | `string` | 封面图,可空 |
|
|
|
+| `scale_text` | `string` | 比例尺,可空 |
|
|
|
+
|
|
|
+`data.event_summary`
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `control_count` | `int` | 控制点数量 |
|
|
|
+| `route_count` | `int` | 路线数量 |
|
|
|
+| `playfield_kind` | `string` | 场地类型 |
|
|
|
+
|
|
|
+### 3.14 `POST /client/v1/competitions/{competition_id}/events/{event_id}/launch`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 赛事入口 `launch`
|
|
|
+- 会校验赛事时间窗、报名状态、`release_id`
|
|
|
+- 成功后创建 session,并返回 `session_token`
|
|
|
+
|
|
|
+认证:
|
|
|
+
|
|
|
+- 需要 `access_token`
|
|
|
+
|
|
|
+Path 参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `competition_id` | `string` | 赛事公开 ID |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+
|
|
|
+请求参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `launch_request_id` | `string` | 是 | 启动幂等号 |
|
|
|
+| `device_id` | `string` | 是 | 设备唯一标识 |
|
|
|
+| `client_type` | `string` | 是 | 必须与 `access_token` 内声明一致 |
|
|
|
+| `release_id` | `string` | 是 | 前端当前持有的发布版 ID |
|
|
|
+| `route_code` | `string` | 否 | 当前选中的路线编码 |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `session_id` | `string` | 会话 ID |
|
|
|
+| `session_token` | `string` | 会话 token |
|
|
|
+| `session_token_expires_at` | `string` | 会话 token 过期时间 |
|
|
|
+| `participant_id` | `string` | 参赛身份 ID |
|
|
|
+| `competition_id` | `string` | 赛事公开 ID |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+| `event_release_id` | `string` | 实际冻结的发布版 ID |
|
|
|
+| `playfield_version_id` | `string` | 场地版本 ID |
|
|
|
+| `route_code` | `string` | 当前冻结的路线编码 |
|
|
|
+| `realtime_endpoint` | `string` | realtime-center 地址 |
|
|
|
+| `realtime_token` | `string` | 当前版本通常为空 |
|
|
|
+
|
|
|
+当前注意:
|
|
|
+
|
|
|
+- 若前端传入的 `release_id` 已过期,会返回 `EVENT_RELEASE_STALE`
|
|
|
+- 当前后端会冻结并回传 `route_code`,但还没有对 manifest 内路线做严格校验
|
|
|
+
|
|
|
+### 3.15 `POST /client/v1/events/{event_id}/launch`
|
|
|
+
|
|
|
+状态:`已实现,已联调`
|
|
|
+
|
|
|
+接口介绍:
|
|
|
+
|
|
|
+- 地图直入 `launch`
|
|
|
+- 不校验赛事报名资格
|
|
|
+- 成功后创建 session,并返回 `session_token`
|
|
|
+
|
|
|
+认证:
|
|
|
+
|
|
|
+- 需要 `access_token`
|
|
|
+
|
|
|
+Path 参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+
|
|
|
+请求参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+| --- | --- | --- | --- |
|
|
|
+| `launch_request_id` | `string` | 是 | 启动幂等号 |
|
|
|
+| `device_id` | `string` | 是 | 设备唯一标识 |
|
|
|
+| `client_type` | `string` | 是 | 必须与 `access_token` 内声明一致 |
|
|
|
+| `release_id` | `string` | 是 | 前端当前持有的发布版 ID |
|
|
|
+| `route_code` | `string` | 否 | 当前选中的路线编码 |
|
|
|
+
|
|
|
+返回参数:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+| --- | --- | --- |
|
|
|
+| `session_id` | `string` | 会话 ID |
|
|
|
+| `session_token` | `string` | 会话 token |
|
|
|
+| `session_token_expires_at` | `string` | 会话 token 过期时间 |
|
|
|
+| `participant_id` | `string` | 参赛身份 ID |
|
|
|
+| `event_id` | `string` | Event 公开 ID |
|
|
|
+| `event_release_id` | `string` | 实际冻结的发布版 ID |
|
|
|
+| `playfield_version_id` | `string` | 场地版本 ID |
|
|
|
+| `route_code` | `string` | 当前冻结的路线编码 |
|
|
|
+| `realtime_endpoint` | `string` | realtime-center 地址 |
|
|
|
+| `realtime_token` | `string` | 当前版本通常为空 |
|
|
|
+
|
|
|
+当前注意:
|
|
|
+
|
|
|
+- 若前端传入的 `release_id` 已过期,会返回 `EVENT_RELEASE_STALE`
|
|
|
+- 当前后端会冻结并回传 `route_code`,但还没有对 manifest 内路线做严格校验
|
|
|
+
|
|
|
+## 4. 预留未就绪接口
|
|
|
+
|
|
|
+以下接口当前在路由中已占位,但实际会直接返回 `not implemented`:
|
|
|
+
|
|
|
+| 接口 | 当前错误码 |
|
|
|
+| --- | --- |
|
|
|
+| `POST /client/v1/session-uploads` | `session_upload_not_ready` |
|
|
|
+| `POST /client/v1/punches` | `session_punch_not_ready` |
|
|
|
+| `POST /client/v1/sessions/{session_id}/finish` | `session_finish_not_ready` |
|
|
|
+| `GET /client/v1/sessions/{session_id}/result` | `session_result_not_ready` |
|
|
|
+| `GET /client/v1/sessions/{session_id}/replay-summary` | `session_replay_summary_not_ready` |
|
|
|
+| `GET /client/v1/sessions/{session_id}/gps-track` | `session_gps_track_not_ready` |
|
|
|
+| `GET /client/v1/sessions/{session_id}/heart-rate` | `session_heart_rate_not_ready` |
|
|
|
+| `GET /client/v1/me/sessions` | `session_history_not_ready` |
|
|
|
+
|
|
|
+说明:
|
|
|
+
|
|
|
+- 所以当前不是“只有 GPS / 心率上报没测”
|
|
|
+- 而是整条 `session` 下游链路都还没开放
|
|
|
+- 当前已实测闭环停在 `launch` 成功返回 `session_token`
|
|
|
+
|
|
|
+## 5. 当前测试数据
|
|
|
+
|
|
|
+以下数据可直接用于本地联调:
|
|
|
+
|
|
|
+| 类型 | ID |
|
|
|
+| --- | --- |
|
|
|
+| `card_id` | `crd_classic_demo_001` |
|
|
|
+| `competition_id` | `cmp_classic_demo_001` |
|
|
|
+| `map_id` | `lxcb-001` |
|
|
|
+| `event_id` | `sample-classic-001` |
|
|
|
+| `release_id` | `sample-classic-001-rel-1` |
|
|
|
+| `route_code` | `classic-001` |
|
|
|
+
|
|
|
+说明:
|
|
|
+
|
|
|
+- 已存在测试赛事卡片、地图、Event、manifest 绑定关系
|
|
|
+- 已存在一个已批准报名的测试用户,可直接验证赛事入口 `launch`
|