diff --git a/frontend-web/src/roundtable-planning/pages/DashboardAgentPage.tsx b/frontend-web/src/roundtable-planning/pages/DashboardAgentPage.tsx index 897bf4e3..6ce2ccb1 100644 --- a/frontend-web/src/roundtable-planning/pages/DashboardAgentPage.tsx +++ b/frontend-web/src/roundtable-planning/pages/DashboardAgentPage.tsx @@ -122,6 +122,15 @@ export default function DashboardAgentPage() { } }, [availableModels, selectedModel]); + // init 只跑一次:start / hydrateTranscript 用 ref 持有,effect 只依赖 [taskId]。 + // 否则它们的 identity 会随 selectedModel/themeMode 变化重建(模型挂载后异步加载即触发), + // 让 effect 在 await 期间 cleanup → 二次进入被 didInitRef 挡掉 → 首跑的 finally 因 cancelled + // 跳过 setLoading(false),loading 永远停在 true(白转圈,卡在「正在加载任务大屏…」)。 + const startRef = useRef(start); + startRef.current = start; + const hydrateTranscriptRef = useRef(hydrateTranscript); + hydrateTranscriptRef.current = hydrateTranscript; + // ── 挂载:按 taskId 取会话 → 决定直显大屏 / 看生成过程(只跑一次) ── const didInitRef = useRef(false); useEffect(() => { @@ -131,37 +140,38 @@ export default function DashboardAgentPage() { return; } didInitRef.current = true; - let cancelled = false; void (async () => { try { - const session = await getDashboardSessionByTask(taskId).catch(() => null); - if (cancelled) return; + // 会话 + 输入 JSON 并行取。输入**始终**备好并写进 inputRef —— 否则恢复历史 + // 后用户点「重新绘制」/续问时 buildInitialPrompt 拿不到源数据,会回退到空的 + // 圆桌 prompt,智能体没东西可分析 → 生成不出数据(即「模拟数据不生效」)。 + const [session, input] = await Promise.all([ + getDashboardSessionByTask(taskId).catch(() => null), + fetchDashboardInputJson(taskId).catch(() => null), + ]); + inputRef.current = input; const savedDialogues = (session?.transcript as Step2Dialogue[] | undefined) ?? []; const validReport = session?.reportJson && parseReportJson(session.reportJson); if (validReport) { // 有有效结果 → 恢复并直接展示大屏页面。 - hydrateTranscript(savedDialogues, session!.reportJson); + hydrateTranscriptRef.current(savedDialogues, session!.reportJson); setView("page"); } else if (savedDialogues.length > 0) { - // 有历史聊天但无有效结果 → 进生成过程展示历史,不自动重跑。 - hydrateTranscript(savedDialogues, session?.reportJson ?? null); + // 有历史聊天但无有效结果 → 进生成过程展示历史,不自动重跑(点「重新绘制」可重生成)。 + hydrateTranscriptRef.current(savedDialogues, session?.reportJson ?? null); setView("chat"); } else { - // 无任何记录 → 拉输入 JSON 自动开跑,让用户看生成过程(不自动跳)。 - const input = await fetchDashboardInputJson(taskId).catch(() => null); - if (cancelled) return; - inputRef.current = input; + // 无任何记录 → 自动开跑,让用户看生成过程(不自动跳)。 setView("chat"); - if (input) start(); + if (input) startRef.current(); } } finally { - if (!cancelled) setLoading(false); + setLoading(false); } })(); - return () => { - cancelled = true; - }; - }, [taskId, hydrateTranscript, start]); + // 只依赖 taskId:start/hydrateTranscript 经 ref 读取,避免其 identity 变化重跑本 effect。 + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [taskId]); // ── 防抖回存聊天记录 + 最新 report-json(按 taskId 共享) ── useEffect(() => { @@ -245,9 +255,9 @@ export default function DashboardAgentPage() { } return ( -
+
{/* 顶栏 */} -
+

大屏绘制智能体

diff --git a/frontend-web/src/styles/globals.css b/frontend-web/src/styles/globals.css index bec6856c..5a563267 100644 --- a/frontend-web/src/styles/globals.css +++ b/frontend-web/src/styles/globals.css @@ -626,6 +626,36 @@ background-attachment: fixed, fixed; } + /* 「大屏绘制智能体」独立页顶栏(DashboardAgentPage,class=dashboard-agent-topbar)深色 + * 适配:顶栏只为浅色写死了 slate/white 渐变,深色(.dark)下统一改深蓝(《深蓝色 UI 规范》 + * 卡片底 #122347 / 页面底 #0C1836 / 边框 #1A2F5A / 字体 #C5CFE0),仅作用于顶栏内, + * 不影响下方大屏/聊天区。浅色不命中,原样式不变。 */ + .dark .dashboard-agent-topbar { + background-image: linear-gradient(to right, #122347, #0c1836) !important; + border-color: #1a2f5a !important; + } + .dark .dashboard-agent-topbar .text-slate-900 { + color: #e8edf5 !important; + } + .dark .dashboard-agent-topbar + :is(.text-slate-700, .hover\:text-slate-700:hover) { + color: #c5cfe0 !important; + } + .dark .dashboard-agent-topbar :is(.text-slate-500, .text-slate-400) { + color: #6e88b0 !important; + } + .dark .dashboard-agent-topbar .bg-white { + background-color: #1a2f5a !important; + } + .dark .dashboard-agent-topbar + :is(.bg-slate-50, .hover\:bg-slate-50:hover) { + background-color: #0c1836 !important; + } + .dark .dashboard-agent-topbar + :is(.border-slate-100, .border-slate-200) { + border-color: #1a2f5a !important; + } + .workspace-panel { border: 1px solid #f0d7d0; background: #ffffff;