zhibo/模块文档/17-礼物打赏模块.md
2025-12-30 11:11:11 +08:00

12 KiB
Raw Blame History

礼物打赏模块

模块概述

礼物打赏模块负责处理直播间内的虚拟礼物赠送功能,包括礼物列表、用户余额、礼物赠送、充值等功能。

相关文件

  • RoomDetailActivity.java - 直播间详情(礼物赠送)
  • Gift.java - 礼物模型
  • GiftAdapter.java - 礼物列表适配器
  • GiftResponse.java - 礼物响应模型
  • SendGiftRequest.java - 赠送礼物请求模型
  • SendGiftResponse.java - 赠送礼物响应模型
  • UserBalanceResponse.java - 用户余额响应模型
  • RechargeOption.java - 充值选项模型
  • RechargeAdapter.java - 充值选项适配器

接口列表

1. 获取礼物列表

接口地址: GET /api/front/gift/list

请求参数: 无

返回数据:

{
  "code": 200,
  "msg": "success",
  "data": [
    {
      "id": "integer",         // 礼物ID
      "name": "string",        // 礼物名称
      "price": "integer",      // 礼物价格(金币)
      "icon": "string",        // 礼物图标URL
      "level": "integer",      // 礼物等级1-5
      "description": "string", // 礼物描述
      "animation": "string",   // 动画效果URL
      "sort": "integer"        // 排序
    }
  ]
}

2. 获取用户余额

接口地址: GET /api/front/gift/balance

请求参数: 无

返回数据 (UserBalanceResponse):

{
  "code": 200,
  "msg": "success",
  "data": {
    "userId": "integer",       // 用户ID
    "coinBalance": "integer",  // 金币余额
    "totalRecharge": "integer",// 累计充值金币
    "totalConsume": "integer", // 累计消费金币
    "vipLevel": "integer"      // VIP等级
  }
}

3. 赠送礼物

接口地址: POST /api/front/gift/send

请求参数 (SendGiftRequest):

{
  "giftId": "integer",       // 礼物ID必填
  "receiverId": "integer",   // 接收者ID必填
  "roomId": "string",        // 直播间ID必填
  "count": "integer",        // 赠送数量(必填)
  "message": "string"        // 附加消息(可选)
}

返回数据 (SendGiftResponse):

{
  "code": 200,
  "msg": "赠送成功",
  "data": {
    "giftRecordId": "long",    // 礼物记录ID
    "giftId": "integer",       // 礼物ID
    "giftName": "string",      // 礼物名称
    "count": "integer",        // 赠送数量
    "totalPrice": "integer",   // 总价格
    "newBalance": "integer",   // 赠送后的余额
    "sendTime": "long"         // 赠送时间戳
  }
}

4. 获取充值选项

接口地址: GET /api/front/gift/recharge/options

请求参数: 无

返回数据:

{
  "code": 200,
  "msg": "success",
  "data": [
    {
      "id": "string",           // 选项ID
      "coinAmount": "integer",  // 金币数量
      "price": "number",        // 价格(元)
      "discountLabel": "string",// 优惠标签(可选)
      "isHot": "boolean",       // 是否热门
      "sort": "integer"         // 排序
    }
  ]
}

5. 创建充值订单

接口地址: POST /api/front/gift/recharge/create

请求参数 (CreateRechargeRequest):

{
  "optionId": "string",      // 充值选项ID必填
  "coinAmount": "integer",   // 金币数量(必填)
  "price": "number"          // 价格(必填)
}

返回数据 (CreateRechargeResponse):

{
  "code": 200,
  "msg": "订单创建成功",
  "data": {
    "orderId": "string",       // 订单ID
    "orderNo": "string",       // 订单号
    "coinAmount": "integer",   // 金币数量
    "price": "number",         // 价格
    "paymentUrl": "string",    // 支付URL
    "createTime": "long"       // 创建时间
  }
}

功能说明

礼物等级

等级 价格范围 说明
1 1-50金币 普通礼物
2 51-100金币 精美礼物
3 101-500金币 豪华礼物
4 501-1000金币 贵族礼物
5 1000+金币 至尊礼物

赠送流程

  1. 用户点击礼物按钮
  2. 显示礼物列表和当前余额
  3. 选择礼物和数量
  4. 检查余额是否足够
  5. 调用赠送接口
  6. 扣除金币,更新余额
  7. 在直播间显示礼物动画
  8. 通过WebSocket推送给其他观众

充值流程

  1. 用户点击充值按钮
  2. 显示充值选项列表
  3. 选择充值金额
  4. 创建充值订单
  5. 选择支付方式(支付宝/微信)
  6. 调用支付接口
  7. 支付成功后更新余额

使用场景

1. 加载礼物列表

private void loadGiftsFromBackend() {
    ApiService apiService = ApiClient.getService(getApplicationContext());
    Call<ApiResponse<List<GiftResponse>>> call = apiService.getGiftList();
    
    call.enqueue(new Callback<ApiResponse<List<GiftResponse>>>() {
        @Override
        public void onResponse(Call<ApiResponse<List<GiftResponse>>> call, 
                             Response<ApiResponse<List<GiftResponse>>> response) {
            if (response.isSuccessful() && response.body() != null) {
                ApiResponse<List<GiftResponse>> apiResponse = response.body();
                if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
                    availableGifts = new ArrayList<>();
                    for (GiftResponse giftResponse : apiResponse.getData()) {
                        Gift gift = new Gift(
                            String.valueOf(giftResponse.getId()),
                            giftResponse.getName(),
                            giftResponse.getPrice().intValue(),
                            R.drawable.ic_gift_rose,
                            giftResponse.getLevel() != null ? giftResponse.getLevel() : 1
                        );
                        availableGifts.add(gift);
                    }
                }
            }
        }

        @Override
        public void onFailure(Call<ApiResponse<List<GiftResponse>>> call, Throwable t) {
            Log.e("Gift", "加载礼物列表失败: " + t.getMessage());
        }
    });
}

