zhibo/模块文档/17-礼物打赏模块.md

395 lines
12 KiB
Markdown
Raw Normal View History

2025-12-30 11:11:11 +08:00
# 礼物打赏模块
## 模块概述
礼物打赏模块负责处理直播间内的虚拟礼物赠送功能,包括礼物列表、用户余额、礼物赠送、充值等功能。
## 相关文件
- `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. 赠送失败时不扣除金币