358 lines
10 KiB
Markdown
358 lines
10 KiB
Markdown
# 成就徽章 Flutter 对接
|
||
|
||
## 地址
|
||
|
||
Base URL:
|
||
|
||
```text
|
||
https://<gateway-host>
|
||
```
|
||
|
||
本地开发:
|
||
|
||
```text
|
||
http://127.0.0.1:13000
|
||
```
|
||
|
||
| 功能 | Method | Path |
|
||
| --- | --- | --- |
|
||
| 我的成就列表 | `GET` | `/api/v1/achievements` |
|
||
| 我的徽章展示 | `GET` | `/api/v1/badges/me` |
|
||
| 设置方形徽章展示槽 | `POST` | `/api/v1/badges/display` |
|
||
|
||
## 通用请求
|
||
|
||
Headers:
|
||
|
||
| Header | 必填 | 说明 |
|
||
| --- | --- | --- |
|
||
| `Authorization` | 是 | `Bearer <access_token>` |
|
||
| `Content-Type` | POST 必填 | `application/json` |
|
||
| `X-App-Code` | 否 | App 编码,默认 `lalu` |
|
||
| `X-App-Package` | 否 | 包名解析 App 时使用 |
|
||
| `X-App-Platform` | 否 | `android` / `ios` |
|
||
|
||
统一返回:
|
||
|
||
```json
|
||
{
|
||
"code": "OK",
|
||
"message": "ok",
|
||
"request_id": "req_xxx",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
失败返回:
|
||
|
||
```json
|
||
{
|
||
"code": "INVALID_ARGUMENT",
|
||
"message": "invalid argument",
|
||
"request_id": "req_xxx"
|
||
}
|
||
```
|
||
|
||
## 请求参数
|
||
|
||
### `GET /api/v1/achievements`
|
||
|
||
Query:
|
||
|
||
| 字段 | 必填 | 默认 | 说明 |
|
||
| --- | --- | --- | --- |
|
||
| `collection_type` | 否 | 全部 | 普通成就传 `ordinary` |
|
||
| `collection_id` | 否 | 全部 | 成就集合 ID |
|
||
| `page` | 否 | `1` | 页码,从 1 开始 |
|
||
| `page_size` | 否 | `20` | 每页数量 |
|
||
|
||
### `GET /api/v1/badges/me`
|
||
|
||
无 query。
|
||
|
||
### `POST /api/v1/badges/display`
|
||
|
||
Body:
|
||
|
||
```json
|
||
{
|
||
"slot": "profile_tile",
|
||
"command_id": "cmd_badge_display_1710000000000",
|
||
"items": [
|
||
{
|
||
"position": 1,
|
||
"resource_id": 8001,
|
||
"entitlement_id": "ent_xxx"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
| 字段 | 必填 | 说明 |
|
||
| --- | --- | --- |
|
||
| `slot` | 是 | 当前只允许 `profile_tile` |
|
||
| `command_id` | 是 | 客户端本次操作幂等 ID;同一次重试使用同一个值 |
|
||
| `items` | 是 | 展示槽完整替换;最多 6 个 |
|
||
| `items[].position` | 否 | 从 1 开始;不传按数组顺序生成 |
|
||
| `items[].resource_id` | 是 | 必须来自用户已获得的可展示徽章 |
|
||
| `items[].entitlement_id` | 否 | 有则透传 |
|
||
|
||
## 返回值
|
||
|
||
以下 JSON 均为统一 envelope 的 `data`。
|
||
|
||
### 我的成就列表
|
||
|
||
```json
|
||
{
|
||
"achievements": [
|
||
{
|
||
"definition": {
|
||
"achievement_id": "ach_first_gift",
|
||
"collection_id": "ordinary",
|
||
"collection_type": "ordinary",
|
||
"achievement_type": "ordinary",
|
||
"title": "First Gift",
|
||
"description": "",
|
||
"status": "active",
|
||
"version": 1,
|
||
"primary_badge_resource_id": 8001,
|
||
"primary_badge_resource": {
|
||
"resource_id": 8001,
|
||
"resource_code": "badge_first_gift",
|
||
"resource_type": "badge",
|
||
"name": "First Gift",
|
||
"status": "active",
|
||
"grantable": true,
|
||
"grant_strategy": "new_entitlement",
|
||
"usage_scopes": ["badge"],
|
||
"asset_url": "https://cdn.example/badge.png",
|
||
"preview_url": "",
|
||
"animation_url": "",
|
||
"metadata_json": "{\"badge_form\":\"tile\"}",
|
||
"sort_order": 10,
|
||
"created_at_ms": 1710000000000,
|
||
"updated_at_ms": 1710000000000
|
||
},
|
||
"reward_resource_group_id": 9001,
|
||
"reward_resource_group": {
|
||
"group_id": 9001,
|
||
"group_code": "ach_first_gift_reward",
|
||
"name": "First Gift Reward",
|
||
"status": "active",
|
||
"description": "",
|
||
"sort_order": 10,
|
||
"items": [
|
||
{
|
||
"group_item_id": 1,
|
||
"item_type": "resource",
|
||
"resource_id": 8001,
|
||
"resource": {
|
||
"resource_id": 8001,
|
||
"resource_code": "badge_first_gift",
|
||
"resource_type": "badge",
|
||
"name": "First Gift",
|
||
"status": "active",
|
||
"grantable": true,
|
||
"grant_strategy": "new_entitlement",
|
||
"usage_scopes": ["badge"],
|
||
"asset_url": "https://cdn.example/badge.png",
|
||
"preview_url": "",
|
||
"animation_url": "",
|
||
"metadata_json": "{\"badge_form\":\"tile\"}",
|
||
"sort_order": 10,
|
||
"created_at_ms": 1710000000000,
|
||
"updated_at_ms": 1710000000000
|
||
},
|
||
"quantity": 1,
|
||
"duration_ms": 0,
|
||
"sort_order": 10
|
||
}
|
||
],
|
||
"created_at_ms": 1710000000000,
|
||
"updated_at_ms": 1710000000000
|
||
},
|
||
"auto_pin_policy": "if_empty",
|
||
"honor_visibility": true,
|
||
"effective_from_ms": 0,
|
||
"effective_to_ms": 0,
|
||
"sort_order": 10,
|
||
"display_config_json": "{}",
|
||
"conditions": [
|
||
{
|
||
"condition_id": "cond_xxx",
|
||
"achievement_id": "ach_first_gift",
|
||
"version": 1,
|
||
"metric_type": "send_gift_count",
|
||
"target_value": 1,
|
||
"target_unit": "count",
|
||
"dimension_filter_json": "{}"
|
||
}
|
||
],
|
||
"created_by_admin_id": 1,
|
||
"updated_by_admin_id": 1,
|
||
"created_at_ms": 1710000000000,
|
||
"updated_at_ms": 1710000000000
|
||
},
|
||
"cycle_key": "lifetime",
|
||
"progress_value": 1,
|
||
"target_value": 1,
|
||
"user_status": "unlocked",
|
||
"unlocked_at_ms": 1710000000000,
|
||
"reward_status": "granted"
|
||
}
|
||
],
|
||
"total": 1,
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"server_time_ms": 1710000000000
|
||
}
|
||
```
|
||
|
||
字段值:
|
||
|
||
| 字段 | 值 |
|
||
| --- | --- |
|
||
| `achievement_type` | `ordinary` / `activity_limited` |
|
||
| `collection_type` | `ordinary` |
|
||
| `user_status` | 空字符串表示未完成;`unlocked` 表示已达成 |
|
||
| `reward_status` | 空字符串 / `pending` / `running` / `granted` / `failed` |
|
||
| `auto_pin_policy` | `none` / `if_empty` / `always` |
|
||
| `primary_badge_resource` | 成就主徽章素材,可直接渲染 |
|
||
| `reward_resource_group.items[].resource` | 成就奖励资源素材,可直接渲染 |
|
||
|
||
### 我的徽章展示
|
||
|
||
```json
|
||
{
|
||
"strip_badges": [
|
||
{
|
||
"slot": "profile_strip",
|
||
"position": 1,
|
||
"badge_form": "strip",
|
||
"resource_id": 8101,
|
||
"resource": {
|
||
"resource_id": 8101,
|
||
"resource_code": "vip_gold_strip",
|
||
"resource_type": "badge",
|
||
"name": "VIP Gold",
|
||
"status": "active",
|
||
"grantable": true,
|
||
"grant_strategy": "new_entitlement",
|
||
"usage_scopes": ["badge"],
|
||
"asset_url": "https://cdn.example/vip-strip.png",
|
||
"preview_url": "",
|
||
"animation_url": "",
|
||
"metadata_json": "{\"badge_form\":\"strip\"}",
|
||
"sort_order": 10,
|
||
"created_at_ms": 1710000000000,
|
||
"updated_at_ms": 1710000000000
|
||
},
|
||
"entitlement_id": "ent_strip_1",
|
||
"source_type": "vip",
|
||
"source_id": "vip_gold",
|
||
"pin_mode": "system",
|
||
"updated_at_ms": 1710000000000
|
||
}
|
||
],
|
||
"profile_tile_badges": [
|
||
{
|
||
"slot": "profile_tile",
|
||
"position": 1,
|
||
"badge_form": "tile",
|
||
"resource_id": 8001,
|
||
"resource": {
|
||
"resource_id": 8001,
|
||
"resource_code": "badge_first_gift",
|
||
"resource_type": "badge",
|
||
"name": "First Gift",
|
||
"status": "active",
|
||
"grantable": true,
|
||
"grant_strategy": "new_entitlement",
|
||
"usage_scopes": ["badge"],
|
||
"asset_url": "https://cdn.example/badge.png",
|
||
"preview_url": "",
|
||
"animation_url": "",
|
||
"metadata_json": "{\"badge_form\":\"tile\"}",
|
||
"sort_order": 10,
|
||
"created_at_ms": 1710000000000,
|
||
"updated_at_ms": 1710000000000
|
||
},
|
||
"entitlement_id": "ent_tile_1",
|
||
"source_type": "achievement",
|
||
"source_id": "ach_first_gift",
|
||
"pin_mode": "user",
|
||
"updated_at_ms": 1710000000000
|
||
}
|
||
],
|
||
"honor_badges": [
|
||
{
|
||
"slot": "honor_wall",
|
||
"position": 1,
|
||
"badge_form": "tile",
|
||
"resource_id": 8001,
|
||
"resource": {
|
||
"resource_id": 8001,
|
||
"resource_code": "badge_first_gift",
|
||
"resource_type": "badge",
|
||
"name": "First Gift",
|
||
"status": "active",
|
||
"grantable": true,
|
||
"grant_strategy": "new_entitlement",
|
||
"usage_scopes": ["badge"],
|
||
"asset_url": "https://cdn.example/badge.png",
|
||
"preview_url": "",
|
||
"animation_url": "",
|
||
"metadata_json": "{\"badge_form\":\"tile\"}",
|
||
"sort_order": 10,
|
||
"created_at_ms": 1710000000000,
|
||
"updated_at_ms": 1710000000000
|
||
},
|
||
"entitlement_id": "ent_tile_1",
|
||
"source_type": "achievement",
|
||
"source_id": "ach_first_gift",
|
||
"pin_mode": "auto",
|
||
"updated_at_ms": 1710000000000
|
||
}
|
||
],
|
||
"server_time_ms": 1710000000000
|
||
}
|
||
```
|
||
|
||
字段值:
|
||
|
||
| 字段 | 说明 |
|
||
| --- | --- |
|
||
| `strip_badges` | 长徽章;身份、等级、VIP 等系统展示 |
|
||
| `profile_tile_badges` | 用户主页方形展示槽;用户可通过 `POST /badges/display` 调整 |
|
||
| `honor_badges` | 荣誉墙方形徽章;成就或系统赠送 |
|
||
| `badge_form` | `strip` 长徽章 / `tile` 方形徽章 |
|
||
| `slot` | `profile_strip` / `profile_tile` / `honor_wall` |
|
||
| `source_type` | `achievement` / `system_grant` / `level` / `vip` / `identity` |
|
||
| `resource` | 徽章素材,可直接渲染 |
|
||
|
||
## 错误处理
|
||
|
||
| HTTP | code | 处理 |
|
||
| --- | --- | --- |
|
||
| `200` | `OK` | 读取 `data` |
|
||
| `400` | `INVALID_JSON` | 请求体不是合法 JSON |
|
||
| `400` | `INVALID_ARGUMENT` | 参数错误;不自动重试 |
|
||
| `401` | `UNAUTHORIZED` | 刷新 token;失败则重新登录 |
|
||
| `403` | `PROFILE_REQUIRED` | 跳转资料补全 |
|
||
| `403` | `PERMISSION_DENIED` | 停止当前操作 |
|
||
| `404` | `NOT_FOUND` | 资源不存在或徽章不可展示 |
|
||
| `429` | `RATE_LIMITED` | 延迟重试 |
|
||
| `500` | `INTERNAL_ERROR` | 提示重试,记录 `request_id` |
|
||
| `502` | `UPSTREAM_ERROR` | 提示重试,记录 `request_id` |
|
||
|
||
`POST /api/v1/badges/display`:
|
||
|
||
| 场景 | 处理 |
|
||
| --- | --- |
|
||
| 网络超时 | 使用同一个 `command_id` 重试 |
|
||
| 用户重新调整排序 | 生成新的 `command_id` |
|
||
| `NOT_FOUND` | 当前用户未获得该 `resource_id` 对应徽章,刷新 `/api/v1/badges/me` |
|
||
| `INVALID_ARGUMENT` | 检查 `slot`、`items.length <= 6`、`resource_id > 0`、重复 `resource_id` |
|
||
|