复制项目

This commit is contained in:
kim.dev.6789
2026-01-14 22:16:44 +08:00
parent e2577b8cee
commit e50142a3b9
691 changed files with 97009 additions and 1 deletions

View File

@@ -0,0 +1,289 @@
# 红包消息结构文档
## 客户端收到的推送消息结构
### 完整消息结构 (MsgData)
客户端通过WebSocket或HTTP拉取收到的红包消息消息结构如下
```json
{
"clientMsgID": "client_1234567890abcdef", // 客户端消息IDstring
"serverMsgID": "msg_1234567890abcdef", // 服务器消息IDstring
"sendID": "user_owner123", // 发送者ID群主IDstring
"recvID": "", // 接收者ID群消息为空string
"groupID": "group123", // 群IDstring
"senderPlatformID": 0, // 发送者平台IDint320表示系统
"senderNickname": "群主昵称", // 发送者昵称string
"senderFaceURL": "https://...", // 发送者头像URLstring
"sessionType": 3, // 会话类型int323-群聊
"msgFrom": 200, // 消息来源int32200-系统消息
"contentType": 110, // 消息类型int32110-自定义消息
"content": "{\"data\":\"{\\\"redPacketID\\\":\\\"rp_123\\\",\\\"redPacketType\\\":1,\\\"blessing\\\":\\\"恭喜发财\\\"}\",\"description\":\"redpacket\",\"extension\":\"\"}", // 消息内容JSON字符串自定义消息格式
"seq": 123456, // 消息序号int64
"sendTime": 1704067200000, // 发送时间戳int64毫秒
"createTime": 1704067200000, // 创建时间戳int64毫秒
"status": 2, // 消息状态int322-发送成功
"isRead": false, // 是否已读bool
"options": { // 消息选项map[string]bool
"history": true, // 是否保存历史
"persistent": true, // 是否持久化
"offlinePush": true, // 是否离线推送
"unreadCount": true, // 是否计入未读数
"conversationUpdate": true, // 是否更新会话
"senderSync": true // 是否同步给发送者
},
"offlinePushInfo": { // 离线推送信息(可选)
"title": "[HONGBAO]", // 推送标题
"desc": "[HONGBAO]", // 推送描述
"ex": "", // 扩展字段
"iosPushSound": "", // iOS推送声音
"iosBadgeCount": false // iOS角标计数
},
"atUserIDList": [], // @用户列表string[]
"attachedInfo": "", // 附加信息string
"ex": "" // 扩展字段string
}
```
### Content字段解析
`content` 字段是一个JSON字符串需要先解析为 `CustomElem` 结构(自定义消息格式),然后从 `data` 字段中解析出 `RedPacketElem` 结构:
#### CustomElem 结构(自定义消息外层结构)
```json
{
"data": "{\"redPacketID\":\"rp_123\",\"redPacketType\":1,\"blessing\":\"恭喜发财\",\"isReceived\":false,\"receiveInfo\":null}", // 红包数据的JSON字符串string必填
"description": "redpacket", // 二级类型标识string"redpacket"表示红包消息
"extension": "" // 扩展字段string可选
}
```
#### RedPacketElem 结构从data字段中解析
```json
{
"redPacketID": "rp_1234567890abcdef", // 红包IDstring必填
"redPacketType": 1, // 红包类型int32必填1-普通红包2-拼手气红包
"blessing": "恭喜发财", // 祝福语string可选
"isReceived": false, // 当前用户是否已领取bool服务器填充
"receiveInfo": null // 领取信息RedPacketReceiveInfo仅拼手气红包且已领取时返回
}
```
#### RedPacketReceiveInfo 结构(领取信息)
```json
{
"amount": 1000, // 领取金额int64单位
"receiveTime": 1704067200000, // 领取时间戳int64毫秒
"isLucky": false // 是否为手气最佳bool仅拼手气红包有效
}
```
#### 字段说明
| 字段名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| `redPacketID` | string | 是 | 红包唯一标识用于后续领取、查询等操作总金额、总个数等信息可通过红包ID查询获取 |
| `redPacketType` | int32 | 是 | 红包类型1-普通红包平均分配2-拼手气红包(随机分配) |
| `blessing` | string | 否 | 祝福语 |
| `isReceived` | bool | 是 | 当前用户是否已领取服务器根据用户ID自动填充 |
| `receiveInfo` | RedPacketReceiveInfo | 否 | 领取信息,仅当 `isReceived=true``redPacketType=2`(拼手气红包)时返回 |
#### receiveInfo 字段说明
| 字段名 | 类型 | 说明 |
|--------|------|------|
| `amount` | int64 | 领取金额,单位:分 |
| `receiveTime` | int64 | 领取时间戳,毫秒 |
| `isLucky` | bool | 是否为手气最佳(仅拼手气红包有效) |
### 消息类型常量
- **ContentType**: `110` (`constant.Custom` - 自定义消息)
- **二级类型标识**: `"redpacket"` (存储在 `CustomElem.description` 字段中)
- **SessionType**: `3` (`constant.ReadGroupChatType` - 群聊)
- **MsgFrom**: `200` (`constant.SysMsgType` - 系统消息)
### 客户端解析示例
#### JavaScript/TypeScript
```typescript
interface RedPacketReceiveInfo {
amount: number; // 领取金额(分)
receiveTime: number; // 领取时间戳(毫秒)
isLucky: boolean; // 是否为手气最佳
}
interface RedPacketElem {
redPacketID: string;
redPacketType: number; // 1-普通红包2-拼手气红包
blessing?: string;
isReceived: boolean; // 当前用户是否已领取
receiveInfo?: RedPacketReceiveInfo; // 领取信息(仅拼手气红包且已领取时返回)
}
interface CustomElem {
data: string; // 红包数据的JSON字符串
description: string; // 二级类型标识:"redpacket"
extension?: string; // 扩展字段
}
interface RedPacketMessage {
clientMsgID: string;
serverMsgID: string;
sendID: string;
groupID: string;
contentType: number; // 110 (自定义消息)
content: string; // CustomElem的JSON字符串
sendTime: number;
// ... 其他字段
}
// 解析消息
function parseRedPacketMessage(msg: RedPacketMessage): RedPacketElem | null {
// 检查是否为自定义消息类型
if (msg.contentType !== 110) {
return null;
}
try {
// 先解析自定义消息结构
const customElem: CustomElem = JSON.parse(msg.content);
// 检查二级类型是否为红包
if (customElem.description !== "redpacket") {
return null;
}
// 从data字段中解析红包数据
const redPacketElem: RedPacketElem = JSON.parse(customElem.data);
return redPacketElem;
} catch (e) {
console.error('Failed to parse red packet content:', e);
return null;
}
}
```
#### Go
```go
type RedPacketReceiveInfo struct {
Amount int64 `json:"amount"` // 领取金额(分)
ReceiveTime int64 `json:"receiveTime"` // 领取时间戳(毫秒)
IsLucky bool `json:"isLucky"` // 是否为手气最佳
}
type RedPacketElem struct {
RedPacketID string `json:"redPacketID"`
RedPacketType int32 `json:"redPacketType"`
TotalAmount int64 `json:"totalAmount"`
TotalCount int32 `json:"totalCount"`
Blessing string `json:"blessing"`
IsReceived bool `json:"isReceived"` // 当前用户是否已领取
ReceiveInfo *RedPacketReceiveInfo `json:"receiveInfo,omitempty"` // 领取信息(仅拼手气红包且已领取时返回)
}
type CustomElem struct {
Data string `json:"data"` // 红包数据的JSON字符串
Description string `json:"description"` // 二级类型标识:"redpacket"
Extension string `json:"extension"` // 扩展字段
}
func ParseRedPacketContent(content []byte) (*RedPacketElem, error) {
// 先解析自定义消息结构
var customElem CustomElem
if err := json.Unmarshal(content, &customElem); err != nil {
return nil, err
}
// 检查二级类型是否为红包
if customElem.Description != "redpacket" {
return nil, fmt.Errorf("not a red packet message")
}
// 从data字段中解析红包数据
var redPacketElem RedPacketElem
if err := json.Unmarshal([]byte(customElem.Data), &redPacketElem); err != nil {
return nil, err
}
return &redPacketElem, nil
}
```
### 完整消息示例
```json
{
"clientMsgID": "client_1704067200000_abc123",
"serverMsgID": "msg_1704067200000_def456",
"sendID": "user_owner123",
"recvID": "",
"groupID": "group123",
"senderPlatformID": 0,
"senderNickname": "群主",
"senderFaceURL": "https://example.com/avatar.jpg",
"sessionType": 3,
"msgFrom": 200,
"contentType": 110,
"content": "{\"data\":\"{\\\"redPacketID\\\":\\\"rp_1234567890abcdef\\\",\\\"redPacketType\\\":1,\\\"blessing\\\":\\\"恭喜发财\\\",\\\"isReceived\\\":false,\\\"receiveInfo\\\":null}\",\"description\":\"redpacket\",\"extension\":\"\"}",
"seq": 123456,
"sendTime": 1704067200000,
"createTime": 1704067200000,
"status": 2,
"isRead": false,
"options": {
"history": true,
"persistent": true,
"offlinePush": true,
"unreadCount": true,
"conversationUpdate": true,
"senderSync": true
},
"offlinePushInfo": {
"title": "[HONGBAO]",
"desc": "[HONGBAO]"
},
"atUserIDList": [],
"attachedInfo": "",
"ex": ""
}
```
### 消息选项说明
| 选项名 | 说明 |
|--------|------|
| `history` | 是否保存到历史记录 |
| `persistent` | 是否持久化存储 |
| `offlinePush` | 是否离线推送 |
| `unreadCount` | 是否计入未读数 |
| `conversationUpdate` | 是否更新会话 |
| `senderSync` | 是否同步给发送者 |
### 注意事项
1. **Content字段**: 是JSON字符串需要先解析为 `CustomElem` 结构,然后从 `data` 字段中解析 `RedPacketElem`
2. **消息类型**: 使用自定义消息类型(`contentType = 110`),通过 `description` 字段标识二级类型为 `"redpacket"`
3. **二级类型扩展**: 未来可以扩展其他自定义消息类型,只需在 `description` 字段中使用不同的标识(如 `"wallet"``"coupon"` 等)
4. **金额单位**: `receiveInfo.amount` 单位是"分",不是"元"
5. **总金额和总个数**: 不在消息中传递,客户端可通过 `redPacketID` 调用查询接口获取详细信息
5. **红包类型**:
- `1` = 普通红包(平均分配)
- `2` = 拼手气红包(随机分配)
6. **发送者**: 固定为群主,`sendID` 为群主ID
7. **消息来源**: `msgFrom = 200` 表示系统消息
8. **会话类型**: `sessionType = 3` 表示群聊
9. **领取状态**: `isReceived` 字段由服务器根据当前用户ID自动填充客户端无需设置
10. **领取信息**: `receiveInfo` 仅在以下情况返回:
- `isReceived = true`(用户已领取)
- `redPacketType = 2`(拼手气红包)
- 普通红包(`redPacketType = 1`)即使已领取也不会返回 `receiveInfo`
11. **客户端存储**: 客户端收到消息后,应将 `isReceived``receiveInfo` 存储到本地用于UI展示
12. **兼容性**: 使用标准自定义消息类型无需修改客户端SDK只需在客户端添加红包消息的解析逻辑