2. 获取用户余额

private void loadUserBalance(TextView coinBalanceView) {
    ApiService apiService = ApiClient.getService(getApplicationContext());
    Call<ApiResponse<UserBalanceResponse>> call = apiService.getUserBalance();
    
    call.enqueue(new Callback<ApiResponse<UserBalanceResponse>>() {
        @Override
        public void onResponse(Call<ApiResponse<UserBalanceResponse>> call, 
                             Response<ApiResponse<UserBalanceResponse>> response) {
            if (response.isSuccessful() && response.body() != null) {
                ApiResponse<UserBalanceResponse> apiResponse = response.body();
                if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
                    userCoinBalance = apiResponse.getData().getCoinBalance().intValue();
                    coinBalanceView.setText(String.valueOf(userCoinBalance));
                }
            }
        }

        @Override
        public void onFailure(Call<ApiResponse<UserBalanceResponse>> call, Throwable t) {
            Log.e("Gift", "获取余额失败: " + t.getMessage());
        }
    });
}

3. 赠送礼物

private void sendGiftToBackend(Gift selectedGift, int count, int totalPrice) {
    // 检查余额
    if (userCoinBalance < totalPrice) {
        Toast.makeText(this, "金币不足,请先充值", Toast.LENGTH_SHORT).show();
        showRechargeDialog();
        return;
    }
    
    ApiService apiService = ApiClient.getService(getApplicationContext());
    
    SendGiftRequest request = new SendGiftRequest();
    request.setGiftId(Integer.parseInt(selectedGift.getId()));
    request.setReceiverId(room.getStreamerId());
    request.setRoomId(roomId);
    request.setCount(count);
    
    Call<ApiResponse<SendGiftResponse>> call = apiService.sendGift(request);
    
    call.enqueue(new Callback<ApiResponse<SendGiftResponse>>() {
        @Override
        public void onResponse(Call<ApiResponse<SendGiftResponse>> call, 
                             Response<ApiResponse<SendGiftResponse>> response) {
            if (response.isSuccessful() && response.body() != null) {
                ApiResponse<SendGiftResponse> apiResponse = response.body();
                if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
                    SendGiftResponse giftResponse = apiResponse.getData();
                    
                    // 更新余额
                    userCoinBalance = giftResponse.getNewBalance().intValue();
                    
                    // 显示赠送消息
                    String giftMessage = String.format("送出了 %d 个 %s", 
                        count, selectedGift.getName());
                    addChatMessage(new ChatMessage("我", giftMessage, true));
                    
                    Toast.makeText(RoomDetailActivity.this, 
                        "赠送成功!", Toast.LENGTH_SHORT).show();
                }
            }
        }

        @Override
        public void onFailure(Call<ApiResponse<SendGiftResponse>> call, Throwable t) {
            Toast.makeText(RoomDetailActivity.this, 
                "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

4. 创建充值订单

private void createRechargeOrder(RechargeOption selectedOption) {
    ApiService apiService = ApiClient.getService(getApplicationContext());
    
    CreateRechargeRequest request = new CreateRechargeRequest();
    request.setOptionId(selectedOption.getId());
    request.setCoinAmount(selectedOption.getCoinAmount());
    request.setPrice(selectedOption.getPrice());
    
    Call<ApiResponse<CreateRechargeResponse>> call = 
        apiService.createRecharge(request);
    
    call.enqueue(new Callback<ApiResponse<CreateRechargeResponse>>() {
        @Override
        public void onResponse(Call<ApiResponse<CreateRechargeResponse>> call, 
                             Response<ApiResponse<CreateRechargeResponse>> response) {
            if (response.isSuccessful() && response.body() != null) {
                ApiResponse<CreateRechargeResponse> apiResponse = response.body();
                if (apiResponse.getCode() == 200 && apiResponse.getData() != null) {
                    CreateRechargeResponse rechargeResponse = apiResponse.getData();
                    String orderId = rechargeResponse.getOrderId();
                    
                    // 显示支付选择对话框
                    showPaymentMethodDialog(orderId, selectedOption);
                }
            }
        }

        @Override
        public void onFailure(Call<ApiResponse<CreateRechargeResponse>> call, Throwable t) {
            Toast.makeText(RoomDetailActivity.this, 
                "网络错误: " + t.getMessage(), Toast.LENGTH_SHORT).show();
        }
    });
}

WebSocket推送

礼物赠送后会通过WebSocket推送给直播间内的所有用户用于显示礼物动画。

推送消息格式:

{
  "type": "gift",
  "giftId": 1,
  "giftName": "玫瑰",
  "count": 10,
  "senderId": 123,
  "senderNickname": "张三",
  "receiverId": 456,
  "receiverNickname": "主播",
  "roomId": "room123"
}

默认礼物列表

如果接口加载失败,可以使用以下默认礼物:

ID 名称 价格 等级
1 玫瑰 10 1
2 爱心 20 1
3 蛋糕 50 2
4 星星 100 2
5 钻石 200 3
6 皇冠 500 4
7 跑车 1000 5
8 火箭 2000 5

注意事项

  1. 所有接口都需要登录认证
  2. 赠送礼物前必须检查余额是否足够
  3. 礼物价格以金币为单位,不是人民币
  4. 充值需要集成第三方支付SDK支付宝/微信)
  5. 礼物动画效果需要前端实现
  6. 建议缓存礼物列表,减少网络请求
  7. 余额变化后及时更新UI显示
  8. 赠送失败时不扣除金币