修复第2章复测发现的3个问题:好友申请通知按钮/时间格式/新机器码样本

- 好友申请通知的"查看新朋友"按钮永远不出现:判断条件是 action.type==='friend_request',
  但实测 GET /system-notifications 拿到的 friend.request.created 通知,action 里只有
  {user_id},从来没有 type 字段——这个判断条件是当初凭对接文档猜的,不是照真实响应写的。
  改用 event_type.startsWith('friend.request')。
- 系统消息时间格式:默认 toLocaleString('zh-CN') 输出"2026/8/20 18:04:00"(年份/斜杠/秒),
  参考图是"6月28日 10:04"。新增 formatNotificationTime。
- 机器码兜底表补一条:新样本 security.risk.continue 事件的 summary 是 decision 字面量
  "continue",同样会被机器码识别但查表落空、原样显示英文单词。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Your Name
2026-09-04 13:06:00 +08:00
co-authored by Claude Sonnet 5
parent 02a565b8e5
commit 8e703d86eb
3 changed files with 31 additions and 8 deletions
+20 -4
View File
@@ -113,6 +113,15 @@ function formatConversationTime(ts) {
return date.toLocaleDateString('zh-CN', {month: 'numeric', day: 'numeric'});
}
// 参考图 系统消息.png 的时间格式是"6月28日 10:04"——不带年份、中文月日、不带秒。原来直接用
// toLocaleString('zh-CN') 默认格式,会输出"2026/8/20 18:04:00"(带年份、斜杠、秒),跟设计不符。
function formatNotificationTime(ts) {
const d = new Date(ts);
const hh = String(d.getHours()).padStart(2, '0');
const mm = String(d.getMinutes()).padStart(2, '0');
return `${d.getMonth() + 1}月${d.getDate()}日 ${hh}:${mm}`;
}
// Entries (system messages / file assistant) come from bootstrap.entries and are always shown --
// unlike the old mock, they don't disappear once the user has real conversations (that was a bug).
function entryConversations(bootstrap) {
@@ -310,7 +319,10 @@ const NOTIFICATION_TEXT = {
'group.role.updated': '群成员角色有变更',
'group.settings.updated': '群设置有更新',
accepted: '对方已通过你的好友申请',
rejected: '对方拒绝了你的好友申请'
rejected: '对方拒绝了你的好友申请',
// 新样本:security.risk.continue 事件的 summary 直接是 decision 字面量 "continue"
// (风险确认审计记录,见 im-api.js 的 confirmRiskChallenge),同样是机器码。
continue: '你确认继续了一次安全风险提示'
};
function systemNotificationText(item) {
@@ -353,7 +365,7 @@ function SystemMessages({authenticated}) {
{error ? <p className="messages-empty"><Icon>error_outline</Icon>{error}</p> : null}
{!loading && !error && items.length === 0 ? <p className="messages-empty"><Icon>notifications_none</Icon>暂无系统消息</p> : null}
{items.map(item => <article key={item.id} className={item.read_at ? 'read' : ''} onClick={() => markRead(item)}>
<time>{new Date(item.created_at).toLocaleString('zh-CN')}</time>
<time>{formatNotificationTime(item.created_at)}</time>
<div className="system-notification-card">
<header><h2>{item.title}</h2>{!item.read_at ? <span>新</span> : null}</header>
<p>{systemNotificationText(item)}</p>
@@ -361,10 +373,14 @@ function SystemMessages({authenticated}) {
{/* 入口按通知自身的 action 决定,不再对所有通知一律显示"前往安全设置"。注意 action.topic
不能直接当成群:好友申请类通知的 action 里带的是 p2p 会话 topic
(db/mysql/tenant_adapter.go:8643),只有 grp 前缀才是真的群。都不匹配时不显示按钮,
避免把人导到跟这条通知无关的页面。 */}
避免把人导到跟这条通知无关的页面。
真实好友申请通知的 action 判断改用 event_type 而不是 action.type:实测
GET /system-notifications 拿到的 friend.request.created 通知,action 里只有
{user_id},从来没有 type 字段(当初写 action.type==='friend_request' 是凭对接文档
猜的,不是照真实响应写的)——导致"查看新朋友"按钮对这条最常见的通知永远不出现。 */}
{item.action && typeof item.action.topic === 'string' && item.action.topic.startsWith('grp') ?
<button type="button" className="system-security-link" onClick={e => { e.stopPropagation(); navigate('group-settings', item.action.topic); }}>查看群聊 <Icon>chevron_right</Icon></button> :
item.action && item.action.type === 'friend_request' ?
item.event_type && item.event_type.startsWith('friend.request') ?
<button type="button" className="system-security-link" onClick={e => { e.stopPropagation(); navigate('friend-requests'); }}>查看新朋友 <Icon>chevron_right</Icon></button> :
item.action && (item.action.device || item.action.ip) ?
<button type="button" className="system-security-link" onClick={e => { e.stopPropagation(); navigate(authenticated ? 'security' : 'identity-check'); }}>前往安全设置 <Icon>chevron_right</Icon></button> :
+10 -3
View File
@@ -12792,6 +12792,12 @@ function formatConversationTime(ts) {
day: 'numeric'
});
}
function formatNotificationTime(ts) {
const d = new Date(ts);
const hh = String(d.getHours()).padStart(2, '0');
const mm = String(d.getMinutes()).padStart(2, '0');
return `${d.getMonth() + 1}月${d.getDate()}日 ${hh}:${mm}`;
}
function entryConversations(bootstrap) {
if (!bootstrap || !bootstrap.entries) return [];
const list = [];
@@ -13158,7 +13164,8 @@ const NOTIFICATION_TEXT = {
'group.role.updated': '群成员角色有变更',
'group.settings.updated': '群设置有更新',
accepted: '对方已通过你的好友申请',
rejected: '对方拒绝了你的好友申请'
rejected: '对方拒绝了你的好友申请',
continue: '你确认继续了一次安全风险提示'
};
function systemNotificationText(item) {
const summary = (item.summary || '').trim();
@@ -13225,7 +13232,7 @@ function SystemMessages({
className: item.read_at ? 'read' : '',
onClick: () => markRead(item),
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("time", {
children: new Date(item.created_at).toLocaleString('zh-CN')
children: formatNotificationTime(item.created_at)
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("div", {
className: "system-notification-card",
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("header", {
@@ -13260,7 +13267,7 @@ function SystemMessages({
children: ["查看群聊 ", (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)(Icon, {
children: "chevron_right"
}, void 0, false)]
}, void 0, true) : item.action && item.action.type === 'friend_request' ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", {
}, void 0, true) : item.event_type && item.event_type.startsWith('friend.request') ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxDEV)("button", {
type: "button",
className: "system-security-link",
onClick: e => {
+1 -1
View File
File diff suppressed because one or more lines are too long