样式修改

This commit is contained in:
fengxiangdebaozi committed 2026-06-11 17:38:36 +08:00
1 parent d9e3a87911
commit d12c50ea4e
5 files changed
+85 -12

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920" height="62" viewBox="0 0 1920 62"><defs><style>.a{fill:url(#a);}.b{fill:rgba(0,98,217,0.1);}.c{fill:#fff;}.d{fill:rgba(0,98,217,0.2);}.e{filter:url(#h);}.f{filter:url(#e);}.g{filter:url(#b);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#0b3776"/><stop offset="1" stop-color="#0c1935"/></linearGradient><filter id="b"><feOffset dy="-3" input="SourceAlpha"/><feGaussianBlur result="c"/><feFlood flood-color="#0062d9" flood-opacity="0.102" result="d"/><feComposite operator="out" in="SourceGraphic" in2="c"/><feComposite operator="in" in="d"/><feComposite operator="in" in2="SourceGraphic"/></filter><filter id="e"><feOffset dy="-3" input="SourceAlpha"/><feGaussianBlur result="f"/><feFlood flood-color="#0062d9" flood-opacity="0.102" result="g"/><feComposite operator="out" in="SourceGraphic" in2="f"/><feComposite operator="in" in="g"/><feComposite operator="in" in2="SourceGraphic"/></filter><filter id="h"><feOffset dy="-3" input="SourceAlpha"/><feGaussianBlur result="i"/><feFlood flood-color="#0062d9" flood-opacity="0.2" result="j"/><feComposite operator="out" in="SourceGraphic" in2="i"/><feComposite operator="in" in="j"/><feComposite operator="in" in2="SourceGraphic"/></filter></defs><g transform="translate(-2009 -3361)"><rect class="a" width="1920" height="62" transform="translate(2009 3361)"/><g data-type="innerShadowGroup"><path class="b" d="M0,0H318L268,62H0Z" transform="translate(2009 3361)"/><g class="g" transform="matrix(1, 0, 0, 1, 2009, 3361)"><path class="c" d="M0,0H318L268,62H0Z"/></g></g><g data-type="innerShadowGroup"><path class="b" d="M0,0H310L260,62H0Z" transform="translate(2009 3361)"/><g class="f" transform="matrix(1, 0, 0, 1, 2009, 3361)"><path class="c" d="M0,0H310L260,62H0Z"/></g></g><g data-type="innerShadowGroup"><path class="d" d="M0,0H302L252,62H0Z" transform="translate(2009 3361)"/><g class="e" transform="matrix(1, 0, 0, 1, 2009, 3361)"><path class="c" d="M0,0H302L252,62H0Z"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

