# 幸运礼物 Flutter 对接 本文只保留 App 对接需要的信息:地址、参数、返回值、IM 字段。服务端实现细节看 [幸运礼物实现文档](../幸运礼物实现文档.md),礼物面板通用字段看 [礼物 Tab Flutter 对接](礼物TabFlutter对接.md)。 ## 1. 送礼前检查 地址: ```http POST /api/v1/activities/lucky-gifts/check Authorization: Bearer X-App-Code: lalu Content-Type: application/json ``` 请求参数: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `room_id` | string | 是 | 当前房间 ID。 | | `gift_id` | string | 是 | 礼物 ID。 | | `pool_id` | string | 是 | 幸运礼物奖池 ID,例如 `lucky`、`super_lucky` 或后台配置值。 | 请求示例: ```json { "room_id": "lalu_room_001", "gift_id": "rose", "pool_id": "super_lucky" } ``` 返回值: | 字段 | 类型 | 说明 | | --- | --- | --- | | `enabled` | bool | 是否可参与幸运礼物抽奖。 | | `reason` | string | 不可参与原因;可为空。 | | `room_id` | string | 房间 ID。 | | `gift_id` | string | 礼物 ID。 | | `pool_id` | string | 奖池 ID。 | | `gift_price` | int64 | 当前规则参考礼物价格,只展示用,扣费以后端送礼结果为准。 | | `rule_version` | int64 | 命中的幸运礼物规则版本。 | | `target_rtp_ppm` | int64 | 目标 RTP,ppm 口径;`950000` 表示 95%。 | | `experience_pool` | string | 当前用户体验池,例如 `novice`、`normal`、`advanced`。 | 返回示例: ```json { "code": "OK", "message": "ok", "request_id": "req_abc", "data": { "enabled": true, "reason": "", "room_id": "lalu_room_001", "gift_id": "rose", "pool_id": "super_lucky", "gift_price": 100, "rule_version": 12, "target_rtp_ppm": 950000, "experience_pool": "novice" } } ``` ## 2. 发送幸运礼物 地址: ```http POST /api/v1/rooms/gift/send Authorization: Bearer X-App-Code: lalu Content-Type: application/json ``` 请求参数: | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | `room_id` | string | 是 | 当前房间 ID。 | | `command_id` | string | 是 | 本次送礼幂等键;同一次重试必须复用。 | | `target_type` | string | 否 | 当前固定传 `user`;为空后端按 `user`。 | | `target_user_ids` | int64[] | 是 | 收礼用户列表;当前只传 1 个用户。 | | `target_user_id` | int64 | 否 | 旧单目标兼容字段,新代码优先用 `target_user_ids`。 | | `gift_id` | string | 是 | 礼物 ID。 | | `gift_count` | int32 | 是 | 礼物数量,必须大于 0;批量送礼会聚合返回一次中奖结果。 | | `pool_id` | string | 是 | 幸运礼物奖池 ID;普通礼物不传。 | 请求示例: ```json { "room_id": "lalu_room_001", "command_id": "gift_1779259000000_10001_rose_01", "target_type": "user", "target_user_ids": [10002], "gift_id": "rose", "gift_count": 9, "pool_id": "super_lucky" } ``` 返回值: | 字段 | 类型 | 说明 | | --- | --- | --- | | `result.applied` | bool | 本次命令是否实际落地;重复提交同一 `command_id` 可能为 `false`。 | | `result.room_version` | int64 | 房间版本。 | | `result.server_time_ms` | int64 | 服务端时间。 | | `billing_receipt_id` | string | 送礼扣费回执。 | | `room_heat` | int64 | 送礼后的房间热度。 | | `gift_rank` | array | 当前房间礼物榜。 | | `room` | object | 房间快照。 | | `rocket` | object | 房间火箭状态。 | | `lucky_gift` | object | 幸运礼物抽奖结果;普通礼物可为空。 | `lucky_gift` 返回字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `enabled` | bool | 本次是否触发幸运礼物。 | | `draw_id` | string | 聚合抽奖 ID。 | | `command_id` | string | 本次送礼命令 ID。 | | `pool_id` | string | 奖池 ID。 | | `gift_id` | string | 礼物 ID。 | | `rule_version` | int64 | 规则版本。 | | `experience_pool` | string | 用户体验池。 | | `selected_tier_id` | string | 命中奖档 ID。 | | `multiplier_ppm` | int64 | 倍率 ppm;`2000000` 表示 2x。 | | `base_reward_coins` | int64 | 基础奖池返奖金币。 | | `room_atmosphere_reward_coins` | int64 | 房间气氛池返奖金币。 | | `activity_subsidy_coins` | int64 | 活动补贴返奖金币。 | | `effective_reward_coins` | int64 | 实际中奖金币;0 表示未中奖。 | | `reward_status` | string | `granted` 已入账;`pending`/`granting` 到账处理中;`failed` 需要人工处理。 | | `stage_feedback` | bool | 是否有阶段反馈表现。 | | `high_multiplier` | bool | 是否高倍率中奖。 | | `created_at_ms` | int64 | 抽奖创建时间。 | | `wallet_transaction_id` | string | 返奖钱包交易 ID;已入账时有值。 | | `coin_balance_after` | int64 | 返奖入账后的 COIN 可用余额。 | 返回示例: ```json { "code": "OK", "message": "ok", "request_id": "req_abc", "data": { "result": { "applied": true, "room_version": 14, "server_time_ms": 1779259000000 }, "billing_receipt_id": "receipt-lucky", "room_heat": 123456, "gift_rank": [], "room": {}, "rocket": {}, "lucky_gift": { "enabled": true, "draw_id": "lucky_draw_test", "command_id": "gift_1779259000000_10001_rose_01", "pool_id": "super_lucky", "gift_id": "rose", "rule_version": 12, "experience_pool": "novice", "selected_tier_id": "novice_2x", "multiplier_ppm": 2000000, "base_reward_coins": 1800, "room_atmosphere_reward_coins": 0, "activity_subsidy_coins": 0, "effective_reward_coins": 1800, "reward_status": "granted", "stage_feedback": false, "high_multiplier": false, "created_at_ms": 1779259000000, "wallet_transaction_id": "wallet_tx_lucky", "coin_balance_after": 8800 } } } ``` 客户端处理: - `reward_status=granted` 且 `effective_reward_coins > 0`:立即展示中奖,并用 `coin_balance_after` 覆盖本地金币余额。 - `reward_status=pending` 或 `granting`:展示“到账处理中”,不要本地加金币,不要生成新 `command_id` 重发。 - `effective_reward_coins=0`:未中奖,只展示普通送礼表现。 - 同一用户同一房间连续发送幸运礼物时,客户端需要本地排队;重试必须复用原 `command_id`。 ## 3. IM 字段 ### 3.1 送礼房间 IM 用途:房间内播放普通送礼动效、同步热度和礼物榜。幸运礼物也会先产生这条送礼 IM。 | 字段 | 值 | | --- | --- | | `MsgContent.Desc` | `room_gift_sent` | | `Data.event_type` | `room_gift_sent` | `Data` 核心字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `event_id` | string | 房间事件 ID,用于去重。 | | `room_id` | string | 房间 ID。 | | `room_version` | int64 | 房间版本。 | | `occurred_at_ms` | int64 | 事件发生时间。 | | `actor_user_id` | string/int64 | 送礼用户 ID。 | | `target_user_id` | string/int64 | 收礼用户 ID。 | | `gift_value` | int64 | 本次送礼房间价值/热度口径。 | | `room_heat` | int64 | 送礼后的房间热度。 | | `attributes.gift_id` | string | 礼物 ID。 | | `attributes.pool_id` | string | 幸运礼物奖池 ID;普通礼物可为空。 | | `attributes.gift_count` | string | 礼物数量,字符串格式。 | | `attributes.billing_receipt_id` | string | 钱包扣费回执。 | | `attributes.coin_spent` | string | 本次实际消耗金币,字符串格式。 | | `attributes.gift_point_added` | string | 主播礼物积分增量,字符串格式。 | | `attributes.price_version` | string | 价格版本。 | 示例: ```json { "event_type": "room_gift_sent", "event_id": "room_event_xxx", "room_id": "lalu_room_001", "room_version": 14, "occurred_at_ms": 1779259000000, "actor_user_id": "10001", "target_user_id": "10002", "gift_value": 900, "room_heat": 123456, "attributes": { "gift_id": "rose", "pool_id": "super_lucky", "gift_count": "9", "billing_receipt_id": "receipt-lucky", "coin_spent": "900", "gift_point_added": "900", "price_version": "v1" } } ``` ### 3.2 幸运礼物开奖 IM 用途:房间公屏展示幸运礼物中奖结果、其他用户同步中奖表现。当前用户自己的余额以 HTTP 返回的 `coin_balance_after` 为准,不等这条 IM。 | 字段 | 值 | | --- | --- | | `MsgContent.Desc` | `lucky_gift_drawn` | | `Data.event_type` | `lucky_gift_drawn` | `Data` 核心字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `event_id` | string | 开奖事件 ID,用于去重。 | | `app_code` | string | App Code。 | | `draw_id` | string | 聚合抽奖 ID。 | | `command_id` | string | 送礼命令 ID。 | | `pool_id` | string | 奖池 ID。 | | `room_id` | string | 房间 ID。 | | `gift_id` | string | 礼物 ID。 | | `gift_count` | int32 | 礼物数量。 | | `user_id` | int64 | 中奖用户 ID。 | | `sender_user_id` | int64 | 送礼用户 ID。 | | `target_user_id` | int64 | 收礼用户 ID。 | | `visible_region_id` | int64 | 展示区域 ID。 | | `coin_spent` | int64 | 本次送礼消耗金币。 | | `rule_version` | int64 | 规则版本。 | | `experience_pool` | string | 用户体验池。 | | `selected_tier_id` | string | 命中奖档 ID。 | | `multiplier_ppm` | int64 | 命中倍率 ppm。 | | `base_reward_coins` | int64 | 基础奖池返奖金币。 | | `room_atmosphere_reward_coins` | int64 | 房间气氛池返奖金币。 | | `activity_subsidy_coins` | int64 | 活动补贴返奖金币。 | | `effective_reward_coins` | int64 | 实际中奖金币。 | | `stage_feedback` | bool | 是否有阶段反馈表现。 | | `high_multiplier` | bool | 是否高倍率中奖。 | | `created_at_ms` | int64 | 抽奖创建时间。 | 示例: ```json { "event_type": "lucky_gift_drawn", "event_id": "lucky_gift_drawn:lucky_draw_test", "app_code": "lalu", "draw_id": "lucky_draw_test", "command_id": "gift_1779259000000_10001_rose_01", "pool_id": "super_lucky", "room_id": "lalu_room_001", "gift_id": "rose", "gift_count": 9, "user_id": 10001, "sender_user_id": 10001, "target_user_id": 10002, "visible_region_id": 688, "coin_spent": 900, "rule_version": 12, "experience_pool": "novice", "selected_tier_id": "novice_2x", "multiplier_ppm": 2000000, "base_reward_coins": 1800, "room_atmosphere_reward_coins": 0, "activity_subsidy_coins": 0, "effective_reward_coins": 1800, "stage_feedback": false, "high_multiplier": false, "created_at_ms": 1779259000000 } ``` ## 4. 状态处理 | 场景 | App 处理 | | --- | --- | | `lucky_gift` 为空 | 当普通礼物处理。 | | `effective_reward_coins=0` | 未中奖,不更新中奖余额。 | | `reward_status=granted` | 已入账;用 `coin_balance_after` 更新余额。 | | `reward_status=pending` / `granting` | 到账处理中;等待钱包通知、刷新余额或后端补偿。 | | `reward_status=failed` | 展示异常状态,记录 `request_id/draw_id/command_id` 方便排查。 | | HTTP 超时 | 保留原 `command_id` 重试,不生成新命令。 |