3 Commits

Author SHA1 Message Date
seaislee1209
aa1a70121a feat(notification): 公告颜色自适应 — 算法 strip 暗色/浅色专用灰度色,彩色保留
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m47s
用户反馈:公告里手写的 <div style="color:#e0e0e0"> 在浅色背景下糊;
工具栏只改了"红字""蓝字"按钮(自动适配),自由手写硬编码颜色还是会踩坑。

方案:写 adaptAnnouncementColors helper,sanitize 前预处理 HTML,用算法识别
"灰度系 + 极端亮度(>200 或 <80)"的颜色 → strip 整条声明,让继承主题色;
彩色(三通道差 ≥ 30)一律保留,因为它们通常双主题都可读。

判断细节:
- 用 canvas.fillStyle 解析任意 CSS 颜色值(支持 hex/rgb/rgba/hsl/命名色)
- 灰度判断:max(r,g,b) - min(r,g,b) < 30(允许微偏色)
- 亮度判断:(r+g+b)/3 > 200(浅) 或 < 80(深) 双向 strip
- CSS var / currentColor / inherit / transparent 一律保留(用户已经主题适配过)
- 不止 color,background-color / border-* / outline-color 都覆盖

实际验证(用户给的 HTML 例子):
- div color: #e0e0e0 (224,224,224)  → 灰度+亮 → strip ✓
- h2 color: #a78bfa (167,139,250)   → 紫色 → 保留 ✓
- span color: #34d399 (52,211,153)  → 绿色 → 保留 ✓
- hr border #374151 (55,65,81)      → 灰度+暗 → strip ✓

实现:
- 新建 web/src/lib/adaptAnnouncementColors.ts(~110 行,纯 DOMParser+canvas,无依赖)
- AnnouncementModal:sanitize 前调用 adaptAnnouncementColors
- NotificationsPage 展开公告:同上
- SSR 安全:document 不存在时原样返回

smoke 验证:
- 测试公告同时含 #e0e0e0/#374151(灰度,应 strip)+ #a78bfa/#34d399(彩,应留)
- 展开后 page.evaluate 扫 inline style 验证 4 项颜色去留 — 4/4 全过
- announcement-integration-smoke 17/17 (从 13 加 4 项颜色检查)
- v0.20.1-smoke 11/11 + modal-interaction 8/8 + v2-smoke 25/25 + vitest 71/162

UX 影响:
- 超管手写 HTML 用 #e0e0e0 类暗色专用默认色 → 自动 strip,浅深都清晰
- 超管手写 #ff5e5e/#34d399 类彩色 → 保留,两个主题都看得见
- "我自定义了颜色就保留,没自定义按系统主题"语义达成

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:48:46 +08:00
seaislee1209
bd3e80fd58 feat(notification): 消息中心改 accordion 模式 + 跳转按钮 + 公告颜色 CSS var 自适应
用户反馈三点:
1. 公告里"红字"/"蓝字"工具按钮硬编码颜色 #ff4d4f / #00b8e6 在浅色下糊
2. 消息中心列表里公告直接渲染完整 HTML,行被撑得很大
3. 点行就自动 navigate(link_url),用户希望"只看不跳",看完主动决定要不要跳转

改动:

a) SettingsPage 公告编辑器颜色按钮(2 个):
   - 红字: <span style="color:#ff4d4f"> → var(--color-danger)
   - 蓝字: <span style="color:#00b8e6"> → var(--color-primary)
   - 分割线 border-top 颜色 #333 → var(--color-border-card)
   - 三个都改成 CSS var,自动适配浅/深主题
   - title 文案加"(自适应主题)"提示超管

b) NotificationsPage accordion 模式:
   - 加 expandedId: number | null state,始终最多 1 条展开
   - 折叠态:chip + title + 时间 + 一行剥 HTML 后的纯文本预览(stripAndTruncate, 60 字 '…')
   - 展开态:头部 + 下方完整内容(announcement 用 DOMPurify+HTML / 其他 plain) +
            link_url 非空时显示【前往查看】按钮(蓝底白字,带箭头 icon)
   - chevron icon 旋转 0deg/180deg 视觉指示折叠/展开
   - 同 id 再点 → 收起;不同 id → 切换(前一个自动收起)
   - 切页时自动重置 expandedId 为 null

c) 点击行为:
   - handleRowClick(自动跳) → handleToggle(只 markRead + 切 expandedId)
   - 新加 handleJump(url):用户主动点【前往查看】才触发 navigate / window.open(http url)
   - 展开区域 onClick 加 stopPropagation 防误触收起

d) smoke test 更新:
   - 测试公告内容做长用 EXPANDED-ONLY-MARKER 末尾标记,preview 截断后看不到
   - 7.2.0 折叠态 preview 截断验证(marker 不可见)
   - 7.2 展开后 marker 可见
   - 7.3 再点收起 marker 不再可见
   - 用 chip [公告] 文字作为稳定点击锚点(只在头部出现不在展开内容里)

验证:
- typecheck 0 error
- announcement-integration-smoke 13/13(从 10 项扩到 13,加 accordion 路径)
- v0.20.1-smoke 11/11 + v2-smoke 25/25 + modal-interaction 8/8 全过
- vitest 71 fail / 162 pass 与基线一致

GlobalAnnouncementGate 强弹 modal 行为不变(plan §一 7 — 公告强制阅读语义保留)。
重看路径走 sidebar 大铃铛 → 消息中心 → accordion 展开看全文 → 可点【前往查看】跳。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:24:49 +08:00
seaislee1209
e55a6665f2 test+docs(notification): announcement-integration-smoke.mjs 10/10 + plan 归档 + 完成报告
新建 web/test/announcement-integration-smoke.mjs 10 项 E2E:
- 空内容 400 / HTML 发送 200 / fan-out 数 = User 总数
- tudou 拿到未读 / 浏览器自动强弹 modal / 关闭标已读 / 再开不弹
- 消息中心 [公告] chip + HTML 渲染 / 无 console.error

跑通基线对比:
- vitest 71 fail / 162 pass (0 新增回归)
- v2-smoke 25/25 + modal-interaction 8/8 + v0.20.1-smoke 11/11
- 新 announcement-integration-smoke 10/10

归档 plan 文件 docs/todo/通知公告整合.md(v2,本次实施的源 plan)。
写完成报告 docs/todo/通知公告整合-完成报告.md(改动文件清单 + 3 commit hash + 测试结果 + 关键设计决策 + 边缘 case 处理)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:04:43 +08:00