fix(web): stale-closure + focus trap + 去边界强转 + a11y/性能打磨 + 类型化客户端
P1-6 useStyleLearn/useKimiOauth 修 stale-closure 依赖。 P1-7 CommandPalette/Drawer 加 focus trap(新 lib/a11y/focusTrap)。 P1-8 SSE 解析与 server.ts 去 as 强转改类型守卫/运行时校验。 P2 删冗余强转、开 noUncheckedIndexedAccess、Toast 清理+稳定 key、列表 key 稳定化、 rel=noopener、useMemo 大文本、ConflictCard role=group、useInjection 加锁、 client.test 真断言。 codegen 重生成 schema.d.ts + 消费 DimensionEntry/ReviewConflictView 强类型。
This commit is contained in:
@@ -12,7 +12,7 @@ import type { StyleDriftReport, StyleDriftSegment } from "@/lib/review/sse";
|
||||
export type { StyleDriftReport, StyleDriftSegment } from "@/lib/review/sse";
|
||||
|
||||
// ── 指纹(16 维 + 证据,UX §6.9)─────────────────────────────────
|
||||
// 后端 dimensions={name:value}、evidence={name:[quotes]}(松散 JSONB)。
|
||||
// 后端 dimensions: DimensionEntry[](每条 {name,value,evidence},强类型,替代弱类型 dict)。
|
||||
export interface FingerprintDimension {
|
||||
name: string;
|
||||
value: string;
|
||||
@@ -24,31 +24,19 @@ export interface Fingerprint {
|
||||
version: number;
|
||||
}
|
||||
|
||||
function asStringArray(v: unknown): string[] {
|
||||
if (!Array.isArray(v)) return [];
|
||||
return v.filter((x): x is string => typeof x === "string");
|
||||
}
|
||||
|
||||
function asDisplayValue(v: unknown): string {
|
||||
if (typeof v === "string") return v;
|
||||
if (typeof v === "number" || typeof v === "boolean") return String(v);
|
||||
return "";
|
||||
}
|
||||
|
||||
// 把松散 GET /style 响应收窄成 Fingerprint。
|
||||
// dimensions 的 key 顺序即维度顺序(身份);evidence 按维度名对齐。
|
||||
// 把 GET /style 响应映射成 Fingerprint。
|
||||
// dimensions 数组顺序即维度顺序(身份);每条已携带 name/value/evidence。
|
||||
export function normalizeFingerprint(
|
||||
resp: StyleFingerprintResponse | undefined,
|
||||
): Fingerprint | null {
|
||||
if (!resp) return null;
|
||||
const dims = resp.dimensions ?? {};
|
||||
const evid = resp.evidence ?? {};
|
||||
const names = Object.keys(dims);
|
||||
const dimensions: FingerprintDimension[] = names.map((name) => ({
|
||||
name,
|
||||
value: asDisplayValue(dims[name]),
|
||||
evidence: asStringArray(evid[name]),
|
||||
}));
|
||||
const dimensions: FingerprintDimension[] = (resp.dimensions ?? []).map(
|
||||
(d) => ({
|
||||
name: d.name,
|
||||
value: d.value,
|
||||
evidence: d.evidence ?? [],
|
||||
}),
|
||||
);
|
||||
return { dimensions, version: resp.version };
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user