feat: 优化对话历史与会商引导体验

列表引导改为手动触发且不跳转创建页;历史 Tab 展示会商步骤/链条与深度研究模板;Step2 增加暂停与内容高度跟随滚动,并修复旧草稿恢复兜底。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
董宏凯andCursor committed 2026-08-28 20:25:21 +08:00
1 parent 832e180c52
commit 4ac7bc21cd
18 files changed
+184 -88

No files matched your search

@@ -18,6 +18,7 @@ import {
useResearchSessions,
type DeepResearchSession,
} from "@/strategy-components/api/deep-research";
import { useReportStructures } from "@/strategy-components/api/report-structures";
import { formatRelative } from "@/open-canvas/components/ai-writing/AIWritingHistoryDropdown";
import { desensitize } from "@/lib/desensitize";
@@ -48,6 +49,25 @@ const RESEARCH_STATUS: Record<
cancelled: { label: "已取消", className: "text-muted-foreground" },
};
/**
* 深度研究会话把选中的报告模板快照为 custom_outline;用结构库里的内容反查标题。
* 内容不再存在或用户输入了自定义大纲时,明确展示为「自定义报告结构」,避免冒充模板名。
*/
function reportTemplateLabel(
session: DeepResearchSession,
structures: { title: string; content: string }[],
): string {
const config = session.config ?? {};
const outline = typeof config.custom_outline === "string"
? config.custom_outline.trim()
: typeof config.customOutline === "string"
? config.customOutline.trim()
: "";
if (!outline) return "默认报告结构";
return structures.find((structure) => structure.content.trim() === outline)?.title ?? "自定义报告结构";
}
export function ResearchHistoryTab({
query,
onTotalChange,
@@ -57,6 +77,7 @@ export function ResearchHistoryTab({
}) {
const navigate = useNavigate();
const { data, isLoading } = useResearchSessions(100);
const structuresQuery = useReportStructures();
const actions = useResearchActions();
const [renameId, setRenameId] = useState<string | null>(null);
const [renameTitle, setRenameTitle] = useState("");
@@ -124,6 +145,7 @@ export function ResearchHistoryTab({
className: "text-muted-foreground",
};
const timestamp = session.updatedAt ?? session.createdAt ?? null;
const template = reportTemplateLabel(session, structuresQuery.data ?? []);
return (
<HistoryRow
key={session.id}
@@ -141,6 +163,10 @@ export function ResearchHistoryTab({
<span>{session.sourceCount} 条来源</span>
</>
)}
<span className="text-muted-foreground/60">·</span>
<span className="max-w-56 truncate" title={`模板:${template}`}>
模板:{template}
</span>
{timestamp && (
<>
<span className="text-muted-foreground/60">·</span>
@@ -33,19 +33,36 @@ import {
const ROUNDTABLE_PATH = "/page/workspace/roundtable/planning";
/** 草稿后台作业状态 → 小标签(映射与原侧栏列表一致)。 */
function statusOf(draft: DraftMeta): { label: string; className: string } {
if (draft.status === "running" || draft.status === "queued") {
return { label: "进行中", className: "text-primary" };
const ROUNDTABLE_STEP_LABEL: Record<DraftMeta["furthestStep"], string> = {
1: "议题梳理",
2: "多智能体会商",
3: "报告生成",
};
/**
* 列表接口会返回草稿已推进到的工作台步骤以及最新后台作业状态。两者须同时展示:
* `furthestStep` 告诉用户做到哪一环,`status` 告诉用户是否已真正完成或被中断。
*/
function progressOf(draft: DraftMeta): {
label: string;
className: string;
stepLabel: string;
} {
const stepLabel = `第 ${draft.furthestStep} 步 · ${ROUNDTABLE_STEP_LABEL[draft.furthestStep]}`;
if (draft.status === "done" || (!draft.status && draft.furthestStep === 3)) {
return { label: "已完成", className: "text-emerald-600", stepLabel };
}
if (draft.status === "error") {
return { label: "执行失败", className: "text-rose-500", stepLabel: `停在${stepLabel}` };
}
if (draft.status === "cancelled") {
return { label: "已取消", className: "text-muted-foreground", stepLabel: `停在${stepLabel}` };
}
if (draft.status === "awaiting_input") {
return { label: "待澄清", className: "text-amber-500" };
return { label: "等待确认", className: "text-amber-500", stepLabel: `当前${stepLabel}` };
}
if (draft.status === "error" || draft.status === "cancelled") {
return { label: "出错", className: "text-rose-500" };
}
// 无进行中作业时展示本次会商所用业务链(无链条 → 自由模式)。
return { label: draft.chainTitle || "自由模式", className: "text-muted-foreground" };
return { label: "进行中", className: "text-primary", stepLabel: `当前${stepLabel}` };
}
export function RoundtableHistoryTab({
@@ -122,7 +139,7 @@ export function RoundtableHistoryTab({
<>
<div>
{filtered.map((draft) => {
const status = statusOf(draft);
const progress = progressOf(draft);
return (
<HistoryRow
key={draft.id}
@@ -131,10 +148,18 @@ export function RoundtableHistoryTab({
meta={
<>
<HistoryStatusPill
label={status.label}
className={status.className}
label={progress.label}
className={progress.className}
/>
<span className="text-muted-foreground/60">·</span>
<span className="max-w-48 truncate" title={progress.stepLabel}>
{progress.stepLabel}
</span>
<span className="text-muted-foreground/60">·</span>
<span className="max-w-40 truncate" title={draft.chainTitle || "自由模式"}>
{draft.chainTitle || "自由模式"}
</span>
<span className="text-muted-foreground/60">·</span>
<span>{formatRelative(draft.updatedAt)}</span>
</>
}