hyapp-server/docs/flutter对接/CP关系Flutter对接.md
2026-06-08 14:12:23 +08:00

456 lines
11 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.

# CP关系Flutter对接
本文只写 App 需要对接的地址、参数、返回值和相关 IM。CP 关系包含 `cp``brother``sister` 三种类型;每个用户同时只能有一个 active 关系,不需要佩戴接口,也没有后台数量配置。
## 1. 礼物面板CP Tab
地址:
```http
GET /api/v1/rooms/{room_id}/gift-panel
Authorization: Bearer <access_token>
X-App-Code: lalu
```
参数:
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `room_id` | string | 是 | 当前房间 ID |
返回值:
`tabs` 里会有 `gift_type_code=cp` 的 Tab。CP 礼物会带:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `gift_id` | string | 送礼时使用 |
| `gift_type_code` | string | CP 礼物为 `cp` |
| `cp_relation_type` | string | `cp``brother``sister` |
| `name` | string | 礼物名 |
| `coin_price` | int64 | 展示价格,扣费以后端为准 |
| `resource.asset_url` | string | 礼物 icon |
| `resource.animation_url` | string | 礼物动效,可为空 |
Flutter 在 CP 礼物 Tab 下按 `cp_relation_type` 分成 CP、兄弟、姐妹三个二级 Tab。
## 2. 发送CP礼物
地址:
```http
POST /api/v1/rooms/gift/send
Authorization: Bearer <access_token>
X-App-Code: lalu
Content-Type: application/json
```
参数:
| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `room_id` | string | 是 | 当前房间 ID |
| `command_id` | string | 是 | 本次送礼幂等键,重试必须复用 |
| `target_type` | string | 否 | 当前传 `user` |
| `target_user_ids` | int64[] | 是 | CP 礼物只传 1 个收礼人 |
| `gift_id` | string | 是 | CP 礼物 ID |
| `gift_count` | int32 | 是 | 必须大于 0 |
示例:
```json
{
"room_id": "room_1001",
"command_id": "cp_gift_1779259000000_10001_10002",
"target_type": "user",
"target_user_ids": [10002],
"gift_id": "cp_ring",
"gift_count": 1
}
```
返回值:
沿用普通送礼响应。关系申请通过 IM 到达,送礼响应不保证返回申请 ID。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `result.applied` | bool | 本次命令是否落地 |
| `billing_receipt_id` | string | 扣费回执 |
| `room_heat` | int64 | 最新房间热度 |
| `gift_rank` | array | 房间礼物榜 |
| `room` | object | 房间快照 |
| `lucky_gift` | object | 幸运礼物结果,普通 CP 礼物为空 |
## 3. 查询我的申请
地址:
```http
GET /api/v1/cp/applications?direction=incoming&status=pending&page=1&page_size=20
Authorization: Bearer <access_token>
X-App-Code: lalu
```
参数:
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `direction` | string | 否 | `incoming` 我收到的;`outgoing` 我发出的 |
| `status` | string | 否 | `pending``accepted``rejected``expired``blocked` |
| `page` | int32 | 否 | 默认 1 |
| `page_size` | int32 | 否 | 默认 20 |
返回值:
```json
{
"applications": [
{
"application_id": "cp_app_10001_10002_cp",
"relation_type": "cp",
"status": "pending",
"requester": {
"user_id": "10001",
"display_user_id": "123456",
"username": "Alice",
"avatar": "https://cdn.example/a.png"
},
"target": {
"user_id": "10002",
"display_user_id": "654321",
"username": "Bob",
"avatar": "https://cdn.example/b.png"
},
"room_id": "room_1001",
"room_region_id": 86,
"gift": {
"gift_id": "cp_ring",
"gift_name": "CP Ring",
"gift_icon_url": "https://cdn.example/cp-ring.png",
"gift_animation_url": "",
"gift_count": 1,
"gift_value": 520,
"billing_receipt_id": "gift_tx_1"
},
"created_at_ms": 1779259000000,
"updated_at_ms": 1779259000000,
"expires_at_ms": 1779345400000,
"decided_at_ms": 0
}
],
"total": 1,
"server_time_ms": 1779259001000
}
```
## 4. 同意申请
地址:
```http
POST /api/v1/cp/applications/{application_id}/accept
Authorization: Bearer <access_token>
X-App-Code: lalu
```
参数:
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `application_id` | string | 是 | 申请 ID |
返回值:
```json
{
"application": {
"application_id": "cp_app_10001_10002_cp",
"relation_type": "cp",
"status": "accepted",
"decided_at_ms": 1779259100000
},
"relationship": {
"relationship_id": "cp_rel_10001_10002",
"relation_type": "cp",
"status": "active",
"me": {
"user_id": "10002",
"display_user_id": "654321",
"username": "Bob",
"avatar": "https://cdn.example/b.png"
},
"partner": {
"user_id": "10001",
"display_user_id": "123456",
"username": "Alice",
"avatar": "https://cdn.example/a.png"
},
"intimacy_value": 0,
"level": 1,
"formed_at_ms": 1779259100000,
"updated_at_ms": 1779259100000
}
}
```
错误处理:
| code | 处理 |
| --- | --- |
| `CONFLICT` | A/B 任一方已经有 active 关系,或申请已过期;刷新申请和关系列表 |
| `NOT_FOUND` | 申请不存在,刷新申请列表 |
| `PERMISSION_DENIED` | 当前用户不是申请目标用户 |
## 5. 拒绝申请
地址:
```http
POST /api/v1/cp/applications/{application_id}/reject
Authorization: Bearer <access_token>
X-App-Code: lalu
Content-Type: application/json
```
参数:
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `application_id` | string | 是 | 申请 ID |
| `reason` | string | 否 | 拒绝原因 |
返回值:
```json
{
"application": {
"application_id": "cp_app_10001_10002_cp",
"relation_type": "cp",
"status": "rejected",
"decided_at_ms": 1779259100000
}
}
```
## 6. 查询我的关系
地址:
```http
GET /api/v1/cp/relationships?relation_type=cp&page=1&page_size=20
Authorization: Bearer <access_token>
X-App-Code: lalu
```
参数:
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `relation_type` | string | 否 | `cp``brother``sister`;不传返回全部 |
| `page` | int32 | 否 | 默认 1 |
| `page_size` | int32 | 否 | 默认 20 |
返回值:
```json
{
"relationships": [
{
"relationship_id": "cp_rel_10001_10002",
"relation_type": "cp",
"status": "active",
"me": {
"user_id": "10001",
"display_user_id": "123456",
"username": "Alice",
"avatar": "https://cdn.example/a.png"
},
"partner": {
"user_id": "10002",
"display_user_id": "654321",
"username": "Bob",
"avatar": "https://cdn.example/b.png"
},
"intimacy_value": 1888,
"level": 2,
"formed_at_ms": 1779259100000,
"updated_at_ms": 1779259200000
}
],
"total": 1
}
```
说明:
- 每个用户同时只能有一个 active 关系。
- 不需要佩戴接口,资料卡直接展示当前 active 关系。
## 7. 相关IM
所有 IM 都是 Tencent `TIMCustomElem``MsgContent.Desc` 等于下表事件名,`MsgContent.Data` 是 JSON 字符串。客户端按 `event_id` 去重。
### 7.1 收到关系申请
房间 IM 和 C2C IM 都会收到:
| 字段 | 值 |
| --- | --- |
| `MsgContent.Desc` | `cp_application_created` |
| `Data.event_type` | `cp_application_created` |
Data
```json
{
"event_id": "cp_application:created:10002:1",
"event_type": "cp_application_created",
"application_id": "cp_app_10001_10002_cp",
"relation_type": "cp",
"status": "pending",
"requester": {
"user_id": "10001",
"display_user_id": "123456",
"username": "Alice",
"avatar": "https://cdn.example/a.png"
},
"target": {
"user_id": "10002",
"display_user_id": "654321",
"username": "Bob",
"avatar": "https://cdn.example/b.png"
},
"room_id": "room_1001",
"room_region_id": 86,
"gift": {
"gift_id": "cp_ring",
"gift_name": "CP Ring",
"gift_icon_url": "https://cdn.example/cp-ring.png",
"gift_animation_url": "",
"gift_count": 1,
"gift_value": 520,
"billing_receipt_id": "gift_tx_1"
},
"expires_at_ms": 1779345400000,
"decided_at_ms": 0,
"source_created_at_ms": 1779259000000,
"recipient_user_id": "10002"
}
```
处理:
- 房间 IM 只有 `recipient_user_id` 等于当前用户时显示同意/拒绝按钮。
- C2C IM 在私聊里显示同意/拒绝按钮。
- `expires_at_ms <= server_time_ms` 时按钮置灰并刷新申请列表。
### 7.2 申请被同意
C2C 和房间 IM 都会收到:
| 字段 | 值 |
| --- | --- |
| `MsgContent.Desc` | `cp_application_accepted` |
| `Data.event_type` | `cp_application_accepted` |
Data 字段和申请消息一致,差异是:
| 字段 | 值 |
| --- | --- |
| `status` | `accepted` |
| `decided_at_ms` | 处理时间 |
| `recipient_user_id` | 房间 IM 中为 A 的 user_id |
处理:
- A 收到后刷新 `/api/v1/cp/relationships`
- B 操作成功后也刷新关系列表。
- 同一对用户其他 pending 申请需要置灰。
### 7.3 申请被拒绝
C2C 和房间 IM 都会收到:
| 字段 | 值 |
| --- | --- |
| `MsgContent.Desc` | `cp_application_rejected` |
| `Data.event_type` | `cp_application_rejected` |
Data 字段和申请消息一致,差异是:
| 字段 | 值 |
| --- | --- |
| `status` | `rejected` |
| `reason` | 拒绝原因,可为空 |
| `decided_at_ms` | 处理时间 |
| `recipient_user_id` | 房间 IM 中为 A 的 user_id |
### 7.4 区域关系成立播报
用户组成任意关系后,会发送区域 IM
| 字段 | 值 |
| --- | --- |
| `MsgContent.Desc` | `cp_relationship_created` |
| `Data.event_type` | `cp_relationship_created` |
Data
```json
{
"event_id": "cp_relationship:created:10002:1",
"event_type": "cp_relationship_created",
"relationship_id": "cp_rel_10001_10002",
"application_id": "cp_app_10001_10002_cp",
"relation_type": "cp",
"requester": {
"user_id": "10001",
"display_user_id": "123456",
"username": "Alice",
"avatar": "https://cdn.example/a.png"
},
"target": {
"user_id": "10002",
"display_user_id": "654321",
"username": "Bob",
"avatar": "https://cdn.example/b.png"
},
"gift": {
"gift_id": "cp_ring",
"gift_name": "CP Ring",
"gift_icon_url": "https://cdn.example/cp-ring.png",
"gift_animation_url": "",
"gift_count": 1,
"gift_value": 520,
"billing_receipt_id": "gift_tx_1"
},
"room_id": "room_1001",
"room_region_id": 86,
"group_id": "hy_lalu_bc_r_86",
"source_created_at_ms": 1779259100000
}
```
处理:
- 只在区域播报位展示,不当作私聊消息。
- 点击可进入 `room_id` 对应房间;房间不存在或进房失败时只关闭播报。
## 8. 客户端错误提示
| code | 建议提示 |
| --- | --- |
| `CONFLICT` | `你或对方已经有关系`;如果申请已过期则提示 `申请已过期` |
| `NOT_FOUND` | `申请不存在或已失效` |
| `PERMISSION_DENIED` | `只能处理发给你的申请` |
## 9. 本地状态规则
- 不要靠送礼成功直接创建关系。
- 不要靠 C2C 或房间按钮本地改关系,必须调用同意或拒绝接口。
- 同一个 `event_id` 只处理一次。
- 同一个 `application_id` 在房间和 C2C 里可能都出现,按钮状态要共享。
- 申请过期时间以 `expires_at_ms` 为准。
- 亲密值和等级以后端关系接口返回为准,不在 Flutter 里按礼物价格推算。