You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7.7 KiB
7.7 KiB
通知第二批:删除、多选与回收站对接
日期:2026-10-28。面向前端开发/联调。仅描述本批后端实现,尚未提交、推送或发布。第一批“业务关联与已读”交接文档继续适用;本批没有新增历史记录页面、永久删除或自动清空。
1. 接口与字段
前缀 /api/v1,全部接口使用正常 access token:Authorization: Bearer <accessToken>,身份从安全上下文取得。不得传 userId 来指定通知归属;企业仍受已有认证门禁限制。
| 操作 | 方法与路径 | 请求 | 成功 data |
|---|---|---|---|
| 正常列表(已有) | GET /notifications?page=0&size=20 |
page≥0,size=1~50 | 原分页信封,仅正常通知 |
| 回收站 | GET /notifications/trash?page=0&size=20 |
同上 | 回收站分页信封 |
| 单条移入回收站 | DELETE /notifications/{id} |
无请求体,正整数通知 ID | {"changed":true} |
| 单条恢复 | POST /notifications/{id}/restore |
无请求体,正整数通知 ID | {"changed":true} |
| 批量移入回收站 | POST /notifications/batch-delete |
{"ids":[28,29]} |
{"requested":2,"changed":2} |
| 批量恢复 | POST /notifications/batch-restore |
{"ids":[28,29]} |
{"requested":2,"changed":2} |
均为统一响应 code=200,data 外仍有 message、requestId、timestamp。重复删除已删除通知、恢复正常通知均成功但 changed=false;批量 changed 是实际改变状态的条数,requested 是去重后的 ID 数。
批量约束
- ids 必须为非空数组,原始数组长度 1~100。超过 100 条即拒绝,不会先去重再绕过上限。
- 只接受 JSON 正整数,不能是字符串、浮点数、布尔值、null、0、负数或超出 int64 范围的值。
- 重复 ID 去重,例如
[28,28]→ requested=1,最多改变一次。 - 整批原子操作:任意 ID 不存在、归属其他账号,整批失败,无部分成功。已经处于目标状态的本人通知是幂等项,不构成失败。
- 前端现有通知 id 若存为 string,发送批量请求前必须严格校验并转为安全整数;不能把 string 数组直接发给后端,也不能用 parseInt 静默截断。
function batchIds(ids: string[]): number[] {
if (ids.length < 1 || ids.length > 100) throw new Error('一次请选择 1~100 条通知');
return [...new Set(ids.map(id => {
if (!/^[1-9]\d*$/.test(id)) throw new Error('通知 ID 无效');
const value = Number(id);
if (!Number.isSafeInteger(value)) throw new Error('通知 ID 超出安全整数范围');
return value;
}))];
}
回收站响应
{
"code": 200,
"message": "ok",
"data": {
"items": [{
"id": 28,
"type": "INTERVIEW_INVITED",
"title": "面试邀请",
"content": "你收到一条面试邀请",
"read": false,
"readAt": null,
"createdAt": "2026-10-27T10:00:00",
"businessType": "INTERVIEW",
"businessId": 123,
"deletedAt": "2026-10-28T10:00:00"
}],
"total": 1,
"page": 0,
"size": 20,
"totalPages": 1
}
}
- 正常列表仍为第一批九个条目字段,不额外返回 deletedAt;回收站在原字段上增加非空 deletedAt。
- 正常列表按原 createdAt/id 倒序;回收站按 deletedAt/id 倒序。恢复后保留原 createdAt,回到正常列表的原时间位置,不保证出现在第一条。
- 删除/恢复不改 type、正文、业务关联、read 或 readAt,也不创建新通知;重复删除不刷新 deletedAt。
2. 左滑、多选与回收站流程
正常通知列表
- 左滑:露出“删除”按钮,点击后才发送 DELETE。不要一次滑动就直接执行。
- 成功后从正常列表移除该项,并刷新分页总数和全局未读数。失败保留或回滚该项,显示可重试反馈。
- 长按:进入多选模式,显示选择数、“取消”“删除所选”,可以提供“全选当前已加载项”。
- 单次最多选择 100 条。已加载更多时应明确限制或提示分批处理,禁止静默截断,也不要后台拆成多批却声称整次操作原子成功。
- 批量删除前确认所选数量。成功后退出或更新选择状态;失败不应清空选择,也不能只移除一部分记录。
- 正常点击继续走第一批“通知全文/业务详情 + 标记已读”,与左滑、长按手势区分,避免误触。
回收站
- 提供独立回收站入口和分页列表,支持单条恢复、长按多选及恢复所选。
- 回收站不提供“再次删除”“永久删除”“清空回收站”,也不自动过期清理。
- 回收站中可以查看通知内容,但不要因浏览而调用标记已读。恢复后再按正常通知流程阅读。
- 恢复成功后刷新正常列表、回收站、两个通知入口和全局未读数;恢复失败保留条目并提示重试。
红点与已读规则
- 未读通知移入回收站后,不再计入
/notifications/unread-count。 - 恢复时保留原 read/readAt:原未读通知重新计数;原已读通知仍已读,不增加未读数。
- 原
POST /notifications/read-all只处理正常列表,不会修改回收站中的通知。 - 对回收站里的通知调用
POST /notifications/{id}/read会拒绝,不得把它当作已读成功。 - 不要直接用 changed 扣减未读数:删除项可能混合已读与未读。成功后以未读数接口为准,并保护账号切换和旧响应覆盖。
3. 权限、错误与业务边界
| 场景 | 行为 |
|---|---|
| 未登录、过期或禁用账号原 Token | 401,走登录恢复 |
| 参数或 JSON ID 格式非法 | 400,通常 code=1001,修正请求后重试 |
| 通知不存在 | 沿用既有 HTTP 400 / code=9105 |
| 对回收站条目标记已读 | HTTP 400 / code=9105,提示先恢复,不假装已读 |
| 删除/恢复其他账号的通知 | 403 / code=2002;批量整批失败 |
| 未认证企业 | 沿用企业认证门禁,按具体错误码展示,不一律解释成通知归属问题 |
| 网络超时,是否成功未知 | 先刷新状态或安全重试;删除/恢复幂等,不能宣称已成功 |
删除仅是当前用户自己的通知软删除,不取消面试、不删除投递/Offer、不影响企业或对方收到的通知。业务详情的访问权限仍由各业务接口校验;业务目标已失效也不妨碍删除或恢复通知。
软删除不是物理清除数据;个人数据导出及账号注销清理继续遵循现有范围和规则。本模块不增加永久删除能力或历史操作记录页面。
4. 联调验收
- 未读删除 → 红点计数减少 → 回收站保留 read=false → 恢复后重新计数。
- 已读删除/恢复后 readAt 不变,未读数不增加;重复操作 changed=false 或 0。
- “全部已读”只影响正常列表;回收站原未读恢复后仍未读。
- 正常列表和回收站分别分页;相同删除时间下顺序稳定,无重复/漏项。
- 1 条、100 条、重复 ID、101 条、非法 ID 和空选择均正确处理。
- 批量混入他人或不存在 ID,整批失败,无部分消失或部分恢复。
- A/B 账号隔离、切账号时旧响应不回写;未认证企业、禁用账号不放宽。
- 并发点击已读与删除,不会让通知意外复活;并发批量删除幂等。
- 前端只提交明确选择的 ID,不进行永久删除、不取消关联业务。
后端定向/迁移测试、完整构建、同次 JAR 黑盒、前端实机手势和线上部署分别登记,不互相替代。第一批验收快照保存在 D:\Acceptance\qsp-notification-full-20261028-a1\;当前工作区已叠加第二批,不能再用第一批旧 13 文件清单直接发布当前工作区。后续须按第一批依赖 + 第二批改动的完整合并基线重新验收。