hyapp-server/docs/flutter对接/礼物墙Flutter对接.md
2026-06-11 17:11:59 +08:00

170 lines
5.6 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.

# Flutter 礼物墙对接
本文描述 Flutter App 查询用户礼物墙的 HTTP 接口。礼物墙事实由 `wallet-service` 在送礼扣费成功后通过异步投影聚合,客户端只展示 gateway 返回的当前投影,不从房间消息或本地缓存推算收礼数量。
## 接口
`GET /api/v1/users/me/gift-wall`
`GET /api/v1/users/{user_id}/gift-wall`
登录接口,需要 `Authorization: Bearer <access_token>`
- `GET /api/v1/users/me/gift-wall` 查询当前登录用户。
- `GET /api/v1/users/{user_id}/gift-wall` 查询资料卡目标用户,`user_id` 是路径参数,必须是正整数。
一致性边界:礼物墙是最终一致读模型,送礼成功后允许延迟数秒到几十秒才出现在接口结果中。客户端不要用该接口判断刚刚送礼是否成功;送礼成功状态仍以送礼接口响应和房间 IM 消息为准。
请求头:
| Header | 必填 | 说明 |
| --- | --- | --- |
| `Authorization` | 是 | App 登录 access token。 |
| `X-App-Code` | 否 | App 编码,默认 `lalu`。 |
示例:
```http
GET /api/v1/users/me/gift-wall
Authorization: Bearer <access_token>
X-App-Code: lalu
```
```http
GET /api/v1/users/10002/gift-wall
Authorization: Bearer <access_token>
X-App-Code: lalu
```
成功响应:
```json
{
"code": "OK",
"message": "ok",
"request_id": "req_abc",
"data": {
"items": [
{
"gift_id": "rose",
"gift_name": "Rose",
"resource_id": 11,
"resource": {
"resource_id": 11,
"resource_code": "gift_rose",
"resource_type": "gift",
"name": "Rose",
"status": "active",
"grantable": true,
"grant_strategy": "increase_quantity",
"usage_scopes": ["gift"],
"asset_url": "https://cdn.example/rose.png",
"preview_url": "",
"animation_url": "",
"metadata_json": "{}",
"sort_order": 10,
"created_at_ms": 1710000000000,
"updated_at_ms": 1710000000000
},
"resource_snapshot_json": "{\"ResourceID\":11}",
"gift_type_code": "normal",
"presentation_json": "{}",
"gift_count": 5,
"total_value": 50,
"total_coin_value": 50,
"total_diamond_value": 0,
"total_gift_point": 50,
"total_heat_value": 50,
"charge_asset_type": "COIN",
"last_price_version": "v1",
"first_received_at_ms": 1710000000000,
"last_received_at_ms": 1710000005000,
"sort_order": 10
}
],
"gift_kind_count": 1,
"gift_total_count": 5,
"total_value": 50,
"total_coin_value": 50,
"total_diamond_value": 0,
"total_gift_point": 50,
"total_heat_value": 50
}
}
```
字段规则:
| 字段 | 说明 |
| --- | --- |
| `items` | 按 `gift_id` 聚合后的礼物列表,固定按后台礼物排序、价值和最近收礼时间排序。 |
| `gift_count` | 当前用户收到该礼物的累计个数。 |
| `gift_kind_count` | 当前用户收到过的礼物种类数,等于 `items.length`。 |
| `gift_total_count` | 当前用户收到的所有礼物数量总和。 |
| `total_value` | 礼物总价值,按送礼时服务端结算的 `charge_amount` 累加。 |
| `total_coin_value` / `total_diamond_value` | 按收费资产拆分的总价值;当前普通礼物通常只读 `total_coin_value`。 |
| `total_gift_point` | 主播礼物积分累计值,不等同于可提现余额。 |
| `total_heat_value` | 房间热度累计值,可用于展示贡献热度,不要反推价格。 |
| `charge_asset_type` | 该礼物历史上只用一种资产收费时为 `COIN``DIAMOND`;发生过资产切换时为 `MIXED`。 |
| `resource` | 礼物展示资源快照,客户端优先用 `asset_url` / `preview_url` / `animation_url` 渲染。 |
| `resource_snapshot_json` | 原始资源快照 JSON主要用于客户端兜底和日志排查。 |
| `*_ms` | Unix epoch milliseconds展示层按用户本地时区格式化。 |
## Flutter 解析示例
```dart
class GiftWall {
GiftWall({
required this.items,
required this.giftKindCount,
required this.giftTotalCount,
required this.totalValue,
});
final List<GiftWallItem> items;
final int giftKindCount;
final int giftTotalCount;
final int totalValue;
factory GiftWall.fromJson(Map<String, dynamic> json) {
return GiftWall(
items: (json['items'] as List<dynamic>? ?? const [])
.map((item) => GiftWallItem.fromJson(item as Map<String, dynamic>))
.toList(),
giftKindCount: (json['gift_kind_count'] as num?)?.toInt() ?? 0,
giftTotalCount: (json['gift_total_count'] as num?)?.toInt() ?? 0,
totalValue: (json['total_value'] as num?)?.toInt() ?? 0,
);
}
}
class GiftWallItem {
GiftWallItem({
required this.giftId,
required this.giftName,
required this.giftCount,
required this.totalValue,
required this.assetUrl,
});
final String giftId;
final String giftName;
final int giftCount;
final int totalValue;
final String assetUrl;
factory GiftWallItem.fromJson(Map<String, dynamic> json) {
final resource = json['resource'] as Map<String, dynamic>? ?? const {};
return GiftWallItem(
giftId: json['gift_id'] as String? ?? '',
giftName: json['gift_name'] as String? ?? '',
giftCount: (json['gift_count'] as num?)?.toInt() ?? 0,
totalValue: (json['total_value'] as num?)?.toInt() ?? 0,
assetUrl: resource['asset_url'] as String? ?? '',
);
}
}
```
调用时先解析外层 envelope只有 `code == "OK"` 时读取 `data`;其他错误按统一网关错误处理,并把 `request_id` 写入客户端日志。