商户通知管理模块提供通知统计、通知列表查询、通知已读标记(单个/批量)等功能,支持系统通知、订单提醒等多种通知类型。
GET /notice/getNoticeStatistics| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| receiverId | String | 是 | 接收人ID(商户ID,格式如:store_18241052019) |
GET /notice/getNoticeStatistics?receiverId=store_18241052019
{
"code": 200,
"success": true,
"data": {
"systemNotice": {
"id": "12345",
"title": "店铺审核通知",
"context": "您的店铺已通过审核",
"noticeType": 1,
"isRead": 0,
"createdTime": "2025-11-12 14:30:00",
"systemNum": 5
},
"orderNotice": {
"id": "12346",
"title": "新订单提醒",
"context": "您有一笔新订单",
"noticeType": 2,
"isRead": 0,
"createdTime": "2025-11-12 15:20:00",
"orderNum": 3
}
},
"msg": "查询成功"
}
GET /notice/getNoticeList| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| pageNum | int | 是 | - | 页码(从1开始) |
| pageSize | int | 是 | - | 每页条数 |
| receiverId | String | 是 | - | 接收人ID(商户ID) |
| noticeType | int | 否 | 0 | 通知类型(0-其他,1-系统通知,2-订单提醒) |
GET /notice/getNoticeList?receiverId=store_18241052019&pageNum=1&pageSize=10¬iceType=0
{
"code": 200,
"success": true,
"data": {
"records": [
{
"id": "12347",
"title": "新评论通知",
"context": "用户对您的店铺进行了评论",
"noticeType": 0,
"isRead": 0,
"userName": "张三",
"userImage": "https://example.com/avatar.jpg",
"createdTime": "2025-11-12 16:00:00"
}
],
"total": 50,
"size": 10,
"current": 1,
"pages": 5
}
}
POST /notice/markNoticeAsRead| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | Integer | 是 | 通知ID |
POST /notice/markNoticeAsRead?id=2589
{
"code": 200,
"success": true,
"data": null,
"msg": "标记已读成功"
}
POST /notice/markAllNoticesAsRead| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| receiverId | String | 是 | 接收人ID(商户ID) |
| noticeType | Integer | 否 | 通知类型(0-其他,1-系统通知,2-订单提醒)。不传则标记所有类型的未读通知 |
POST /notice/markAllNoticesAsRead?receiverId=store_18241052019
POST /notice/markAllNoticesAsRead?receiverId=store_18241052019¬iceType=1
POST /notice/markAllNoticesAsRead?receiverId=store_18241052019¬iceType=2
{
"code": 200,
"success": true,
"data": 15,
"msg": "批量标记已读成功,共标记 15 条通知"
}
{
"code": 200,
"success": true,
"data": 0,
"msg": "没有需要标记的通知"
}
{
"code": 500,
"success": false,
"data": null,
"msg": "批量标记失败:数据库异常"
}
| 字段名 | 类型 | 说明 |
|---|---|---|
| code | Integer | 响应状态码,200表示成功 |
| success | Boolean | 是否成功 |
| data | Integer | 标记的通知数量 |
| msg | String | 响应消息 |
| noticeType | 说明 |
|---|---|
| 0 | 系统通知和订单提醒之外的类型(如评论、关注、举报等) |
| 1 | 系统通知(店铺审核、违规处理等) |
| 2 | 订单提醒(新订单、订单核销等) |
接口四(markAllNoticesAsRead) 的核心逻辑:
条件组合:
receiverId = ? AND isRead = 0noticeType = ?(如果传入)更新操作:
isRead 字段更新为 1返回结果:
SQL 等效:
-- 标记所有未读通知
UPDATE life_notice
SET is_read = 1
WHERE receiver_id = 'store_18241052019'
AND is_read = 0
AND delete_flag = 0;
-- 只标记系统通知
UPDATE life_notice
SET is_read = 1
WHERE receiver_id = 'store_18241052019'
AND is_read = 0
AND notice_type = 1
AND delete_flag = 0;
@ApiOperation("批量标记通知为已读(一键已读)")
@PostMapping("/markAllNoticesAsRead")
public R<Integer> markAllNoticesAsRead(
@RequestParam("receiverId") String receiverId,
@RequestParam(value = "noticeType", required = false) Integer noticeType) {
try {
int result = noticeService.markAllNoticesAsRead(receiverId, noticeType);
if (result > 0) {
return R.data(result, "批量标记已读成功,共标记 " + result + " 条通知");
}
return R.data(0, "没有需要标记的通知");
} catch (Exception e) {
log.error("批量标记失败: {}", e.getMessage(), e);
return R.fail(e.getMessage());
}
}
/**
* 批量标记通知为已读(一键已读)
*
* @param receiverId 接收人ID(商户ID)
* @param noticeType 通知类型(可选,不传则标记所有类型)
* @return 影响行数
*/
int markAllNoticesAsRead(String receiverId, Integer noticeType);
@Override
public int markAllNoticesAsRead(String receiverId, Integer noticeType) {
log.info("批量标记通知为已读: receiverId={}, noticeType={}",
receiverId, noticeType);
// 使用 LambdaUpdateWrapper 批量更新 isRead 字段
LambdaUpdateWrapper<LifeNotice> wrapper = new LambdaUpdateWrapper<>();
// 1. 接收人条件(必须)
wrapper.eq(LifeNotice::getReceiverId, receiverId);
// 2. 只更新未读的通知
wrapper.eq(LifeNotice::getIsRead, 0);
// 3. 通知类型条件(可选)
if (noticeType != null) {
wrapper.eq(LifeNotice::getNoticeType, noticeType);
}
// 4. 设置为已读
wrapper.set(LifeNotice::getIsRead, 1);
int result = lifeNoticeMapper.update(null, wrapper);
log.info("批量标记完成: 影响行数={}", result);
return result;
}
用户进入通知中心,点击"一键已读"按钮:
// 前端调用示例
async function markAllAsRead() {
const response = await axios.post('/notice/markAllNoticesAsRead', null, {
params: {
receiverId: 'store_18241052019'
}
});
if (response.data.success) {
console.log(`成功标记 ${response.data.data} 条通知为已读`);
// 刷新通知列表和统计
refreshNoticeList();
refreshNoticeStatistics();
}
}
用户在"系统通知"标签页点击"全部已读":
// 只标记系统通知为已读
async function markSystemNoticesAsRead() {
const response = await axios.post('/notice/markAllNoticesAsRead', null, {
params: {
receiverId: 'store_18241052019',
noticeType: 1 // 系统通知
}
});
if (response.data.success) {
console.log(`成功标记 ${response.data.data} 条系统通知为已读`);
}
}
后台定时任务,自动标记超过7天的未读通知(需扩展接口)
用户进入通知中心
↓
① 调用 getNoticeStatistics
↓
显示:系统通知(5)、订单提醒(3)
↓
② 调用 getNoticeList(noticeType=1)
↓
显示系统通知列表
↓
用户点击"全部已读"按钮
↓
③ 调用 markAllNoticesAsRead(receiverId, noticeType=1)
↓
返回:成功标记 5 条通知
↓
④ 重新调用 getNoticeStatistics
↓
显示:系统通知(0)、订单提醒(3)
| 特性 | 单个标记 | 批量标记 |
|---|---|---|
| 接口 | markNoticeAsRead | markAllNoticesAsRead |
| 参数 | id(通知ID) | receiverId + noticeType(可选) |
| 更新范围 | 单条通知 | 多条未读通知 |
| 返回值 | 影响行数(0或1) | 影响行数(实际标记数量) |
| 使用场景 | 点击单条通知 | 一键清除未读 |
| 性能 | 单次更新 | 批量更新(更高效) |
假设有 100 条未读通知:
方式一:循环调用单个标记
// ❌ 效率低:需要 100 次网络请求
for (let id of noticeIds) {
await markNoticeAsRead(id); // 100次请求
}
方式二:调用批量标记
// ✅ 效率高:只需 1 次网络请求
await markAllNoticesAsRead(receiverId, noticeType); // 1次请求
{
"code": 500,
"success": false,
"data": null,
"msg": "批量标记失败:receiverId 不能为空"
}
noticeType 不传,验证所有未读通知被标记noticeType=1,验证只标记系统通知-- 查询商户的未读通知数量(标记前)
SELECT
notice_type,
COUNT(*) AS unread_count
FROM life_notice
WHERE receiver_id = 'store_18241052019'
AND is_read = 0
AND delete_flag = 0
GROUP BY notice_type;
-- 执行批量标记(模拟)
UPDATE life_notice
SET is_read = 1
WHERE receiver_id = 'store_18241052019'
AND is_read = 0
AND delete_flag = 0;
-- 验证标记结果(标记后)
SELECT
notice_type,
COUNT(*) AS unread_count
FROM life_notice
WHERE receiver_id = 'store_18241052019'
AND is_read = 0
AND delete_flag = 0
GROUP BY notice_type;
-- 应该返回 0 条记录
delete_flag=1 的记录noticeType 不传时标记所有类型,传入时只标记指定类型receiverId 的合法性,防止越权操作| 序号 | 接口名称 | 接口路径 | 请求方式 | 主要功能 |
|---|---|---|---|---|
| 1 | 获取通知统计 | /notice/getNoticeStatistics | GET | 查询未读数量和最新通知 |
| 2 | 获取通知列表 | /notice/getNoticeList | GET | 分页查询通知列表 |
| 3 | 标记单个已读 | /notice/markNoticeAsRead | POST | 标记指定通知为已读 |
| 4 | 批量标记已读 | /notice/markAllNoticesAsRead | POST | 一键标记多个通知为已读 |
新增接口:
/markAllNoticesAsRead 接口markAllNoticesAsRead 方法定义noticeType,可按类型筛选其他接口:
A:
A:当前版本不支持按时间范围筛选。如需此功能,可以扩展接口,添加 startTime 和 endTime 参数。
A:不会。批量标记只会更新 isRead = 0(未读)的通知,已读通知(isRead = 1)会被自动跳过。
A:需要扩展接口,添加时间范围参数:
wrapper.ge(LifeNotice::getCreatedTime, LocalDate.now().minusDays(7));
A:性能优异。使用 MyBatis-Plus 的批量更新,一次SQL执行完成所有更新操作,比循环调用单个标记接口效率高数百倍。
A:建议的方案:
getNoticeStatistics 更新角标按时间范围标记:
startTime 和 endTime 参数按ID列表标记:
ids 数组参数标记并删除:
定时自动标记:
标记统计: