feat(站内通知): 铃铛面板支持时间/内容搜索、按天分组与分页

- 列表接口加 keyword(标题/内容模糊)与 startDate/endDate(年月日闭区间)参数,
  两端控制器透传,服务端补筛选日志
- 两端铃铛面板:搜索框(防抖 300ms)+ 日期区间 + 按年月日分组 + 翻页,
  面板改 Teleport 到 body(挂在顶栏时会被页面 el-select 压住,提 z-index 无效)
- 固化可见范围回归测试:超管全量/管理员只看本组/普通用户只看自己,
  含读写两侧的 user_id+audience 裁剪断言与两端控制器身份来源断言
This commit is contained in:
2026-09-13 23:59:06 +08:00
parent 9ffd68bae5
commit ff1ffbbfa3
18 changed files with 1426 additions and 136 deletions
@@ -3,6 +3,7 @@ import assert from 'node:assert/strict'
import {
formatNotificationTime,
formatUnreadBadge,
groupNotificationsByDay,
hasNewNotification,
readLastNotifiedId,
writeLastNotifiedId,
@@ -80,3 +81,49 @@ test('test_时间展示:今天/昨天/更早', () => {
assert.equal(formatNotificationTime(null, now), '')
assert.equal(formatNotificationTime('not-a-date', now), '')
})
test('test_按年月日分组:今天/昨天/更早,组内保持原顺序', () => {
const now = new Date(2026, 8, 13, 15, 30)
const items = [
{ id: 4, createdAt: new Date(2026, 8, 13, 15, 0).toISOString() },
{ id: 3, createdAt: new Date(2026, 8, 13, 9, 0).toISOString() },
{ id: 2, createdAt: new Date(2026, 8, 12, 23, 0).toISOString() },
{ id: 1, createdAt: new Date(2026, 8, 1, 8, 0).toISOString() },
]
const groups = groupNotificationsByDay(items, now)
assert.equal(groups.length, 3)
assert.deepEqual(
groups.map((group) => [group.day, group.label]),
[
['2026-09-13', '今天'],
['2026-09-12', '昨天'],
['2026-09-01', '2026年9月1日'],
],
)
assert.deepEqual(
groups[0].items.map((item) => item.id),
[4, 3],
'同一天的多条合为一组且保持倒序',
)
})
test('test_按年月日分组:时间缺失/非法归入未知时间组', () => {
const now = new Date(2026, 8, 13, 15, 30)
const groups = groupNotificationsByDay(
[
{ id: 2, createdAt: null },
{ id: 1, createdAt: 'not-a-date' },
],
now,
)
assert.equal(groups.length, 1)
assert.equal(groups[0].day, '')
assert.equal(groups[0].label, '未知时间')
assert.deepEqual(
groups[0].items.map((item) => item.id),
[2, 1],
)
})