feat(小宝): 优化助手入口与预警已读
关键改动: - 更新 README 项目说明和小宝相关入口命名 - 优化问翻小宝页面与侧边栏测试 - 小宝预警已读状态抑制同签名重复 AI 请求 Co-Authored-By: Codex GPT-5 <codex@openai.com>
This commit is contained in:
@@ -3,15 +3,17 @@ import assert from 'node:assert/strict';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
test('sidebar links wenfan xiaobao as an independent entry before xiaobao warning', () => {
|
||||
test('sidebar labels AI assistant before smart warning', () => {
|
||||
const sidebar = readFileSync(join(process.cwd(), 'components/layout/Sidebar.tsx'), 'utf8');
|
||||
|
||||
const askIndex = sidebar.indexOf("label: '问翻小宝'");
|
||||
const warningIndex = sidebar.indexOf("label: '小宝预警'");
|
||||
const askIndex = sidebar.indexOf("label: 'AI 助手'");
|
||||
const warningIndex = sidebar.indexOf("label: '智能预警'");
|
||||
|
||||
assert.notEqual(askIndex, -1);
|
||||
assert.notEqual(warningIndex, -1);
|
||||
assert.ok(askIndex < warningIndex);
|
||||
assert.doesNotMatch(sidebar, /label: '问翻小宝'/);
|
||||
assert.doesNotMatch(sidebar, /label: '小宝预警'/);
|
||||
assert.match(sidebar, /path: '\/wenfan-xiaobao'/);
|
||||
});
|
||||
|
||||
@@ -36,6 +38,7 @@ test('wenfan xiaobao page provides records, chat, and voice input surfaces', ()
|
||||
assert.match(page, /deleteWenfanConversationRecord/);
|
||||
assert.match(page, /删除历史记录/);
|
||||
assert.doesNotMatch(page, /setHistory\(\(current\) => \[question/);
|
||||
assert.doesNotMatch(page, /<p className="mb-1 text-\[13px\] font-semibold text-\[#171717\]">问翻小宝<\/p>/);
|
||||
assert.match(page, /入口路径/);
|
||||
assert.match(page, /必填字段/);
|
||||
assert.match(page, /状态流转/);
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
getXiaobaoWarningUpdateSignature,
|
||||
isXiaobaoWarningUpdated,
|
||||
markXiaobaoWarningRead,
|
||||
shouldSkipXiaobaoRiskInsightRequestForReadState,
|
||||
sanitizeRiskInsight,
|
||||
} from './xiaobao-warning-view';
|
||||
|
||||
@@ -192,6 +193,31 @@ test('xiaobao warning update state is unread until the current user reads the sa
|
||||
assert.equal(isXiaobaoWarningUpdated(baseRisk, readStates, 'user-2'), true);
|
||||
});
|
||||
|
||||
test('read current warning state suppresses refresh-triggered AI requests only for the same signature', () => {
|
||||
const baseRisk = risk();
|
||||
const readStates = markXiaobaoWarningRead([], 'user-1', baseRisk, '2026-06-30T11:00:00.000Z');
|
||||
const changedRisk = risk({
|
||||
signals: {
|
||||
...baseRisk.signals,
|
||||
failedTestCount: 1,
|
||||
},
|
||||
riskScore: 72,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
shouldSkipXiaobaoRiskInsightRequestForReadState(baseRisk, readStates, 'user-1', true),
|
||||
true,
|
||||
);
|
||||
assert.equal(
|
||||
shouldSkipXiaobaoRiskInsightRequestForReadState(changedRisk, readStates, 'user-1', true),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
shouldSkipXiaobaoRiskInsightRequestForReadState(baseRisk, readStates, 'user-1', false),
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
test('xiaobao warning update state becomes unread again when risk facts change', () => {
|
||||
const baseRisk = risk();
|
||||
const readStates = markXiaobaoWarningRead([], 'user-1', baseRisk, '2026-06-30T11:00:00.000Z');
|
||||
|
||||
@@ -87,6 +87,17 @@ export function isXiaobaoWarningUpdated(
|
||||
return readSignature !== currentSignature;
|
||||
}
|
||||
|
||||
export function shouldSkipXiaobaoRiskInsightRequestForReadState(
|
||||
risk: XiaobaoVersionRisk,
|
||||
readStates: XiaobaoWarningReadState[],
|
||||
userId: string | undefined,
|
||||
readStateLoaded: boolean,
|
||||
): boolean {
|
||||
if (!userId) return false;
|
||||
if (!readStateLoaded) return true;
|
||||
return !isXiaobaoWarningUpdated(risk, readStates, userId);
|
||||
}
|
||||
|
||||
export function getXiaobaoWarningUnreadUpdateCount(
|
||||
risks: XiaobaoVersionRisk[],
|
||||
readStates: XiaobaoWarningReadState[],
|
||||
|
||||
Reference in New Issue
Block a user