# 成就徽章 Flutter 对接 ## 地址 Base URL: ```text https:// ``` 本地开发: ```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 ` | | `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` |