feat:冗余代码清理

This commit is contained in:
liailing1026
2026-01-14 17:54:00 +08:00
parent edb39d4c1f
commit 029df6b5a5
13 changed files with 290 additions and 485 deletions

View File

@@ -16,8 +16,8 @@ const configStore = useConfigStore()
const searchValue = ref('') const searchValue = ref('')
const triggerOnFocus = ref(true) const triggerOnFocus = ref(true)
const isFocus = ref(false) const isFocus = ref(false)
const hasAutoSearched = ref(false) // 防止重复自动搜索 const hasAutoSearched = ref(false)
const isExpanded = ref(false) // 控制搜索框是否展开 const isExpanded = ref(false)
// 解析URL参数 // 解析URL参数
function getUrlParam(param: string): string | null { function getUrlParam(param: string): string | null {
@@ -29,7 +29,6 @@ const planReady = computed(() => {
return agentsStore.agentRawPlan.data !== undefined return agentsStore.agentRawPlan.data !== undefined
}) })
const openAgentAllocationDialog = () => { const openAgentAllocationDialog = () => {
console.log('打开智能体分配弹窗')
agentsStore.openAgentAllocationDialog() agentsStore.openAgentAllocationDialog()
} }
// 自动搜索函数 // 自动搜索函数
@@ -70,12 +69,12 @@ function handleBlur() {
// 重置文本区域高度到最小行数 // 重置文本区域高度到最小行数
function resetTextareaHeight() { function resetTextareaHeight() {
nextTick(() => { nextTick(() => {
// 修复:使用更可靠的方式获取textarea元素 // 获取textarea元素
const textarea = const textarea =
document.querySelector('#task-container .el-textarea__inner') || document.querySelector('#task-container .el-textarea__inner') ||
document.querySelector('#task-container textarea') document.querySelector('#task-container textarea')
if (textarea) { if (textarea instanceof HTMLElement) {
// 强制设置最小高度 // 强制设置最小高度
textarea.style.height = 'auto' textarea.style.height = 'auto'
textarea.style.minHeight = '56px' textarea.style.minHeight = '56px'
@@ -100,7 +99,7 @@ async function handleSearch() {
}) })
data['Collaboration Process'] = changeBriefs(data['Collaboration Process']) data['Collaboration Process'] = changeBriefs(data['Collaboration Process'])
agentsStore.setAgentRawPlan({ data }) agentsStore.setAgentRawPlan({ data })
console.log('agentsStore.agentRawPlan', agentsStore.agentRawPlan)
emit('search', searchValue.value) emit('search', searchValue.value)
} finally { } finally {
triggerOnFocus.value = true triggerOnFocus.value = true
@@ -182,7 +181,7 @@ onMounted(() => {
/> />
</el-button> </el-button>
</div> </div>
<AssignmentButton v-dev-only v-if="planReady" @click="openAgentAllocationDialog" /> <AssignmentButton v-if="planReady" @click="openAgentAllocationDialog" />
</div> </div>
</el-tooltip> </el-tooltip>
</template> </template>

View File

@@ -1,10 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, onMounted } from 'vue' import { ref, computed, onMounted } from 'vue'
import { ElNotification } from 'element-plus'
import { pick } from 'lodash' import { pick } from 'lodash'
import { ElMessage } from 'element-plus'
import api from '@/api/index.ts' import api from '@/api/index.ts'
import SvgIcon from '@/components/SvgIcon/index.vue' import SvgIcon from '@/components/SvgIcon/index.vue'
import { agentMapDuty } from '@/layout/components/config.ts' import { agentMapDuty } from '@/layout/components/config.ts'
import { type Agent, useAgentsStore } from '@/stores' import { type Agent, useAgentsStore } from '@/stores'
@@ -39,82 +37,41 @@ const handleFileSelect = (event: Event) => {
} }
} }
// 在validateApiConfig函数中添加更详细的日志 // 验证API配置三个字段必须同时存在或同时不存在
const validateApiConfig = (agent: any) => { const validateApiConfig = (agent: any) => {
const hasApiUrl = 'apiUrl' in agent const hasApiUrl = 'apiUrl' in agent
const hasApiKey = 'apiKey' in agent const hasApiKey = 'apiKey' in agent
const hasApiModel = 'apiModel' in agent const hasApiModel = 'apiModel' in agent
// 三个字段必须同时存在或同时不存在 return hasApiUrl === hasApiKey && hasApiKey === hasApiModel
if (hasApiUrl !== hasApiKey || hasApiKey !== hasApiModel) {
console.error('❌ API配置不完整:', {
agentName: agent.Name,
missingFields: {
apiUrl: !hasApiUrl,
apiKey: !hasApiKey,
apiModel: !hasApiModel
}
})
return false
}
if (hasApiUrl && hasApiKey && hasApiModel) {
console.log('✅ API配置完整将使用自定义API配置:', {
apiUrl: agent.apiUrl,
apiKey: agent.apiKey ? '***' + agent.apiKey.slice(-4) : '未设置',
apiModel: agent.apiModel
})
} else {
console.log(' 未设置API配置将使用默认URL配置')
}
return true
} }
const readFileContent = (file: File) => { const readFileContent = (file: File) => {
console.log('📁 开始读取文件:', file.name, '大小:', file.size, '类型:', file.type)
const reader = new FileReader() const reader = new FileReader()
reader.onload = e => { reader.onload = e => {
try { try {
console.log('📄 文件读取完成开始解析JSON')
const content = e.target?.result as string const content = e.target?.result as string
const jsonData = JSON.parse(content) const jsonData = JSON.parse(content)
console.log('🔍 解析的JSON数据:', jsonData)
console.log(
'📊 数据类型:',
Array.isArray(jsonData) ? '数组' : '对象',
'长度:',
Array.isArray(jsonData) ? jsonData.length : 'N/A'
)
if (!Array.isArray(jsonData)) { if (!Array.isArray(jsonData)) {
console.error('❌ JSON格式错误: 必须为数组格式')
ElMessage.error('JSON格式错误: 必须为数组格式') ElMessage.error('JSON格式错误: 必须为数组格式')
return return
} }
console.log('🔍 开始验证智能体数据...') const validAgents = jsonData.filter((agent) => {
const validAgents = jsonData.filter((agent, index) => {
console.log(`🔍 验证第${index + 1}个智能体:`, agent.Name || '未命名')
// 验证必需字段 // 验证必需字段
if (!agent.Name || typeof agent.Name !== 'string') { if (!agent.Name || typeof agent.Name !== 'string') {
console.error(`❌ 智能体${index + 1}缺少Name字段或格式错误`)
return false return false
} }
if (!agent.Icon || typeof agent.Icon !== 'string') { if (!agent.Icon || typeof agent.Icon !== 'string') {
console.error(`❌ 智能体${index + 1}缺少Icon字段或格式错误`)
return false return false
} }
if (!agent.Profile || typeof agent.Profile !== 'string') { if (!agent.Profile || typeof agent.Profile !== 'string') {
console.error(`❌ 智能体${index + 1}缺少Profile字段或格式错误`)
return false return false
} }
// 验证API配置 // 验证API配置
if (!validateApiConfig(agent)) { if (!validateApiConfig(agent)) {
console.error(`❌ 智能体${index + 1}API配置验证失败`)
return false return false
} }
@@ -137,21 +94,17 @@ const readFileContent = (file: File) => {
api api
.setAgents(processedAgents) .setAgents(processedAgents)
.then(() => { .then(() => {
console.log('✅ 后端API调用成功')
ElMessage.success('智能体上传成功') ElMessage.success('智能体上传成功')
}) })
.catch(error => { .catch(() => {
console.error('❌ 后端API调用失败:', error)
ElMessage.error('智能体上传失败') ElMessage.error('智能体上传失败')
}) })
} catch (error) { } catch {
console.error('❌ JSON解析错误:', error)
ElMessage.error('JSON解析错误') ElMessage.error('JSON解析错误')
} }
} }
reader.onerror = error => { reader.onerror = () => {
console.error('❌ 文件读取错误:', error)
ElMessage.error('文件读取错误') ElMessage.error('文件读取错误')
} }

View File

@@ -23,15 +23,14 @@ const emit = defineEmits<{
(e: 'save-edit', stepId: string, processId: string, value: string): void (e: 'save-edit', stepId: string, processId: string, value: string): void
}>() }>()
// 🔄 从 currentTask 中获取数据(与分支切换联动) //从 currentTask 中获取数据
const currentTaskProcess = computed(() => { const currentTaskProcess = computed(() => {
// ✅ 优先使用 currentTask包含分支切换后的数据
const currentTask = agentsStore.currentTask const currentTask = agentsStore.currentTask
if (currentTask && currentTask.Id === props.step.Id && currentTask.TaskProcess) { if (currentTask && currentTask.Id === props.step.Id && currentTask.TaskProcess) {
return currentTask.TaskProcess return currentTask.TaskProcess
} }
// ⚠️ 降级:从 agentRawPlan 中获取原始数据(不受分支切换影响) //从 agentRawPlan 中获取原始数据
const collaborationProcess = agentsStore.agentRawPlan.data?.['Collaboration Process'] || [] const collaborationProcess = agentsStore.agentRawPlan.data?.['Collaboration Process'] || []
const rawData = collaborationProcess.find((task: any) => task.Id === props.step.Id) const rawData = collaborationProcess.find((task: any) => task.Id === props.step.Id)
return rawData?.TaskProcess || [] return rawData?.TaskProcess || []
@@ -39,19 +38,18 @@ const currentTaskProcess = computed(() => {
// 当前正在编辑的process ID // 当前正在编辑的process ID
const editingProcessId = ref<string | null>(null) const editingProcessId = ref<string | null>(null)
// 编辑框的值
const editValue = ref('') const editValue = ref('')
// 鼠标悬停的process ID // 鼠标悬停的process ID
const hoverProcessId = ref<string | null>(null) const hoverProcessId = ref<string | null>(null)
// 🆕 处理卡片点击事件(非编辑模式下) // 处理卡片点击事件
function handleCardClick() { function handleCardClick() {
// 如果正在编辑,不处理点击 // 如果正在编辑,不处理点击
if (editingProcessId.value) return if (editingProcessId.value) return
// 设置当前任务,与任务大纲联动 // 设置当前任务,与任务大纲联动
if (props.step.Id) { if (props.step.Id) {
agentsStore.setCurrentTask(props.step) agentsStore.setCurrentTask(props.step as any)
} }
} }

View File

@@ -1,10 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch, nextTick, onMounted } from 'vue' import { ref, computed, nextTick, onMounted } from 'vue'
import { VueFlow, useVueFlow, Handle, Position, type Node, type Edge } from '@vue-flow/core' import { VueFlow, useVueFlow, Handle, Position, type Node, type Edge } from '@vue-flow/core'
import { Controls } from '@vue-flow/controls'
import '@vue-flow/core/dist/style.css' import '@vue-flow/core/dist/style.css'
import '@vue-flow/core/dist/theme-default.css' import '@vue-flow/core/dist/theme-default.css'
import '@vue-flow/controls/dist/style.css'
import { import {
useAgentsStore, useAgentsStore,
useSelectionStore, useSelectionStore,
@@ -22,7 +20,7 @@ const agentsStore = useAgentsStore()
const selectionStore = useSelectionStore() const selectionStore = useSelectionStore()
const { onConnect, addEdges, fitView: fit } = useVueFlow() const { onConnect, addEdges, fitView: fit } = useVueFlow()
// 🆕 直接从 store 获取当前任务和任务过程数据 // 直接从 store 获取当前任务和任务过程数据
const currentTask = computed(() => agentsStore.currentTask) const currentTask = computed(() => agentsStore.currentTask)
const taskProcess = computed(() => agentsStore.currentTask?.TaskProcess ?? []) const taskProcess = computed(() => agentsStore.currentTask?.TaskProcess ?? [])
@@ -50,12 +48,10 @@ let isSyncing = false
//初始化标记,避免重复初始化 //初始化标记,避免重复初始化
const BRANCHES_INIT_KEY_PREFIX = 'plan-task-branches-initialized-' const BRANCHES_INIT_KEY_PREFIX = 'plan-task-branches-initialized-'
// 🆕 最后选中的分支ID //最后选中的分支ID
const LAST_SELECTED_BRANCH_KEY = 'plan-task-last-selected-branch' const LAST_SELECTED_BRANCH_KEY = 'plan-task-last-selected-branch'
// ==================== 辅助函数定义 ==================== // 获取分支的所有节点
// 🆕 获取分支的所有节点只沿着分支创建方向遍历right handle连接
const getAllBranchNodes = (startNodeId: string): string[] => { const getAllBranchNodes = (startNodeId: string): string[] => {
const visited = new Set<string>() const visited = new Set<string>()
const toVisit: string[] = [startNodeId] const toVisit: string[] = [startNodeId]
@@ -68,14 +64,14 @@ const getAllBranchNodes = (startNodeId: string): string[] => {
} }
visited.add(currentId) visited.add(currentId)
// 🆕 只查找通过 right handle 连接的后续节点(分支创建方向) // 只查找通过 right handle 连接的后续节点
const outgoingEdges = edges.value.filter( const outgoingEdges = edges.value.filter(
edge => edge.source === currentId && edge.sourceHandle === 'right' edge => edge.source === currentId && edge.sourceHandle === 'right'
) )
for (const edge of outgoingEdges) { for (const edge of outgoingEdges) {
const targetNodeId = edge.target const targetNodeId = edge.target
// 只访问分支节点(不包含主流程节点和根节点) // 只访问分支节点
if ( if (
!visited.has(targetNodeId) && !visited.has(targetNodeId) &&
targetNodeId !== 'root' && targetNodeId !== 'root' &&
@@ -89,7 +85,7 @@ const getAllBranchNodes = (startNodeId: string): string[] => {
return Array.from(visited) return Array.from(visited)
} }
// 🆕 获取从指定节点回溯到根节点的路径(只包含主流程节点) //获取从指定节点回溯到根节点的路径(只包含主流程节点)
const getPathToRoot = (targetNodeId: string): string[] => { const getPathToRoot = (targetNodeId: string): string[] => {
const path: string[] = [] const path: string[] = []
const visited = new Set<string>() const visited = new Set<string>()
@@ -126,7 +122,7 @@ const getPathToRoot = (targetNodeId: string): string[] => {
return path return path
} }
// 🆕 向上回溯分支的父节点链(只包含分支节点) // 向上回溯分支的父节点链(只包含分支节点)
const getBranchParentChain = (targetNodeId: string): string[] => { const getBranchParentChain = (targetNodeId: string): string[] => {
const parentChain: string[] = [] const parentChain: string[] = []
let currentId = targetNodeId let currentId = targetNodeId
@@ -153,8 +149,7 @@ const getBranchParentChain = (targetNodeId: string): string[] => {
return parentChain return parentChain
} }
// 初始化流程图
// ==================== 初始化流程图 ====================
const initializeFlow = () => { const initializeFlow = () => {
if (!currentTask.value) { if (!currentTask.value) {
nodes.value = [] nodes.value = []
@@ -162,20 +157,17 @@ const initializeFlow = () => {
return return
} }
// 🆕 获取当前流程数据 // 获取当前流程数据
const taskStepId = currentTask.value.Id const taskStepId = currentTask.value.Id
// 🆕 获取当前 agent 组合(用于区分不同 agent 组合的分支数据) // 获取当前 agent 组合(用于区分不同 agent 组合的分支数据)
const currentAgents = currentTask.value.AgentSelection || [] const currentAgents = currentTask.value.AgentSelection || []
// 🆕 直接使用 taskProcess.value 作为数据源 // 直接使用 taskProcess.value 作为数据源
// 注意:虽然 currentTask.id 相同,但不同的 agent 组合对应的 agent 任务过程不同
// taskProcess.value 从 currentTask.TaskProcess 获取,能正确反映当前 agent 组合的任务过程
const currentTaskProcess = taskProcess.value const currentTaskProcess = taskProcess.value
console.log('currentTaskProcess:', currentTaskProcess) // 立即保存为副本(深拷贝)
// 🆕 立即保存为副本(深拷贝)
const taskProcessCopy = JSON.parse(JSON.stringify(currentTaskProcess)) const taskProcessCopy = JSON.parse(JSON.stringify(currentTaskProcess))
// 🆕 使用副本数据创建节点(而不是 currentTaskProcess // 使用副本数据创建节点(而不是 currentTaskProcess
const taskProcessForNodes = taskProcessCopy const taskProcessForNodes = taskProcessCopy
const newNodes: Node[] = [] const newNodes: Node[] = []
const newEdges: Edge[] = [] const newEdges: Edge[] = []
@@ -233,7 +225,14 @@ const initializeFlow = () => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#43a8aa', strokeWidth: 2 } style: { stroke: '#43a8aa', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
}) })
} }
@@ -247,21 +246,27 @@ const initializeFlow = () => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#43a8aa', strokeWidth: 2 } style: { stroke: '#43a8aa', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
}) })
} }
nodes.value = newNodes nodes.value = newNodes
edges.value = newEdges edges.value = newEdges
// 📂 从 store 恢复已保存的任务过程分支数据 // 从 store 恢复已保存的任务过程分支数据
// taskStepId 已在前面声明 (line 163)
if (taskStepId) { if (taskStepId) {
// 🆕 使用当前 agent 组合获取分支数据 // 使用当前 agent 组合获取分支数据
const savedBranches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents) const savedBranches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
// 🆕 检查是否已经初始化过(针对该任务和 agent 组合) // 检查是否已经初始化过(针对该任务和 agent 组合)
const branchesInitKey = `${BRANCHES_INIT_KEY_PREFIX}${taskStepId}_${selectionStore.getAgentGroupKey( const branchesInitKey = `${BRANCHES_INIT_KEY_PREFIX}${taskStepId}_${selectionStore.getAgentGroupKey(
currentAgents currentAgents
)}` )}`
@@ -272,17 +277,17 @@ const initializeFlow = () => {
edges.value = [] edges.value = []
savedBranches.forEach(branch => { savedBranches.forEach(branch => {
// 恢复节点(深拷贝,避免引用问题) // 恢复节点
branch.nodes.forEach(node => { branch.nodes.forEach(node => {
nodes.value.push(JSON.parse(JSON.stringify(node))) nodes.value.push(JSON.parse(JSON.stringify(node)))
}) })
// 恢复边(深拷贝) // 恢复边
branch.edges.forEach(edge => { branch.edges.forEach(edge => {
edges.value.push(JSON.parse(JSON.stringify(edge))) edges.value.push(JSON.parse(JSON.stringify(edge)))
}) })
}) })
// 🆕 恢复最后选中的分支 // 恢复最后选中的分支
const lastSelectedBranchId = sessionStorage.getItem(LAST_SELECTED_BRANCH_KEY) const lastSelectedBranchId = sessionStorage.getItem(LAST_SELECTED_BRANCH_KEY)
if (lastSelectedBranchId) { if (lastSelectedBranchId) {
const lastSelectedBranch = savedBranches.find(branch => branch.id === lastSelectedBranchId) const lastSelectedBranch = savedBranches.find(branch => branch.id === lastSelectedBranchId)
@@ -313,7 +318,7 @@ const initializeFlow = () => {
} }
} }
// 🆕 使用多级分支逻辑:获取父节点链和子节点 // 获取父节点链和子节点
const branchParentChain = getBranchParentChain(firstBranchNode.id) const branchParentChain = getBranchParentChain(firstBranchNode.id)
const branchChildNodes = getAllBranchNodes(firstBranchNode.id) const branchChildNodes = getAllBranchNodes(firstBranchNode.id)
@@ -338,11 +343,11 @@ const initializeFlow = () => {
selectedNodeIds.value = new Set(mainProcessNodes) selectedNodeIds.value = new Set(mainProcessNodes)
} }
} else { } else {
// 🆕 首次初始化:设置节点和边,并保存为"初始流程"分支 // 首次初始化:设置节点和边,并保存为"初始流程"分支
nodes.value = newNodes nodes.value = newNodes
edges.value = newEdges edges.value = newEdges
const initialBranchNodes = newNodes // ✅ 保留所有节点,包括根节点 const initialBranchNodes = newNodes
const initialBranchEdges = [...newEdges] const initialBranchEdges = [...newEdges]
const initialBranchId = selectionStore.addTaskProcessBranch(taskStepId, currentAgents, { const initialBranchId = selectionStore.addTaskProcessBranch(taskStepId, currentAgents, {
@@ -351,13 +356,13 @@ const initializeFlow = () => {
branchType: 'root', branchType: 'root',
nodes: JSON.parse(JSON.stringify(initialBranchNodes)), nodes: JSON.parse(JSON.stringify(initialBranchNodes)),
edges: JSON.parse(JSON.stringify(initialBranchEdges)), edges: JSON.parse(JSON.stringify(initialBranchEdges)),
tasks: taskProcessCopy // 👈 使用副本(已经是深拷贝) tasks: taskProcessCopy
}) })
// 🆕 标记已初始化(针对该任务步骤和 agent 组合) // 标记已初始化(针对该任务步骤和 agent 组合)
sessionStorage.setItem(branchesInitKey, 'true') sessionStorage.setItem(branchesInitKey, 'true')
// 🆕 首次初始化时,设置初始流程为当前选中分支 // 首次初始化时,设置初始流程为当前选中分支
selectionStore.setActiveTaskProcessBranch(taskStepId, currentAgents, initialBranchId) selectionStore.setActiveTaskProcessBranch(taskStepId, currentAgents, initialBranchId)
// 默认选中"初始流程"的高亮状态 // 默认选中"初始流程"的高亮状态
@@ -369,166 +374,6 @@ const initializeFlow = () => {
} }
} }
// 同步当前所有分支数据到 store
const syncBranchesToStore = () => {
if (isSyncing || !currentTask.value?.Id) return
isSyncing = true
const taskStepId = currentTask.value.Id
// 🆕 获取当前 agent 组合
const currentAgents = currentTask.value.AgentSelection || []
// 🔄 获取现有的分支数据(用于保留初始流程分支)
const existingBranches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
const existingBranchesMap = new Map<string, any>()
existingBranches.forEach(branch => {
// 使用分支ID作为key
existingBranchesMap.set(branch.id, branch)
})
// 获取当前所有分支节点(标记为 isBranchTask
const currentBranchNodes = nodes.value.filter((n: Node) => n.data.isBranchTask)
if (currentBranchNodes.length === 0) {
isSyncing = false
return
}
// 按照分支分组节点和边
// 通过 parentId 将节点分组
const branchesMap = new Map<
string,
{
nodes: Node[]
edges: Edge[]
branchContent: string
branchType: 'root' | 'task'
createdAt: number
tasks?: any[] // 🆕 添加 tasks 字段
}
>()
currentBranchNodes.forEach((node: Node) => {
// 找到连接到该节点的边,确定父节点
const incomingEdge = edges.value.find((e: Edge) => e.target === node.id)
const parentNodeId = incomingEdge?.source || 'root'
const isFirstBranchNode = incomingEdge?.sourceHandle === 'bottom'
if (isFirstBranchNode) {
if (!branchesMap.has(parentNodeId)) {
// 🆕 从现有分支数据中恢复元数据
const existingMetadata = existingBranchesMap.get(node.id)
branchesMap.set(parentNodeId, {
nodes: [],
edges: [],
branchContent: existingMetadata?.branchContent || '分支',
branchType: existingMetadata?.branchType || (parentNodeId === 'root' ? 'root' : 'task'),
createdAt: Date.now(),
tasks: existingMetadata?.tasks //
})
}
// 收集该分支的所有节点(从第一个节点开始,通过 right handle 连接的节点)
const branchNodes: Node[] = []
let currentNode: Node | undefined = node
while (currentNode) {
branchNodes.push(currentNode)
// 查找通过 right handle 连接的下一个节点
const outgoingEdge = edges.value.find(
(e: Edge) => e.source === currentNode!.id && e.sourceHandle === 'right'
)
if (outgoingEdge) {
currentNode = currentBranchNodes.find((n: Node) => n.id === outgoingEdge.target)
} else {
currentNode = undefined
}
}
// 添加所有分支节点
branchNodes.forEach((n: Node) => {
if (
!branchesMap
.get(parentNodeId)!
.nodes.find((existingNode: Node) => existingNode.id === n.id)
) {
branchesMap.get(parentNodeId)!.nodes.push(n)
}
})
// 找到该分支的所有边
branchNodes.forEach((branchNode: Node) => {
const branchEdges = edges.value.filter(
(e: Edge) => e.source === branchNode.id || e.target === branchNode.id
)
branchEdges.forEach((edge: Edge) => {
if (!branchesMap.get(parentNodeId)!.edges.find((e: Edge) => e.id === edge.id)) {
branchesMap.get(parentNodeId)!.edges.push(edge)
}
})
})
}
})
// 保存所有分支到 store使用深拷贝
branchesMap.forEach((branchData, parentNodeId) => {
// 🆕 优先使用恢复的 tasks 数据,如果没有才重新创建
let tasks = branchData.tasks
if (!tasks || tasks.length === 0) {
// 转换节点数据为 IRawStepTask 格式
tasks = branchData.nodes.map((node: Node) => ({
Id: node.id,
StepName: node.data.actionTypeName,
TaskContent: node.data.agentDescription,
InputObject_List: [],
OutputObject: '',
AgentSelection: [node.data.agentName],
Collaboration_Brief_frontEnd: {
template: '',
data: {}
} as any,
TaskProcess: []
}))
} else {
}
selectionStore.addTaskProcessBranch(taskStepId, currentAgents, {
parentNodeId,
branchContent: JSON.parse(JSON.stringify(branchData.branchContent)),
branchType: JSON.parse(JSON.stringify(branchData.branchType)),
nodes: JSON.parse(JSON.stringify(branchData.nodes)),
edges: JSON.parse(JSON.stringify(branchData.edges)),
tasks: JSON.parse(JSON.stringify(tasks)) // 🆕 优先使用恢复的 tasks
})
})
// 延迟重置标志,避免连续触发
setTimeout(() => {
isSyncing = false
}, 100)
}
// 监听节点和边的变化,同步到 store
// ⚠️ 已禁用自动同步因为会导致分支ID变化sessionStorage中保存的选中分支无法恢复
// 分支数据在添加分支时就已经保存到store了不需要在nodes/edges变化时重新同步
// watch(
// [nodes, edges],
// () => {
// // 如果正在同步,跳过
// if (isSyncing) return
// // 只在有分支节点时才同步
// const hasBranchNodes = nodes.value.some((n: Node) => n.data.isBranchTask)
// if (hasBranchNodes && currentTask.value) {
// syncBranchesToStore()
// }
// },
// { deep: true }
// )
// 组件挂载后初始化 // 组件挂载后初始化
onMounted(() => { onMounted(() => {
if (currentTask.value) { if (currentTask.value) {
@@ -556,7 +401,7 @@ const cancelAddBranch = () => {
branchInput.value = '' branchInput.value = ''
} }
// 🆕 节点点击事件 // 节点点击事件
const onNodeClick = (event: any) => { const onNodeClick = (event: any) => {
const nodeId = event.node.id const nodeId = event.node.id
const nodeData = event.node.data as any const nodeData = event.node.data as any
@@ -571,10 +416,10 @@ const onNodeClick = (event: any) => {
if (isBranchNode) { if (isBranchNode) {
// 点击的是分支节点 // 点击的是分支节点
// 🆕 向上回溯分支父节点链(多级分支) // 向上回溯分支父节点链(多级分支)
const branchParentChain = getBranchParentChain(nodeId) const branchParentChain = getBranchParentChain(nodeId)
// 🆕 向下遍历分支的子节点只沿right handle方向 // 向下遍历分支的子节点只沿right handle方向
const branchChildNodes = getAllBranchNodes(nodeId) const branchChildNodes = getAllBranchNodes(nodeId)
// 找到最顶层的分支父节点(连接到主流程或根节点的) // 找到最顶层的分支父节点(连接到主流程或根节点的)
@@ -599,7 +444,7 @@ const onNodeClick = (event: any) => {
// 回溯到根节点,获取主流程路径 // 回溯到根节点,获取主流程路径
const pathToRoot = getPathToRoot(parentNodeId) const pathToRoot = getPathToRoot(parentNodeId)
// 🔧 getPathToRoot 已经返回正序(从左到右),不需要反转 // getPathToRoot 已经返回正序(从左到右),不需要反转
const correctPathToRoot = pathToRoot // [agent-0, agent-1, agent-2, ...] const correctPathToRoot = pathToRoot // [agent-0, agent-1, agent-2, ...]
const correctBranchParentChain = [...branchParentChain].reverse() // 顶层分支 → ... → 直接父分支(正序) const correctBranchParentChain = [...branchParentChain].reverse() // 顶层分支 → ... → 直接父分支(正序)
@@ -611,27 +456,18 @@ const onNodeClick = (event: any) => {
] ]
selectedNodeIds.value = new Set(allNodesToHighlight) selectedNodeIds.value = new Set(allNodesToHighlight)
console.log('📋 路径顺序(从上到下、从左到右):', { // 保存完整的 TaskProcess 数据(主流程 + 分支)到 store
pathToRoot: correctPathToRoot,
branchParentChain: correctBranchParentChain,
branchChildNodes: branchChildNodes,
total: allNodesToHighlight.length
})
// 🆕 保存完整的 TaskProcess 数据(主流程 + 分支)到 store
if (currentTask.value) { if (currentTask.value) {
const completeTaskProcess: any[] = [] const completeTaskProcess: any[] = []
// 🆕 从 store 中获取"初始流程"副本(而不是使用 taskProcess.value // 从 store 中获取"初始流程"副本(而不是使用 taskProcess.value
const taskStepId = currentTask.value.Id const taskStepId = currentTask.value.Id
const currentAgents = currentTask.value.AgentSelection || [] const currentAgents = currentTask.value.AgentSelection || []
const branches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents) const branches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
const initialBranch = branches.find(branch => branch.branchContent === '初始流程') const initialBranch = branches.find(branch => branch.branchContent === '初始流程')
const mainProcessData = initialBranch?.tasks || taskProcess.value const mainProcessData = initialBranch?.tasks || taskProcess.value
console.log('🔍 开始按高亮路径收集数据,总节点数:', allNodesToHighlight.length) // 按照高亮路径顺序收集每个节点的数据
// 🆕 按照高亮路径顺序收集每个节点的数据
allNodesToHighlight.forEach(nodeId => { allNodesToHighlight.forEach(nodeId => {
const node = nodes.value.find(n => n.id === nodeId) const node = nodes.value.find(n => n.id === nodeId)
@@ -644,7 +480,6 @@ const onNodeClick = (event: any) => {
const processData = mainProcessData[originalIndex] const processData = mainProcessData[originalIndex]
if (processData && processData.ID && processData.AgentName && processData.Description) { if (processData && processData.ID && processData.AgentName && processData.Description) {
completeTaskProcess.push(processData) completeTaskProcess.push(processData)
console.log(` 📦 添加主流程节点: ${nodeId}, 索引: ${originalIndex}`)
} }
} else if (node.data.isBranchTask) { } else if (node.data.isBranchTask) {
// 分支节点:从对应的分支数据中获取(按索引匹配) // 分支节点:从对应的分支数据中获取(按索引匹配)
@@ -657,25 +492,19 @@ const onNodeClick = (event: any) => {
const taskData = parentBranch.tasks[nodeIndex] const taskData = parentBranch.tasks[nodeIndex]
if (taskData.ID && taskData.AgentName && taskData.Description) { if (taskData.ID && taskData.AgentName && taskData.Description) {
completeTaskProcess.push(taskData) completeTaskProcess.push(taskData)
console.log(
` 📦 添加分支节点: ${nodeId}, 分支: ${parentBranch.branchContent}, 索引: ${nodeIndex}`
)
} }
} }
} }
} }
}) })
console.log(`✅ 数据收集完成,总任务数: ${completeTaskProcess.length}`) // 找到当前点击节点所属的分支,用于保存选中状态
// 🆕 找到当前点击节点所属的分支,用于保存选中状态
const matchedBranch = branches.find(branch => { const matchedBranch = branches.find(branch => {
return branch.nodes.some(node => node.id === nodeId) return branch.nodes.some(node => node.id === nodeId)
}) })
if (matchedBranch) { if (matchedBranch) {
sessionStorage.setItem(LAST_SELECTED_BRANCH_KEY, matchedBranch.id) sessionStorage.setItem(LAST_SELECTED_BRANCH_KEY, matchedBranch.id)
console.log(`💾 保存选中的分支ID: ${matchedBranch.id}`)
} }
selectionStore.setActiveTaskProcessData( selectionStore.setActiveTaskProcessData(
@@ -691,14 +520,14 @@ const onNodeClick = (event: any) => {
selectedNodeIds.value = new Set(allBranchNodes) selectedNodeIds.value = new Set(allBranchNodes)
} }
} else { } else {
// 🆕 点击的是主流程节点,高亮所有主流程节点(初始流程) // 点击的是主流程节点,高亮所有主流程节点(初始流程)
const mainProcessNodes = nodes.value const mainProcessNodes = nodes.value
.filter(n => !n.data.isBranchTask && n.id !== 'root') .filter(n => !n.data.isBranchTask && n.id !== 'root')
.map(n => n.id) .map(n => n.id)
selectedNodeIds.value = new Set(mainProcessNodes) selectedNodeIds.value = new Set(mainProcessNodes)
// 🆕 点击主流程节点时,从 store 读取"初始流程"分支的副本 // 点击主流程节点时,从 store 读取"初始流程"分支的副本
if (currentTask.value) { if (currentTask.value) {
const taskStepId = currentTask.value.Id const taskStepId = currentTask.value.Id
if (!taskStepId) { if (!taskStepId) {
@@ -712,17 +541,17 @@ const onNodeClick = (event: any) => {
// 使用 store 中保存的初始流程副本 // 使用 store 中保存的初始流程副本
selectionStore.setActiveTaskProcessData(taskStepId, currentAgents, initialBranch.tasks) selectionStore.setActiveTaskProcessData(taskStepId, currentAgents, initialBranch.tasks)
// 🆕 同步更新 currentTask.TaskProcess实现全局数据联动 // 同步更新 currentTask.TaskProcess实现全局数据联动
agentsStore.setCurrentTaskProcess(initialBranch.tasks) agentsStore.setCurrentTaskProcess(initialBranch.tasks)
// 🆕 保存选中的分支ID到 sessionStorage // 保存选中的分支ID到 sessionStorage
sessionStorage.setItem(LAST_SELECTED_BRANCH_KEY, initialBranch.id) sessionStorage.setItem(LAST_SELECTED_BRANCH_KEY, initialBranch.id)
} else { } else {
// 降级:使用 taskProcess.value // 降级:使用 taskProcess.value
const originalTaskProcess = taskProcess.value const originalTaskProcess = taskProcess.value
selectionStore.setActiveTaskProcessData(taskStepId, currentAgents, originalTaskProcess) selectionStore.setActiveTaskProcessData(taskStepId, currentAgents, originalTaskProcess)
// 🆕 同步更新 currentTask.TaskProcess实现全局数据联动 // 同步更新 currentTask.TaskProcess实现全局数据联动
agentsStore.setCurrentTaskProcess(originalTaskProcess) agentsStore.setCurrentTaskProcess(originalTaskProcess)
} }
} }
@@ -747,8 +576,8 @@ const submitBranch = async () => {
branchLoading.value = true branchLoading.value = true
try { try {
// ==================== 移动已有分支 ==================== // 移动已有分支
// 🆕 只移动在当前父节点下方的分支节点Y坐标 > 父节点Y坐标 // 只移动在当前父节点下方的分支节点Y坐标 > 父节点Y坐标
const parentNodeY = parentNode.position.y const parentNodeY = parentNode.position.y
// 查找所有已有的分支任务节点(标记为 isBranchTask // 查找所有已有的分支任务节点(标记为 isBranchTask
@@ -761,10 +590,6 @@ const submitBranch = async () => {
const branchIdsBelowParent = branchesBelowParent.map((n: Node) => n.id) const branchIdsBelowParent = branchesBelowParent.map((n: Node) => n.id)
console.log(
`📍 移动了 ${branchIdsBelowParent.length} 个分支Y坐标 > ${parentNodeY}),总共 ${allExistingBranchNodes.length} 个分支`
)
// 将当前父节点下方的分支向下移动250px通过创建新节点来触发响应式更新 // 将当前父节点下方的分支向下移动250px通过创建新节点来触发响应式更新
nodes.value = nodes.value.map((node: Node) => { nodes.value = nodes.value.map((node: Node) => {
if (branchIdsBelowParent.includes(node.id)) { if (branchIdsBelowParent.includes(node.id)) {
@@ -779,7 +604,7 @@ const submitBranch = async () => {
return node return node
}) })
// 💾 同步更新 store 中保存的分支位置 // 同步更新 store 中保存的分支位置
if (currentTask.value?.Id) { if (currentTask.value?.Id) {
const taskStepId = currentTask.value.Id const taskStepId = currentTask.value.Id
const currentAgents = currentTask.value.AgentSelection || [] const currentAgents = currentTask.value.AgentSelection || []
@@ -800,21 +625,21 @@ const submitBranch = async () => {
// 判断是根节点还是 agent 节点 // 判断是根节点还是 agent 节点
if (parentNodeId === 'root') { if (parentNodeId === 'root') {
// ========== 根节点分支 ========== // 根节点分支
let newAgentActions: IApiAgentAction[] = [] let newAgentActions: IApiAgentAction[] = []
if (USE_MOCK_DATA) { if (USE_MOCK_DATA) {
// 使用 Mock API // 使用 Mock API
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || '' const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
// 🆕 根节点分支:从零开始生成完整方案 // 根节点分支:从零开始生成完整方案
// Baseline_Completion = 0 表示没有已完成的部分,需要生成所有阶段 // Baseline_Completion = 0 表示没有已完成的部分,需要生成所有阶段
// Existing_Steps 传空数组,不传递初始流程信息 // Existing_Steps 传空数组,不传递初始流程信息
const response = await api.mockBranchTaskProcess({ const response = await api.mockBranchTaskProcess({
branch_Number: 1, branch_Number: 1,
Modification_Requirement: branchContent, Modification_Requirement: branchContent,
Existing_Steps: [], // ← 根节点分支不传递现有步骤 Existing_Steps: [], // ← 根节点分支不传递现有步骤
Baseline_Completion: 0, // ← 从零开始 Baseline_Completion: 0, // ← 从零开始
stepTaskExisting: currentTask.value, stepTaskExisting: currentTask.value,
goal: generalGoal goal: generalGoal
}) })
@@ -842,14 +667,14 @@ const submitBranch = async () => {
// 调用真实 API // 调用真实 API
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || '' const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
// 🆕 根节点分支:从零开始生成完整方案 // 根节点分支:从零开始生成完整方案
// Baseline_Completion = 0 表示没有已完成的部分,需要生成所有阶段 // Baseline_Completion = 0 表示没有已完成的部分,需要生成所有阶段
// Existing_Steps 传空数组,不传递初始流程信息 // Existing_Steps 传空数组,不传递初始流程信息
const response = await api.branchTaskProcess({ const response = await api.branchTaskProcess({
branch_Number: 1, branch_Number: 1,
Modification_Requirement: branchContent, Modification_Requirement: branchContent,
Existing_Steps: [], // ← 根节点分支不传递现有步骤 Existing_Steps: [], // ← 根节点分支不传递现有步骤
Baseline_Completion: 0, // ← 从零开始 Baseline_Completion: 0, // ← 从零开始
stepTaskExisting: currentTask.value, stepTaskExisting: currentTask.value,
goal: generalGoal goal: generalGoal
}) })
@@ -933,7 +758,14 @@ const submitBranch = async () => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#67c23a', strokeWidth: 2, strokeDasharray: '5,5' } style: { stroke: '#67c23a', strokeWidth: 2, strokeDasharray: '5,5' },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
} }
edges.value.push(newEdge) edges.value.push(newEdge)
newBranchEdges.push(newEdge) newBranchEdges.push(newEdge)
@@ -948,14 +780,21 @@ const submitBranch = async () => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#67c23a', strokeWidth: 2 } style: { stroke: '#67c23a', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
} }
edges.value.push(newEdge) edges.value.push(newEdge)
newBranchEdges.push(newEdge) newBranchEdges.push(newEdge)
} }
}) })
// 📂 保存分支数据到 store // 保存分支数据到 store
if (newBranchNodes.length > 0) { if (newBranchNodes.length > 0) {
// 将 IApiAgentAction 转换为 TaskProcess 格式用于存储 // 将 IApiAgentAction 转换为 TaskProcess 格式用于存储
// 与 fill-step-task-mock.ts 中的 TaskProcess 格式保持一致 // 与 fill-step-task-mock.ts 中的 TaskProcess 格式保持一致
@@ -986,7 +825,7 @@ const submitBranch = async () => {
} }
} }
} else { } else {
// ========== Agent 节点分支 ========== // Agent 节点分支
const parentIsBranchTask = parentNode.data.isBranchTask || false const parentIsBranchTask = parentNode.data.isBranchTask || false
const parentOriginalIndex = parentNode.data.originalIndex ?? 0 const parentOriginalIndex = parentNode.data.originalIndex ?? 0
let newAgentActions: IApiAgentAction[] = [] let newAgentActions: IApiAgentAction[] = []
@@ -996,7 +835,7 @@ const submitBranch = async () => {
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || '' const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
const currentTaskProcess = taskProcess.value || [] const currentTaskProcess = taskProcess.value || []
// 🆕 根据父节点类型构建 existingSteps // 根据父节点类型构建 existingSteps
let existingSteps: any[] = [] let existingSteps: any[] = []
let baselineCompletion = 100 let baselineCompletion = 100
@@ -1078,7 +917,7 @@ const submitBranch = async () => {
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || '' const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
const currentTaskProcess = taskProcess.value || [] const currentTaskProcess = taskProcess.value || []
// 🆕 根据父节点类型构建 existingSteps // 根据父节点类型构建 existingSteps
let existingSteps: any[] = [] let existingSteps: any[] = []
let baselineCompletion = 100 let baselineCompletion = 100
@@ -1135,7 +974,6 @@ const submitBranch = async () => {
goal: generalGoal goal: generalGoal
}) })
console.log('branchTaskProcess response:', response)
// 后端返回格式: [[action1, action2], [action3, action4]] // 后端返回格式: [[action1, action2], [action3, action4]]
// 取第一个分支 // 取第一个分支
if (response && response.length > 0) { if (response && response.length > 0) {
@@ -1215,7 +1053,14 @@ const submitBranch = async () => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#409eff', strokeWidth: 2, strokeDasharray: '5,5' } style: { stroke: '#409eff', strokeWidth: 2, strokeDasharray: '5,5' },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
} }
edges.value.push(newEdge) edges.value.push(newEdge)
newBranchEdges.push(newEdge) newBranchEdges.push(newEdge)
@@ -1230,17 +1075,22 @@ const submitBranch = async () => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#409eff', strokeWidth: 2 } style: { stroke: '#409eff', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
} }
edges.value.push(newEdge) edges.value.push(newEdge)
newBranchEdges.push(newEdge) newBranchEdges.push(newEdge)
} }
}) })
// 📂 保存分支数据到 store // 保存分支数据到 store
if (newBranchNodes.length > 0) { if (newBranchNodes.length > 0) {
// 将 IApiAgentAction 转换为 TaskProcess 格式用于存储
// 与 fill-step-task-mock.ts 中的 TaskProcess 格式保持一致
const branchTasks = newAgentActions.map(action => ({ const branchTasks = newAgentActions.map(action => ({
ID: action.id || uuidv4(), ID: action.id || uuidv4(),
ActionType: action.type, ActionType: action.type,
@@ -1317,9 +1167,6 @@ onConnect(params => addEdges(params))
@node-click="onNodeClick" @node-click="onNodeClick"
class="vue-flow-container" class="vue-flow-container"
> >
<!-- <Background /> -->
<!-- <Controls /> -->
<template #node-root="nodeProps"> <template #node-root="nodeProps">
<div class="root-task-node-wrapper"> <div class="root-task-node-wrapper">
<Handle type="source" :position="Position.Right" id="right" /> <Handle type="source" :position="Position.Right" id="right" />
@@ -1645,7 +1492,7 @@ onConnect(params => addEdges(params))
.el-input__inner { .el-input__inner {
font-size: 13px; font-size: 13px;
color: var(--color-text-primary); color: #000;
padding-right: 40px; padding-right: 40px;
} }
} }
@@ -1684,7 +1531,7 @@ onConnect(params => addEdges(params))
opacity: 0.9; opacity: 0.9;
transition: all 0.2s ease; transition: all 0.2s ease;
// 🆕 分支选中高亮样式 // 分支选中高亮样式
&.is-branch-selected { &.is-branch-selected {
box-shadow: 0 0 0 3px #000, 0 0 20px rgba(0, 0, 0, 0.5); box-shadow: 0 0 0 3px #000, 0 0 20px rgba(0, 0, 0, 0.5);
z-index: 10; z-index: 10;
@@ -1719,17 +1566,6 @@ onConnect(params => addEdges(params))
} }
} }
:deep(.vue-flow__controls) {
button {
background-color: #43a8aa;
border-color: #43a8aa;
&:hover {
background-color: #358d8f;
}
}
}
/* 智能体悬浮提示样式 */ /* 智能体悬浮提示样式 */
:deep(.agent-tooltip-popper) { :deep(.agent-tooltip-popper) {
z-index: 4000 !important; z-index: 4000 !important;

View File

@@ -12,21 +12,19 @@ const props = defineProps<{
step?: any step?: any
}>() }>()
// 获取分支数量 - 主分支(1) + 额外分支数量 // 获取分支数量
const branchCount = computed(() => { const branchCount = computed(() => {
if (!props.step?.Id) return 1 if (!props.step?.Id) return 1
// 获取该任务步骤的分支数据 // 获取该任务步骤的分支数据
const taskStepId = props.step.Id const taskStepId = props.step.Id
// 🆕 获取该任务的 agent 组合 // 获取该任务的 agent 组合
const agents = props.step.AgentSelection || [] const agents = props.step.AgentSelection || []
const branches = selectionStore.getTaskProcessBranches(taskStepId, agents) const branches = selectionStore.getTaskProcessBranches(taskStepId, agents)
// 主分支(1) + 额外分支数量
return branches.length || 1 return branches.length || 1
}) })
// 🆕 判断按钮是否可点击(只有当前按钮对应的任务是任务大纲中选中的任务时才可点击) // 判断按钮是否可点击
const isClickable = computed(() => { const isClickable = computed(() => {
if (!props.step?.Id || !agentsStore.currentTask?.Id) { if (!props.step?.Id || !agentsStore.currentTask?.Id) {
return false return false
@@ -35,7 +33,7 @@ const isClickable = computed(() => {
}) })
const handleClick = (event?: MouseEvent) => { const handleClick = (event?: MouseEvent) => {
// 🆕 只有可点击时才执行操作 // 只有可点击时才执行操作
if (!isClickable.value) { if (!isClickable.value) {
return return
} }
@@ -102,7 +100,7 @@ const handleClick = (event?: MouseEvent) => {
filter: brightness(0.9); filter: brightness(0.9);
} }
// 🆕 禁用状态 // 禁用状态
&.is-disabled { &.is-disabled {
background-color: #bdc3c7; background-color: #bdc3c7;
cursor: not-allowed; cursor: not-allowed;

View File

@@ -59,7 +59,7 @@ function handlePrev() {
<!-- <div>{{ `${displayIndex + 1}/${data.length}` }}</div> <!-- <div>{{ `${displayIndex + 1}/${data.length}` }}</div>
<el-button type="primary" size="small" @click="handleNext">下一个</el-button> --> <el-button type="primary" size="small" @click="handleNext">下一个</el-button> -->
<!-- 关闭 --> <!-- 关闭 -->
<SvgIcon icon-class="close" size="15px" /> <!-- <SvgIcon icon-class="close" size="15px" /> -->
</div> </div>
</div> </div>
<!-- 分割线 --> <!-- 分割线 -->

View File

@@ -38,9 +38,9 @@ watch(
) )
// 编辑逻辑 // 编辑逻辑
const editMode = ref(false) //全局编辑开关 const editMode = ref(false)
const editMap = reactive<Record<string, boolean>>({}) //行级编辑状态 const editMap = reactive<Record<string, boolean>>({})
const editBuffer = reactive<Record<string, string | undefined>>({}) //临时输入 const editBuffer = reactive<Record<string, string | undefined>>({})
const showPopover = ref(false) const showPopover = ref(false)
function getProcessDescription(stepId: string, processId: string) { function getProcessDescription(stepId: string, processId: string) {
const step = collaborationProcess.value.find(s => s.Id === stepId) const step = collaborationProcess.value.find(s => s.Id === stepId)
@@ -201,7 +201,6 @@ async function handleTaskProcess() {
// 重置执行结果 // 重置执行结果
function handleRefresh() { function handleRefresh() {
agentsStore.setExecutePlan([]) agentsStore.setExecutePlan([])
console.log('🔄 已重置执行结果')
} }
// 添加滚动状态标识 // 添加滚动状态标识
@@ -241,10 +240,8 @@ function clear() {
jsplumb.reset() jsplumb.reset()
} }
// 🆕 封装连线重绘方法 //封装连线重绘方法
const redrawInternalLines = (highlightId?: string) => { const redrawInternalLines = (highlightId?: string) => {
console.log('🔄 TaskResult: 重新绘制连线', highlightId ? `高亮: ${highlightId}` : '')
// 等待 DOM 更新完成 // 等待 DOM 更新完成
nextTick(() => { nextTick(() => {
// 清除旧连线 // 清除旧连线
@@ -253,28 +250,25 @@ const redrawInternalLines = (highlightId?: string) => {
// 等待 DOM 稳定后重新绘制 // 等待 DOM 稳定后重新绘制
setTimeout(() => { setTimeout(() => {
createInternalLine(highlightId) createInternalLine(highlightId)
console.log('✅ TaskResult: 连线重绘完成,任务数:', collaborationProcess.value.length)
}, 100) }, 100)
}) })
} }
// 🆕 监听 collaborationProcess 变化,自动重绘连线 //监听 collaborationProcess 变化,自动重绘连线
watch( watch(
() => collaborationProcess, () => collaborationProcess,
() => { () => {
console.log('🔍 TaskResult: collaborationProcess 发生变化,触发重绘')
redrawInternalLines() redrawInternalLines()
}, },
{ deep: true } { deep: true }
) )
// 🆕 组件挂载后初始化连线 // 组件挂载后初始化连线
onMounted(() => { onMounted(() => {
// 初始化时绘制连线 // 初始化时绘制连线
nextTick(() => { nextTick(() => {
setTimeout(() => { setTimeout(() => {
createInternalLine() createInternalLine()
console.log('✅ TaskResult: 初始化连线完成')
}, 100) }, 100)
}) })
}) })
@@ -328,7 +322,6 @@ onUnmounted(() => {
}) })
// 计算按钮类名 // 计算按钮类名
const processBtnClass = computed(() => { const processBtnClass = computed(() => {
// 当刷新或执行按钮悬停时,过程按钮变圆形
if (buttonHoverState.value === 'refresh' || buttonHoverState.value === 'execute') { if (buttonHoverState.value === 'refresh' || buttonHoverState.value === 'execute') {
return 'circle' return 'circle'
} }
@@ -336,20 +329,16 @@ const processBtnClass = computed(() => {
}) })
const executeBtnClass = computed(() => { const executeBtnClass = computed(() => {
// 鼠标悬停在过程按钮或刷新按钮上时,执行按钮变圆形
if (buttonHoverState.value === 'process' || buttonHoverState.value === 'refresh') { if (buttonHoverState.value === 'process' || buttonHoverState.value === 'refresh') {
return 'circle' return 'circle'
} }
//如果有任务数据就显示椭圆形,否则显示圆形
return agentsStore.agentRawPlan.data ? 'ellipse' : 'circle' return agentsStore.agentRawPlan.data ? 'ellipse' : 'circle'
}) })
const refreshBtnClass = computed(() => { const refreshBtnClass = computed(() => {
// 当过程或执行按钮悬停时,刷新按钮变圆形
if (buttonHoverState.value === 'process' || buttonHoverState.value === 'execute') { if (buttonHoverState.value === 'process' || buttonHoverState.value === 'execute') {
return 'circle' return 'circle'
} }
// 有执行结果就显示椭圆形,否则显示圆形
return agentsStore.executePlan.length > 0 ? 'ellipse' : 'circle' return agentsStore.executePlan.length > 0 ? 'ellipse' : 'circle'
}) })
@@ -359,9 +348,7 @@ const showProcessText = computed(() => {
}) })
const showExecuteText = computed(() => { const showExecuteText = computed(() => {
// 鼠标悬停在过程按钮上时,执行按钮不显示文字
if (buttonHoverState.value === 'process') return false if (buttonHoverState.value === 'process') return false
// 其他情况:如果有任务数据就显示文字,否则不显示
return agentsStore.agentRawPlan.data return agentsStore.agentRawPlan.data
}) })
@@ -398,7 +385,7 @@ defineExpose({
<div class="text-[18px] font-bold mb-[7px] flex justify-between items-center px-[20px]"> <div class="text-[18px] font-bold mb-[7px] flex justify-between items-center px-[20px]">
<span class="text-[var(--color-text-title-header)]">执行结果</span> <span class="text-[var(--color-text-title-header)]">执行结果</span>
<div <div
class="flex items-center justify-end gap-[14px] task-button-group min-w-[175px]" class="flex items-center justify-end gap-[10px] task-button-group w-[230px]"
@mouseleave="handleButtonMouseLeave" @mouseleave="handleButtonMouseLeave"
> >
<!-- 刷新按钮 --> <!-- 刷新按钮 -->
@@ -758,7 +745,7 @@ defineExpose({
} }
} }
// ========== 新增:按钮交互样式 ========== //按钮交互样式
.task-button-group { .task-button-group {
display: flex; display: flex;
flex-direction: row-reverse; flex-direction: row-reverse;
@@ -766,7 +753,8 @@ defineExpose({
display: inline-flex !important; display: inline-flex !important;
align-items: center !important; align-items: center !important;
justify-content: center !important; justify-content: center !important;
transition: width 0.2s ease-out, padding 0.2s ease-out, border-radius 0.2s ease-out, transform 0.2s ease-out, box-shadow 0.2s ease-out, filter 0.2s ease-out !important; transition: width 0.2s ease-out, padding 0.2s ease-out, border-radius 0.2s ease-out,
transform 0.2s ease-out, box-shadow 0.2s ease-out, filter 0.2s ease-out !important;
overflow: hidden !important; overflow: hidden !important;
white-space: nowrap !important; white-space: nowrap !important;
border: 1px solid transparent !important; border: 1px solid transparent !important;
@@ -812,6 +800,7 @@ defineExpose({
width: 40px !important; width: 40px !important;
height: 40px !important; height: 40px !important;
min-width: 40px !important; min-width: 40px !important;
max-width: 40px !important;
padding: 0 !important; padding: 0 !important;
border-radius: 50% !important; border-radius: 50% !important;

View File

@@ -50,8 +50,6 @@ import type { Node, Edge } from '@vue-flow/core'
import { useAgentsStore, useSelectionStore, type IRawStepTask } from '@/stores' import { useAgentsStore, useSelectionStore, type IRawStepTask } from '@/stores'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import api from '@/api' import api from '@/api'
import { v4 as uuidv4 } from 'uuid'
import '@vue-flow/core/dist/style.css' import '@vue-flow/core/dist/style.css'
import '@vue-flow/core/dist/theme-default.css' import '@vue-flow/core/dist/theme-default.css'
import '@vue-flow/minimap/dist/style.css' import '@vue-flow/minimap/dist/style.css'
@@ -64,8 +62,7 @@ import TaskNode from './components/TaskNode.vue'
const agentsStore = useAgentsStore() const agentsStore = useAgentsStore()
const selectionStore = useSelectionStore() const selectionStore = useSelectionStore()
// Mock 数据配置 // Mock 数据开关
// 开关:控制是否使用 mock 数据(开发时设置为 true生产时设置为 false
const USE_MOCK_DATA = false const USE_MOCK_DATA = false
// 获取协作流程数据 // 获取协作流程数据
@@ -80,16 +77,13 @@ const edges = ref<Edge[]>([])
// Vue Flow 实例方法 // Vue Flow 实例方法
const { fitView: fit, setTransform, updateNode, findNode } = useVueFlow() const { fitView: fit, setTransform, updateNode, findNode } = useVueFlow()
// 编辑状态管理
const editingTasks = ref<Record<string, string>>({})
// 当前正在添加分支的节点 ID // 当前正在添加分支的节点 ID
const currentAddingBranchNodeId = ref<string | null>(null) const currentAddingBranchNodeId = ref<string | null>(null)
// 当前选中的节点ID集合 // 当前选中的节点ID集合
const selectedNodeIds = ref<Set<string>>(new Set()) const selectedNodeIds = ref<Set<string>>(new Set())
// 获取从目标节点回溯到根节点的路径 // 回溯到根节点的路径
const getPathToRoot = (targetNodeId: string): string[] => { const getPathToRoot = (targetNodeId: string): string[] => {
const path: string[] = [] const path: string[] = []
const visited = new Set<string>() const visited = new Set<string>()
@@ -121,7 +115,7 @@ const getPathToRoot = (targetNodeId: string): string[] => {
return path return path
} }
// 获取分支的所有子节点(只向右遍历,不跨分支) // 获取分支的所有子节点
const getAllBranchNodes = (startNodeId: string): string[] => { const getAllBranchNodes = (startNodeId: string): string[] => {
const visited = new Set<string>() const visited = new Set<string>()
const toVisit: string[] = [startNodeId] const toVisit: string[] = [startNodeId]
@@ -134,7 +128,7 @@ const getAllBranchNodes = (startNodeId: string): string[] => {
} }
visited.add(currentId) visited.add(currentId)
// 查找通过 right handle 连接的后续节点(分支创建方向 // 查找分支创建方向的后续节点
const outgoingEdges = edges.value.filter( const outgoingEdges = edges.value.filter(
edge => edge.source === currentId && edge.sourceHandle === 'right' edge => edge.source === currentId && edge.sourceHandle === 'right'
) )
@@ -155,7 +149,7 @@ const getAllBranchNodes = (startNodeId: string): string[] => {
return Array.from(visited) return Array.from(visited)
} }
// 向上回溯分支的父节点链(只包含分支节点) // 回溯分支的父节点链
const getBranchParentChain = (targetNodeId: string): string[] => { const getBranchParentChain = (targetNodeId: string): string[] => {
const parentChain: string[] = [] const parentChain: string[] = []
let currentId = targetNodeId let currentId = targetNodeId
@@ -170,12 +164,12 @@ const getBranchParentChain = (targetNodeId: string): string[] => {
const sourceNode = nodes.value.find(n => n.id === incomingEdge.source) const sourceNode = nodes.value.find(n => n.id === incomingEdge.source)
// 如果父节点不是分支节点停止回溯 // 分支节点停止回溯
if (!sourceNode || !sourceNode.id.startsWith('branch-task-')) { if (!sourceNode || !sourceNode.id.startsWith('branch-task-')) {
break break
} }
// 添加父节点到链中 // 添加父节点
parentChain.push(sourceNode.id) parentChain.push(sourceNode.id)
currentId = sourceNode.id currentId = sourceNode.id
} }
@@ -183,35 +177,35 @@ const getBranchParentChain = (targetNodeId: string): string[] => {
return parentChain return parentChain
} }
// 判断节点是否为主流程节点 // 判断是否为主流程节点
const isMainProcessNode = (nodeId: string): boolean => { const isMainProcessNode = (nodeId: string): boolean => {
return nodeId.startsWith('task-') && !nodeId.startsWith('branch-task-') return nodeId.startsWith('task-') && !nodeId.startsWith('branch-task-')
} }
// 分支操作加载状态 // 分支加载状态
const branchLoading = ref(false) const branchLoading = ref(false)
// 初始化标记,避免重复适应视图(使用 sessionStorage 持久化) // 初始化标记
const INIT_KEY = 'plan-modification-initialized' const INIT_KEY = 'plan-modification-initialized'
const isInitialized = ref(sessionStorage.getItem(INIT_KEY) === 'true') const isInitialized = ref(sessionStorage.getItem(INIT_KEY) === 'true')
// 分支初始化标记 // 分支初始化标记
const BRANCHES_INIT_KEY = 'plan-modification-branches-initialized' const BRANCHES_INIT_KEY = 'plan-modification-branches-initialized'
// 最后选中的分支ID // 最后选中的分支ID
const LAST_SELECTED_BRANCH_KEY = 'plan-modification-last-selected-branch' const LAST_SELECTED_BRANCH_KEY = 'plan-modification-last-selected-branch'
// 标记是否已经挂载 // 挂载标记
const isMounted = ref(false) const isMounted = ref(false)
// 节点尺寸配置 // 节点尺寸配置
const NODE_WIDTH = 120 // 任务节点宽度 const NODE_WIDTH = 120
const ROOT_WIDTH = 200 // 根节点宽度 const ROOT_WIDTH = 200
const NODE_GAP = 80 // 节点间距 const NODE_GAP = 80
const START_X = 40 // 起始 X 坐标 const START_X = 40
const START_Y = 50 // 起始 Y 坐标 const START_Y = 50
// 初始化流程图 - 横向布局(根节点为初始目标,只展示流程卡片) // 初始化流程图
const initializeFlow = () => { const initializeFlow = () => {
const branchesInitialized = sessionStorage.getItem(BRANCHES_INIT_KEY) === 'true' const branchesInitialized = sessionStorage.getItem(BRANCHES_INIT_KEY) === 'true'
const savedBranches = selectionStore.getAllFlowBranches() const savedBranches = selectionStore.getAllFlowBranches()
@@ -308,16 +302,16 @@ const initializeFlow = () => {
return return
} }
// 首次初始化:创建完整的流程 // 首次初始化
const newNodes: Node[] = [] const newNodes: Node[] = []
const newEdges: Edge[] = [] const newEdges: Edge[] = []
// 获取初始目标作为根节点 // 获取根节点
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] const generalGoal = agentsStore.agentRawPlan.data?.['General Goal']
const initialInput = agentsStore.agentRawPlan.data?.['Initial Input Object'] const initialInput = agentsStore.agentRawPlan.data?.['Initial Input Object']
// 创建根节点(初始目标) // 创建根节点
if (generalGoal) { if (generalGoal) {
newNodes.push({ newNodes.push({
id: 'root-goal', id: 'root-goal',
@@ -331,7 +325,7 @@ const initializeFlow = () => {
}) })
} }
// 遍历协作流程,创建任务节点 // 创建任务节点
collaborationProcess.value.forEach((task, index) => { collaborationProcess.value.forEach((task, index) => {
const taskId = task.Id || `task-${index}` const taskId = task.Id || `task-${index}`
@@ -364,13 +358,21 @@ const initializeFlow = () => {
animated: true, animated: true,
type: 'smoothstep', type: 'smoothstep',
style: { stroke: '#e6a23c', strokeWidth: 2 }, style: { stroke: '#e6a23c', strokeWidth: 2 },
label: '' markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
}) })
} }
// 如果不是第一个任务,创建从前一个任务到当前任务的连接 // 如果不是第一个任务,创建从前一个任务到当前任务的连接
if (index > 0) { if (index > 0) {
const prevTaskId = collaborationProcess.value[index - 1].Id || `task-${index - 1}` // const prevTaskId = collaborationProcess.value[index - 1].Id || `task-${index - 1}`
const prev = collaborationProcess.value[index - 1]
const prevTaskId = prev?.Id || `task-${index - 1}`
newEdges.push({ newEdges.push({
id: `edge-task-${prevTaskId}-${taskId}`, id: `edge-task-${prevTaskId}-${taskId}`,
source: `task-${prevTaskId}`, source: `task-${prevTaskId}`,
@@ -380,7 +382,13 @@ const initializeFlow = () => {
animated: true, animated: true,
type: 'smoothstep', type: 'smoothstep',
style: { stroke: '#409eff', strokeWidth: 2 }, style: { stroke: '#409eff', strokeWidth: 2 },
label: '' markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
}) })
} }
}) })
@@ -388,8 +396,7 @@ const initializeFlow = () => {
nodes.value = newNodes nodes.value = newNodes
edges.value = newEdges edges.value = newEdges
// 🆕 检查是否需要保存初始流程为分支 // 检查是否需要保存初始流程为分支
// 如果没有任何分支(首次初始化),将初始流程保存为一个分支
if (savedBranches.length === 0) { if (savedBranches.length === 0) {
const initialBranchNodes = newNodes.filter(node => node.id !== 'root-goal') const initialBranchNodes = newNodes.filter(node => node.id !== 'root-goal')
const initialBranchEdges = [...newEdges] const initialBranchEdges = [...newEdges]
@@ -406,7 +413,7 @@ const initializeFlow = () => {
sessionStorage.setItem(BRANCHES_INIT_KEY, 'true') sessionStorage.setItem(BRANCHES_INIT_KEY, 'true')
} }
// 后续初始化:从 store 恢复所有分支节点 // 从 store 恢复分支
if (savedBranches.length > 0) { if (savedBranches.length > 0) {
savedBranches.forEach(branch => { savedBranches.forEach(branch => {
branch.nodes.forEach(node => { branch.nodes.forEach(node => {
@@ -425,7 +432,7 @@ const initializeFlow = () => {
.map(node => node.id) .map(node => node.id)
selectedNodeIds.value = new Set(mainProcessNodeIds) selectedNodeIds.value = new Set(mainProcessNodeIds)
// 只在首次挂载后初始化时适应视图,后续数据变化不适应 // 首次挂载后适应视图
if (isMounted.value && !isInitialized.value) { if (isMounted.value && !isInitialized.value) {
nextTick(() => { nextTick(() => {
setTimeout(() => { setTimeout(() => {
@@ -437,15 +444,15 @@ const initializeFlow = () => {
} }
} }
// 监听 currentTask 变化,自动高亮对应分支并更新节点数据 // 监听 currentTask 变化
watch( watch(
() => agentsStore.currentTask, () => agentsStore.currentTask,
(newTask, oldTask) => { newTask => {
if (!newTask) { if (!newTask) {
return return
} }
// 1. 找到包含 currentTask 的分支 // 找到包含 currentTask 的分支
const allBranches = selectionStore.getAllFlowBranches() const allBranches = selectionStore.getAllFlowBranches()
const matchedBranch = allBranches.find(branch => { const matchedBranch = allBranches.find(branch => {
@@ -456,7 +463,7 @@ watch(
const branchNodeIds = matchedBranch.nodes.map(node => node.id) const branchNodeIds = matchedBranch.nodes.map(node => node.id)
selectedNodeIds.value = new Set(branchNodeIds) selectedNodeIds.value = new Set(branchNodeIds)
// 更新对应节点的 task 数据(同步 AgentAllocation 中的修改) // 更新节点数据
if (newTask.StepName) { if (newTask.StepName) {
const matchedNodes = nodes.value.filter(node => { const matchedNodes = nodes.value.filter(node => {
return node.data?.task?.StepName === newTask.StepName return node.data?.task?.StepName === newTask.StepName
@@ -474,11 +481,24 @@ watch(
}) })
const nodeIndex = nodes.value.findIndex(n => n.id === node.id) const nodeIndex = nodes.value.findIndex(n => n.id === node.id)
// if (nodeIndex !== -1) {
// const updatedNode = {
// ...nodes.value[nodeIndex],
// data: {
// ...nodes.value[nodeIndex].data,
// task: { ...newTask },
// updateKey: newUpdateKey
// }
// }
// nodes.value.splice(nodeIndex, 1, updatedNode)
// }
if (nodeIndex !== -1) { if (nodeIndex !== -1) {
const existingNode = nodes.value[nodeIndex]
const existingData = existingNode?.data || {}
const updatedNode = { const updatedNode = {
...nodes.value[nodeIndex], ...existingNode,
data: { data: {
...nodes.value[nodeIndex].data, ...existingData,
task: { ...newTask }, task: { ...newTask },
updateKey: newUpdateKey updateKey: newUpdateKey
} }
@@ -497,7 +517,7 @@ onMounted(() => {
isMounted.value = true isMounted.value = true
initializeFlow() initializeFlow()
// 主动同步 currentTask 数据到节点(解决组件晚挂载的问题) // 同步 currentTask 数据
if (agentsStore.currentTask && agentsStore.currentTask.StepName) { if (agentsStore.currentTask && agentsStore.currentTask.StepName) {
const matchedNodes = nodes.value.filter(node => { const matchedNodes = nodes.value.filter(node => {
return node.data?.task?.StepName === agentsStore.currentTask!.StepName return node.data?.task?.StepName === agentsStore.currentTask!.StepName
@@ -508,10 +528,12 @@ onMounted(() => {
const nodeIndex = nodes.value.findIndex(n => n.id === node.id) const nodeIndex = nodes.value.findIndex(n => n.id === node.id)
if (nodeIndex !== -1) { if (nodeIndex !== -1) {
const existingNode = nodes.value[nodeIndex]
const existingData = existingNode?.data || {}
const updatedNode = { const updatedNode = {
...nodes.value[nodeIndex], ...existingNode,
data: { data: {
...nodes.value[nodeIndex].data, ...existingData,
task: { ...agentsStore.currentTask! }, task: { ...agentsStore.currentTask! },
updateKey: newUpdateKey updateKey: newUpdateKey
} }
@@ -537,7 +559,7 @@ const onNodeClick = (event: any) => {
const nodeId = event.node.id const nodeId = event.node.id
const nodeData = event.node.data as any const nodeData = event.node.data as any
// 如果点击的是根节点,不做处理(根节点不参与高亮 // 根节点不参与高亮
if (nodeId === 'root-goal') { if (nodeId === 'root-goal') {
return return
} }
@@ -549,7 +571,7 @@ const onNodeClick = (event: any) => {
// 点击的是主流程节点,高亮所有主流程节点 // 点击的是主流程节点,高亮所有主流程节点
nodesToHighlight = nodes.value.filter(node => isMainProcessNode(node.id)).map(node => node.id) nodesToHighlight = nodes.value.filter(node => isMainProcessNode(node.id)).map(node => node.id)
// 🆕 切换到初始流程分支 // 切换到初始流程分支
const allBranches = selectionStore.getAllFlowBranches() const allBranches = selectionStore.getAllFlowBranches()
const initialBranch = allBranches.find(branch => branch.branchContent === '初始流程') const initialBranch = allBranches.find(branch => branch.branchContent === '初始流程')
@@ -598,7 +620,7 @@ const onNodeClick = (event: any) => {
}) })
if (matchedBranch) { if (matchedBranch) {
// 🆕 按照高亮路径顺序收集每个节点的任务数据 // 按照高亮路径顺序收集每个节点的任务数据
const fullProcessTasks: IRawStepTask[] = [] const fullProcessTasks: IRawStepTask[] = []
const allBranches = selectionStore.getAllFlowBranches() const allBranches = selectionStore.getAllFlowBranches()
@@ -635,7 +657,7 @@ const onNodeClick = (event: any) => {
} }
}) })
// 🆕 保存最后选中的分支ID // 保存最后选中的分支ID
sessionStorage.setItem(LAST_SELECTED_BRANCH_KEY, matchedBranch.id) sessionStorage.setItem(LAST_SELECTED_BRANCH_KEY, matchedBranch.id)
} }
} else { } else {
@@ -648,15 +670,7 @@ const onNodeClick = (event: any) => {
selectedNodeIds.value = new Set(nodesToHighlight) selectedNodeIds.value = new Set(nodesToHighlight)
} }
// 编辑任务 // 开始添加分支
const handleEditTask = (taskId: string) => {
const node = nodes.value.find(n => n.id === taskId)
if (node && node.data.task) {
editingTasks.value[taskId] = node.data.task.TaskContent || ''
node.data.isEditing = true
}
}
// 开始添加分支(确保同一时间只有一个输入框)
const handleStartAddBranch = (nodeId: string) => { const handleStartAddBranch = (nodeId: string) => {
currentAddingBranchNodeId.value = nodeId currentAddingBranchNodeId.value = nodeId
} }
@@ -668,42 +682,39 @@ const handleCancelAddBranch = () => {
// 添加分支 // 添加分支
const handleAddBranch = async (taskId: string, branchContent: string) => { const handleAddBranch = async (taskId: string, branchContent: string) => {
// 获取父节点 // 获取父节点数据
const parentNode = nodes.value.find(n => n.id === taskId) const parentNode = nodes.value.find(n => n.id === taskId)
if (!parentNode) return if (!parentNode) return
// ==================== 移动已有分支 ==================== // 查找已有分支节点
// 查找所有已有的分支任务节点(标记为 isBranchTask
const allExistingBranchNodes = nodes.value.filter(n => n.data.isBranchTask) const allExistingBranchNodes = nodes.value.filter(n => n.data.isBranchTask)
// 🆕 只移动在当前父节点下方的分支节点Y坐标 > 父节点Y坐标 // 移动父节点下方的分支
const parentNodeY = parentNode.position.y const parentNodeY = parentNode.position.y
const branchesBelowParent = allExistingBranchNodes.filter(node => node.position.y > parentNodeY) const branchesBelowParent = allExistingBranchNodes.filter(node => node.position.y > parentNodeY)
// 将当前父节点下方的分支向下移动200px // 向下移动分支
branchesBelowParent.forEach(node => { branchesBelowParent.forEach(node => {
node.position.y += 200 node.position.y += 200
}) })
// 开始加载 // 加载
branchLoading.value = true branchLoading.value = true
try { try {
// 创建分支节点ID // 创建分支节点ID
const branchId = `branch-${Date.now()}` const branchId = `branch-${Date.now()}`
// 计算分支节点位置 // 计算分支位置
// 根节点分支:向下分叉
// 任务节点分支:向右下方分叉
let branchX: number let branchX: number
let branchY: number let branchY: number
if (taskId === 'root-goal') { if (taskId === 'root-goal') {
// 根节点分支:在根节点下方 // 根节点分支位置
branchX = parentNode.position.x branchX = parentNode.position.x
branchY = parentNode.position.y + 200 branchY = parentNode.position.y + 200
} else { } else {
// 任务节点分支:在任务节点右下方 // 任务节点分支位置
branchX = parentNode.position.x + 200 branchX = parentNode.position.x + 200
branchY = parentNode.position.y + 150 branchY = parentNode.position.y + 150
} }
@@ -770,11 +781,18 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
goal: generalGoal goal: generalGoal
}) })
// 直接获取协作流程数据API 返回二维数组 [[task1, task2, ...]],取第一个分支) // 直接获取协作流程数据
newTasks = response?.[0] || [] // newTasks = response?.[0] || []
// 直接获取协作流程数据:兼容返回数组或对象的情况,优先处理二维数组返回
// 调试日志:验证数据提取 if (Array.isArray(response)) {
// 可能是二维数组
newTasks = (response as any[])[0] || []
} else if (response && (response as any)['Collaboration Process']) {
// 如果返回的是对象,尝试读取 Collaboration Process 字段
newTasks = (response as any)['Collaboration Process'] || []
} else {
newTasks = []
}
// ========== 填充每个任务的 TaskProcess ========== // ========== 填充每个任务的 TaskProcess ==========
for (let i = 0; i < newTasks.length; i++) { for (let i = 0; i < newTasks.length; i++) {
const task = newTasks[i] const task = newTasks[i]
@@ -834,7 +852,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
// 创建连接边 // 创建连接边
if (index === 0) { if (index === 0) {
// 第一个任务连接到父节点(从根节点底部到第一个任务左边) // 连接到父节点
const newEdge: Edge = { const newEdge: Edge = {
id: `edge-${taskId}-${taskNodeId}`, id: `edge-${taskId}-${taskNodeId}`,
source: taskId, source: taskId,
@@ -844,7 +862,13 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#409eff', strokeWidth: 2, strokeDasharray: '5,5' }, style: { stroke: '#409eff', strokeWidth: 2, strokeDasharray: '5,5' },
label: '' markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
} }
edges.value.push(newEdge) edges.value.push(newEdge)
newBranchEdges.push(newEdge) newBranchEdges.push(newEdge)
@@ -859,7 +883,14 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#409eff', strokeWidth: 2 } style: { stroke: '#409eff', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
} }
edges.value.push(newEdge) edges.value.push(newEdge)
newBranchEdges.push(newEdge) newBranchEdges.push(newEdge)
@@ -867,7 +898,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
}) })
} }
// 保存分支数据到 store // 保存分支到 store
if (newBranchNodes.length > 0) { if (newBranchNodes.length > 0) {
selectionStore.addFlowBranch({ selectionStore.addFlowBranch({
parentNodeId: taskId, parentNodeId: taskId,
@@ -886,7 +917,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
const newBranchNodes: Node[] = [] const newBranchNodes: Node[] = []
const newBranchEdges: Edge[] = [] const newBranchEdges: Edge[] = []
// 🆕 判断父节点是否是分支节点 // 判断父节点是否是分支节点
const parentIsBranchTask = parentNode.data.isBranchTask || false const parentIsBranchTask = parentNode.data.isBranchTask || false
if (USE_MOCK_DATA) { if (USE_MOCK_DATA) {
@@ -894,7 +925,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || '' const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
const initialInput = agentsStore.agentRawPlan.data?.['Initial Input Object'] || [] const initialInput = agentsStore.agentRawPlan.data?.['Initial Input Object'] || []
// 🆕 根据父节点类型构建 existingSteps // 根据父节点类型构建 existingSteps
let existingSteps: any[] = [] let existingSteps: any[] = []
let baselineCompletion = 0 let baselineCompletion = 0
@@ -958,8 +989,6 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
// 从响应中获取协作流程数据 // 从响应中获取协作流程数据
newTasks = response['Collaboration Process'] || [] newTasks = response['Collaboration Process'] || []
// ========== 填充每个任务的 TaskProcess ==========
for (let i = 0; i < newTasks.length; i++) { for (let i = 0; i < newTasks.length; i++) {
const task = newTasks[i] const task = newTasks[i]
if (!task) continue if (!task) continue
@@ -984,7 +1013,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || '' const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
const initialInput = agentsStore.agentRawPlan.data?.['Initial Input Object'] || [] const initialInput = agentsStore.agentRawPlan.data?.['Initial Input Object'] || []
// 🆕 根据父节点类型构建 existingSteps //根据父节点类型构建 existingSteps
let existingSteps: any[] = [] let existingSteps: any[] = []
let baselineCompletion = 0 let baselineCompletion = 0
@@ -1045,12 +1074,17 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
initialInputs: Array.isArray(initialInput) ? initialInput : [initialInput], initialInputs: Array.isArray(initialInput) ? initialInput : [initialInput],
goal: generalGoal goal: generalGoal
}) })
// 直接获取协作流程数据
console.log('API Response:', response) // newTasks = response?.[0] || []
// 直接获取协作流程数据API 返回二维数组 [[task1, task2, ...]],取第一个分支) if (Array.isArray(response)) {
newTasks = response?.[0] || [] // 可能是二维数组
console.log('获取到的新newTasks:', newTasks) newTasks = (response as any[])[0] || []
// ========== 填充每个任务的 TaskProcess ========== } else if (response && (response as any)['Collaboration Process']) {
// 如果返回的是对象,尝试读取 Collaboration Process 字段
newTasks = (response as any)['Collaboration Process'] || []
} else {
newTasks = []
}
for (let i = 0; i < newTasks.length; i++) { for (let i = 0; i < newTasks.length; i++) {
const task = newTasks[i] const task = newTasks[i]
if (!task) continue if (!task) continue
@@ -1118,7 +1152,13 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#67c23a', strokeWidth: 2, strokeDasharray: '5,5' }, style: { stroke: '#67c23a', strokeWidth: 2, strokeDasharray: '5,5' },
label: '' markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
} }
edges.value.push(newEdge) edges.value.push(newEdge)
newBranchEdges.push(newEdge) newBranchEdges.push(newEdge)
@@ -1133,7 +1173,14 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#67c23a', strokeWidth: 2 } style: { stroke: '#67c23a', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
width: 20,
height: 20,
strokeWidth: 2
}
} }
edges.value.push(newEdge) edges.value.push(newEdge)
newBranchEdges.push(newEdge) newBranchEdges.push(newEdge)
@@ -1141,7 +1188,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
}) })
} }
// 📂 保存分支数据到 store(新增) // 保存分支数据到 store
if (newBranchNodes.length > 0) { if (newBranchNodes.length > 0) {
selectionStore.addFlowBranch({ selectionStore.addFlowBranch({
parentNodeId: taskId, parentNodeId: taskId,
@@ -1157,7 +1204,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
// 重置当前添加分支的节点 ID // 重置当前添加分支的节点 ID
currentAddingBranchNodeId.value = null currentAddingBranchNodeId.value = null
// 适应视图以显示新节点 // 适应视图
nextTick(() => { nextTick(() => {
setTimeout(() => { setTimeout(() => {
fit({ padding: 100, duration: 300 }) fit({ padding: 100, duration: 300 })
@@ -1172,21 +1219,12 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
} }
} }
// 删除分支
const handleDeleteBranch = (branchId: string) => {
// 删除分支节点
nodes.value = nodes.value.filter(n => n.id !== branchId)
// 删除相关的边
edges.value = edges.value.filter(e => e.source !== branchId && e.target !== branchId)
}
// 重置视图 // 重置视图
const resetView = () => { const resetView = () => {
setTransform({ x: 0, y: 0, zoom: 0.5 }) setTransform({ x: 0, y: 0, zoom: 0.5 })
} }
// 重置初始化状态并重新适应视图 // 重新适应视图
const refitView = () => { const refitView = () => {
isInitialized.value = false isInitialized.value = false
sessionStorage.removeItem(INIT_KEY) sessionStorage.removeItem(INIT_KEY)
@@ -1199,7 +1237,7 @@ const refitView = () => {
}) })
} }
// 暴露方法给父组件 // 暴露方法
defineExpose({ defineExpose({
initializeFlow, initializeFlow,
resetView, resetView,

View File

@@ -335,7 +335,7 @@ const handleBranchKeydown = (event: KeyboardEvent) => {
.el-input__inner { .el-input__inner {
font-size: 13px; font-size: 13px;
color: var(--color-text-primary); color: #000;
padding-right: 40px; padding-right: 40px;
} }
} }

View File

@@ -476,7 +476,7 @@ const handleBranchKeydown = (event: KeyboardEvent) => {
.el-input__inner { .el-input__inner {
font-size: 13px; font-size: 13px;
color: var(--color-text-primary); color: #000;
padding-right: 40px; padding-right: 40px;
} }
} }

View File

@@ -14,7 +14,7 @@ const isDisabled = computed(() => {
return !agentsStore.currentTask return !agentsStore.currentTask
}) })
// 获取agent组合卡片数量 - 当前任务agents(1) + 已确认的agent组合数量 // 获取agent组合卡片数量
const agentGroupCount = computed(() => { const agentGroupCount = computed(() => {
if (!agentsStore.currentTask?.Id) return 1 if (!agentsStore.currentTask?.Id) return 1

View File

@@ -8,16 +8,15 @@ const emit = defineEmits<{
(e: 'click'): void (e: 'click'): void
}>() }>()
// 获取分支数量 - 主分支(1) + 额外分支数量 // 获取分支数量
const branchCount = computed(() => { const branchCount = computed(() => {
// flowBranches 包含所有通过 Branch 创建的分支 // flowBranches 包含所有通过 Branch 创建的分支
const extraBranches = selectionStore.flowBranches?.length || 1 const extraBranches = selectionStore.flowBranches?.length || 1
// 始终至少有1个主分支
return extraBranches return extraBranches
}) })
const handleClick = () => { const handleClick = () => {
// console.log('点击分支按钮')
emit('click') emit('click')
// 触发打开分支窗口 // 触发打开分支窗口
agentsStore.openPlanModification() agentsStore.openPlanModification()

View File

@@ -201,10 +201,8 @@ function clear() {
jsplumb.reset() jsplumb.reset()
} }
// 🆕 封装连线重绘方法 // 封装连线重绘方法
const redrawConnections = () => { const redrawConnections = () => {
console.log('🔄 重新绘制 jsplumb 连线')
// 等待 DOM 更新完成 // 等待 DOM 更新完成
nextTick(() => { nextTick(() => {
// 清除旧连线 // 清除旧连线
@@ -221,22 +219,20 @@ const redrawConnections = () => {
}) })
jsplumb.connects(arr) jsplumb.connects(arr)
console.log('✅ jsplumb 连线重绘完成,任务数:', collaborationProcess.value.length)
}, 100) }, 100)
}) })
} }
// 🆕 监听 collaborationProcess 变化,自动重绘连线 // 监听 collaborationProcess 变化,自动重绘连线
watch( watch(
() => collaborationProcess, () => collaborationProcess,
() => { () => {
console.log('🔍 collaborationProcess 发生变化,触发重绘')
redrawConnections() redrawConnections()
}, },
{ deep: true } { deep: true }
) )
// 🆕 组件挂载后初始化连线 // 组件挂载后初始化连线
onMounted(() => { onMounted(() => {
// 初始化时绘制连线 // 初始化时绘制连线
nextTick(() => { nextTick(() => {
@@ -246,7 +242,6 @@ onMounted(() => {
arr.push(...handleCurrentTask(item, true)) arr.push(...handleCurrentTask(item, true))
}) })
jsplumb.connects(arr) jsplumb.connects(arr)
console.log('✅ 初始化 jsplumb 连线完成')
}, 100) }, 100)
}) })
}) })
@@ -440,7 +435,7 @@ defineExpose({
</div> </div>
</div> </div>
</div> </div>
<BranchButton v-dev-only v-if="planReady" @click="openPlanModification" /> <BranchButton v-if="planReady" @click="openPlanModification" />
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>