@@ -9,7 +9,7 @@
*
* 进入即自动开跑(`useStep3Report.start`),右上角「重新绘制」可重跑。
*/
import { useEffect, useMemo, useRef, useState } from "react";
import { useEffect, useMemo, useRef, useState, type FormEvent } from "react";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import {
@@ -23,6 +23,7 @@ import {
PanelLeftClose,
PanelLeftOpen,
RefreshCw,
SendHorizontal,
Sparkles,
X,
} from "lucide-react";
@@ -197,7 +198,7 @@ export function Step3ReportMode({
<div className="flex items-center gap-2">
<button
type="button"
onClick={redraw}
onClick={() => redraw()}
disabled={phase === "creating" || phase === "streaming"}
className="bg-white border border-slate-200 text-slate-700 hover:bg-slate-50 disabled:opacity-50 disabled:cursor-not-allowed text-[10.5px] font-bold px-3 py-1.5 rounded-xl flex items-center gap-1 transition"
>
@@ -311,6 +312,7 @@ export function Step3ReportMode({
dialogues={dialogues}
error={error}
onRetry={redraw}
onRevisionSubmit={redraw}
onArtifactStepClick={openArtifactFromStep}
onArtifactPreview={openArtifactPreview}
selectedModel={selectedModel}
@@ -432,6 +434,7 @@ function AgentProgressPanel({
dialogues,
error,
onRetry,
onRevisionSubmit,
onArtifactStepClick,
onArtifactPreview,
selectedModel,
@@ -443,6 +446,7 @@ function AgentProgressPanel({
dialogues: ReturnType<typeof useStep3Report>["dialogues"];
error: string | null;
onRetry: () => void;
onRevisionSubmit: (revisionInstruction: string) => void;
onArtifactStepClick: ReturnType<typeof useStep3Report>["openArtifactFromStep"];
onArtifactPreview: ReturnType<typeof useStep3Report>["openArtifactPreview"];
selectedModel: string;
@@ -453,6 +457,15 @@ function AgentProgressPanel({
const busy = phase === "creating" || phase === "streaming";
const scrollRef = useRef<HTMLDivElement>(null);
const { atBottom, scrollToBottom } = useAutoScroll(scrollRef, [dialogues]);
const [revisionText, setRevisionText] = useState("");
const handleRevisionSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const text = revisionText.trim();
if (!text || busy) return;
setRevisionText("");
onRevisionSubmit(text);
};
return (
<div className="flex h-full min-h-0 flex-col bg-slate-50/20">
@@ -549,6 +562,39 @@ function AgentProgressPanel({
)}
</div>
{!atBottom && <ScrollToBottomButton onClick={scrollToBottom} />}
<form
onSubmit={handleRevisionSubmit}
className="shrink-0 border-t border-slate-100 bg-white px-3 py-3"
>
<div className="flex items-end gap-2 rounded-2xl border border-slate-200 bg-slate-50/70 px-3 py-2 focus-within:border-primary/60 focus-within:bg-white focus-within:ring-2 focus-within:ring-[var(--brand-200)]/40">
<textarea
value={revisionText}
onChange={(e) => setRevisionText(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
e.currentTarget.form?.requestSubmit();
}
}}
disabled={busy}
rows={1}
placeholder="输入修改要求,例如:把右侧页面改成深色风格,并增加风险矩阵"
className="min-h-8 max-h-28 flex-1 resize-none bg-transparent py-1.5 text-xs leading-relaxed text-slate-800 placeholder:text-slate-400 focus:outline-none disabled:cursor-not-allowed disabled:opacity-60"
/>
<button
type="submit"
disabled={busy || revisionText.trim().length === 0}
title={busy ? "正在绘制,请稍后发送" : "发送修改要求"}
className="mb-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-xl bg-primary text-white transition hover:bg-[var(--brand-900)] disabled:cursor-not-allowed disabled:opacity-50"
>
{busy ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<SendHorizontal className="h-4 w-4" />
)}
</button>
</div>
</form>
</div>
</div>
);
@@ -72,11 +72,11 @@ export interface UseStep3ReportReturn {
/** 当前沙箱预览绑定的 thread id(这里恒为报告线程)。 */
activeArtifactThreadId: string | null;
/** 启动绘制(幂等:进行中重复调用会被忽略)。 */
start: () => void;
start: (revisionInstruction?: string) => void;
/** 从草稿快照恢复展示(建合成 stub + 气泡 + 打开沙箱,phase=done,不重新绘制)。 */
hydrateSaved: (snapshot: DraftStep3Snapshot) => void;
/** 重新绘制(先中断在途请求再重跑)。 */
redraw: () => void;
redraw: (revisionInstruction?: string) => void;
/** 中断在途请求(卸载 / 切回普通视图时调用)。 */
abort: () => void;
/** 点击气泡内工具步骤时打开沙箱(与第 2 步 openArtifactFromStep 同义)。 */
@@ -92,8 +92,10 @@ function buildReportPrompt(opts: {
intentReady: ReportIntent | null;
seatDeliveries: ReportSeatDelivery[];
consensusText: string;
revisionInstruction?: string;
previousHtml?: string;
}): string {
const { intentReady, seatDeliveries, consensusText } = opts;
const { intentReady, seatDeliveries, consensusText, revisionInstruction, previousHtml } = opts;
const parts: string[] = [];
parts.push(
"请基于以下圆桌多智能体研讨的成果,撰写一份图文并茂、以文字叙述为主线的 HTML「方案研讨汇报」," +
@@ -135,6 +137,23 @@ function buildReportPrompt(opts: {
parts.push("");
}
const cleanRevisionInstruction = revisionInstruction?.trim();
if (cleanRevisionInstruction) {
parts.push("# User revision request");
parts.push(cleanRevisionInstruction);
parts.push("");
if (previousHtml?.trim()) {
parts.push("# Previous rendered HTML to revise");
parts.push(
"Use this as the baseline. Preserve parts not contradicted by the revision request, and output a complete updated self-contained HTML file.",
);
parts.push("```html");
parts.push(previousHtml.trim());
parts.push("```");
parts.push("");
}
}
parts.push(
"请严格遵循你的职责设定:自包含离线(纯 inline SVG 图表、禁止任何外链 CDN)、研讨叙事型结构" +
"(结论+KPI → 背景目标 → 各席位观点 → 综合分析 → 最终共识方案 → 执行路线)、" +
@@ -173,7 +192,7 @@ function reportPhaseLabel(phase: StreamPhase, toolName?: string): string {
export function useStep3Report(
options: UseStep3ReportOptions,
): UseStep3ReportReturn {
const { intentReady, seatDeliveries, consensusText, selectedModel, onReportSaved } =
const { intentReady, seatDeliveries, consensusText, selectedModel, savedReport, onReportSaved } =
options;
// onReportSaved 身份可能每次 render 变 —— 打到 ref,避免进 run() 的 deps 反复重建。
@@ -601,7 +620,7 @@ export function useStep3Report(
runningRef.current = false;
}, []);
const run = useCallback(async () => {
const run = useCallback(async (revisionInstruction?: string) => {
if (runningRef.current) return;
runningRef.current = true;
setError(null);
@@ -632,7 +651,13 @@ export function useStep3Report(
);
setPhase("streaming");
const prompt = buildReportPrompt({ intentReady, seatDeliveries, consensusText });
const prompt = buildReportPrompt({
intentReady,
seatDeliveries,
consensusText,
revisionInstruction,
previousHtml: savedReport?.html,
});
const res = await streamMultiAgent({
agentType: "special",
agentName,
@@ -687,6 +712,7 @@ export function useStep3Report(
intentReady,
seatDeliveries,
consensusText,
savedReport?.html,
selectedModel,
appendStreamingDialogue,
appendToDialogue,
@@ -699,8 +725,8 @@ export function useStep3Report(
reconcileStubFromRealFile,
]);
const start = useCallback(() => {
void run();
const start = useCallback((revisionInstruction?: string) => {
void run(revisionInstruction);
}, [run]);
// 从草稿快照恢复:不跑 SSE,用保存的 HTML 重建一条「完成」气泡 + 合成 stub,
@@ -766,9 +792,9 @@ export function useStep3Report(
[abort, buildWriteFileVirtualUrl, openArtifact],
);
const redraw = useCallback(() => {
const redraw = useCallback((revisionInstruction?: string) => {
abort();
void run();
void run(revisionInstruction);
}, [abort, run]);
return {