diff --git a/frontend-web/src/core/page-layout/sidebar-menu.ts b/frontend-web/src/core/page-layout/sidebar-menu.ts
index b959d0b2..1d3f3bd3 100644
--- a/frontend-web/src/core/page-layout/sidebar-menu.ts
+++ b/frontend-web/src/core/page-layout/sidebar-menu.ts
@@ -21,6 +21,7 @@ import {
Grid3X3,
HelpCircle,
History,
+ Layers,
Layout,
Library,
List,
@@ -209,10 +210,16 @@ export const sidebarMenuItems: MenuItem[] = [
{ id: "mgmt-agents", label: "智能体管理", icon: Bot, path: "/page/strategy/agents" },
{
id: "mgmt-business-chain-mapping",
- label: "业务链条管理",
+ label: "配置管理",
icon: Network,
path: "/page/strategy/business-chain-mapping",
},
+ {
+ id: "mgmt-business-chains",
+ label: "业务链条配置",
+ icon: Layers,
+ path: "/page/strategy/business-chains",
+ },
{ id: "mgmt-skills", label: "技能管理", icon: Sparkles, path: "/page/strategy/skills" },
{ id: "mgmt-memory", label: "记忆管理", icon: Brain, path: "/page/strategy/memory" },
{
diff --git a/frontend-web/src/pages/BusinessChainMappingPage.tsx b/frontend-web/src/pages/BusinessChainMappingPage.tsx
index a3d05703..ae2db62d 100644
--- a/frontend-web/src/pages/BusinessChainMappingPage.tsx
+++ b/frontend-web/src/pages/BusinessChainMappingPage.tsx
@@ -1,5 +1,5 @@
/**
- * 业务链条管理页 —— 把固定业务码(3Q/6BF/7BF/8BF)绑定到「智能体」+「业务链」。
+ * 配置管理页 —— 把固定业务码(3Q/6BF/7BF/8BF)绑定到「智能体」+「业务链」。
*
* 表格三列:业务(只读)/ 智能体 / 业务链。编辑模式下后两列为可搜索下拉:
* - 智能体来自 `/api/agents`
@@ -129,7 +129,7 @@ export default function BusinessChainMappingPage() {
- 业务链条管理
+ 配置管理
为每个业务绑定智能体与业务链。多智能体会商从对应业务自动取用此处配置的业务链。业务链仅可选择「公共」链条。
diff --git a/frontend-web/src/pages/StrategyRoutes.tsx b/frontend-web/src/pages/StrategyRoutes.tsx
index 5f0129ed..dd8180b4 100644
--- a/frontend-web/src/pages/StrategyRoutes.tsx
+++ b/frontend-web/src/pages/StrategyRoutes.tsx
@@ -17,6 +17,8 @@ import { ActionAnalyzes } from "@/strategy-components/components/task-components
import KnowledgeBaseResourceManagement from "@/strategy-components/components/resource-management/KnowledgeBaseResourceManagement";
import NetworkActorResourceManagement from "@/strategy-components/components/resource-management/NetworkActorResourceManagement";
import RoundtablePlanningPage from "@/roundtable-planning/pages/RoundtablePlanningPage";
+import BusinessChainListPage from "@/roundtable-planning/pages/BusinessChainListPage";
+import BusinessChainEditorPage from "@/roundtable-planning/pages/BusinessChainEditorPage";
import "@/roundtable-planning/styles/roundtable-planning.css";
import AgentChatPage from "./AgentChatPage";
import AgentsPage from "./AgentsPage";
@@ -174,6 +176,8 @@ export default function StrategyRoutes() {
} />
} />
} />
+ } />
+ } />
}
/>
+
+
+
+ }
+ />
{/* Phase 7 临时预览入口:派活链路流程图弹窗(假数据自测,接通后台后可删) */}
void;
}
-export function BusinessChainListDialog({
- open,
- onOpenChange,
+export interface BusinessChainListBodyProps {
+ /**
+ * 是否激活(控制何时拉取列表):弹窗里传 `open`(打开才拉),
+ * 独立页面里恒为 `true`。
+ */
+ active: boolean;
+ /** 进入配置页。带 chainId = 打开并切到该链条;不带 = 空白新建。 */
+ onConfigure: (chainId?: string) => void;
+ /** 列表为空时的「去创建」引导文案差异(弹窗说「点下方配置」,页面说「点右上配置」)。 */
+ emptyHint?: string;
+}
+
+/**
+ * 业务链条列表主体(筛选 tab + 滚动卡片列表)。
+ *
+ * 从 `BusinessChainListDialog` 抽出,供弹窗与独立配置页(`BusinessChainListPage`)
+ * 复用,保证两处的加载 / 发布 / 卡片渲染逻辑完全一致。外层负责标题栏与「配置」入口、
+ * 以及撑出 `flex flex-col` 高度(本组件用 `flex-1` 占满剩余空间)。
+ */
+export function BusinessChainListBody({
+ active,
onConfigure,
-}: BusinessChainListDialogProps) {
+ emptyHint,
+}: BusinessChainListBodyProps) {
const [chains, setChains] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
@@ -65,9 +84,9 @@ export function BusinessChainListDialog({
}
}, []);
- // 每次打开 / 切换筛选都重新拉,保证配置页改动后回来看到的是最新列表。
+ // 每次激活 / 切换筛选都重新拉,保证配置页改动后回来看到的是最新列表。
useEffect(() => {
- if (!open) return;
+ if (!active) return;
let cancelled = false;
void (async () => {
setLoading(true);
@@ -84,7 +103,7 @@ export function BusinessChainListDialog({
return () => {
cancelled = true;
};
- }, [open, scope]);
+ }, [active, scope]);
const handleTogglePublic = useCallback(
async (chain: BusinessChain) => {
@@ -101,6 +120,73 @@ export function BusinessChainListDialog({
[refresh, scope],
);
+ return (
+ <>
+ {/* 筛选:我的 / 公共 */}
+
+ {(["mine", "public"] as const).map((s) => (
+
+ ))}
+
+
+
+ {loading ? (
+
+
+ 正在加载业务链条…
+
+ ) : error ? (
+
+ 加载业务链条失败:{error}
+
+ ) : chains.length === 0 ? (
+
+
+
+ {scope === "public" ? "还没有公共链条" : "还没有业务链条"}
+
+
+ {scope === "public"
+ ? "公共链条是其他账号(或你自己)发布出来、所有人可见的链条。去「我的」里发布一条试试。"
+ : emptyHint ??
+ "业务链条是可复用的有序智能体编排。点击下方「配置」去创建第一条链条。"}
+
+
+ ) : (
+
+ {chains.map((chain) => (
+ onConfigure(chain.id)}
+ onTogglePublic={() => handleTogglePublic(chain)}
+ />
+ ))}
+
+ )}
+
+ >
+ );
+}
+
+export function BusinessChainListDialog({
+ open,
+ onOpenChange,
+ onConfigure,
+}: BusinessChainListDialogProps) {
return (
+ );
+}
+
+// ── 链条席位编排流(体现「同层并行 · 层间串行」)─────────────────────────────
+
+function ChainSeatsFlow({ chain }: { chain: BusinessChain }) {
+ // 名称回退表:用落库快照(seats)解析 stage 里的 agent_id。
+ const seatById = new Map(chain.seats.map((s) => [s.agent_id, s] as const));
+
+ // 分层来源:带 stages(分层编排)就按 stages 渲染(过滤空阶段);否则每个席位各成
+ // 一段、顺序串行(线性链,与旧版展示一致)。
+ const stages =
+ chain.stages && chain.stages.length > 0
+ ? chain.stages.filter((s) => s.length > 0)
+ : chain.seats.map((s) => [s.agent_id]);
+
+ // 跨阶段累加的全局序号 —— 决定头像配色,与编辑器 / 展平 seats 顺序对齐。
+ const orderById = new Map
();
+ let counter = 0;
+ for (const stageIds of stages) {
+ for (const id of stageIds) {
+ orderById.set(id, counter);
+ counter += 1;
+ }
+ }
+
+ const seatTag = (agentId: string) => {
+ const seat = seatById.get(agentId);
+ return (
+
+ {seat?.name || agentId}
+
+ );
+ };
+
+ return (
+
+ {stages.map((stageIds, stageIdx) => (
+
+ {stageIdx > 0 && (
+
+ )}
+ {stageIds.length > 1 ? (
+ // 并行阶段:席位竖向并列在虚线框里,左上角标「并行 N」。
+
+
+ 并行 {stageIds.length}
+
+ {stageIds.map((id) => seatTag(id))}
+
+ ) : (
+ seatTag(stageIds[0])
+ )}
+
+ ))}
);
}
diff --git a/frontend-web/src/roundtable-planning/pages/BusinessChainListPage.tsx b/frontend-web/src/roundtable-planning/pages/BusinessChainListPage.tsx
new file mode 100644
index 00000000..0929ce46
--- /dev/null
+++ b/frontend-web/src/roundtable-planning/pages/BusinessChainListPage.tsx
@@ -0,0 +1,64 @@
+/**
+ * 业务链条配置页(独立页面版)。
+ *
+ * 把原本挂在圆桌页顶栏「业务链条」按钮上的 `BusinessChainListDialog` 弹窗内容,
+ * 单独画成一个全屏页面:综合管理 → 业务链条配置 入口进来即是本页。
+ *
+ * - 列表主体复用 `BusinessChainListBody`(与弹窗同一份加载 / 发布 / 卡片逻辑)。
+ * - 顶部「配置」按钮 = 进入编辑器空白新建;卡片「设置」= 进入编辑器并切到该链条。
+ *
+ * 路由 base 感知:用 `useRouteNavigate` 跳转,strategy / workspace 两套路由树下
+ * 都能落到当前 base 的编辑器(`roundtable/chains`)。
+ */
+import { LayersIcon, SettingsIcon } from "lucide-react";
+
+import { Button } from "@/components/ui/button";
+import { useRouteNavigate } from "@/core/route-base";
+
+import { BusinessChainListBody } from "@/roundtable-planning/components/BusinessChainListDialog";
+
+export default function BusinessChainListPage() {
+ const navigate = useRouteNavigate();
+
+ // 进入编辑器:带 chainId = 打开并切到该链条;不带 = 空白新建。
+ // 路径写 workspace base,`useRouteNavigate` 会按当前路由 base 改写。
+ const goConfigure = (chainId?: string) => {
+ navigate(
+ chainId
+ ? `/page/workspace/roundtable/chains?chainId=${encodeURIComponent(chainId)}`
+ : "/page/workspace/roundtable/chains",
+ );
+ };
+
+ return (
+
+ {/* 顶栏:标题 + 描述 + 配置入口 */}
+
+
+
+
+
+ 业务链条配置
+
+
+ 可复用的有序智能体编排。点击卡片「设置」可进入编辑器修改该链条;「发布」后所有账号都能在「公共」里查看 / 选用。
+
+
+
+
+
+
+ {/* 列表主体(与弹窗共用 BusinessChainListBody) */}
+
+
+
+
+ );
+}
diff --git a/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx b/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx
index d7aa1d58..735c9075 100644
--- a/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx
+++ b/frontend-web/src/strategy-components/components/task-components/SentimentAnalyzes.tsx
@@ -170,7 +170,7 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa
setShowAnalysisModal(false);
};
- // 单智能体分析:用「业务链条管理」里为本业务配置的智能体,跳转到其问答页(新会话),
+ // 单智能体分析:用「配置管理」里为本业务配置的智能体,跳转到其问答页(新会话),
// 把任务名称/简介作为开场消息暂存,由 AgentChatPage 读取 sessionStorage.pendingAgentMessage
// 自动发出并开始问答。未配置智能体则提示去配置。
const handleSingleAgentAnalysis = async () => {
@@ -184,7 +184,7 @@ const SentimentAnalyzes: React.FC = ({ title, category, subCa
/* ignore → 下面按未配置处理 */
}
if (!agentId) {
- toast.error('该业务尚未在「业务链条管理」中配置单智能体');
+ toast.error('该业务尚未在「配置管理」中配置单智能体');
return;
}
const text = [
diff --git a/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx b/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx
index 5b689846..13f9e94f 100644
--- a/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx
+++ b/frontend-web/src/strategy-components/components/task-components/TaskAnalyzes.tsx
@@ -170,7 +170,7 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor
setShowAnalysisModal(false);
};
- // 单智能体分析:用「业务链条管理」里为本业务配置的智能体,跳转到其问答页(新会话),
+ // 单智能体分析:用「配置管理」里为本业务配置的智能体,跳转到其问答页(新会话),
// 把任务名称/简介作为开场消息暂存,由 AgentChatPage 读取 sessionStorage.pendingAgentMessage
// 自动发出并开始问答。未配置智能体则提示去配置。
const handleSingleAgentAnalysis = async () => {
@@ -184,7 +184,7 @@ const TaskAnalyzes: React.FC = ({ title, category, subCategor
/* ignore → 下面按未配置处理 */
}
if (!agentId) {
- toast.error('该业务尚未在「业务链条管理」中配置单智能体');
+ toast.error('该业务尚未在「配置管理」中配置单智能体');
return;
}
const text = [