5.6 KiB
5.6 KiB
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。 |
示例:
GET /api/v1/users/me/gift-wall
Authorization: Bearer <access_token>
X-App-Code: lalu
GET /api/v1/users/10002/gift-wall
Authorization: Bearer <access_token>
X-App-Code: lalu
成功响应:
{
"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 解析示例
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 写入客户端日志。