Files
deerflow-code/web-code/pages/SceneDetail.tsx
T
2026-05-28 18:29:37 +08:00

557 lines
31 KiB
TypeScript

import React, { useState } from 'react';
import { ArrowLeft, Save, RotateCcw, Play, Pause, Settings, FileText, GitBranch, ListChecks, Shield, Bot, Clock, CheckCircle, X, Plus, ChevronDown, AlertTriangle } from 'lucide-react';
import { useTheme } from '../contexts/ThemeContext';
interface SceneDetailProps {
sceneId: string | null;
onBack: () => void;
}
interface FlowNode {
id: number;
name: string;
agent: string;
status: 'completed' | 'active' | 'pending';
inputs: number;
outputs: number;
inputSource: string[];
outputFields: string[];
releaseCondition: string;
rollbackNode: string;
allowParallel: boolean;
description: string;
}
const SceneDetail: React.FC<SceneDetailProps> = ({ sceneId, onBack }) => {
const { theme } = useTheme();
const isDark = theme === 'dark';
// 主题颜色类
const cardBg = isDark ? 'bg-slate-800/30' : 'bg-white';
const cardBorder = isDark ? 'border-blue-800/30' : 'border-red-200';
const textPrimary = isDark ? 'text-white' : 'text-gray-900';
const textSecondary = isDark ? 'text-slate-400' : 'text-gray-600';
const textMuted = isDark ? 'text-slate-500' : 'text-gray-500';
const btnSecondary = isDark ? 'bg-slate-700/50 hover:bg-slate-600/50 border-blue-800/30 text-slate-300' : 'bg-gray-100 hover:bg-gray-200 border-gray-300 text-gray-700';
const btnPrimary = isDark ? 'bg-blue-600 hover:bg-blue-500' : 'bg-red-600 hover:bg-red-500';
const inputBg = isDark ? 'bg-slate-900/50' : 'bg-gray-50';
const inputBorder = isDark ? 'border-blue-800/30' : 'border-gray-300';
const [activeTab, setActiveTab] = useState('flow');
const [selectedNode, setSelectedNode] = useState<FlowNode | null>(null);
const tabs = [
{ id: 'basic', label: '基础设置', icon: FileText },
{ id: 'flow', label: '流程编排', icon: GitBranch },
{ id: 'template', label: '输入输出模板', icon: ListChecks },
{ id: 'rules', label: '运行规则', icon: Shield },
];
const flowNodes: FlowNode[] = [
{ id: 1, name: '目标分析', agent: 'GoalAgent', status: 'completed', inputs: 2, outputs: 3, inputSource: ['task_background', 'primary_goal_hint'], outputFields: ['goal_model.primary_goal', 'goal_model.secondary_goal'], releaseCondition: '目标明确且可量化', rollbackNode: '无', allowParallel: false, description: '分析并确定宣传的核心目标' },
{ id: 2, name: '受众分析', agent: 'AudienceAgent', status: 'completed', inputs: 3, outputs: 4, inputSource: ['goal_model', 'task_background'], outputFields: ['audience_model.core_audience', 'audience_model.secondary_audience'], releaseCondition: '核心受众明确', rollbackNode: '目标分析', allowParallel: false, description: '分析目标受众特征和需求' },
{ id: 3, name: '行为分析', agent: 'BehaviorAgent', status: 'active', inputs: 4, outputs: 3, inputSource: ['audience_model', 'goal_model'], outputFields: ['behavior_model.target_behavior', 'behavior_model.conversion_path'], releaseCondition: '目标行为明确', rollbackNode: '受众分析', allowParallel: false, description: '设计目标受众的预期行为' },
{ id: 4, name: '驱动分析', agent: 'DriverAgent', status: 'pending', inputs: 3, outputs: 2, inputSource: ['behavior_model', 'audience_model'], outputFields: ['driver_model.primary_driver', 'driver_model.secondary_driver'], releaseCondition: '核心驱动明确', rollbackNode: '行为分析', allowParallel: true, description: '分析影响受众行为的关键驱动因素' },
{ id: 5, name: '叙事分析', agent: 'NarrativeAgent', status: 'pending', inputs: 2, outputs: 4, inputSource: ['driver_model', 'audience_model'], outputFields: ['narrative_model.core_narrative', 'narrative_model.message_points'], releaseCondition: '叙事框架明确', rollbackNode: '驱动分析', allowParallel: false, description: '设计传播叙事策略' },
{ id: 6, name: '逻辑链收敛', agent: 'LogicChainAgent', status: 'pending', inputs: 4, outputs: 2, inputSource: ['goal_model', 'audience_model', 'behavior_model', 'narrative_model'], outputFields: ['strategy_chain.logic_statement', 'strategy_chain.consistency_score'], releaseCondition: '逻辑链校验通过', rollbackNode: '叙事分析', allowParallel: false, description: '验证策略链完整性和一致性' },
{ id: 7, name: '风险评估', agent: 'RiskAgent', status: 'pending', inputs: 2, outputs: 3, inputSource: ['strategy_chain', 'task_constraints'], outputFields: ['risk_model.risk_items', 'risk_model.mitigation_suggestions'], releaseCondition: '高风险项已处理', rollbackNode: '逻辑链收敛', allowParallel: true, description: '评估策略执行风险' },
{ id: 8, name: '方案生成', agent: 'DraftAgent', status: 'pending', inputs: 3, outputs: 5, inputSource: ['strategy_chain', 'narrative_model', 'risk_model'], outputFields: ['final_plan', 'execution_timeline', 'evaluation_metrics'], releaseCondition: '方案完整可执行', rollbackNode: '风险评估', allowParallel: false, description: '生成最终宣传方案' },
];
const sceneSummary = {
flowNodesCount: 8,
boundAgentsCount: 8,
serialNodes: 6,
parallelNodes: 2,
logicChainEnabled: true,
lastPublishedTime: '2026-03-18 14:30',
};
const inputTemplate = [
{ name: '任务标题', type: 'STRING', required: true },
{ name: '任务背景', type: 'TEXT', required: true },
{ name: '上级要求', type: 'TEXT', required: false },
{ name: '时间要求', type: 'DATE', required: true },
{ name: '资源条件', type: 'JSON', required: false },
{ name: '风险边界', type: 'TEXT', required: false },
];
const outputTemplate = {
middle: ['goal_model', 'audience_model', 'behavior_model', 'driver_model', 'narrative_model', 'strategy_chain'],
final: ['讨论结果摘要', '最终策略链', '正式方案', '风险说明', '评估指标'],
};
return (
<div className="space-y-6">
{/* 顶部导航 */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<button
onClick={onBack}
className={`p-2 ${isDark ? 'hover:bg-slate-800/50' : 'hover:bg-gray-100'} rounded-lg transition-colors`}
>
<ArrowLeft className={`w-5 h-5 ${textSecondary}`} />
</button>
<div>
<div className="flex items-center gap-3">
<h1 className={`text-2xl font-bold ${textPrimary}`}>业务链条配置详情</h1>
<span className="px-2.5 py-1 bg-green-500/20 text-green-400 rounded-full text-xs font-medium">
启用
</span>
</div>
<p className={`${textSecondary} text-sm mt-1`}></p>
</div>
</div>
{/* <div className="flex items-center gap-3">
<button className={`flex items-center gap-2 px-4 py-2.5 ${btnSecondary} rounded-lg transition-colors`}>
<RotateCcw className="w-4 h-4" />
<span className="text-sm">重置</span>
</button>
<button className={`flex items-center gap-2 px-4 py-2.5 ${btnPrimary} ${textPrimary} rounded-lg transition-colors`}>
<Save className="w-4 h-4" />
<span className="text-sm">保存配置</span>
</button>
</div> */}
</div>
{/* Tab切换 */}
{/* <div className={`flex items-center gap-2 border-b ${cardBorder}`}>
{tabs.map((tab) => {
const Icon = tab.icon;
return (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
className={`flex items-center gap-2 px-4 py-3 border-b-2 transition-colors ${
activeTab === tab.id
? 'border-blue-500 text-blue-400'
: `border-transparent ${textSecondary} hover:${textPrimary}`
}`}
>
<Icon className="w-4 h-4" />
<span className="text-sm font-medium">{tab.label}</span>
</button>
);
})}
</div> */}
{/* 内容区 */}
<div className="grid grid-cols-4 gap-6">
{/* 主内容区 */}
<div className="col-span-3">
{activeTab === 'basic' && (
<div className="grid grid-cols-2 gap-6">
{/* 左侧表单区 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6 space-y-4`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>基础信息</h3>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>场景名称</label>
<input
type="text"
defaultValue="宣传策略生成"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none focus:border-blue-500/50`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>场景编码</label>
<input
type="text"
defaultValue="SCENE_001"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none focus:border-blue-500/50`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>场景说明</label>
<textarea
rows={3}
defaultValue="用于生成完整的宣传策略方案,包含目标、受众、行为、驱动、叙事等维度的分析"
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none focus:border-blue-500/50 resize-none`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>场景分类</label>
<select className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none focus:border-blue-500/50`}>
<option>策略生成</option>
<option>方案推演</option>
<option>活动复盘</option>
</select>
</div>
</div>
{/* 右侧说明区 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6 space-y-4`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>场景说明</h3>
<div className="p-4 bg-blue-500/10 border border-blue-500/30 rounded-lg">
<p className="text-blue-400 text-sm font-medium mb-2">场景简介</p>
<p className={`${textSecondary} text-sm`}>完整的宣传策略生成流程,覆盖从目标分析到方案输出的全链路。</p>
</div>
<div className={`p-4 ${inputBg} ${inputBorder} rounded-lg`}>
<p className={`${textSecondary} text-sm font-medium mb-2`}>最近修改记录</p>
<p className={`${textSecondary} text-sm`}>2026-03-18 14:30 由 张策略 修改</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="p-3 bg-cyan-500/10 border border-cyan-500/30 rounded-lg text-center">
<p className="text-cyan-400 text-2xl font-bold">12</p>
<p className={`${textSecondary} text-xs`}>关联任务</p>
</div>
<div className="p-3 bg-purple-500/10 border border-purple-500/30 rounded-lg text-center">
<p className="text-purple-400 text-2xl font-bold">8</p>
<p className={`${textSecondary} text-xs`}>关联智能体</p>
</div>
</div>
<div className={`flex items-center justify-between py-3 border-t ${cardBorder}`}>
<span className={`${textSecondary} text-sm`}>设为默认场景</span>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked />
<div className="w-11 h-6 bg-slate-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
</label>
</div>
</div>
</div>
)}
{activeTab === 'flow' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<div className="flex items-center justify-between mb-6">
<h3 className={`${textPrimary} font-semibold`}>流程编排</h3>
<button className="flex items-center gap-2 px-3 py-1.5 bg-blue-600/20 hover:bg-blue-600/30 border border-blue-500/30 text-blue-400 rounded-lg text-sm transition-colors">
<Plus className="w-4 h-4" />
添加节点
</button>
</div>
{/* 流程图区域 */}
<div className="relative">
{/* 流程节点 */}
<div className="space-y-4">
{flowNodes.map((node, index) => (
<div key={node.id} className="relative">
<div className="flex items-center gap-4">
{/* 连接线 */}
{index > 0 && (
<div className="absolute left-6 -top-4 w-0.5 h-4 bg-blue-500/50" />
)}
{/* 节点卡片 */}
<button
onClick={() => setSelectedNode(node)}
className={`flex-1 flex items-center gap-4 p-4 rounded-xl border-2 transition-all text-left ${
selectedNode?.id === node.id
? 'bg-blue-500/20 border-blue-500 shadow-lg shadow-blue-500/20'
: node.status === 'completed'
? 'bg-green-500/10 border-green-500/30 hover:border-green-500/50'
: node.status === 'active'
? 'bg-blue-500/10 border-blue-500/50 hover:border-blue-500'
: `${inputBg} ${cardBorder} ${isDark ? 'hover:border-blue-700' : 'hover:border-red-300'}`
}`}
>
{/* 节点序号 */}
<div className={`w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold ${
node.status === 'completed'
? 'bg-green-500 text-white'
: node.status === 'active'
? 'bg-blue-500 text-white'
: isDark ? 'bg-slate-700 text-slate-400' : 'bg-gray-200 text-gray-600'
}`}>
{node.status === 'completed' ? <CheckCircle className="w-5 h-5" /> : node.id}
</div>
{/* 节点信息 */}
<div className="flex-1">
<div className="flex items-center gap-3 mb-1">
<h4 className={`${textPrimary} font-medium`}>{node.name}</h4>
<span className={`px-2 py-0.5 rounded text-xs font-medium ${
node.status === 'completed' ? 'bg-green-500/20 text-green-400' :
node.status === 'active' ? 'bg-blue-500/20 text-blue-400' :
isDark ? 'bg-slate-700 text-slate-400' : 'bg-gray-200 text-gray-600'
}`}>
{node.status === 'completed' ? '已完成' : node.status === 'active' ? '进行中' : '待执行'}
</span>
{node.allowParallel && (
<span className="px-2 py-0.5 bg-amber-500/20 text-amber-400 rounded text-xs">
可并行
</span>
)}
</div>
<div className={`flex items-center gap-4 text-sm ${textSecondary}`}>
<span className="flex items-center gap-1">
<Bot className="w-3 h-3" />
{node.agent}
</span>
<span>输入 {node.inputs}</span>
<span>输出 {node.outputs}</span>
</div>
</div>
{/* 放行条件 */}
<div className="text-right">
<p className={`${textMuted} text-xs mb-1`}>放行条件</p>
<p className={`${textSecondary} text-sm`}>{node.releaseCondition}</p>
</div>
<ChevronDown className={`w-5 h-5 ${textMuted}`} />
</button>
{/* 回退虚线 */}
{node.rollbackNode !== '无' && (
<div className="absolute -right-16 top-1/2 transform -translate-y-1/2">
<div className="flex items-center gap-1 text-amber-400 text-xs">
<span className="w-8 border-t-2 border-dashed border-amber-400/50" />
<RotateCcw className="w-3 h-3" />
</div>
</div>
)}
</div>
</div>
))}
</div>
</div>
{/* 图例 */}
<div className={`mt-6 flex items-center gap-6 pt-6 border-t ${cardBorder}`}>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-green-400" />
<span className={`${textSecondary} text-sm`}>已完成</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-blue-400" />
<span className={`${textSecondary} text-sm`}>进行中</span>
</div>
<div className="flex items-center gap-2">
<div className={`w-3 h-3 rounded-full ${isDark ? 'bg-slate-600' : 'bg-gray-400'}`} />
<span className={`${textSecondary} text-sm`}>待执行</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-amber-400" />
<span className={`${textSecondary} text-sm`}>可并行</span>
</div>
</div>
</div>
)}
{activeTab === 'template' && (
<div className="space-y-6">
{/* 任务输入模板 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>任务输入模板</h3>
<div className="grid grid-cols-3 gap-4">
{inputTemplate.map((field) => (
<div key={field.name} className={`p-4 ${inputBg} ${inputBorder} rounded-lg`}>
<div className="flex items-center justify-between mb-2">
<p className={`${textPrimary} text-sm font-medium`}>{field.name}</p>
{field.required && (
<span className="px-2 py-0.5 bg-red-500/20 text-red-400 rounded text-xs">必填</span>
)}
</div>
<p className={`${textMuted} text-xs`}>{field.type}</p>
</div>
))}
</div>
</div>
{/* 中间输出模板 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>中间输出模板</h3>
<div className="grid grid-cols-3 gap-4">
{outputTemplate.middle.map((field) => (
<div key={field} className="p-4 bg-cyan-500/10 border border-cyan-500/30 rounded-lg">
<p className="text-cyan-400 text-sm font-mono">{field}</p>
</div>
))}
</div>
</div>
{/* 最终输出模板 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>最终输出模板</h3>
<div className="grid grid-cols-3 gap-4">
{outputTemplate.final.map((field) => (
<div key={field} className="p-4 bg-green-500/10 border border-green-500/30 rounded-lg">
<p className="text-green-400 text-sm">{field}</p>
</div>
))}
</div>
</div>
</div>
)}
{activeTab === 'rules' && (
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-6 space-y-6`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>运行规则配置</h3>
{[
{ title: '启用状态门控', desc: '每个阶段需要明确放行才能进入下一阶段', enabled: true },
{ title: '启用逻辑链校验', desc: '自动检查策略链的完整性和一致性', enabled: true },
{ title: '启用风险强制复核', desc: '高风险项必须人工确认才能继续', enabled: false },
{ title: '允许局部并行', desc: '部分独立阶段可以并行执行', enabled: true },
].map((rule, index) => (
<div key={index} className={`flex items-center justify-between py-4 border-b ${cardBorder} last:border-0`}>
<div>
<div className="flex items-center gap-2">
<p className={`${textPrimary} font-medium`}>{rule.title}</p>
{rule.enabled && (
<CheckCircle className="w-4 h-4 text-green-400" />
)}
</div>
<p className={`${textMuted} text-sm mt-1`}>{rule.desc}</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input type="checkbox" className="sr-only peer" defaultChecked={rule.enabled} />
<div className="w-11 h-6 bg-slate-700 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
</label>
</div>
))}
<div className="grid grid-cols-2 gap-6 pt-4">
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>最大讨论轮数</label>
<input
type="number"
defaultValue={10}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none focus:border-blue-500/50`}
/>
</div>
<div>
<label className={`block ${textSecondary} text-sm mb-2`}>最大回退次数</label>
<input
type="number"
defaultValue={3}
className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none focus:border-blue-500/50`}
/>
</div>
</div>
<div className="pt-4">
<label className={`block ${textSecondary} text-sm mb-2`}>异常中断处理方式</label>
<select className={`w-full px-4 py-2.5 ${inputBg} ${inputBorder} rounded-lg ${textPrimary} text-sm focus:outline-none focus:border-blue-500/50`}>
<option>自动保存并暂停</option>
<option>自动回退到上一节点</option>
<option>通知负责人并等待</option>
</select>
</div>
</div>
)}
</div>
{/* 右侧场景摘要区 */}
<div className="space-y-4">
{/* 场景统计卡片 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-5`}>
<h3 className={`${textPrimary} font-semibold mb-4`}>场景摘要</h3>
<div className="space-y-3">
<div className="flex items-center justify-between p-3 bg-blue-500/10 border border-blue-500/30 rounded-lg">
<span className={`${textSecondary} text-sm`}>流程节点数</span>
<span className="text-blue-400 font-bold">{sceneSummary.flowNodesCount}</span>
</div>
<div className="flex items-center justify-between p-3 bg-purple-500/10 border border-purple-500/30 rounded-lg">
<span className={`${textSecondary} text-sm`}>绑定智能体</span>
<span className="text-purple-400 font-bold">{sceneSummary.boundAgentsCount}</span>
</div>
<div className={`flex items-center justify-between p-3 ${inputBg} ${isDark ? 'border-slate-700/30' : 'border-gray-300'} rounded-lg`}>
<span className={`${textSecondary} text-sm`}>串行节点</span>
<span className={`${textSecondary}`}>{sceneSummary.serialNodes}</span>
</div>
<div className="flex items-center justify-between p-3 bg-amber-500/10 border border-amber-500/30 rounded-lg">
<span className={`${textSecondary} text-sm`}>并行节点</span>
<span className="text-amber-400">{sceneSummary.parallelNodes}</span>
</div>
<div className="flex items-center justify-between p-3 bg-green-500/10 border border-green-500/30 rounded-lg">
<span className={`${textSecondary} text-sm`}>逻辑链校验</span>
<span className="text-green-400">{sceneSummary.logicChainEnabled ? '已启用' : '未启用'}</span>
</div>
</div>
</div>
{/* 最近发布时间 */}
<div className={`${cardBg} backdrop-blur-xl ${cardBorder} rounded-xl p-5`}>
<div className={`flex items-center gap-2 ${textSecondary} text-sm mb-2`}>
<Clock className="w-4 h-4" />
最近发布时间
</div>
<p className={`${textPrimary}`}>{sceneSummary.lastPublishedTime}</p>
</div>
{/* 节点属性面板 */}
{selectedNode && (
<div className={`${cardBg} backdrop-blur-xl border border-blue-500/30 rounded-xl p-5`}>
<div className="flex items-center justify-between mb-4">
<h3 className={`${textPrimary} font-semibold`}>节点属性</h3>
<button
onClick={() => setSelectedNode(null)}
className={`p-1 ${isDark ? 'hover:bg-slate-700/50' : 'hover:bg-gray-100'} rounded`}
>
<X className={`w-4 h-4 ${textSecondary}`} />
</button>
</div>
<div className="space-y-4">
<div>
<p className={`${textMuted} text-xs mb-1`}>节点名称</p>
<p className={`${textPrimary}`}>{selectedNode.name}</p>
</div>
<div>
<p className={`${textMuted} text-xs mb-1`}>绑定智能体</p>
<p className="text-cyan-400">{selectedNode.agent}</p>
</div>
<div>
<p className={`${textMuted} text-xs mb-1`}>上游依赖</p>
<div className="space-y-1">
{selectedNode.inputSource.map((input) => (
<div key={input} className={`${textSecondary} text-sm ${inputBg} px-2 py-1 rounded`}>
{input}
</div>
))}
</div>
</div>
<div>
<p className={`${textMuted} text-xs mb-1`}>输出字段</p>
<div className="space-y-1">
{selectedNode.outputFields.map((output) => (
<div key={output} className="text-green-400 text-sm bg-green-500/10 px-2 py-1 rounded">
{output}
</div>
))}
</div>
</div>
<div>
<p className={`${textMuted} text-xs mb-1`}>放行条件</p>
<p className="text-amber-400 text-sm">{selectedNode.releaseCondition}</p>
</div>
<div>
<p className={`${textMuted} text-xs mb-1`}>回退节点</p>
<p className={`${textSecondary} text-sm`}>{selectedNode.rollbackNode}</p>
</div>
<div className="flex items-center justify-between">
<span className={`${textMuted} text-sm`}>允许并行</span>
<span className={selectedNode.allowParallel ? 'text-green-400' : `${textSecondary}`}>
{selectedNode.allowParallel ? '是' : '否'}
</span>
</div>
</div>
<div className={`mt-4 pt-4 border-t ${cardBorder} space-y-2`}>
<button className={`w-full flex items-center justify-center gap-2 px-3 py-2 ${btnPrimary} ${textPrimary} rounded-lg text-sm transition-colors`}>
<Settings className="w-4 h-4" />
编辑节点
</button>
<div className="flex gap-2">
<button className={`flex-1 flex items-center justify-center gap-1 px-3 py-2 ${btnSecondary} rounded-lg text-sm transition-colors`}>
<Plus className="w-3 h-3" />
前置
</button>
<button className={`flex-1 flex items-center justify-center gap-1 px-3 py-2 ${btnSecondary} rounded-lg text-sm transition-colors`}>
<Plus className="w-3 h-3" />
后置
</button>
</div>
</div>
</div>
)}
</div>
</div>
</div>
);
};
export default SceneDetail;