import { useEffect, useState } from 'react'; import type { EventStore } from '../../engine/eventStore'; import type { JevClient } from '../../services/jev'; import { BADGE_MAP } from './badges'; import { scoreProfile } from '../../engine/scoring'; import type { DimensionScore } from '../../engine/scoring'; export type { DimensionScore } from '../../engine/scoring'; import { ShareCard } from './ShareCard'; interface Props { store: EventStore; jev: JevClient; onReplay: () => void; } /** Act 1 结束后的画像报告页:Jev 一次调用并行问 7 个维度 score */ export function ReportPage({ store, jev, onReplay }: Props) { const [scores, setScores] = useState(null); const [error, setError] = useState(null); const [retry, setRetry] = useState(0); const [playerName, setPlayerName] = useState(''); useEffect(() => { let cancelled = false; (async () => { try { const events = await store.list(); // 最近一次身份登记的称呼(旧数据缺 name 字段时回退空串 → 只显示编号) const name = [...events].reverse().find((e) => e.kind === 'profile')?.profile?.name ?? ''; if (!cancelled) setPlayerName(name); const result = await scoreProfile(events, jev); if (cancelled) return; setScores(result); } catch (e) { if (!cancelled) setError(e instanceof Error ? e.message : String(e)); } })(); return () => { cancelled = true; }; }, [store, jev, retry]); if (error) { return (

画像报告生成失败

{error}

); } if (!scores) { return (

档案馆正在整理你的记忆……

Jev 正在评估 7 个维度。

); } // 勋章 = 置信度最高的维度 const top = [...scores].sort((a, b) => b.confidence - a.confidence)[0]; const badge = BADGE_MAP[top.id]; return (

人格画像报告 · Act 1

C-2049{playerName ? `「${playerName}」` : ''}的档案

勋

{badge.title}

{badge.flavor}

(取自实测置信度最高的维度:{top.label},置信度 {Math.round(top.confidence * 100)}%)

{scores.map((s) => (
{s.label}
{s.score.toFixed(1)}/{s.max} · 置信度 {Math.round(s.confidence * 100)}% {s.confidence < 0.6 && ' · 证据不足'}
))}
); }