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

395 lines
12 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.

# 礼物打赏模块
## 模块概述
礼物打赏模块负责处理直播间内的虚拟礼物赠送功能,包括礼物列表、用户余额、礼物赠送、充值等功能。
## 相关文件
- `RoomDetailActivity.java` - 直播间详情(礼物赠送)
- `Gift.java` - 礼物模型
- `GiftAdapter.java` - 礼物列表适配器
- `GiftResponse.java` - 礼物响应模型
- `SendGiftRequest.java` - 赠送礼物请求模型
- `SendGiftResponse.java` - 赠送礼物响应模型
- `UserBalanceResponse.java` - 用户余额响应模型
- `RechargeOption.java` - 充值选项模型
- `RechargeAdapter.java` - 充值选项适配器
---
## 接口列表
### 1. 获取礼物列表
**接口地址**: `GET /api/front/gift/list`
**请求参数**: 无
**返回数据**:
```json
{
"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):
```json
{
"code": 200,
"msg": "success",
"data": {
"userId": "integer", // 用户ID
"coinBalance": "integer", // 金币余额
"totalRecharge": "integer",// 累计充值金币
"totalConsume": "integer", // 累计消费金币
"vipLevel": "integer" // VIP等级
}
}
```
---
### 3. 赠送礼物
**接口地址**: `POST /api/front/gift/send`
**请求参数** (SendGiftRequest):
```json
{
"giftId": "integer", // 礼物ID必填
"receiverId": "integer", // 接收者ID必填
"roomId": "string", // 直播间ID必填
"count": "integer", // 赠送数量(必填)
"message": "string" // 附加消息(可选)
}
```
**返回数据** (SendGiftResponse):
```json
{
"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`
**请求参数**: 无
**返回数据**:
```json
{
"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):
```json
{
"optionId": "string", // 充值选项ID必填
"coinAmount": "integer", // 金币数量(必填)
"price": "number" // 价格(必填)
}
```
**返回数据** (CreateRechargeResponse):
```json
{
"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. 加载礼物列表
```java
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. 获取用户余额
```java
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. 赠送礼物
```java
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. 创建充值订单
```java
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推送给直播间内的所有用户用于显示礼物动画。
**推送消息格式**:
```json
{
"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. 赠送失败时不扣除金币