);
diff --git a/frontend-web/src/pages/SkillsPage.tsx b/frontend-web/src/pages/SkillsPage.tsx
index 08f9586a..f9a5ea9d 100644
--- a/frontend-web/src/pages/SkillsPage.tsx
+++ b/frontend-web/src/pages/SkillsPage.tsx
@@ -2,7 +2,7 @@ import { SkillSettingsPage } from "@/components/workspace/settings/skill-setting
export default function SkillsPage() {
return (
-
+
);
diff --git a/frontend-web/src/roundtable-planning/components/FlowGraphPanel.tsx b/frontend-web/src/roundtable-planning/components/FlowGraphPanel.tsx
index f49e1425..c9877edd 100644
--- a/frontend-web/src/roundtable-planning/components/FlowGraphPanel.tsx
+++ b/frontend-web/src/roundtable-planning/components/FlowGraphPanel.tsx
@@ -22,6 +22,7 @@ import {
BackgroundVariant,
Handle,
MarkerType,
+ MiniMap,
Position,
ReactFlow,
ReactFlowProvider,
@@ -48,16 +49,36 @@ import {
} from "lucide-react";
import { cn } from "@/lib/utils";
+import { useTheme } from "@/contexts/ThemeContext";
import {
applyNodeEdit,
deleteNodeFromGraph,
- FLOW_NODE_TYPE_META,
+ flowNodeMeta,
FLOW_NODE_W,
layoutFlowGraph,
type FlowGraphData,
type FlowGraphNode,
+ type FlowOrientation,
} from "@/roundtable-planning/lib/flow-graph";
+/**
+ * 深蓝主题色板(《深蓝色 UI 规范》ZS-004 / ZS-002)。浅色保持原 slate/white。
+ * 用于流程图弹窗在深色下的容器 / 头部 / 画布 / 连线 / 图例 / 小地图 / 详情弹窗。
+ */
+const DARK = {
+ pageBg: "#0C1836", // ZS-004-09 画布底
+ cardBg: "#122347", // ZS-004-08 头部 / 详情卡底
+ border: "#1A2F5A", // ZS-004-07 卡片边框
+ borderStrong: "#2D4473", // ZS-004-06 弱分割
+ text: "#C5CFE0", // ZS-004-02 正文
+ textMuted: "#6E88B0", // ZS-004-04 次级文字
+ primary: "#1677FF", // ZS-002-06 主色
+ link: "#4096FF", // ZS-002-05 链接
+ dots: "#2D4473", // 画布点阵
+ edge: "#4A6491", // ZS-004-05 静态连线
+ edgeActive: "#4096FF", // 活动连线
+} as const;
+
interface FlowGraphPanelProps {
data: FlowGraphData;
/** 流式绘制中(决定蚂蚁线 + 自动 fitView 跟随)。 */
@@ -67,17 +88,32 @@ interface FlowGraphPanelProps {
onSwitchToReport?: () => void;
/** Phase 3:画布手动编辑——传入则节点详情弹窗出现「编辑 / 删除」,回写整张新图。 */
onChange?: (next: FlowGraphData) => void;
+ /** 布局方向:默认 "vertical"(自上而下);弹窗里用 "horizontal" 横向铺开。 */
+ orientation?: FlowOrientation;
+ /** 右下角缩略图(小地图)—— 弹窗大画布里便于纵览定位。 */
+ miniMap?: boolean;
}
// ── 自定义节点(按 type 着色的卡片)────────────────────────────────────────
function FlowCardNode({ data }: NodeProps) {
- const node = (data as { node?: FlowGraphNode; scale?: number }).node;
- const scale = (data as { node?: FlowGraphNode; scale?: number }).scale ?? 1;
+ const d = data as {
+ node?: FlowGraphNode;
+ scale?: number;
+ orientation?: FlowOrientation;
+ dark?: boolean;
+ };
+ const node = d.node;
+ const scale = d.scale ?? 1;
if (!node) return null;
- const meta = FLOW_NODE_TYPE_META[node.type];
+ const meta = flowNodeMeta(d.dark ?? false)[node.type];
// 节点宽度随容器宽度缩放(宽时放大、窄时缩小)。
const scaledWidth = FLOW_NODE_W * scale;
+ // 横向布局连入/连出走左右两侧,纵向走上下。
+ const horizontal = d.orientation === "horizontal";
+ const targetPos = horizontal ? Position.Left : Position.Top;
+ const sourcePos = horizontal ? Position.Right : Position.Bottom;
+ const handleColor = d.dark ? "!bg-[#4A6491]" : "!bg-slate-400";
return (
-
+
@@ -97,7 +133,7 @@ function FlowCardNode({ data }: NodeProps) {
{node.label}
-
+
);
}
@@ -115,8 +151,12 @@ function FlowCanvasInner({
onClose,
onSwitchToReport,
onChange,
+ orientation = "vertical",
+ miniMap = false,
}: FlowGraphPanelProps & { fullscreen: boolean; onToggleFullscreen: () => void }) {
const rf = useReactFlow();
+ const { theme } = useTheme();
+ const isDark = theme === "dark";
const [selectedId, setSelectedId] = useState
(null);
const [scale, setScale] = useState(1);
const containerRef = useRef(null);
@@ -145,7 +185,7 @@ function FlowCanvasInner({
};
}, [rf]);
- const layoutNodes = useMemo(() => layoutFlowGraph(data), [data]);
+ const layoutNodes = useMemo(() => layoutFlowGraph(data, orientation), [data, orientation]);
const derivedNodes: Node[] = useMemo(
() =>
layoutNodes.map((n) => ({
@@ -153,9 +193,9 @@ function FlowCanvasInner({
type: "flowCard",
// 节点随 scale 放大 → 布局坐标同步乘 scale,间距一起拉开,避免同层重叠。
position: manualPosRef.current.get(n.id) ?? { x: n.x * scale, y: n.y * scale },
- data: { node: n, scale },
+ data: { node: n, scale, orientation, dark: isDark },
})),
- [layoutNodes, scale],
+ [layoutNodes, scale, orientation, isDark],
);
const [nodes, setNodes] = useState(derivedNodes);
@@ -174,7 +214,13 @@ function FlowCanvasInner({
() =>
data.edges.map((e) => {
const active = streaming && (e.to === newestNodeId || e.from === newestNodeId);
- const color = active ? "#3b82f6" : "#94a3b8";
+ const color = active
+ ? isDark
+ ? DARK.edgeActive
+ : "#3b82f6"
+ : isDark
+ ? DARK.edge
+ : "#94a3b8";
return {
id: `e-${e.from}->${e.to}`,
source: e.from,
@@ -183,11 +229,11 @@ function FlowCanvasInner({
animated: active,
style: { stroke: color, strokeWidth: active ? 2 : 1.5 },
markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },
- labelStyle: { fontSize: 10, fill: "#64748b", fontWeight: 700 },
- labelBgStyle: { fill: "#ffffff", fillOpacity: 0.85 },
+ labelStyle: { fontSize: 10, fill: isDark ? DARK.text : "#64748b", fontWeight: 700 },
+ labelBgStyle: { fill: isDark ? DARK.cardBg : "#ffffff", fillOpacity: isDark ? 0.9 : 0.85 },
} satisfies Edge;
}),
- [data.edges, streaming, newestNodeId],
+ [data.edges, streaming, newestNodeId, isDark],
);
// 流式中节点增加 → 画布平滑 fitView 跟随生长(用户暂停流后不再打扰)。
@@ -202,15 +248,30 @@ function FlowCanvasInner({
const selectedNode = selectedId ? data.nodes.find((n) => n.id === selectedId) ?? null : null;
return (
-
+
{/* 头部:标题 + 工具栏 */}
-
+
-
+
{data.title || "方案流程图"}
-
+
{data.nodes.length} 节点 · {data.edges.length} 连线
{streaming && (
@@ -226,7 +287,8 @@ function FlowCanvasInner({
type="button"
title="切回 Markdown 报告预览(流程图可随时再打开)"
onClick={onSwitchToReport}
- className="mr-1 inline-flex h-7 items-center gap-1 rounded-lg border border-slate-200/70 bg-white px-2 text-[10.5px] font-bold text-slate-600 transition hover:border-primary/40 hover:text-primary"
+ className="mr-1 inline-flex h-7 items-center gap-1 rounded-lg border border-slate-200/70 bg-white px-2 text-[10.5px] font-bold text-slate-600 transition hover:border-primary/40 hover:text-primary dark:hover:text-primary"
+ style={isDark ? { background: "transparent", borderColor: DARK.border, color: DARK.text } : undefined}
>
MD 报告
@@ -271,13 +333,50 @@ function FlowCanvasInner({
deleteKeyCode={null}
proOptions={{ hideAttribution: true }}
>
-
+
+ {miniMap && (
+ {
+ const t = (n.data as { node?: FlowGraphNode }).node?.type;
+ return (t && flowNodeMeta(isDark)[t]?.dot) || (isDark ? DARK.textMuted : "#94a3b8");
+ }}
+ nodeStrokeWidth={2}
+ maskColor={isDark ? "rgba(6,14,36,0.6)" : "rgba(240,240,240,0.6)"}
+ className={cn(
+ "!bottom-2 !right-2 !m-0 overflow-hidden rounded-lg border shadow-sm backdrop-blur-sm",
+ isDark ? "" : "border-slate-200/70 bg-white/90",
+ )}
+ style={
+ isDark
+ ? { width: 168, height: 112, background: "rgba(18,35,71,0.9)", borderColor: DARK.border }
+ : { width: 168, height: 112 }
+ }
+ />
+ )}
{/* 图例 */}
-
- {Object.entries(FLOW_NODE_TYPE_META).map(([type, meta]) => (
-
+
+ {Object.entries(flowNodeMeta(isDark)).map(([type, meta]) => (
+
{meta.label}
@@ -290,6 +389,7 @@ function FlowCanvasInner({
setSelectedId(null)}
onJump={(id) => setSelectedId(id)}
onChange={onChange}
@@ -308,12 +408,15 @@ function ToolButton({
onClick: () => void;
children: React.ReactNode;
}) {
+ const { theme } = useTheme();
+ const isDark = theme === "dark";
return (
@@ -325,18 +428,20 @@ function ToolButton({
function NodeDetailModal({
node,
data,
+ dark = false,
onClose,
onJump,
onChange,
}: {
node: FlowGraphNode;
data: FlowGraphData;
+ dark?: boolean;
onClose: () => void;
onJump: (id: string) => void;
/** Phase 3:传入则可编辑 / 删除该节点(回写整张新图)。 */
onChange?: (next: FlowGraphData) => void;
}) {
- const meta = FLOW_NODE_TYPE_META[node.type];
+ const meta = flowNodeMeta(dark)[node.type];
const labelOf = (id: string) => data.nodes.find((n) => n.id === id)?.label ?? id;
const incoming = data.edges.filter((e) => e.to === node.id);
const outgoing = data.edges.filter((e) => e.from === node.id);
@@ -366,6 +471,7 @@ function NodeDetailModal({
>
e.stopPropagation()}
>
{node.group?.trim() || meta.label}
@@ -388,6 +494,7 @@ function NodeDetailModal({
type="button"
onClick={onClose}
className="shrink-0 rounded-md p-1 text-slate-500 hover:bg-white/60 hover:text-slate-700"
+ style={dark ? { color: DARK.textMuted } : undefined}
>
@@ -395,36 +502,48 @@ function NodeDetailModal({
{editing ? (
-
-
-
+
+
+
) : (
-
详细说明
-
+
+ 详细说明
+
+
{node.detail?.trim() || "(该节点未提供详细说明)"}
{incoming.length > 0 && (
-
({ id: e.from, label: labelOf(e.from), edgeLabel: e.label }))} onJump={onJump} />
+ ({ id: e.from, label: labelOf(e.from), edgeLabel: e.label }))} onJump={onJump} dark={dark} />
)}
{outgoing.length > 0 && (
- ({ id: e.to, label: labelOf(e.to), edgeLabel: e.label }))} onJump={onJump} />
+ ({ id: e.to, label: labelOf(e.to), edgeLabel: e.label }))} onJump={onJump} dark={dark} />
)}
)}
{/* 编辑 / 删除 操作栏(仅传入 onChange 时显示) */}
{onChange && (
-
+
{editing ? (
<>
@@ -451,6 +570,7 @@ function NodeDetailModal({
type="button"
onClick={() => setEditing(true)}
className="inline-flex items-center gap-1 rounded-lg border border-slate-200 px-3 py-1.5 text-[11px] font-bold text-slate-700 hover:border-primary/40 hover:text-primary"
+ style={dark ? { borderColor: DARK.border, color: DARK.text } : undefined}
>
编辑
@@ -469,27 +589,39 @@ function EditField({
value,
onChange,
multiline,
+ dark = false,
}: {
label: string;
value: string;
onChange: (v: string) => void;
multiline?: boolean;
+ dark?: boolean;
}) {
+ const fieldStyle = dark
+ ? { background: "rgba(6,14,36,0.45)", borderColor: DARK.border, color: DARK.text }
+ : undefined;
return (
-
{label}
+
+ {label}
+
{multiline ? (
@@ -500,14 +632,19 @@ function ConnectionList({
title,
entries,
onJump,
+ dark = false,
}: {
title: string;
entries: Array<{ id: string; label: string; edgeLabel?: string }>;
onJump: (id: string) => void;
+ dark?: boolean;
}) {
return (
-
+
{title}
@@ -517,11 +654,15 @@ function ConnectionList({
type="button"
onClick={() => onJump(entry.id)}
className="inline-flex items-center gap-1 rounded-lg border border-slate-200 bg-slate-50 px-2 py-1 text-[11px] font-semibold text-slate-700 transition hover:border-primary/40 hover:text-primary"
+ style={dark ? { borderColor: DARK.border, background: "rgba(6,14,36,0.4)", color: DARK.text } : undefined}
title="查看该节点详情"
>
{entry.label}
{entry.edgeLabel && (
-
+
{entry.edgeLabel}
)}
@@ -534,8 +675,10 @@ function ConnectionList({
// ── 外壳:覆盖右栏 / 全屏切换 ───────────────────────────────────────────────
-export function FlowGraphPanel({ data, streaming, onClose, onSwitchToReport, onChange }: FlowGraphPanelProps) {
+export function FlowGraphPanel({ data, streaming, onClose, onSwitchToReport, onChange, orientation, miniMap }: FlowGraphPanelProps) {
const [fullscreen, setFullscreen] = useState(false);
+ const { theme } = useTheme();
+ const isDark = theme === "dark";
const inner = (
diff --git a/frontend-web/src/roundtable-planning/components/Step1Panel.tsx b/frontend-web/src/roundtable-planning/components/Step1Panel.tsx
index 9c295404..ceb91abc 100644
--- a/frontend-web/src/roundtable-planning/components/Step1Panel.tsx
+++ b/frontend-web/src/roundtable-planning/components/Step1Panel.tsx
@@ -67,6 +67,11 @@ import type { IntentSummary } from "@/roundtable-planning/api/intent";
export interface Step1PanelProps {
// ─── State ────────────────────────────────────────────────────
+ /**
+ * 头部左侧自定义内容(深链 taskId 模式:用「策划流程」小图取代默认标题)。
+ * 不传 → 显示默认「任务意图理解 (人机问答)」标题。右侧「问答轮次」始终保留。
+ */
+ headerLeftSlot?: React.ReactNode;
interactiveMessages: InteractiveMessage[];
intentThreadId: string | null;
intentReady: object | null;
@@ -93,6 +98,7 @@ export interface Step1PanelProps {
export function Step1Panel(props: Step1PanelProps) {
const {
+ headerLeftSlot,
interactiveMessages,
intentThreadId,
intentReady,
@@ -157,14 +163,16 @@ export function Step1Panel(props: Step1PanelProps) {
return (
{/* Dialogue Header */}
-
-
-
-
- 任务意图理解 (人机问答)
-
-
-
+
+ {headerLeftSlot ?? (
+
+
+
+ 任务意图理解 (人机问答)
+
+
+ )}
+
问答轮次:{interactiveMessages.filter((m) => m.sender === "user").length} 轮
diff --git a/frontend-web/src/roundtable-planning/lib/flow-graph.ts b/frontend-web/src/roundtable-planning/lib/flow-graph.ts
index c9466334..128ee3f2 100644
--- a/frontend-web/src/roundtable-planning/lib/flow-graph.ts
+++ b/frontend-web/src/roundtable-planning/lib/flow-graph.ts
@@ -53,11 +53,16 @@ export interface FlowGraphData {
edges: FlowGraphEdge[];
}
+export interface FlowNodeColors {
+ label: string;
+ bg: string;
+ border: string;
+ text: string;
+ dot: string;
+}
+
/** 各类型节点的配色(浅底 + 深字 + 强调点),前端按 type 区分颜色。 */
-export const FLOW_NODE_TYPE_META: Record<
- FlowNodeType,
- { label: string; bg: string; border: string; text: string; dot: string }
-> = {
+export const FLOW_NODE_TYPE_META: Record = {
start: { label: "开始", bg: "#f1f5f9", border: "#94a3b8", text: "#334155", dot: "#64748b" },
end: { label: "结束", bg: "#f1f5f9", border: "#94a3b8", text: "#334155", dot: "#64748b" },
stage: { label: "阶段", bg: "#eff6ff", border: "#60a5fa", text: "#1d4ed8", dot: "#3b82f6" },
@@ -68,6 +73,27 @@ export const FLOW_NODE_TYPE_META: Record<
role: { label: "角色", bg: "#faf5ff", border: "#c084fc", text: "#7e22ce", dot: "#a855f7" },
};
+/**
+ * 深蓝主题下的节点配色(对齐《深蓝色 UI 规范》ZS-004 深底):保留各类型色相作识别,
+ * 底色取该色相在深底上的低透明度叠色(dot @ ~16–18%),描边取色相高透明度,
+ * 文字用同色相浅色调(深底可读),强调点沿用亮色。供流程图弹窗 + 头部小节点用。
+ */
+export const FLOW_NODE_TYPE_META_DARK: Record = {
+ start: { label: "开始", bg: "rgba(100,116,139,0.20)", border: "rgba(148,163,184,0.55)", text: "#C5CFE0", dot: "#94a3b8" },
+ end: { label: "结束", bg: "rgba(100,116,139,0.20)", border: "rgba(148,163,184,0.55)", text: "#C5CFE0", dot: "#94a3b8" },
+ stage: { label: "阶段", bg: "rgba(59,130,246,0.20)", border: "rgba(96,165,250,0.60)", text: "#bfdbfe", dot: "#60a5fa" },
+ task: { label: "任务", bg: "rgba(6,182,212,0.20)", border: "rgba(34,211,238,0.60)", text: "#a5f3fc", dot: "#22d3ee" },
+ decision: { label: "判断", bg: "rgba(245,158,11,0.18)", border: "rgba(251,191,36,0.55)", text: "#fcd34d", dot: "#fbbf24" },
+ risk: { label: "风险", bg: "rgba(239,68,68,0.18)", border: "rgba(248,113,113,0.55)", text: "#fecaca", dot: "#f87171" },
+ deliverable: { label: "交付物", bg: "rgba(34,197,94,0.18)", border: "rgba(74,222,128,0.55)", text: "#bbf7d0", dot: "#4ade80" },
+ role: { label: "角色", bg: "rgba(168,85,247,0.20)", border: "rgba(192,132,252,0.58)", text: "#e9d5ff", dot: "#c084fc" },
+};
+
+/** 按明暗取节点配色表。 */
+export function flowNodeMeta(dark: boolean): Record {
+ return dark ? FLOW_NODE_TYPE_META_DARK : FLOW_NODE_TYPE_META;
+}
+
const VALID_TYPES = new Set(Object.keys(FLOW_NODE_TYPE_META));
export const FLOW_FENCE_OPEN = "```flow-json";
@@ -395,9 +421,22 @@ export interface PositionedFlowNode extends FlowGraphNode {
export const FLOW_NODE_W = 176;
const X_GAP = 224;
const Y_GAP = 132;
+// 横向布局:层间走 x(节点宽 176 + 连线/标签留白),层内同层节点沿 y 堆叠。
+const LAYER_GAP_X = 248;
+const NODE_GAP_Y = 104;
-/** 最长路径分层(环保护:访问中的节点按 0 层处理,保证终止)。 */
-export function layoutFlowGraph(data: FlowGraphData): PositionedFlowNode[] {
+export type FlowOrientation = "vertical" | "horizontal";
+
+/**
+ * 最长路径分层(环保护:访问中的节点按 0 层处理,保证终止)。
+ *
+ * orientation="vertical"(默认):层自上而下、同层横向铺开。
+ * orientation="horizontal":层自左而右、同层纵向铺开(弹窗里宽屏看着更舒展)。
+ */
+export function layoutFlowGraph(
+ data: FlowGraphData,
+ orientation: FlowOrientation = "vertical",
+): PositionedFlowNode[] {
const preds = new Map();
for (const e of data.edges) {
const list = preds.get(e.to);
@@ -428,10 +467,19 @@ export function layoutFlowGraph(data: FlowGraphData): PositionedFlowNode[] {
const pos = new Map();
for (const [layer, nodes] of byLayer) {
- const rowWidth = (nodes.length - 1) * X_GAP;
- nodes.forEach((n, i) => {
- pos.set(n.id, { x: i * X_GAP - rowWidth / 2, y: layer * Y_GAP });
- });
+ if (orientation === "horizontal") {
+ // 层 → x,同层节点沿 y 居中堆叠。
+ const colHeight = (nodes.length - 1) * NODE_GAP_Y;
+ nodes.forEach((n, i) => {
+ pos.set(n.id, { x: layer * LAYER_GAP_X, y: i * NODE_GAP_Y - colHeight / 2 });
+ });
+ } else {
+ // 层 → y,同层节点沿 x 居中铺开(原默认)。
+ const rowWidth = (nodes.length - 1) * X_GAP;
+ nodes.forEach((n, i) => {
+ pos.set(n.id, { x: i * X_GAP - rowWidth / 2, y: layer * Y_GAP });
+ });
+ }
}
// 保持原始(流式)顺序输出,方便调用方做「最新节点」判断。
return data.nodes.map((n) => ({ ...n, ...pos.get(n.id)! }));
diff --git a/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx b/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx
index b3703515..50add085 100644
--- a/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx
+++ b/frontend-web/src/roundtable-planning/pages/RoundtablePlanningPage.tsx
@@ -26,6 +26,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import {
Activity,
+ BookOpen,
Check,
CheckCircle,
ChevronRight,
@@ -46,10 +47,12 @@ import {
Save,
Settings,
Sparkles,
+ Target,
Trash2,
Upload,
Users,
X,
+ Zap,
} from "lucide-react";
import { useTheme } from "@/contexts/ThemeContext";
@@ -62,6 +65,13 @@ import { useModels } from "@/core/models/hooks";
import { getAvatar, Man1Avatar, RobotAvatar } from "@/roundtable-planning/components/Avatars";
import { ImportRoundtableDraftDialog } from "@/components/workspace/roundtable-draft-share-dialogs";
+import { TaskPurposeDialog } from "@/strategy-components/components/task-components/TaskPurposeDialog";
+import {
+ derivePurposeLevels,
+ fetchTaskPurposeDetail,
+ type PurposeLevel,
+} from "@/core/auth/task-purpose";
+import { flowNodeMeta, type FlowNodeType } from "@/roundtable-planning/lib/flow-graph";
import { RecommendAgentsDialog } from "@/roundtable-planning/components/RecommendAgentsDialog";
import { BusinessChainListDialog } from "@/roundtable-planning/components/BusinessChainListDialog";
import { DispatchChainJobModal } from "@/roundtable-planning/components/DispatchChainJobModal";
@@ -231,6 +241,11 @@ export default function RoundtablePlanningPage() {
const [chainModalJobId, setChainModalJobId] = useState(null);
// 「导入会商」弹窗(输入分享码把别人分享的会商复制到本账号)。
const [isImportOpen, setIsImportOpen] = useState(false);
+ // 任务目的弹窗(多智能体会商深链 taskId 模式:查看线上当前策划进度/目的树)。
+ const [isTaskPurposeOpen, setIsTaskPurposeOpen] = useState(false);
+ // 深链 taskId 模式:消息列表上方的「策划流程示例图」——按目的树层级画彩色小图标
+ // (任务→目的→…→叙事),点击打开任务目的流程图弹窗。空 = 无数据/未取到,不显示。
+ const [purposeLevels, setPurposeLevels] = useState([]);
const [selectedModel, setSelectedModel] = useState("");
// Step 2 席位执行模式(快速/思考/专业问答/多智能体问答)——决定每个子智能体席位的
// 推理深度。由「选择参会智能体」弹窗确认时的 SeatSelectionResult.seatMode 决定。
@@ -897,6 +912,25 @@ export default function RoundtablePlanningPage() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // 仅挂载时执行一次
+ // 深链 taskId 模式:挂载即取目的树,抽出有序层级供消息列表上方的「策划流程示例图」。
+ // 与任务目的弹窗同一条接口(弹窗打开时再各自取一帧,互不影响);取不到则保持空、不显示。
+ useEffect(() => {
+ const tid = prefillRef.current?.taskId;
+ if (!tid) return;
+ let cancelled = false;
+ void fetchTaskPurposeDetail(tid)
+ .then((r) => {
+ if (!cancelled) setPurposeLevels(derivePurposeLevels(r.tree));
+ })
+ .catch(() => {
+ if (!cancelled) setPurposeLevels([]);
+ });
+ return () => {
+ cancelled = true;
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []); // 仅挂载时执行一次
+
// C2:带 autoStart 时,等 Step 1 意图线程就绪后自动把「任务名称/描述」作为首条用户消息发出,
// 触发任务理解智能体自动分析(只发一次)。
useEffect(() => {
@@ -1551,6 +1585,15 @@ export default function RoundtablePlanningPage() {
}}
/>
+ {/* 任务目的弹窗(深链 taskId 模式:查看线上当前策划进度/目的树,只读) */}
+ {prefillRef.current?.taskId && (
+
+ )}
+
{/* 派活链路流程图弹窗(订阅进行中作业的真实 SSE 进度) */}
+ {/* 深链 taskId 模式:查看线上当前策划进度(目的树)。与单智能体闸门同一条接口。 */}
+ {prefillRef.current?.taskId && (
+
+ )}
+
{!inWujieEmbed && (