import { ref } from 'vue' import { defineStore } from 'pinia' import { v4 as uuidv4 } from 'uuid' import { store } from '../index' import type { IRawStepTask, IApiStepTask } from './agents' import type { Node, Edge } from '@vue-flow/core' import { useAgentsStoreHook } from './agents' /** * 分支数据接口 * @description 用于存储流程图中的分支节点和边数据 */ export interface IBranchData { /** 分支唯一 ID */ id: string /** 父节点 ID(根节点或任务节点) */ parentNodeId: string /** 分支需求内容 */ branchContent: string /** 分支类型 */ branchType: 'root' | 'task' /** 分支包含的所有节点 */ nodes: Node[] /** 分支包含的所有边 */ edges: Edge[] /** 分支的任务数据 */ tasks: IRawStepTask[] /** 创建时间 */ createdAt: number } export const useSelectionStore = defineStore('selection', () => { // ==================== 任务大纲探索分支数据存储 ==================== /** 流程图分支列表 */ const flowBranches = ref([]) /** * 添加流程图分支 * @param data 分支数据 * @returns 分支 ID */ function addFlowBranch(data: { parentNodeId: string branchContent: string branchType: 'root' | 'task' nodes: Node[] edges: Edge[] tasks: IRawStepTask[] }): string { const branchId = `flow-branch-${uuidv4()}` const newBranch: IBranchData = { id: branchId, parentNodeId: data.parentNodeId, branchContent: data.branchContent, branchType: data.branchType, nodes: data.nodes, edges: data.edges, tasks: data.tasks, createdAt: Date.now(), } flowBranches.value.push(newBranch) return branchId } /** * 获取所有流程图分支 * @returns 所有流程图分支数据 */ function getAllFlowBranches(): IBranchData[] { return flowBranches.value } /** * 根据父节点 ID 获取流程图分支 * @param parentNodeId 父节点 ID * @returns 匹配的流程图分支列表 */ function getFlowBranchesByParent(parentNodeId: string): IBranchData[] { return flowBranches.value.filter((branch) => branch.parentNodeId === parentNodeId) } /** * 删除流程图分支 * @param branchId 分支 ID * @returns 是否删除成功 */ function removeFlowBranch(branchId: string): boolean { const index = flowBranches.value.findIndex((branch) => branch.id === branchId) if (index > -1) { flowBranches.value.splice(index, 1) return true } return false } /** 清除所有流程图分支 */ function clearFlowBranches() { flowBranches.value = [] } /** * 根据父节点 ID 清除流程图分支 * @param parentNodeId 父节点 ID */ function clearFlowBranchesByParent(parentNodeId: string) { flowBranches.value = flowBranches.value.filter((branch) => branch.parentNodeId !== parentNodeId) } // ==================== 任务过程探索分支数据存储 ==================== /** * 任务过程分支数据映射 * @description 存储结构: Map> * - taskStepId: 任务步骤 ID * - agentGroupKey: agent 组合的唯一标识(排序后的 JSON 字符串) * - IBranchData[]: 该 agent 组合在该任务下的所有分支数据 */ const taskProcessBranchesMap = ref>>(new Map()) /** * 添加任务过程分支 * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @param data 分支数据 * @returns 分支 ID */ function addTaskProcessBranch( taskStepId: string, agents: string[], data: { parentNodeId: string branchContent: string branchType: 'root' | 'task' nodes: Node[] edges: Edge[] tasks: IRawStepTask[] id?: string // 允许传入自定义 id }, ): string { const branchId = data.id || `task-process-branch-${uuidv4()}` console.log('[store.addTaskProcessBranch] 生成的 branchId:', branchId, '传入的 id:', data.id) const agentGroupKey = getAgentGroupKey(agents) const newBranch: IBranchData = { id: branchId, parentNodeId: data.parentNodeId, branchContent: data.branchContent, branchType: data.branchType, nodes: data.nodes, edges: data.edges, tasks: data.tasks, createdAt: Date.now(), } // 获取或创建该任务步骤的 Map if (!taskProcessBranchesMap.value.has(taskStepId)) { taskProcessBranchesMap.value.set(taskStepId, new Map()) } // 获取或创建该 agent 组合的分支列表 const agentMap = taskProcessBranchesMap.value.get(taskStepId)! if (!agentMap.has(agentGroupKey)) { agentMap.set(agentGroupKey, []) } agentMap.get(agentGroupKey)!.push(newBranch) return branchId } /** * 获取指定任务步骤和 agent 组合的所有分支 * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @returns 匹配的任务过程分支列表 */ function getTaskProcessBranches(taskStepId: string, agents: string[]): IBranchData[] { const agentGroupKey = getAgentGroupKey(agents) return taskProcessBranchesMap.value.get(taskStepId)?.get(agentGroupKey) || [] } /** * 获取所有任务过程分支 * @returns 所有任务过程分支数据映射 */ function getAllTaskProcessBranches(): Map> { return taskProcessBranchesMap.value } /** * 根据父节点 ID 获取任务过程分支 * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @param parentNodeId 父节点 ID * @returns 匹配的任务过程分支列表 */ function getTaskProcessBranchesByParent( taskStepId: string, agents: string[], parentNodeId: string, ): IBranchData[] { const agentGroupKey = getAgentGroupKey(agents) const branches = taskProcessBranchesMap.value.get(taskStepId)?.get(agentGroupKey) || [] return branches.filter((branch) => branch.parentNodeId === parentNodeId) } /** * 删除任务过程分支 * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @param branchId 分支 ID * @returns 是否删除成功 */ function removeTaskProcessBranch( taskStepId: string, agents: string[], branchId: string, ): boolean { const agentGroupKey = getAgentGroupKey(agents) const branches = taskProcessBranchesMap.value.get(taskStepId)?.get(agentGroupKey) if (branches) { const index = branches.findIndex((branch) => branch.id === branchId) if (index > -1) { branches.splice(index, 1) return true } } return false } /** * 精准删除分支中的单个节点 * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @param branchId 分支 ID * @param nodeId 要删除的节点 ID * @param incomingEdges 入边(用于更新 edges) * @param outgoingEdges 出边(用于更新 edges) * @param newEdges 新创建的边(用于重新连接) * @returns 是否删除成功 */ function removeNodeFromBranch( taskStepId: string, agents: string[], branchId: string, nodeId: string, incomingEdges: any[] = [], outgoingEdges: any[] = [], newEdges: any[] = [], ): boolean { const agentGroupKey = getAgentGroupKey(agents) const branches = taskProcessBranchesMap.value.get(taskStepId)?.get(agentGroupKey) if (!branches) return false const branchIndex = branches.findIndex((branch) => branch.id === branchId) if (branchIndex === -1) return false const branch = branches[branchIndex] if (!branch || !branch.nodes || !branch.tasks) return false // 找到节点在分支中的索引 const nodeIndex = branch.nodes.findIndex((n: any) => n.id === nodeId) if (nodeIndex === -1) return false // 精准删除:只删除对应索引的节点和任务 branch.nodes.splice(nodeIndex, 1) branch.tasks.splice(nodeIndex, 1) // 更新 edges:移除相关边,添加新边 if (incomingEdges.length > 0 || outgoingEdges.length > 0) { const relatedEdgeIds = [ ...incomingEdges.map((e: any) => e.id), ...outgoingEdges.map((e: any) => e.id), ] // 过滤掉相关的旧边 branch.edges = (branch.edges || []).filter((e: any) => !relatedEdgeIds.includes(e.id)) // 添加新边 if (newEdges.length > 0) { branch.edges.push(...newEdges) } } return true } /** * 清除指定任务步骤和 agent 组合的所有分支 * @param taskStepId 任务步骤 ID * @param agents Agent 列表(可选,不传则清除该任务步骤的所有分支) */ function clearTaskProcessBranches(taskStepId: string, agents?: string[]) { if (agents) { // 清除指定 agent 组合的分支 const agentGroupKey = getAgentGroupKey(agents) const agentMap = taskProcessBranchesMap.value.get(taskStepId) if (agentMap) { agentMap.delete(agentGroupKey) } } else { // 清除该任务步骤的所有分支(所有 agent 组合) taskProcessBranchesMap.value.delete(taskStepId) } } // ==================== 数据库持久化方法 ==================== /** * 从数据库恢复分支数据 * @param dbBranches 从数据库读取的分支数据数组 */ function restoreBranchesFromDB(dbBranches: IBranchData[]) { // 清除现有分支 clearFlowBranches() // 恢复分支数据到 store dbBranches.forEach((branch) => { if (branch && branch.id && branch.tasks) { addFlowBranch({ parentNodeId: branch.parentNodeId, branchContent: branch.branchContent, branchType: branch.branchType, nodes: branch.nodes || [], edges: branch.edges || [], tasks: branch.tasks, }) } }) } /** * 保存分支数据到数据库 * @param taskId 任务ID * @returns Promise 是否保存成功 */ async function saveBranchesToDB(taskId: string): Promise { // 导入 api(避免循环导入问题) const { default: api } = await import('@/api') const branches = getAllFlowBranches() const result = await api.saveBranches(taskId, branches) return result } /** * 保存任务过程分支数据到数据库 * @param TaskID 大任务ID(数据库主键) * @returns Promise 是否保存成功 * @description 存储结构: Map> */ async function saveTaskProcessBranchesToDB(TaskID: string): Promise { // 导入 api(避免循环导入问题) const { default: api } = await import('@/api') // 将 Map 转换为普通对象,便于序列化 const branchesMap = getAllTaskProcessBranches() const branchesObj: Record> = {} for (const [taskStepId, agentMap] of branchesMap.entries()) { branchesObj[taskStepId] = {} for (const [agentGroupKey, branches] of agentMap.entries()) { branchesObj[taskStepId][agentGroupKey] = branches } } const result = await api.saveTaskProcessBranches(TaskID, branchesObj) return result } /** * 从数据库删除指定分支 * @param TaskID 大任务ID(数据库主键) * @param stepId 小任务ID * @param branchId 要删除的分支ID * @returns Promise 是否删除成功 */ async function deleteTaskProcessBranchFromDB( TaskID: string, stepId: string, branchId: string, ): Promise { // 导入 api(避免循环导入问题) const { default: api } = await import('@/api') const result = await api.deleteTaskProcessBranch(TaskID, stepId, branchId) return result } /** * 从数据库删除指定节点 * @param TaskID 大任务ID(数据库主键) * @param stepId 小任务ID * @param branchId 分支ID * @param nodeId 要删除的节点ID * @returns Promise 是否删除成功 */ async function deleteTaskProcessNodeFromDB( TaskID: string, stepId: string, branchId: string, nodeId: string, edges: any[] = [], ): Promise { // 导入 api(避免循环导入问题) const { default: api } = await import('@/api') const result = await api.deleteTaskProcessNode(TaskID, stepId, branchId, nodeId, edges) return result } /** * 从数据库恢复任务过程分支数据 * @param dbBranches 从数据库读取的任务过程分支数据 * @param TaskID 大任务ID(用于获取全局 __CURRENT_TASK_ID__) * @description 数据格式: { stepId(小任务UUID): { agentGroupKey: [IBranchData...] } } */ function restoreTaskProcessBranchesFromDB(dbBranches: Record>) { // 清除现有数据 taskProcessBranchesMap.value.clear() if (!dbBranches) { return } // 恢复数据 for (const [taskStepId, agentMap] of Object.entries(dbBranches)) { if (typeof agentMap !== 'object' || agentMap === null) { continue } // 获取或创建该步骤的 Map if (!taskProcessBranchesMap.value.has(taskStepId)) { taskProcessBranchesMap.value.set(taskStepId, new Map()) } const stepMap = taskProcessBranchesMap.value.get(taskStepId)! // 恢复 agent combinations for (const [agentGroupKey, branches] of Object.entries(agentMap)) { if (Array.isArray(branches)) { stepMap.set(agentGroupKey, branches) } } } } // ==================== Agent 组合 TaskProcess 数据存储 ==================== /** * Agent 组合 TaskProcess 数据映射 * @description 用于存储 fill_stepTask_TaskProcess 接口返回的数据 * 存储结构: Map> * - taskId: 任务 ID * - agentGroupKey: agent 组合的唯一标识(排序后的 JSON 字符串) * - IApiStepTask: 该 agent 组合的完整 TaskProcess 数据 */ const agentTaskProcessMap = ref>>(new Map()) /** * 生成 agent 组合的唯一 key * @description 排序后保证一致性 * @param agents Agent 列表 * @returns Agent 组合的唯一标识 */ function getAgentGroupKey(agents: string[]): string { // 处理 undefined 或 null 的情况 if (!agents || !Array.isArray(agents)) { return JSON.stringify([]) } return JSON.stringify([...agents].sort()) } /** * 存储 agent 组合的 TaskProcess 数据 * @param stepId 步骤 ID(小任务 UUID,用于作为 agentTaskProcessMap 的第一层主键) * @param agents Agent 列表 * @param taskProcess TaskProcess 数据(支持完整格式或简化格式) * @description 存储结构: Map> * agentTaskProcessMap = { stepId: { agentGroupKey: { process, brief } } } * 注意:简化格式 { process, brief } 与后端数据库格式一致 */ function setAgentTaskProcess( stepId: string, agents: string[], taskProcess: IApiStepTask | { process: any; brief: any }, ) { const groupKey = getAgentGroupKey(agents) // 获取或创建该步骤的 Map if (!agentTaskProcessMap.value.has(stepId)) { agentTaskProcessMap.value.set(stepId, new Map()) } const stepMap = agentTaskProcessMap.value.get(stepId)! // 统一转换为简化格式 { process, brief },与后端期望格式一致 const simplifiedData = { process: (taskProcess as IApiStepTask).process || taskProcess.process || [], brief: (taskProcess as IApiStepTask).brief || taskProcess.brief || {}, } // 存储该 agent 组合的 TaskProcess 数据 stepMap.set(groupKey, simplifiedData) } /** * 获取 agent 组合的 TaskProcess 数据 * @param taskId 任务 ID * @param agents Agent 列表 * @returns TaskProcess 数据 */ function getAgentTaskProcess(taskId: string, agents: string[]): IApiStepTask | undefined { const groupKey = getAgentGroupKey(agents) return agentTaskProcessMap.value.get(taskId)?.get(groupKey) } /** * 检查 agent 组合是否已有 TaskProcess 数据 * @param taskId 任务 ID * @param agents Agent 列表 * @returns 是否存在数据 */ function hasAgentTaskProcess(taskId: string, agents: string[]): boolean { const groupKey = getAgentGroupKey(agents) return agentTaskProcessMap.value.get(taskId)?.has(groupKey) || false } /** * 删除指定任务的某个 agent 组合的 TaskProcess 数据 * @param taskId 任务 ID * @param agents Agent 列表 */ function removeAgentTaskProcess(taskId: string, agents: string[]) { const groupKey = getAgentGroupKey(agents) agentTaskProcessMap.value.get(taskId)?.delete(groupKey) } /** * 清除指定任务的所有 agent 组合 TaskProcess 数据 * @param taskId 任务 ID */ function clearAgentTaskProcess(taskId: string) { agentTaskProcessMap.value.delete(taskId) } /** 清除所有任务的 agent 组合 TaskProcess 数据 */ function clearAllAgentTaskProcess() { agentTaskProcessMap.value.clear() } /** * 获取指定步骤的所有 agent 组合的 TaskProcess 数据 * @param stepId 步骤 ID(小任务 UUID) * @returns agent_combinations 对象格式 { "[\"AgentA\",\"AgentB\"]": { process, brief }, ... } * @description 存储结构: Map> * 注意:简化设计后,第一层 key 就是 stepId */ function getAgentCombinations( stepId: string, ): Record | undefined { // 直接使用 stepId 作为第一层 key const stepMap = agentTaskProcessMap.value.get(stepId) if (!stepMap) { return undefined } // 将 Map 转换为普通对象 const result: Record = {} for (const [key, value] of stepMap.entries()) { result[key] = value } return result } // ==================== 数据库持久化恢复方法 ==================== /** * 从数据库 assigned_agents 字段恢复 agent 组合数据 * @param assignedAgents 从数据库读取的 assigned_agents 数据 * @param taskId 大任务 ID(此参数已不再使用,因为简化后直接用 stepId 作为 key) * @description 数据格式: { step_id(小任务UUID): { current: [...], confirmed_groups: [...], agent_combinations: {...} } } * 存储结构: Map> * agentTaskProcessMap = { stepId: { agentGroupKey: data } } */ function restoreAgentCombinationsFromDB(assignedAgents: Record, taskId: string) { // 获取 agents store 实例 const agentsStore = useAgentsStoreHook() // 清除现有数据 clearAllAgentTaskProcess() agentsStore.clearAllConfirmedAgentGroups() if (!assignedAgents) { return } // 🆕 简化版本:直接使用 stepId 作为第一层 key // 遍历每个步骤的数据 for (const [stepId, stepData] of Object.entries(assignedAgents)) { if (typeof stepData !== 'object' || stepData === null) { continue } // 获取或创建该步骤的 Map if (!agentTaskProcessMap.value.has(stepId)) { agentTaskProcessMap.value.set(stepId, new Map()) } const stepMap = agentTaskProcessMap.value.get(stepId)! // 恢复 agent_combinations 到 stepMap // 格式: { agentGroupKey: { process, brief } } if (stepData.agent_combinations) { for (const [agentGroupKey, combinationData] of Object.entries( stepData.agent_combinations, )) { stepMap.set(agentGroupKey, combinationData as IApiStepTask) } } // 恢复 confirmed_groups if (stepData.confirmed_groups) { agentsStore.setConfirmedAgentGroups(stepId, stepData.confirmed_groups) } // 恢复 current(当前选中的 agent 组合) if (stepData.current) { agentsStore.setSelectedAgentGroup(stepId, stepData.current) // 同步更新 agentRawPlan 中对应步骤的 AgentSelection const planData = agentsStore.agentRawPlan.data if (planData && planData['Collaboration Process']) { const process = planData['Collaboration Process'] const step = process.find((s: any) => s.Id === stepId) if (step) { step.AgentSelection = stepData.current } } } } } // ==================== 当前生效的任务过程分支 ==================== /** * 当前生效的任务过程分支映射 * @description 记录每个任务步骤和 agent 组合当前生效的分支 ID(持久化选中状态) * 存储结构: Map> * - taskStepId: 任务步骤 ID * - agentGroupKey: agent 组合的唯一标识 * - branchId: 当前选中的分支 ID */ const activeTaskProcessBranchMap = ref>>(new Map()) /** * 当前生效的 TaskProcess 数据映射 * @description 用于外部组件显示职责分配 * 存储结构: Map> */ const activeTaskProcessDataMap = ref>>(new Map()) /** * 设置当前生效的分支 * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @param branchId 分支 ID */ function setActiveTaskProcessBranch(taskStepId: string, agents: string[], branchId: string) { const agentGroupKey = getAgentGroupKey(agents) // 获取或创建该任务步骤的 Map if (!activeTaskProcessBranchMap.value.has(taskStepId)) { activeTaskProcessBranchMap.value.set(taskStepId, new Map()) } activeTaskProcessBranchMap.value.get(taskStepId)!.set(agentGroupKey, branchId) } /** * 设置当前生效的 TaskProcess 数据 * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @param taskProcess TaskProcess 数据 */ function setActiveTaskProcessData(taskStepId: string, agents: string[], taskProcess: any[]) { const agentGroupKey = getAgentGroupKey(agents) // 获取或创建该任务步骤的 Map if (!activeTaskProcessDataMap.value.has(taskStepId)) { activeTaskProcessDataMap.value.set(taskStepId, new Map()) } activeTaskProcessDataMap.value.get(taskStepId)!.set(agentGroupKey, taskProcess) } /** * 获取当前生效的分支 ID * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @returns 分支 ID */ function getActiveTaskProcessBranch(taskStepId: string, agents: string[]): string | undefined { const agentGroupKey = getAgentGroupKey(agents) return activeTaskProcessBranchMap.value.get(taskStepId)?.get(agentGroupKey) } /** * 获取当前生效的 TaskProcess 数据 * @param taskStepId 任务步骤 ID * @param agents Agent 列表 * @returns TaskProcess 数据 */ function getActiveTaskProcessData(taskStepId: string, agents: string[]): any[] | undefined { const agentGroupKey = getAgentGroupKey(agents) return activeTaskProcessDataMap.value.get(taskStepId)?.get(agentGroupKey) } /** * 清除生效分支 * @param taskStepId 任务步骤 ID * @param agents Agent 列表(可选,不传则清除该任务步骤的所有生效分支) */ function clearActiveTaskProcessBranch(taskStepId: string, agents?: string[]) { if (agents) { // 清除指定 agent 组合的生效分支 const agentGroupKey = getAgentGroupKey(agents) activeTaskProcessBranchMap.value.get(taskStepId)?.delete(agentGroupKey) activeTaskProcessDataMap.value.get(taskStepId)?.delete(agentGroupKey) } else { // 清除该任务步骤的所有生效分支(所有 agent 组合) activeTaskProcessBranchMap.value.delete(taskStepId) activeTaskProcessDataMap.value.delete(taskStepId) } } return { // ==================== 状态 ==================== flowBranches, taskProcessBranchesMap, agentTaskProcessMap, activeTaskProcessBranchMap, activeTaskProcessDataMap, // ==================== 任务大纲分支管理方法 ==================== addFlowBranch, getAllFlowBranches, getFlowBranchesByParent, removeFlowBranch, clearFlowBranches, clearFlowBranchesByParent, // ==================== 任务过程分支管理方法 ==================== addTaskProcessBranch, getTaskProcessBranches, getAllTaskProcessBranches, getTaskProcessBranchesByParent, removeTaskProcessBranch, removeNodeFromBranch, clearTaskProcessBranches, // ==================== 任务过程分支生效状态管理方法 ==================== setActiveTaskProcessBranch, setActiveTaskProcessData, getActiveTaskProcessBranch, getActiveTaskProcessData, clearActiveTaskProcessBranch, // ==================== Agent 组合 TaskProcess 数据管理方法 ==================== getAgentGroupKey, setAgentTaskProcess, getAgentTaskProcess, hasAgentTaskProcess, removeAgentTaskProcess, clearAgentTaskProcess, getAgentCombinations, clearAllAgentTaskProcess, // ==================== 数据库持久化方法 ==================== restoreBranchesFromDB, saveBranchesToDB, restoreAgentCombinationsFromDB, saveTaskProcessBranchesToDB, deleteTaskProcessBranchFromDB, deleteTaskProcessNodeFromDB, restoreTaskProcessBranchesFromDB, } }) /** * 用于在组件外部使用 Selection Store * @returns Selection Store 实例 */ export function useSelectionStoreHook() { return useSelectionStore(store) }