feat: 优化对话历史与会商引导体验
列表引导改为手动触发且不跳转创建页;历史 Tab 展示会商步骤/链条与深度研究模板;Step2 增加暂停与内容高度跟随滚动,并修复旧草稿恢复兜底。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
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>
|
||||
</>
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user