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

通知第二批:删除、多选与回收站对接

日期: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. 左滑、多选与回收站流程

正常通知列表

  1. 左滑:露出“删除”按钮,点击后才发送 DELETE。不要一次滑动就直接执行。
  2. 成功后从正常列表移除该项,并刷新分页总数和全局未读数。失败保留或回滚该项,显示可重试反馈。
  3. 长按:进入多选模式,显示选择数、“取消”“删除所选”,可以提供“全选当前已加载项”。
  4. 单次最多选择 100 条。已加载更多时应明确限制或提示分批处理,禁止静默截断,也不要后台拆成多批却声称整次操作原子成功。
  5. 批量删除前确认所选数量。成功后退出或更新选择状态;失败不应清空选择,也不能只移除一部分记录。
  6. 正常点击继续走第一批“通知全文/业务详情 + 标记已读”,与左滑、长按手势区分,避免误触。

回收站

  1. 提供独立回收站入口和分页列表,支持单条恢复、长按多选及恢复所选。
  2. 回收站不提供“再次删除”“永久删除”“清空回收站”,也不自动过期清理。
  3. 回收站中可以查看通知内容,但不要因浏览而调用标记已读。恢复后再按正常通知流程阅读。
  4. 恢复成功后刷新正常列表、回收站、两个通知入口和全局未读数;恢复失败保留条目并提示重试。

红点与已读规则

  • 未读通知移入回收站后,不再计入 /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 文件清单直接发布当前工作区。后续须按第一批依赖 + 第二批改动的完整合并基线重新验收。