添加红点
This commit is contained in:
568
_doc/前端红点功能接口文档.md
Normal file
568
_doc/前端红点功能接口文档.md
Normal file
@@ -0,0 +1,568 @@
|
||||
# 前端红点功能接口文档
|
||||
|
||||
## 一、功能概述
|
||||
|
||||
消息红点功能用于提示用户有未读的评论/回复和新增关注消息。
|
||||
|
||||
**红点显示条件**:
|
||||
- 有别人回复给我的评论/回复未读
|
||||
- 有新用户关注我未读
|
||||
|
||||
---
|
||||
|
||||
## 二、接口列表
|
||||
|
||||
| 接口 | 用途 |
|
||||
|------|------|
|
||||
| `POST /api/message/reddot_info` | 获取红点信息(数量统计) |
|
||||
| `POST /api/message/mark_as_read` | 标记消息已读(统一接口) |
|
||||
| `POST /api/comments/my_activities` | 获取评论/回复消息列表 |
|
||||
| `POST /api/user_follow/new_fans_list` | 获取新增关注列表 |
|
||||
|
||||
---
|
||||
|
||||
## 三、核心接口详情
|
||||
|
||||
### 1. 获取红点信息 ⭐
|
||||
|
||||
**接口**: `POST /api/message/reddot_info`
|
||||
|
||||
**请求参数**: 无
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功",
|
||||
"data": {
|
||||
"comment_unread_count": 5, // 评论/回复未读数量
|
||||
"follow_unread_count": 3, // 新增关注未读数量
|
||||
"total_unread_count": 8, // 总未读数量
|
||||
"has_reddot": true // 是否显示红点
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**:
|
||||
- `comment_unread_count`: Number,评论/回复未读数量
|
||||
- `follow_unread_count`: Number,新增关注未读数量
|
||||
- `total_unread_count`: Number,总未读数量
|
||||
- `has_reddot`: Boolean,是否显示红点
|
||||
- `true`: 有未读消息,显示红点
|
||||
- `false`: 无未读消息,隐藏红点
|
||||
|
||||
**使用场景**:
|
||||
- TabBar 显示红点和未读数
|
||||
- 消息页面显示各类消息的未读数
|
||||
- 应用启动时检查红点状态
|
||||
|
||||
---
|
||||
|
||||
### 2. 标记消息已读 ⭐
|
||||
|
||||
**接口**: `POST /api/message/mark_as_read`
|
||||
|
||||
**请求参数**:
|
||||
```json
|
||||
{
|
||||
"type": "comment", // 消息类型: comment-评论, follow-关注, all-全部
|
||||
"ids": [123, 456, 789] // 消息ID数组(type为all时可不传)
|
||||
}
|
||||
```
|
||||
|
||||
**type 参数说明**:
|
||||
- `"comment"`: 标记指定评论/回复为已读,需传 `ids`(评论ID数组)
|
||||
- `"follow"`: 标记指定关注为已读,需传 `ids`(关注者用户ID数组)
|
||||
- `"all"`: 标记所有未读消息为已读,不需要传 `ids`
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功",
|
||||
"data": {
|
||||
"updated_count": 8, // 总更新数量
|
||||
"detail": {
|
||||
"comment_count": 5, // 评论更新数量
|
||||
"follow_count": 3 // 关注更新数量
|
||||
},
|
||||
"message": "标记成功"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**使用示例**:
|
||||
|
||||
1. 标记指定评论为已读:
|
||||
```json
|
||||
{
|
||||
"type": "comment",
|
||||
"ids": [123, 456]
|
||||
}
|
||||
```
|
||||
|
||||
2. 标记指定关注为已读:
|
||||
```json
|
||||
{
|
||||
"type": "follow",
|
||||
"ids": [789, 012]
|
||||
}
|
||||
```
|
||||
|
||||
3. 标记全部消息为已读:
|
||||
```json
|
||||
{
|
||||
"type": "all"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、辅助接口
|
||||
|
||||
### 3. 获取评论/回复消息列表
|
||||
|
||||
**接口**: `POST /api/comments/my_activities`
|
||||
|
||||
**请求参数**:
|
||||
```json
|
||||
{
|
||||
"page": 1,
|
||||
"pageSize": 20
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功",
|
||||
"data": {
|
||||
"rows": [
|
||||
{
|
||||
"id": 456,
|
||||
"type": "reply",
|
||||
"activity_type": "received_reply",
|
||||
"content": "回复内容",
|
||||
"create_time": "2025-11-20 10:00:00",
|
||||
"is_read": 0, // 👈 0-未读, 1-已读
|
||||
"user": {
|
||||
"id": 789,
|
||||
"nickname": "回复者昵称",
|
||||
"avatar_url": "头像地址"
|
||||
},
|
||||
"game": {
|
||||
"id": 101,
|
||||
"title": "球局标题"
|
||||
}
|
||||
}
|
||||
],
|
||||
"count": 50
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**字段说明**:
|
||||
- `is_read`: 0-未读, 1-已读
|
||||
- `activity_type`:
|
||||
- `"my_activity"` - 我发表的
|
||||
- `"received_reply"` - 别人回复我的(需要处理的)
|
||||
|
||||
---
|
||||
|
||||
### 4. 获取新增关注列表
|
||||
|
||||
**接口**: `POST /api/user_follow/new_fans_list`
|
||||
|
||||
**请求参数**:
|
||||
```json
|
||||
{
|
||||
"page": 1,
|
||||
"page_size": 20
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例**:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"message": "获取成功",
|
||||
"data": {
|
||||
"list": [
|
||||
{
|
||||
"id": 123,
|
||||
"nickname": "粉丝昵称",
|
||||
"avatar_url": "头像地址",
|
||||
"follow_time": "2025-11-20 09:00:00",
|
||||
"is_mutual": false,
|
||||
"is_read": 0 // 👈 0-未读, 1-已读
|
||||
}
|
||||
],
|
||||
"total": 30
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、前端使用示例
|
||||
|
||||
### 1. 显示 TabBar 红点
|
||||
|
||||
```javascript
|
||||
// app.js 或全局方法
|
||||
async function checkAndShowReddot() {
|
||||
const res = await request({
|
||||
url: '/api/message/reddot_info',
|
||||
method: 'POST'
|
||||
})
|
||||
|
||||
const { has_reddot, total_unread_count } = res.data
|
||||
|
||||
if (has_reddot) {
|
||||
// 显示红点和数字
|
||||
wx.setTabBarBadge({
|
||||
index: 2, // 消息Tab的索引
|
||||
text: total_unread_count > 99 ? '99+' : String(total_unread_count)
|
||||
})
|
||||
} else {
|
||||
// 隐藏红点
|
||||
wx.removeTabBarBadge({
|
||||
index: 2
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// App 启动时检查
|
||||
App({
|
||||
onLaunch() {
|
||||
this.checkReddot()
|
||||
},
|
||||
|
||||
checkReddot() {
|
||||
checkAndShowReddot()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 消息页面显示分类红点
|
||||
|
||||
```javascript
|
||||
// pages/message/message.js
|
||||
Page({
|
||||
data: {
|
||||
commentUnreadCount: 0,
|
||||
followUnreadCount: 0
|
||||
},
|
||||
|
||||
onShow() {
|
||||
this.loadReddotInfo()
|
||||
},
|
||||
|
||||
async loadReddotInfo() {
|
||||
const res = await request({
|
||||
url: '/api/message/reddot_info',
|
||||
method: 'POST'
|
||||
})
|
||||
|
||||
this.setData({
|
||||
commentUnreadCount: res.data.comment_unread_count,
|
||||
followUnreadCount: res.data.follow_unread_count
|
||||
})
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- pages/message/message.wxml -->
|
||||
<view class="message-page">
|
||||
<!-- 评论消息入口 -->
|
||||
<view class="menu-item" bindtap="goToComments">
|
||||
<text>评论与回复</text>
|
||||
<view wx:if="{{commentUnreadCount > 0}}" class="badge">
|
||||
{{commentUnreadCount}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 关注消息入口 -->
|
||||
<view class="menu-item" bindtap="goToFollows">
|
||||
<text>新增关注</text>
|
||||
<view wx:if="{{followUnreadCount > 0}}" class="badge">
|
||||
{{followUnreadCount}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 评论消息列表(进入时自动标记已读)
|
||||
|
||||
```javascript
|
||||
// pages/message/comment-list.js
|
||||
Page({
|
||||
data: {
|
||||
commentList: []
|
||||
},
|
||||
|
||||
async onLoad() {
|
||||
await this.loadComments()
|
||||
await this.markAllAsRead()
|
||||
},
|
||||
|
||||
// 加载评论列表
|
||||
async loadComments() {
|
||||
const res = await request({
|
||||
url: '/api/comments/my_activities',
|
||||
method: 'POST',
|
||||
data: { page: 1, pageSize: 20 }
|
||||
})
|
||||
|
||||
// 筛选出别人回复给我的
|
||||
const receivedReplies = res.data.rows.filter(
|
||||
item => item.activity_type === 'received_reply'
|
||||
)
|
||||
|
||||
this.setData({ commentList: receivedReplies })
|
||||
},
|
||||
|
||||
// 标记所有评论为已读
|
||||
async markAllAsRead() {
|
||||
const unreadIds = this.data.commentList
|
||||
.filter(item => item.is_read === 0)
|
||||
.map(item => item.id)
|
||||
|
||||
if (unreadIds.length > 0) {
|
||||
await request({
|
||||
url: '/api/message/mark_as_read',
|
||||
method: 'POST',
|
||||
data: {
|
||||
type: 'comment',
|
||||
ids: unreadIds
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
// 离开页面时刷新红点
|
||||
getApp().checkReddot()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 关注消息列表(进入时自动标记已读)
|
||||
|
||||
```javascript
|
||||
// pages/message/follow-list.js
|
||||
Page({
|
||||
data: {
|
||||
fansList: []
|
||||
},
|
||||
|
||||
async onLoad() {
|
||||
await this.loadFans()
|
||||
await this.markAllAsRead()
|
||||
},
|
||||
|
||||
async loadFans() {
|
||||
const res = await request({
|
||||
url: '/api/user_follow/new_fans_list',
|
||||
method: 'POST',
|
||||
data: { page: 1, page_size: 20 }
|
||||
})
|
||||
|
||||
this.setData({ fansList: res.data.list })
|
||||
},
|
||||
|
||||
async markAllAsRead() {
|
||||
const unreadFanIds = this.data.fansList
|
||||
.filter(item => item.is_read === 0)
|
||||
.map(item => item.id)
|
||||
|
||||
if (unreadFanIds.length > 0) {
|
||||
await request({
|
||||
url: '/api/message/mark_as_read',
|
||||
method: 'POST',
|
||||
data: {
|
||||
type: 'follow',
|
||||
ids: unreadFanIds
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
getApp().checkReddot()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 一键清空所有未读
|
||||
|
||||
```javascript
|
||||
// 清空所有未读消息
|
||||
async function markAllMessagesAsRead() {
|
||||
wx.showLoading({ title: '处理中...' })
|
||||
|
||||
try {
|
||||
await request({
|
||||
url: '/api/message/mark_as_read',
|
||||
method: 'POST',
|
||||
data: { type: 'all' }
|
||||
})
|
||||
|
||||
wx.showToast({ title: '已全部标记为已读', icon: 'success' })
|
||||
|
||||
// 刷新红点
|
||||
getApp().checkReddot()
|
||||
|
||||
} catch (err) {
|
||||
wx.showToast({ title: '操作失败', icon: 'none' })
|
||||
} finally {
|
||||
wx.hideLoading()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、最佳实践
|
||||
|
||||
### 1. 红点刷新时机
|
||||
|
||||
```javascript
|
||||
// 推荐刷新时机
|
||||
const REFRESH_TIMING = {
|
||||
onLaunch: true, // App启动时
|
||||
onShow: true, // App从后台进入前台
|
||||
onTabSwitch: true, // 切换到消息Tab
|
||||
afterMarkRead: true, // 标记已读后
|
||||
onPullRefresh: true // 下拉刷新
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 防抖优化
|
||||
|
||||
```javascript
|
||||
// utils/debounce.js
|
||||
let timer = null
|
||||
export function debounceCheckReddot() {
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
getApp().checkReddot()
|
||||
}, 300)
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
```javascript
|
||||
async function safeMarkAsRead(type, ids) {
|
||||
try {
|
||||
await request({
|
||||
url: '/api/message/mark_as_read',
|
||||
method: 'POST',
|
||||
data: { type, ids }
|
||||
})
|
||||
} catch (err) {
|
||||
// 标记已读失败不影响用户体验,静默处理
|
||||
console.error('标记已读失败:', err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、完整流程图
|
||||
|
||||
```
|
||||
用户打开App
|
||||
↓
|
||||
调用 /message/reddot_info
|
||||
↓
|
||||
获取红点数据
|
||||
↓
|
||||
┌─────────────────┐
|
||||
│ has_reddot? │
|
||||
└────┬────────┬───┘
|
||||
│ │
|
||||
true false
|
||||
↓ ↓
|
||||
显示红点 隐藏红点
|
||||
带数字
|
||||
│
|
||||
│ 用户点击
|
||||
↓
|
||||
进入消息页面
|
||||
↓
|
||||
显示各分类未读数
|
||||
│
|
||||
│ 点击某分类
|
||||
↓
|
||||
加载消息列表
|
||||
↓
|
||||
标记已读
|
||||
↓
|
||||
┌─────────────────┐
|
||||
│ 选择标记方式 │
|
||||
└─┬─────────┬─────┘
|
||||
│ │
|
||||
按ID 全部
|
||||
标记 标记
|
||||
↓ ↓
|
||||
调用 mark_as_read
|
||||
type=comment/follow
|
||||
ids=[...]
|
||||
│ │
|
||||
└────┬────┘
|
||||
↓
|
||||
标记成功
|
||||
↓
|
||||
刷新红点
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、接口对比说明
|
||||
|
||||
### 旧方案 vs 新方案
|
||||
|
||||
| 功能 | 旧方案 | 新方案 |
|
||||
|------|--------|--------|
|
||||
| 获取红点 | `/api/user/detail` | `/api/message/reddot_info` |
|
||||
| 标记评论已读 | `/api/comments/mark_as_read` | `/api/message/mark_as_read` (type=comment) |
|
||||
| 标记关注已读 | `/api/user_follow/mark_as_read` | `/api/message/mark_as_read` (type=follow) |
|
||||
| 标记全部已读 | ❌ 无 | `/api/message/mark_as_read` (type=all) |
|
||||
|
||||
**新方案优势**:
|
||||
- ✅ 统一的接口设计
|
||||
- ✅ 减少接口数量
|
||||
- ✅ 支持一键清空所有未读
|
||||
- ✅ 返回详细的未读数统计
|
||||
- ✅ 更清晰的职责划分
|
||||
|
||||
---
|
||||
|
||||
## 九、注意事项
|
||||
|
||||
1. **权限控制**: 只能标记属于自己的消息
|
||||
2. **分页处理**: 翻页时注意标记已读
|
||||
3. **实时性**: 标记后刷新红点状态
|
||||
4. **错误处理**: 标记失败可静默处理
|
||||
5. **type 参数**: 必须是 `comment`、`follow` 或 `all`
|
||||
|
||||
---
|
||||
|
||||
## 十、联系后端
|
||||
|
||||
**相关文件**:
|
||||
- 消息接口: `api/controller_front/msg_message.js` ⭐
|
||||
- 评论接口: `api/controller_front/gme_comments.js`
|
||||
- 关注接口: `api/controller_front/user_follow.js`
|
||||
Reference in New Issue
Block a user