feat:1.数据库存储功能添加(初版)2.后端REST API版本代码清理
This commit is contained in:
@@ -36,6 +36,7 @@ const handleFileSelect = (event: Event) => {
|
||||
if (input.files && input.files[0]) {
|
||||
const file = input.files[0]
|
||||
readFileContent(file)
|
||||
input.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
<template>
|
||||
<div class="history-list">
|
||||
<div class="header">
|
||||
<h3>📋 历史任务</h3>
|
||||
<el-button type="primary" link @click="fetchPlans">
|
||||
<el-icon><Refresh /></el-icon>
|
||||
刷新
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="loading" class="loading">
|
||||
<el-icon class="is-loading"><Loading /></el-icon>
|
||||
<span>加载中...</span>
|
||||
</div>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<el-empty v-else-if="plans.length === 0" description="暂无历史任务" />
|
||||
|
||||
<!-- 任务列表 -->
|
||||
<div v-else class="plan-list">
|
||||
<div
|
||||
v-for="plan in plans"
|
||||
:key="plan.id"
|
||||
class="plan-item"
|
||||
:class="{ active: selectedPlanId === plan.id }"
|
||||
@click="selectPlan(plan)"
|
||||
>
|
||||
<div class="plan-info">
|
||||
<div class="plan-goal">{{ plan.general_goal || '未知任务' }}</div>
|
||||
<div class="plan-meta">
|
||||
<el-tag size="small" :type="getStatusType(plan.status)">
|
||||
{{ getStatusText(plan.status) }}
|
||||
</el-tag>
|
||||
<span class="plan-time">{{ formatTime(plan.created_at) }}</span>
|
||||
</div>
|
||||
<div class="plan-stats">
|
||||
<span>执行次数: {{ plan.execution_count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="plan-actions">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click.stop="restorePlan(plan)"
|
||||
:disabled="restoring"
|
||||
>
|
||||
恢复
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
size="small"
|
||||
link
|
||||
@click.stop="deletePlan(plan)"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div v-if="plans.length > 0" class="pagination">
|
||||
<span>共 {{ total }} 个任务</span>
|
||||
</div>
|
||||
|
||||
<!-- 删除确认对话框 -->
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="删除确认"
|
||||
width="400px"
|
||||
:close-on-click-modal="false"
|
||||
>
|
||||
<span>确定要删除任务 "{{ planToDelete?.general_goal }}" 吗?此操作不可恢复。</span>
|
||||
<template #footer>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="danger" @click="confirmDelete" :loading="deleting">确定删除</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { Refresh, Loading, Delete } from '@element-plus/icons-vue'
|
||||
import websocket from '@/utils/websocket'
|
||||
|
||||
// 事件定义
|
||||
const emit = defineEmits<{
|
||||
(e: 'restore', plan: PlanInfo): void
|
||||
(e: 'close'): void
|
||||
}>()
|
||||
|
||||
// 数据类型
|
||||
interface PlanInfo {
|
||||
id: string // 对应数据库 task_id
|
||||
general_goal: string // 对应数据库 query
|
||||
status: string
|
||||
execution_count: number
|
||||
created_at: string
|
||||
// 完整恢复数据
|
||||
task_outline?: any
|
||||
assigned_agents?: any
|
||||
agent_scores?: any
|
||||
agents_info?: any[]
|
||||
}
|
||||
|
||||
// 响应式数据
|
||||
const plans = ref<PlanInfo[]>([])
|
||||
const loading = ref(false)
|
||||
const restoring = ref(false)
|
||||
const selectedPlanId = ref<string | null>(null)
|
||||
const total = ref(0)
|
||||
const isConnected = ref(false)
|
||||
|
||||
// 删除对话框相关
|
||||
const dialogVisible = ref(false)
|
||||
const planToDelete = ref<PlanInfo | null>(null)
|
||||
const deleting = ref(false)
|
||||
|
||||
// 生成唯一请求ID
|
||||
let requestIdCounter = 0
|
||||
const generateRequestId = () => `ws_req_${Date.now()}_${++requestIdCounter}`
|
||||
|
||||
// WebSocket 监听器引用(用于清理)
|
||||
const historyUpdatedHandler = () => {
|
||||
console.log('📡 收到历史列表更新通知,自动刷新')
|
||||
fetchPlans()
|
||||
}
|
||||
|
||||
// 获取任务列表
|
||||
const fetchPlans = async () => {
|
||||
loading.value = true
|
||||
const reqId = generateRequestId()
|
||||
|
||||
try {
|
||||
const result = await websocket.send('get_plans', { id: reqId })
|
||||
plans.value = (result.data || []) as PlanInfo[]
|
||||
total.value = plans.value.length
|
||||
isConnected.value = true
|
||||
} catch (error) {
|
||||
console.error('获取任务列表失败:', error)
|
||||
ElMessage.error('获取任务列表失败')
|
||||
isConnected.value = false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 选择任务
|
||||
const selectPlan = (plan: PlanInfo) => {
|
||||
selectedPlanId.value = plan.id
|
||||
}
|
||||
|
||||
// 恢复任务
|
||||
const restorePlan = async (plan: PlanInfo) => {
|
||||
if (restoring.value) return
|
||||
|
||||
console.log('🔍 [HistoryList] 恢复计划:', plan)
|
||||
console.log('🔍 [HistoryList] plan.id:', plan.id)
|
||||
|
||||
if (!plan.id) {
|
||||
ElMessage.error('任务 ID 为空,无法恢复')
|
||||
return
|
||||
}
|
||||
|
||||
restoring.value = true
|
||||
selectedPlanId.value = plan.id
|
||||
|
||||
const reqId = generateRequestId()
|
||||
|
||||
try {
|
||||
const result = await websocket.send('restore_plan', {
|
||||
id: reqId,
|
||||
data: { plan_id: plan.id }
|
||||
})
|
||||
const planData = (result.data || result) as any
|
||||
|
||||
// 发送恢复事件
|
||||
emit('restore', {
|
||||
...plan,
|
||||
...planData
|
||||
})
|
||||
|
||||
ElMessage.success('任务已恢复')
|
||||
} catch (error) {
|
||||
console.error('恢复任务失败:', error)
|
||||
ElMessage.error('恢复任务失败')
|
||||
} finally {
|
||||
restoring.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 删除任务
|
||||
const deletePlan = (plan: PlanInfo) => {
|
||||
planToDelete.value = plan
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
// 确认删除
|
||||
const confirmDelete = async () => {
|
||||
if (!planToDelete.value) return
|
||||
|
||||
deleting.value = true
|
||||
const reqId = generateRequestId()
|
||||
|
||||
try {
|
||||
await websocket.send('delete_plan', {
|
||||
id: reqId,
|
||||
data: { plan_id: planToDelete.value.id }
|
||||
})
|
||||
|
||||
dialogVisible.value = false
|
||||
ElMessage.success('删除成功')
|
||||
// 删除成功后会自动通过 history_updated 事件刷新列表
|
||||
} catch (error) {
|
||||
console.error('删除任务失败:', error)
|
||||
ElMessage.error('删除任务失败')
|
||||
} finally {
|
||||
deleting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (timeStr: string | undefined) => {
|
||||
if (!timeStr) return ''
|
||||
try {
|
||||
const date = new Date(timeStr)
|
||||
return date.toLocaleString('zh-CN', {
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
} catch {
|
||||
return timeStr
|
||||
}
|
||||
}
|
||||
|
||||
// 获取状态类型
|
||||
const getStatusType = (status: string): string => {
|
||||
const statusMap: Record<string, string> = {
|
||||
'generating': 'warning',
|
||||
'executing': 'warning',
|
||||
'completed': 'success',
|
||||
'stopped': 'danger'
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: string): string => {
|
||||
const statusMap: Record<string, string> = {
|
||||
'generating': '生成中',
|
||||
'executing': '执行中',
|
||||
'completed': '已完成',
|
||||
'stopped': '已停止'
|
||||
}
|
||||
return statusMap[status] || status
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
fetchPlans()
|
||||
// 监听历史列表更新事件(多标签页实时同步)
|
||||
websocket.on('history_updated', historyUpdatedHandler)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// 移除事件监听
|
||||
websocket.off('history_updated', historyUpdatedHandler)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.history-list {
|
||||
padding: 16px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40px;
|
||||
color: #909399;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.plan-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.plan-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
margin-bottom: 8px;
|
||||
border-radius: 8px;
|
||||
background: #f5f7fa;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: #ecf5ff;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #ecf5ff;
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.plan-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.plan-goal {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 6px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.plan-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.plan-time {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.plan-stats {
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.plan-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 16px;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
useAgentsStore,
|
||||
useSelectionStore,
|
||||
type IRawStepTask,
|
||||
type TaskProcess,
|
||||
type IApiAgentAction
|
||||
} from '@/stores'
|
||||
import { getAgentMapIcon, getActionTypeDisplay } from '@/layout/components/config.ts'
|
||||
@@ -32,9 +33,6 @@ const branchInputRef = ref<InstanceType<typeof HTMLInputElement>>()
|
||||
// 分支加载状态
|
||||
const branchLoading = ref(false)
|
||||
|
||||
// Mock 数据配置
|
||||
const USE_MOCK_DATA = false
|
||||
|
||||
// 节点和边数据
|
||||
const nodes = ref<Node[]>([])
|
||||
const edges = ref<Edge[]>([])
|
||||
@@ -51,6 +49,191 @@ const BRANCHES_INIT_KEY_PREFIX = 'plan-task-branches-initialized-'
|
||||
//最后选中的分支ID
|
||||
const LAST_SELECTED_BRANCH_KEY = 'plan-task-last-selected-branch'
|
||||
|
||||
// ==================== 公共函数提取 ====================
|
||||
|
||||
// 获取 agent 个人简介
|
||||
const getAgentProfile = (agentName: string): string => {
|
||||
return (
|
||||
agentsStore.agents.find((agent: any) => agent.Name === agentName)?.Profile || '暂无个人简介'
|
||||
)
|
||||
}
|
||||
|
||||
// 创建 VueFlow 边的通用函数
|
||||
const createFlowEdge = (
|
||||
source: string,
|
||||
target: string,
|
||||
sourceHandle: string = 'right',
|
||||
targetHandle: string = 'left',
|
||||
strokeColor: string = '#43a8aa',
|
||||
isFirstNode: boolean = false
|
||||
): Edge => {
|
||||
return {
|
||||
id: `edge-${source}-${target}`,
|
||||
source,
|
||||
target,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
type: 'smoothstep',
|
||||
animated: true,
|
||||
style: {
|
||||
stroke: strokeColor,
|
||||
strokeWidth: 2,
|
||||
...(isFirstNode ? { strokeDasharray: '5,5' } : {})
|
||||
},
|
||||
markerEnd: {
|
||||
type: 'arrow' as any,
|
||||
color: '#43a8aa',
|
||||
width: 20,
|
||||
height: 20,
|
||||
strokeWidth: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建分支 agent 节点的通用函数
|
||||
const createBranchAgentNode = (
|
||||
agentNodeId: string,
|
||||
action: IApiAgentAction,
|
||||
position: { x: number; y: number }
|
||||
): Node => {
|
||||
const agentInfo = getAgentMapIcon(action.agent)
|
||||
const actionTypeInfo = getActionTypeDisplay(action.type)
|
||||
const agentProfile = getAgentProfile(action.agent)
|
||||
|
||||
return {
|
||||
id: agentNodeId,
|
||||
type: 'agent',
|
||||
position,
|
||||
data: {
|
||||
agentName: action.agent,
|
||||
agentIcon: agentInfo.icon,
|
||||
agentColor: agentInfo.color,
|
||||
actionTypeColor: actionTypeInfo?.color || '#909399',
|
||||
agentDescription: action.description || '暂无描述',
|
||||
agentProfile: agentProfile,
|
||||
actionTypeName: actionTypeInfo?.name || '未知职责',
|
||||
actionTypeKey: actionTypeInfo?.key || 'unknown',
|
||||
isRoot: false,
|
||||
isBranchTask: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 保存分支到 store 的通用函数
|
||||
const saveBranchToStore = (
|
||||
branchType: 'root' | 'task',
|
||||
newBranchNodes: Node[],
|
||||
newBranchEdges: Edge[],
|
||||
branchTasks: any[]
|
||||
) => {
|
||||
if (newBranchNodes.length === 0) return
|
||||
|
||||
const taskStepId = currentTask.value?.Id || ''
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
|
||||
isSyncing = true
|
||||
selectionStore.addTaskProcessBranch(taskStepId, currentAgents, {
|
||||
parentNodeId: addingBranchNodeId.value!,
|
||||
branchContent: branchInput.value.trim(),
|
||||
branchType,
|
||||
nodes: JSON.parse(JSON.stringify(newBranchNodes)),
|
||||
edges: JSON.parse(JSON.stringify(newBranchEdges)),
|
||||
tasks: JSON.parse(JSON.stringify(branchTasks))
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
isSyncing = false
|
||||
}, 100)
|
||||
|
||||
saveTaskProcessBranchesToDB()
|
||||
}
|
||||
|
||||
// 解析分支 API 响应的通用函数
|
||||
const parseBranchResponse = (response: any): IApiAgentAction[] => {
|
||||
const newAgentActions: IApiAgentAction[] = []
|
||||
const responseData = response.data || response
|
||||
|
||||
if (responseData && responseData.length > 0) {
|
||||
const firstBranch = responseData[0]
|
||||
firstBranch.forEach((action: any) => {
|
||||
newAgentActions.push({
|
||||
id: action.ID || uuidv4(),
|
||||
type: action.ActionType,
|
||||
agent: action.AgentName,
|
||||
description: action.Description,
|
||||
inputs: action.ImportantInput || []
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return newAgentActions
|
||||
}
|
||||
|
||||
// 获取主流程节点 ID 列表的通用函数
|
||||
const getMainProcessNodeIds = (nodeList?: Node[]): string[] => {
|
||||
const targetNodes = nodeList || nodes.value
|
||||
return targetNodes.filter(n => !n.data.isBranchTask && n.id !== 'root').map(n => n.id)
|
||||
}
|
||||
|
||||
// 设置主流程高亮的通用函数
|
||||
const highlightMainProcess = (nodeList?: Node[]) => {
|
||||
const mainProcessNodes = getMainProcessNodeIds(nodeList)
|
||||
selectedNodeIds.value = new Set(mainProcessNodes)
|
||||
}
|
||||
|
||||
// 创建分支节点和边的通用函数
|
||||
const createBranchNodesAndEdges = (
|
||||
newAgentActions: IApiAgentAction[],
|
||||
branchStartX: number,
|
||||
branchStartY: number,
|
||||
parentNodeId: string,
|
||||
strokeColor: string = '#67c23a'
|
||||
): { nodes: Node[]; edges: Edge[] } => {
|
||||
const newBranchNodes: Node[] = []
|
||||
const newBranchEdges: Edge[] = []
|
||||
const timestamp = Date.now()
|
||||
const agentNodeIds: string[] = []
|
||||
|
||||
newAgentActions.forEach((action, index) => {
|
||||
const agentNodeId = `branch-agent-${parentNodeId}-${timestamp}-${index}`
|
||||
agentNodeIds.push(agentNodeId)
|
||||
|
||||
// 计算位置:横向排列
|
||||
const nodeX = branchStartX + (parentNodeId === 'root' ? 100 : 0) + index * 120
|
||||
const nodeY = branchStartY
|
||||
|
||||
// 创建 agent 节点
|
||||
const newAgentNode = createBranchAgentNode(agentNodeId, action, { x: nodeX, y: nodeY })
|
||||
nodes.value.push(newAgentNode)
|
||||
newBranchNodes.push(newAgentNode)
|
||||
|
||||
// 创建连接边
|
||||
if (index === 0) {
|
||||
// 第一个 agent 连接到父节点
|
||||
const newEdge = createFlowEdge(parentNodeId, agentNodeId, 'bottom', 'left', strokeColor, true)
|
||||
edges.value.push(newEdge)
|
||||
newBranchEdges.push(newEdge)
|
||||
} else {
|
||||
// 后续 agent 连接到前一个 agent
|
||||
const prevAgentNodeId = agentNodeIds[index - 1]!
|
||||
const newEdge = createFlowEdge(
|
||||
prevAgentNodeId,
|
||||
agentNodeId,
|
||||
'right',
|
||||
'left',
|
||||
strokeColor,
|
||||
false
|
||||
)
|
||||
edges.value.push(newEdge)
|
||||
newBranchEdges.push(newEdge)
|
||||
}
|
||||
})
|
||||
|
||||
return { nodes: newBranchNodes, edges: newBranchEdges }
|
||||
}
|
||||
|
||||
// ==================== 原有函数保持不变 ====================
|
||||
|
||||
// 获取分支的所有节点
|
||||
const getAllBranchNodes = (startNodeId: string): string[] => {
|
||||
const visited = new Set<string>()
|
||||
@@ -272,14 +455,44 @@ const initializeFlow = () => {
|
||||
)}`
|
||||
const branchesInitialized = sessionStorage.getItem(branchesInitKey) === 'true'
|
||||
|
||||
if (branchesInitialized && savedBranches.length > 0) {
|
||||
nodes.value = []
|
||||
edges.value = []
|
||||
// 【修复】优先检查 store 中是否有数据,而不是依赖 sessionStorage 标记
|
||||
// 原逻辑:if (branchesInitialized && savedBranches.length > 0)
|
||||
// 问题:从历史记录恢复时,store 有数据但 sessionStorage 无标记,导致重复创建"初始流程"分支
|
||||
if (savedBranches.length > 0) {
|
||||
// 先创建根节点和主流程节点(作为分支的基础)
|
||||
nodes.value = newNodes
|
||||
edges.value = newEdges
|
||||
|
||||
savedBranches.forEach(branch => {
|
||||
// 恢复节点
|
||||
branch.nodes.forEach(node => {
|
||||
nodes.value.push(JSON.parse(JSON.stringify(node)))
|
||||
// 找出非初始流程的分支(只处理真正需要偏移的分支)
|
||||
const actualBranches = savedBranches.filter(branch => branch.branchContent !== '初始流程')
|
||||
|
||||
// 统计每个父节点下有多少个分支,用于计算垂直偏移
|
||||
const parentBranchIndex: Record<string, number> = {}
|
||||
actualBranches.forEach(branch => {
|
||||
parentBranchIndex[branch.parentNodeId] = parentBranchIndex[branch.parentNodeId] || 0
|
||||
})
|
||||
|
||||
// 恢复分支时,按顺序处理,同一父节点的分支依次向下偏移
|
||||
actualBranches.forEach(branch => {
|
||||
const parentNodeId = branch.parentNodeId
|
||||
|
||||
// 获取父节点的Y坐标
|
||||
const parentNode = nodes.value.find(n => n.id === parentNodeId)
|
||||
const parentNodeY = parentNode?.position.y || 150
|
||||
|
||||
// 获取该分支在同一父节点下的索引
|
||||
const branchIndex = parentBranchIndex[parentNodeId] ?? 0
|
||||
parentBranchIndex[parentNodeId] = branchIndex + 1
|
||||
|
||||
// 计算分支起始Y坐标:父节点Y + 200 + 分支索引 * 250
|
||||
const branchStartY = parentNodeY + 200 + branchIndex * 250
|
||||
|
||||
// 恢复节点(计算新的Y坐标)
|
||||
branch.nodes.forEach((node, nodeIndex) => {
|
||||
const restoredNode = JSON.parse(JSON.stringify(node))
|
||||
// 计算新位置:分支起始Y + 节点索引 * 120(横向排列)
|
||||
restoredNode.position.y = branchStartY
|
||||
nodes.value.push(restoredNode)
|
||||
})
|
||||
// 恢复边
|
||||
branch.edges.forEach(edge => {
|
||||
@@ -287,6 +500,11 @@ const initializeFlow = () => {
|
||||
})
|
||||
})
|
||||
|
||||
// 【修复】补充标记已初始化,避免后续重复创建"初始流程"分支
|
||||
if (!branchesInitialized) {
|
||||
sessionStorage.setItem(branchesInitKey, 'true')
|
||||
}
|
||||
|
||||
// 恢复最后选中的分支
|
||||
const lastSelectedBranchId = sessionStorage.getItem(LAST_SELECTED_BRANCH_KEY)
|
||||
if (lastSelectedBranchId) {
|
||||
@@ -297,9 +515,7 @@ const initializeFlow = () => {
|
||||
|
||||
if (lastSelectedBranch.branchContent === '初始流程') {
|
||||
// 初始流程:高亮所有主流程节点(从恢复的nodes中获取)
|
||||
nodesToHighlight = nodes.value
|
||||
.filter(n => !n.data.isBranchTask && n.id !== 'root')
|
||||
.map(n => n.id)
|
||||
nodesToHighlight = getMainProcessNodeIds()
|
||||
} else {
|
||||
// 其他分支:高亮主流程路径 + 分支节点(支持多级分支)
|
||||
const firstBranchNode = lastSelectedBranch.nodes[0]
|
||||
@@ -311,7 +527,7 @@ const initializeFlow = () => {
|
||||
let currentNode = nodes.value.find(n => n.id === incomingEdge.source)
|
||||
while (currentNode && currentNode.id !== 'root') {
|
||||
nodesToHighlight.unshift(currentNode.id)
|
||||
const prevEdge = edges.value.find(e => e.target === currentNode.id)
|
||||
const prevEdge = edges.value.find(e => e.target === currentNode?.id)
|
||||
currentNode = prevEdge
|
||||
? nodes.value.find(n => n.id === prevEdge.source)
|
||||
: undefined
|
||||
@@ -330,17 +546,11 @@ const initializeFlow = () => {
|
||||
selectedNodeIds.value = new Set(nodesToHighlight)
|
||||
} else {
|
||||
// 找不到最后选中的分支,默认选中初始流程的高亮状态
|
||||
const mainProcessNodes = nodes.value
|
||||
.filter(n => !n.data.isBranchTask && n.id !== 'root')
|
||||
.map(n => n.id)
|
||||
selectedNodeIds.value = new Set(mainProcessNodes)
|
||||
highlightMainProcess()
|
||||
}
|
||||
} else {
|
||||
// 没有保存的选中分支,默认选中初始流程的高亮状态
|
||||
const mainProcessNodes = nodes.value
|
||||
.filter(n => !n.data.isBranchTask && n.id !== 'root')
|
||||
.map(n => n.id)
|
||||
selectedNodeIds.value = new Set(mainProcessNodes)
|
||||
highlightMainProcess()
|
||||
}
|
||||
} else {
|
||||
// 首次初始化:设置节点和边,并保存为"初始流程"分支
|
||||
@@ -362,14 +572,14 @@ const initializeFlow = () => {
|
||||
// 标记已初始化(针对该任务步骤和 agent 组合)
|
||||
sessionStorage.setItem(branchesInitKey, 'true')
|
||||
|
||||
// 保存任务过程分支到数据库
|
||||
saveTaskProcessBranchesToDB()
|
||||
|
||||
// 首次初始化时,设置初始流程为当前选中分支
|
||||
selectionStore.setActiveTaskProcessBranch(taskStepId, currentAgents, initialBranchId)
|
||||
|
||||
// 默认选中"初始流程"的高亮状态
|
||||
const mainProcessNodes = newNodes
|
||||
.filter(n => !n.data.isBranchTask && n.id !== 'root')
|
||||
.map(n => n.id)
|
||||
selectedNodeIds.value = new Set(mainProcessNodes)
|
||||
highlightMainProcess(newNodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,7 +636,7 @@ const onNodeClick = (event: any) => {
|
||||
let topBranchNodeId: string | null = null
|
||||
if (branchParentChain.length > 0) {
|
||||
// 取父节点链的最后一个(最顶层的分支节点)
|
||||
topBranchNodeId = branchParentChain[branchParentChain.length - 1]
|
||||
topBranchNodeId = branchParentChain[branchParentChain.length - 1]!
|
||||
} else {
|
||||
// 如果没有分支父节点,当前节点就是最顶层
|
||||
topBranchNodeId = nodeId
|
||||
@@ -460,8 +670,12 @@ const onNodeClick = (event: any) => {
|
||||
if (currentTask.value) {
|
||||
const completeTaskProcess: any[] = []
|
||||
|
||||
// 类型守卫:检查是否为 TaskProcess 类型(有 Description 字段)
|
||||
const isTaskProcess = (data: any): data is TaskProcess =>
|
||||
data && 'Description' in data
|
||||
|
||||
// 从 store 中获取"初始流程"副本(而不是使用 taskProcess.value)
|
||||
const taskStepId = currentTask.value.Id
|
||||
const taskStepId = currentTask.value.Id!
|
||||
const currentAgents = currentTask.value.AgentSelection || []
|
||||
const branches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
|
||||
const initialBranch = branches.find(branch => branch.branchContent === '初始流程')
|
||||
@@ -478,7 +692,7 @@ const onNodeClick = (event: any) => {
|
||||
// 主流程节点:从初始流程数据中获取
|
||||
const originalIndex = node.data.originalIndex
|
||||
const processData = mainProcessData[originalIndex]
|
||||
if (processData && processData.ID && processData.AgentName && processData.Description) {
|
||||
if (processData && isTaskProcess(processData) && processData.ID && processData.AgentName && processData.Description) {
|
||||
completeTaskProcess.push(processData)
|
||||
}
|
||||
} else if (node.data.isBranchTask) {
|
||||
@@ -490,7 +704,7 @@ const onNodeClick = (event: any) => {
|
||||
const nodeIndex = parentBranch.nodes.findIndex(n => n.id === nodeId)
|
||||
if (nodeIndex !== -1 && parentBranch.tasks[nodeIndex]) {
|
||||
const taskData = parentBranch.tasks[nodeIndex]
|
||||
if (taskData.ID && taskData.AgentName && taskData.Description) {
|
||||
if (isTaskProcess(taskData) && taskData.ID && taskData.AgentName && taskData.Description) {
|
||||
completeTaskProcess.push(taskData)
|
||||
}
|
||||
}
|
||||
@@ -508,7 +722,7 @@ const onNodeClick = (event: any) => {
|
||||
}
|
||||
|
||||
selectionStore.setActiveTaskProcessData(
|
||||
currentTask.value.Id,
|
||||
taskStepId,
|
||||
currentAgents,
|
||||
completeTaskProcess
|
||||
)
|
||||
@@ -521,11 +735,7 @@ const onNodeClick = (event: any) => {
|
||||
}
|
||||
} else {
|
||||
// 点击的是主流程节点,高亮所有主流程节点(初始流程)
|
||||
const mainProcessNodes = nodes.value
|
||||
.filter(n => !n.data.isBranchTask && n.id !== 'root')
|
||||
.map(n => n.id)
|
||||
|
||||
selectedNodeIds.value = new Set(mainProcessNodes)
|
||||
highlightMainProcess()
|
||||
|
||||
// 点击主流程节点时,从 store 读取"初始流程"分支的副本
|
||||
if (currentTask.value) {
|
||||
@@ -542,7 +752,7 @@ const onNodeClick = (event: any) => {
|
||||
selectionStore.setActiveTaskProcessData(taskStepId, currentAgents, initialBranch.tasks)
|
||||
|
||||
// 同步更新 currentTask.TaskProcess(实现全局数据联动)
|
||||
agentsStore.setCurrentTaskProcess(initialBranch.tasks)
|
||||
agentsStore.setCurrentTaskProcess(initialBranch.tasks as unknown as TaskProcess[])
|
||||
|
||||
// 保存选中的分支ID到 sessionStorage
|
||||
sessionStorage.setItem(LAST_SELECTED_BRANCH_KEY, initialBranch.id)
|
||||
@@ -626,181 +836,48 @@ const submitBranch = async () => {
|
||||
// 判断是根节点还是 agent 节点
|
||||
if (parentNodeId === 'root') {
|
||||
// 根节点分支
|
||||
let newAgentActions: IApiAgentAction[] = []
|
||||
|
||||
if (USE_MOCK_DATA) {
|
||||
// 使用 Mock API
|
||||
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
|
||||
// 调用真实 API
|
||||
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
|
||||
|
||||
// 根节点分支:从零开始生成完整方案
|
||||
// Baseline_Completion = 0 表示没有已完成的部分,需要生成所有阶段
|
||||
// Existing_Steps 传空数组,不传递初始流程信息
|
||||
const response = await api.mockBranchTaskProcess({
|
||||
branch_Number: 1,
|
||||
Modification_Requirement: branchContent,
|
||||
Existing_Steps: [], // ← 根节点分支不传递现有步骤
|
||||
Baseline_Completion: 0, // ← 从零开始
|
||||
stepTaskExisting: currentTask.value,
|
||||
goal: generalGoal
|
||||
})
|
||||
// 根节点分支:从零开始生成完整方案
|
||||
// Baseline_Completion = 0 表示没有已完成的部分,需要生成所有阶段
|
||||
// Existing_Steps 传空数组,不传递初始流程信息
|
||||
const response = await api.branchTaskProcess({
|
||||
branch_Number: 1,
|
||||
Modification_Requirement: branchContent,
|
||||
Existing_Steps: [], // ← 根节点分支不传递现有步骤
|
||||
Baseline_Completion: 0, // ← 从零开始
|
||||
stepTaskExisting: currentTask.value,
|
||||
goal: generalGoal
|
||||
})
|
||||
|
||||
// 后端返回格式: [[action1, action2], [action3, action4]]
|
||||
// 取第一个分支
|
||||
if (response && response.length > 0) {
|
||||
const firstBranch = response[0]
|
||||
// WebSocket 返回格式: { data: [[action1, action2], [action3, action4]], ... }
|
||||
// REST API 返回格式: [[action1, action2], [action3, action4]]
|
||||
// 使用通用函数解析 API 响应
|
||||
const newAgentActions = parseBranchResponse(response)
|
||||
|
||||
// 直接遍历 action 数组
|
||||
firstBranch.forEach((action: any) => {
|
||||
// 直接使用接口返回的 ActionType
|
||||
newAgentActions.push({
|
||||
id: action.ID || uuidv4(),
|
||||
type: action.ActionType,
|
||||
agent: action.AgentName,
|
||||
description: action.Description,
|
||||
inputs: action.ImportantInput || []
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ElMessage.success('[Mock] 任务流程分支创建成功')
|
||||
} else {
|
||||
// 调用真实 API
|
||||
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
|
||||
|
||||
// 根节点分支:从零开始生成完整方案
|
||||
// Baseline_Completion = 0 表示没有已完成的部分,需要生成所有阶段
|
||||
// Existing_Steps 传空数组,不传递初始流程信息
|
||||
const response = await api.branchTaskProcess({
|
||||
branch_Number: 1,
|
||||
Modification_Requirement: branchContent,
|
||||
Existing_Steps: [], // ← 根节点分支不传递现有步骤
|
||||
Baseline_Completion: 0, // ← 从零开始
|
||||
stepTaskExisting: currentTask.value,
|
||||
goal: generalGoal
|
||||
})
|
||||
|
||||
// WebSocket 返回格式: { data: [[action1, action2], [action3, action4]], ... }
|
||||
// REST API 返回格式: [[action1, action2], [action3, action4]]
|
||||
const responseData = response.data || response
|
||||
// 后端返回格式: [[action1, action2], [action3, action4]]
|
||||
// 取第一个分支
|
||||
if (responseData && responseData.length > 0) {
|
||||
const firstBranch = responseData[0]
|
||||
|
||||
// 直接遍历 action 数组
|
||||
firstBranch.forEach((action: any) => {
|
||||
// 直接使用接口返回的 ActionType
|
||||
newAgentActions.push({
|
||||
id: action.ID || uuidv4(),
|
||||
type: action.ActionType,
|
||||
agent: action.AgentName,
|
||||
description: action.Description,
|
||||
inputs: action.ImportantInput || []
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ElMessage.success('任务流程分支创建成功')
|
||||
}
|
||||
ElMessage.success('任务流程分支创建成功')
|
||||
|
||||
// 创建新的 agent 节点
|
||||
if (newAgentActions.length > 0) {
|
||||
// 计算分支起始位置:在根节点下方(固定位置)
|
||||
const branchStartX = parentNode.position.x
|
||||
const branchStartY = parentNode.position.y + 200 // 固定位置:父节点下方200px
|
||||
const timestamp = Date.now()
|
||||
const agentNodeIds: string[] = []
|
||||
const branchStartY = parentNode.position.y + 200
|
||||
|
||||
// 为每个动作创建一个 agent 节点
|
||||
newAgentActions.forEach((action, index) => {
|
||||
const agentNodeId = `branch-agent-${parentNodeId}-${timestamp}-${index}`
|
||||
agentNodeIds.push(agentNodeId)
|
||||
|
||||
const agentInfo = getAgentMapIcon(action.agent)
|
||||
const actionTypeInfo = getActionTypeDisplay(action.type)
|
||||
|
||||
// 从 agentsStore 中获取 agent 的个人简介
|
||||
const agentProfile =
|
||||
agentsStore.agents.find((agent: any) => agent.Name === action.agent)?.Profile ||
|
||||
'暂无个人简介'
|
||||
|
||||
// 计算位置:横向排列
|
||||
const nodeX = branchStartX + 100 + index * 120
|
||||
const nodeY = branchStartY
|
||||
|
||||
// 创建 agent 节点
|
||||
const newAgentNode: Node = {
|
||||
id: agentNodeId,
|
||||
type: 'agent',
|
||||
position: { x: nodeX, y: nodeY },
|
||||
data: {
|
||||
agentName: action.agent,
|
||||
agentIcon: agentInfo.icon,
|
||||
agentColor: agentInfo.color,
|
||||
actionTypeColor: actionTypeInfo?.color || '#909399',
|
||||
agentDescription: action.description || '暂无描述',
|
||||
agentProfile: agentProfile,
|
||||
actionTypeName: actionTypeInfo?.name || '未知职责',
|
||||
actionTypeKey: actionTypeInfo?.key || 'unknown',
|
||||
isRoot: false,
|
||||
isBranchTask: true // 标记为分支任务
|
||||
}
|
||||
}
|
||||
|
||||
nodes.value.push(newAgentNode)
|
||||
newBranchNodes.push(newAgentNode)
|
||||
|
||||
// 创建连接边
|
||||
if (index === 0) {
|
||||
// 第一个 agent 连接到父节点(根节点)
|
||||
const newEdge: Edge = {
|
||||
id: `edge-${parentNodeId}-${agentNodeId}`,
|
||||
source: parentNodeId,
|
||||
target: agentNodeId,
|
||||
sourceHandle: 'bottom',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
animated: true,
|
||||
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)
|
||||
newBranchEdges.push(newEdge)
|
||||
} else {
|
||||
// 后续 agent 连接到前一个 agent
|
||||
const prevAgentNodeId = agentNodeIds[index - 1]
|
||||
const newEdge: Edge = {
|
||||
id: `edge-${prevAgentNodeId}-${agentNodeId}`,
|
||||
source: prevAgentNodeId,
|
||||
target: agentNodeId,
|
||||
sourceHandle: 'right',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
animated: true,
|
||||
style: { stroke: '#67c23a', strokeWidth: 2 },
|
||||
markerEnd: {
|
||||
type: 'arrow' as any,
|
||||
color: '#43a8aa',
|
||||
width: 20,
|
||||
height: 20,
|
||||
strokeWidth: 2
|
||||
}
|
||||
}
|
||||
edges.value.push(newEdge)
|
||||
newBranchEdges.push(newEdge)
|
||||
}
|
||||
})
|
||||
// 使用通用函数创建分支节点和边
|
||||
const result = createBranchNodesAndEdges(
|
||||
newAgentActions,
|
||||
branchStartX,
|
||||
branchStartY,
|
||||
parentNodeId,
|
||||
'#67c23a' // 根节点分支颜色
|
||||
)
|
||||
newBranchNodes.push(...result.nodes)
|
||||
newBranchEdges.push(...result.edges)
|
||||
|
||||
// 保存分支数据到 store
|
||||
if (newBranchNodes.length > 0) {
|
||||
// 将 IApiAgentAction 转换为 TaskProcess 格式用于存储
|
||||
// 与 fill-step-task-mock.ts 中的 TaskProcess 格式保持一致
|
||||
const branchTasks = newAgentActions.map(action => ({
|
||||
ID: action.id || uuidv4(),
|
||||
ActionType: action.type,
|
||||
@@ -809,291 +886,94 @@ const submitBranch = async () => {
|
||||
ImportantInput: action.inputs || []
|
||||
}))
|
||||
|
||||
// 使用任务过程分支存储
|
||||
// 注意:需要对 nodes 和 edges 进行深拷贝,避免保存响应式引用
|
||||
const taskStepId = currentTask.value?.Id || ''
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
isSyncing = true // 设置标志,避免 watch 触发重复同步
|
||||
selectionStore.addTaskProcessBranch(taskStepId, currentAgents, {
|
||||
parentNodeId: parentNodeId,
|
||||
branchContent: branchContent,
|
||||
branchType: 'root',
|
||||
nodes: JSON.parse(JSON.stringify(newBranchNodes)),
|
||||
edges: JSON.parse(JSON.stringify(newBranchEdges)),
|
||||
tasks: JSON.parse(JSON.stringify(branchTasks))
|
||||
})
|
||||
setTimeout(() => {
|
||||
isSyncing = false
|
||||
}, 100)
|
||||
saveBranchToStore('root', newBranchNodes, newBranchEdges, branchTasks)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Agent 节点分支
|
||||
const parentIsBranchTask = parentNode.data.isBranchTask || false
|
||||
const parentOriginalIndex = parentNode.data.originalIndex ?? 0
|
||||
let newAgentActions: IApiAgentAction[] = []
|
||||
|
||||
if (USE_MOCK_DATA) {
|
||||
// 使用 Mock API
|
||||
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
|
||||
const currentTaskProcess = taskProcess.value || []
|
||||
// 调用真实 API
|
||||
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
|
||||
const currentTaskProcess = taskProcess.value || []
|
||||
|
||||
// 根据父节点类型构建 existingSteps
|
||||
let existingSteps: any[] = []
|
||||
let baselineCompletion = 100
|
||||
// 根据父节点类型构建 existingSteps
|
||||
let existingSteps: any[] = []
|
||||
let baselineCompletion = 100
|
||||
|
||||
if (!parentIsBranchTask) {
|
||||
// 父节点是主流程节点:传递主流程从 0 到父节点的步骤
|
||||
baselineCompletion =
|
||||
currentTaskProcess.length > 0
|
||||
? Math.round(((parentOriginalIndex + 1) / currentTaskProcess.length) * 100)
|
||||
: 100
|
||||
if (!parentIsBranchTask) {
|
||||
// 父节点是主流程节点:传递主流程从 0 到父节点的步骤
|
||||
baselineCompletion =
|
||||
currentTaskProcess.length > 0
|
||||
? Math.round(((parentOriginalIndex + 1) / currentTaskProcess.length) * 100)
|
||||
: 100
|
||||
|
||||
existingSteps = currentTaskProcess.slice(0, parentOriginalIndex + 1).map((p: any) => ({
|
||||
ID: p.ID,
|
||||
ActionType: p.ActionType,
|
||||
AgentName: p.AgentName,
|
||||
Description: p.Description,
|
||||
ImportantInput: p.ImportantInput || []
|
||||
}))
|
||||
} else {
|
||||
// 父节点是分支节点:从分支数据中获取步骤
|
||||
const taskStepId = currentTask.value?.Id || ''
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
const branches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
|
||||
|
||||
// 找到父节点所属的分支
|
||||
const parentBranch = branches.find(branch =>
|
||||
branch.nodes.some(n => n.id === parentNode.id)
|
||||
)
|
||||
|
||||
if (parentBranch && parentBranch.tasks) {
|
||||
// 获取分支中从第一个节点到父节点的所有步骤
|
||||
const parentIndexInBranch = parentBranch.nodes.findIndex(n => n.id === parentNode.id)
|
||||
existingSteps = parentBranch.tasks.slice(0, parentIndexInBranch + 1).map((p: any) => ({
|
||||
ID: p.ID,
|
||||
ActionType: p.ActionType,
|
||||
AgentName: p.AgentName,
|
||||
Description: p.Description,
|
||||
ImportantInput: p.ImportantInput || []
|
||||
}))
|
||||
|
||||
// 分支节点的基线完成度:根据主流程进度计算
|
||||
baselineCompletion =
|
||||
currentTaskProcess.length > 0
|
||||
? Math.round(((parentOriginalIndex + 1) / currentTaskProcess.length) * 100)
|
||||
: 100
|
||||
}
|
||||
}
|
||||
|
||||
// 调用 Mock API
|
||||
const response = await api.mockBranchTaskProcess({
|
||||
branch_Number: 1,
|
||||
Modification_Requirement: branchContent,
|
||||
Existing_Steps: existingSteps,
|
||||
Baseline_Completion: baselineCompletion,
|
||||
stepTaskExisting: currentTask.value,
|
||||
goal: generalGoal
|
||||
})
|
||||
|
||||
// 后端返回格式: [[action1, action2], [action3, action4]]
|
||||
// 取第一个分支
|
||||
if (response && response.length > 0) {
|
||||
const firstBranch = response[0]
|
||||
|
||||
// 直接遍历 action 数组
|
||||
firstBranch.forEach((action: any) => {
|
||||
// 直接使用接口返回的 ActionType
|
||||
newAgentActions.push({
|
||||
id: action.ID || uuidv4(),
|
||||
type: action.ActionType,
|
||||
agent: action.AgentName,
|
||||
description: action.Description,
|
||||
inputs: action.ImportantInput || []
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ElMessage.success('[Mock] 任务流程分支创建成功')
|
||||
existingSteps = currentTaskProcess.slice(0, parentOriginalIndex + 1).map((p: any) => ({
|
||||
ID: p.ID,
|
||||
ActionType: p.ActionType,
|
||||
AgentName: p.AgentName,
|
||||
Description: p.Description,
|
||||
ImportantInput: p.ImportantInput || []
|
||||
}))
|
||||
} else {
|
||||
// 调用真实 API
|
||||
const generalGoal = agentsStore.agentRawPlan.data?.['General Goal'] || ''
|
||||
const currentTaskProcess = taskProcess.value || []
|
||||
// 父节点是分支节点:从分支数据中获取步骤
|
||||
const taskStepId = currentTask.value?.Id || ''
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
const branches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
|
||||
|
||||
// 根据父节点类型构建 existingSteps
|
||||
let existingSteps: any[] = []
|
||||
let baselineCompletion = 100
|
||||
// 找到父节点所属的分支
|
||||
const parentBranch = branches.find(branch => branch.nodes.some(n => n.id === parentNode.id))
|
||||
|
||||
if (!parentIsBranchTask) {
|
||||
// 父节点是主流程节点:传递主流程从 0 到父节点的步骤
|
||||
baselineCompletion =
|
||||
currentTaskProcess.length > 0
|
||||
? Math.round(((parentOriginalIndex + 1) / currentTaskProcess.length) * 100)
|
||||
: 100
|
||||
|
||||
existingSteps = currentTaskProcess.slice(0, parentOriginalIndex + 1).map((p: any) => ({
|
||||
if (parentBranch && parentBranch.tasks) {
|
||||
// 获取分支中从第一个节点到父节点的所有步骤
|
||||
const parentIndexInBranch = parentBranch.nodes.findIndex(n => n.id === parentNode.id)
|
||||
existingSteps = parentBranch.tasks.slice(0, parentIndexInBranch + 1).map((p: any) => ({
|
||||
ID: p.ID,
|
||||
ActionType: p.ActionType,
|
||||
AgentName: p.AgentName,
|
||||
Description: p.Description,
|
||||
ImportantInput: p.ImportantInput || []
|
||||
}))
|
||||
} else {
|
||||
// 父节点是分支节点:从分支数据中获取步骤
|
||||
const taskStepId = currentTask.value?.Id || ''
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
const branches = selectionStore.getTaskProcessBranches(taskStepId, currentAgents)
|
||||
|
||||
// 找到父节点所属的分支
|
||||
const parentBranch = branches.find(branch =>
|
||||
branch.nodes.some(n => n.id === parentNode.id)
|
||||
)
|
||||
|
||||
if (parentBranch && parentBranch.tasks) {
|
||||
// 获取分支中从第一个节点到父节点的所有步骤
|
||||
const parentIndexInBranch = parentBranch.nodes.findIndex(n => n.id === parentNode.id)
|
||||
existingSteps = parentBranch.tasks.slice(0, parentIndexInBranch + 1).map((p: any) => ({
|
||||
ID: p.ID,
|
||||
ActionType: p.ActionType,
|
||||
AgentName: p.AgentName,
|
||||
Description: p.Description,
|
||||
ImportantInput: p.ImportantInput || []
|
||||
}))
|
||||
|
||||
// 分支节点的基线完成度:根据主流程进度计算
|
||||
baselineCompletion =
|
||||
currentTaskProcess.length > 0
|
||||
? Math.round(((parentOriginalIndex + 1) / currentTaskProcess.length) * 100)
|
||||
: 100
|
||||
}
|
||||
// 分支节点的基线完成度:根据主流程进度计算
|
||||
baselineCompletion =
|
||||
currentTaskProcess.length > 0
|
||||
? Math.round(((parentOriginalIndex + 1) / currentTaskProcess.length) * 100)
|
||||
: 100
|
||||
}
|
||||
|
||||
const response = await api.branchTaskProcess({
|
||||
branch_Number: 1,
|
||||
Modification_Requirement: branchContent,
|
||||
Existing_Steps: existingSteps,
|
||||
Baseline_Completion: baselineCompletion,
|
||||
stepTaskExisting: currentTask.value,
|
||||
goal: generalGoal
|
||||
})
|
||||
|
||||
// WebSocket 返回格式: { data: [[action1, action2], [action3, action4]], ... }
|
||||
// REST API 返回格式: [[action1, action2], [action3, action4]]
|
||||
const responseData = response.data || response
|
||||
// 后端返回格式: [[action1, action2], [action3, action4]]
|
||||
// 取第一个分支
|
||||
if (responseData && responseData.length > 0) {
|
||||
const firstBranch = responseData[0]
|
||||
|
||||
// 直接遍历 action 数组
|
||||
firstBranch.forEach((action: any) => {
|
||||
// 直接使用接口返回的 ActionType
|
||||
newAgentActions.push({
|
||||
id: action.ID || uuidv4(),
|
||||
type: action.ActionType,
|
||||
agent: action.AgentName,
|
||||
description: action.Description,
|
||||
inputs: action.ImportantInput || []
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
ElMessage.success('任务流程分支创建成功')
|
||||
}
|
||||
|
||||
const response = await api.branchTaskProcess({
|
||||
branch_Number: 1,
|
||||
Modification_Requirement: branchContent,
|
||||
Existing_Steps: existingSteps,
|
||||
Baseline_Completion: baselineCompletion,
|
||||
stepTaskExisting: currentTask.value,
|
||||
goal: generalGoal
|
||||
})
|
||||
|
||||
// 使用通用函数解析 API 响应
|
||||
const newAgentActions = parseBranchResponse(response)
|
||||
|
||||
ElMessage.success('任务流程分支创建成功')
|
||||
|
||||
// 创建新的 agent 节点
|
||||
if (newAgentActions.length > 0) {
|
||||
// 计算分支起始位置:在父 agent 节点右下方(固定位置)
|
||||
const branchStartX = parentNode.position.x + 150
|
||||
const branchStartY = parentNode.position.y + 200 // 固定位置:父节点下方200px
|
||||
const timestamp = Date.now()
|
||||
const agentNodeIds: string[] = []
|
||||
const branchStartY = parentNode.position.y + 200
|
||||
|
||||
// 为每个动作创建一个 agent 节点
|
||||
newAgentActions.forEach((action, index) => {
|
||||
const agentNodeId = `branch-agent-${parentNodeId}-${timestamp}-${index}`
|
||||
agentNodeIds.push(agentNodeId)
|
||||
|
||||
const agentInfo = getAgentMapIcon(action.agent)
|
||||
const actionTypeInfo = getActionTypeDisplay(action.type)
|
||||
|
||||
// 从 agentsStore 中获取 agent 的个人简介
|
||||
const agentProfile =
|
||||
agentsStore.agents.find((agent: any) => agent.Name === action.agent)?.Profile ||
|
||||
'暂无个人简介'
|
||||
|
||||
// 计算位置:横向排列
|
||||
const nodeX = branchStartX + index * 120
|
||||
const nodeY = branchStartY
|
||||
|
||||
// 创建 agent 节点
|
||||
const newAgentNode: Node = {
|
||||
id: agentNodeId,
|
||||
type: 'agent',
|
||||
position: { x: nodeX, y: nodeY },
|
||||
data: {
|
||||
agentName: action.agent,
|
||||
agentIcon: agentInfo.icon,
|
||||
agentColor: agentInfo.color,
|
||||
actionTypeColor: actionTypeInfo?.color || '#909399',
|
||||
agentDescription: action.description || '暂无描述',
|
||||
agentProfile: agentProfile,
|
||||
actionTypeName: actionTypeInfo?.name || '未知职责',
|
||||
actionTypeKey: actionTypeInfo?.key || 'unknown',
|
||||
isRoot: false,
|
||||
isBranchTask: true // 标记为分支任务
|
||||
}
|
||||
}
|
||||
|
||||
nodes.value.push(newAgentNode)
|
||||
newBranchNodes.push(newAgentNode)
|
||||
|
||||
// 创建连接边
|
||||
if (index === 0) {
|
||||
// 第一个 agent 连接到父节点
|
||||
const newEdge: Edge = {
|
||||
id: `edge-${parentNodeId}-${agentNodeId}`,
|
||||
source: parentNodeId,
|
||||
target: agentNodeId,
|
||||
sourceHandle: 'bottom',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
animated: true,
|
||||
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)
|
||||
newBranchEdges.push(newEdge)
|
||||
} else {
|
||||
// 后续 agent 连接到前一个 agent
|
||||
const prevAgentNodeId = agentNodeIds[index - 1]
|
||||
const newEdge: Edge = {
|
||||
id: `edge-${prevAgentNodeId}-${agentNodeId}`,
|
||||
source: prevAgentNodeId,
|
||||
target: agentNodeId,
|
||||
sourceHandle: 'right',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
animated: true,
|
||||
style: { stroke: '#409eff', strokeWidth: 2 },
|
||||
markerEnd: {
|
||||
type: 'arrow' as any,
|
||||
color: '#43a8aa',
|
||||
width: 20,
|
||||
height: 20,
|
||||
strokeWidth: 2
|
||||
}
|
||||
}
|
||||
edges.value.push(newEdge)
|
||||
newBranchEdges.push(newEdge)
|
||||
}
|
||||
})
|
||||
// 使用通用函数创建分支节点和边
|
||||
const result = createBranchNodesAndEdges(
|
||||
newAgentActions,
|
||||
branchStartX,
|
||||
branchStartY,
|
||||
parentNodeId,
|
||||
'#409eff' // Agent 节点分支颜色
|
||||
)
|
||||
newBranchNodes.push(...result.nodes)
|
||||
newBranchEdges.push(...result.edges)
|
||||
|
||||
// 保存分支数据到 store
|
||||
if (newBranchNodes.length > 0) {
|
||||
@@ -1105,22 +985,7 @@ const submitBranch = async () => {
|
||||
ImportantInput: action.inputs || []
|
||||
}))
|
||||
|
||||
// 使用任务过程分支存储
|
||||
// 注意:需要对 nodes 和 edges 进行深拷贝,避免保存响应式引用
|
||||
const taskStepId = currentTask.value?.Id || ''
|
||||
const currentAgents = currentTask.value?.AgentSelection || []
|
||||
isSyncing = true // 设置标志,避免 watch 触发重复同步
|
||||
selectionStore.addTaskProcessBranch(taskStepId, currentAgents, {
|
||||
parentNodeId: parentNodeId,
|
||||
branchContent: branchContent,
|
||||
branchType: 'task',
|
||||
nodes: JSON.parse(JSON.stringify(newBranchNodes)),
|
||||
edges: JSON.parse(JSON.stringify(newBranchEdges)),
|
||||
tasks: JSON.parse(JSON.stringify(branchTasks))
|
||||
})
|
||||
setTimeout(() => {
|
||||
isSyncing = false
|
||||
}, 100)
|
||||
saveBranchToStore('task', newBranchNodes, newBranchEdges, branchTasks)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1154,6 +1019,20 @@ const handleBranchKeydown = (event: KeyboardEvent) => {
|
||||
}
|
||||
|
||||
onConnect(params => addEdges(params))
|
||||
|
||||
// 保存任务过程分支到数据库
|
||||
const saveTaskProcessBranchesToDB = async () => {
|
||||
const TaskID = (window as any).__CURRENT_TASK_ID__
|
||||
if (TaskID) {
|
||||
try {
|
||||
await selectionStore.saveTaskProcessBranchesToDB(TaskID)
|
||||
} catch (error) {
|
||||
console.error('保存任务过程分支数据失败:', error)
|
||||
}
|
||||
} else {
|
||||
console.warn('[saveTaskProcessBranchesToDB] 未找到 TaskID,跳过保存')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
// 模拟后端原始返回格式的 Mock 数据 - fill_stepTask_TaskProcess 接口
|
||||
// 后端返回格式: IRawStepTask { StepName, TaskContent, InputObject_List, OutputObject, AgentSelection, TaskProcess, Collaboration_Brief_frontEnd }
|
||||
|
||||
import type { IRawStepTask } from '@/stores'
|
||||
|
||||
// TaskProcess 项格式
|
||||
interface RawTaskProcessItem {
|
||||
ID: string
|
||||
ActionType: string
|
||||
AgentName: string
|
||||
Description: string
|
||||
ImportantInput: string[]
|
||||
}
|
||||
|
||||
// Collaboration_Brief_frontEnd 数据项格式
|
||||
interface RawBriefDataItem {
|
||||
text: string
|
||||
color: number[] // [h, s, l]
|
||||
}
|
||||
|
||||
// 后端返回的完整数据格式
|
||||
export interface RawAgentTaskProcessResponse {
|
||||
StepName: string
|
||||
TaskContent: string
|
||||
InputObject_List: string[]
|
||||
OutputObject: string
|
||||
AgentSelection: string[]
|
||||
TaskProcess: RawTaskProcessItem[]
|
||||
Collaboration_Brief_frontEnd?: {
|
||||
template: string
|
||||
data: Record<string, RawBriefDataItem>
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟后端返回的原始数据结构(与后端缓存数据格式一致)
|
||||
// 使用与 AgentAssignmentBackendMock 相同的 agent 列表
|
||||
export const mockBackendAgentTaskProcessData: RawAgentTaskProcessResponse = {
|
||||
StepName: '腐蚀类型识别',
|
||||
TaskContent: '分析船舶制造中常见的材料腐蚀类型及其成因。',
|
||||
InputObject_List: [],
|
||||
OutputObject: '腐蚀类型及成因列表',
|
||||
AgentSelection: ['腐蚀机理研究员', '实验材料学家', '防护工程专家'],
|
||||
TaskProcess: [
|
||||
{
|
||||
ID: 'action_101',
|
||||
ActionType: 'Propose',
|
||||
AgentName: '腐蚀机理研究员',
|
||||
Description: '分析海洋环境下的腐蚀机理,确定关键防护要素',
|
||||
ImportantInput: ['海洋环境参数', '防护性能指标'],
|
||||
},
|
||||
{
|
||||
ID: 'action_102',
|
||||
ActionType: 'Critique',
|
||||
AgentName: '实验材料学家',
|
||||
Description: '基于腐蚀机理分析结果,设计涂层材料的基础配方',
|
||||
ImportantInput: ['腐蚀机理分析结果', '涂层材料配方'],
|
||||
},
|
||||
{
|
||||
ID: 'action_103',
|
||||
ActionType: 'Improve',
|
||||
AgentName: '防护工程专家',
|
||||
Description: '筛选适用于防护涂层的二维材料,评估其性能潜力',
|
||||
ImportantInput: ['材料配方设计', '涂层材料配方'],
|
||||
},
|
||||
{
|
||||
ID: 'action_104',
|
||||
ActionType: 'Finalize',
|
||||
AgentName: '实验材料学家',
|
||||
Description: '制定涂层材料性能测试实验方案,包括测试指标和方法',
|
||||
ImportantInput: ['二维材料筛选结果', '防护性能指标'],
|
||||
},
|
||||
{
|
||||
ID: 'action_105',
|
||||
ActionType: 'Critique',
|
||||
AgentName: '防护工程专家',
|
||||
Description: '模拟海洋流体环境对涂层材料的影响,优化涂层结构',
|
||||
ImportantInput: ['实验方案', '海洋环境参数'],
|
||||
},
|
||||
{
|
||||
ID: 'action_106',
|
||||
ActionType: 'Improve',
|
||||
AgentName: '腐蚀机理研究员',
|
||||
Description: '综合评估涂层材料的防护性能,提出改进建议',
|
||||
ImportantInput: ['流体力学模拟结果', '实验材料学测试结果', '二维材料性能数据'],
|
||||
},
|
||||
{
|
||||
ID: 'action_107',
|
||||
ActionType: 'Improve',
|
||||
AgentName: '实验材料学家',
|
||||
Description: '整理研发数据和测试结果,撰写完整的研发报告',
|
||||
ImportantInput: ['综合性能评估', '所有研发数据'],
|
||||
},
|
||||
],
|
||||
Collaboration_Brief_frontEnd: {
|
||||
template: '基于!<0>!、!<1>!和!<2>!,!<3>!、!<4>!、!<5>!和!<6>!执行!<7>!任务,以获得!<8>!。',
|
||||
data: {
|
||||
'0': {
|
||||
text: '涂层材料配方',
|
||||
color: [120, 60, 70], // hsl(120, 60%, 70%)
|
||||
},
|
||||
'1': {
|
||||
text: '海洋环境参数',
|
||||
color: [120, 60, 70], // hsl(120, 60%, 70%)
|
||||
},
|
||||
'2': {
|
||||
text: '防护性能指标',
|
||||
color: [120, 60, 70], // hsl(120, 60%, 70%)
|
||||
},
|
||||
'3': {
|
||||
text: '腐蚀机理研究员',
|
||||
color: [0, 0, 90], // hsl(0, 0%, 90%)
|
||||
},
|
||||
'4': {
|
||||
text: '先进材料研发员',
|
||||
color: [0, 0, 90], // hsl(0, 0%, 90%)
|
||||
},
|
||||
'5': {
|
||||
text: '二维材料科学家',
|
||||
color: [0, 0, 90], // hsl(0, 0%, 90%)
|
||||
},
|
||||
'6': {
|
||||
text: '实验材料学家',
|
||||
color: [0, 0, 90], // hsl(0, 0%, 90%)
|
||||
},
|
||||
'7': {
|
||||
text: '研发适用于海洋环境的耐腐蚀防护涂层材料,并进行性能测试与评估',
|
||||
color: [0, 0, 87], // hsl(0, 0%, 87%)
|
||||
},
|
||||
'8': {
|
||||
text: '防护涂层材料研发报告',
|
||||
color: [30, 100, 80], // hsl(30, 100%, 80%)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// 模拟后端API调用 - fill_stepTask_TaskProcess
|
||||
export const mockBackendFillAgentTaskProcess = async (
|
||||
goal: string,
|
||||
stepTask: any,
|
||||
agents: string[],
|
||||
): Promise<RawAgentTaskProcessResponse> => {
|
||||
// 模拟网络延迟 500ms
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
|
||||
// 在真实场景中,后端会根据传入的 goal、stepTask 和 agents 生成不同的 TaskProcess
|
||||
// 这里我们直接返回预设的 Mock 数据
|
||||
// 可以根据传入的 agents 动态修改 AgentSelection 和 TaskProcess
|
||||
|
||||
// 确保 agents 数组不为空
|
||||
const safeAgents = agents.length > 0 ? agents : ['腐蚀机理研究员']
|
||||
|
||||
const responseData: RawAgentTaskProcessResponse = {
|
||||
...mockBackendAgentTaskProcessData,
|
||||
AgentSelection: agents,
|
||||
TaskProcess: mockBackendAgentTaskProcessData.TaskProcess.map((action, index) => ({
|
||||
...action,
|
||||
AgentName: safeAgents[index % safeAgents.length],
|
||||
})),
|
||||
Collaboration_Brief_frontEnd: mockBackendAgentTaskProcessData.Collaboration_Brief_frontEnd
|
||||
? {
|
||||
template: mockBackendAgentTaskProcessData.Collaboration_Brief_frontEnd.template,
|
||||
data: { ...mockBackendAgentTaskProcessData.Collaboration_Brief_frontEnd.data },
|
||||
}
|
||||
: undefined,
|
||||
}
|
||||
|
||||
// 更新 Collaboration_Brief_frontEnd.data 中的 agent 引用
|
||||
if (responseData.Collaboration_Brief_frontEnd?.data) {
|
||||
const agentCount = Math.min(safeAgents.length, 4) // 最多4个agent
|
||||
for (let i = 0; i < agentCount; i++) {
|
||||
const key = String(i + 3) // agent从索引3开始
|
||||
if (responseData.Collaboration_Brief_frontEnd.data[key]) {
|
||||
responseData.Collaboration_Brief_frontEnd.data[key] = {
|
||||
...responseData.Collaboration_Brief_frontEnd.data[key],
|
||||
text: safeAgents[i]!,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return responseData
|
||||
}
|
||||
@@ -14,9 +14,15 @@ import websocket from '@/utils/websocket'
|
||||
import Notification from '@/components/Notification/Notification.vue'
|
||||
import { useNotification } from '@/composables/useNotification'
|
||||
|
||||
// 定义组件 props
|
||||
const props = defineProps<{
|
||||
TaskID?: string // 任务唯一标识,用于写入数据库
|
||||
}>()
|
||||
|
||||
// 定义组件事件
|
||||
const emit = defineEmits<{
|
||||
(e: 'refreshLine'): void
|
||||
(el: 'setCurrentTask', task: IRawStepTask): void
|
||||
(e: 'setCurrentTask', task: IRawStepTask): void
|
||||
}>()
|
||||
|
||||
const agentsStore = useAgentsStore()
|
||||
@@ -411,7 +417,10 @@ async function executeBatchSteps(readySteps: IRawStepTask[]) {
|
||||
isStreaming.value = true
|
||||
currentExecutionId.value = executionId
|
||||
},
|
||||
currentExecutionId.value || undefined
|
||||
currentExecutionId.value || undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
props.TaskID || undefined
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -961,7 +970,8 @@ async function restartFromStep(stepIndex: number) {
|
||||
},
|
||||
newExecutionId, // 传入前端生成的 execution_id
|
||||
stepIndex,
|
||||
truncatedLog
|
||||
truncatedLog,
|
||||
props.TaskID || undefined // 传入 TaskID 用于更新数据库
|
||||
)
|
||||
|
||||
success('重新执行', `正在从步骤 ${stepIndex + 1} 重新执行...`)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,155 +0,0 @@
|
||||
// branch_TaskProcess 接口的 Mock 数据和 Mock API
|
||||
export interface BranchAction {
|
||||
ID: string
|
||||
ActionType: string
|
||||
AgentName: string
|
||||
Description: string
|
||||
ImportantInput: string[]
|
||||
}
|
||||
|
||||
export type BranchTaskProcessResponse = BranchAction[][]
|
||||
|
||||
// Mock 数据:模拟后端返回的原始任务流程数据(2D 数组)
|
||||
// 格式:[[action1, action2], [action3, action4]]
|
||||
const mockBranchTaskProcessDataRaw: BranchAction[][] = [
|
||||
// 第一个任务分支方案
|
||||
[
|
||||
{
|
||||
ID: 'agent3',
|
||||
ActionType: 'Critique',
|
||||
AgentName: '实验材料学家',
|
||||
Description: '详细分析用户需求文档',
|
||||
ImportantInput: ['agent2'],
|
||||
},
|
||||
{
|
||||
ID: 'agent4',
|
||||
ActionType: 'Critique',
|
||||
AgentName: '腐蚀机理研究员',
|
||||
Description: '设计系统整体架构',
|
||||
ImportantInput: ['agent3'],
|
||||
},
|
||||
{
|
||||
ID: 'agent5',
|
||||
ActionType: 'Improve',
|
||||
AgentName: '防护工程专家',
|
||||
Description: '实现系统核心功能',
|
||||
ImportantInput: ['agent4'],
|
||||
},
|
||||
{
|
||||
ID: 'agent6',
|
||||
ActionType: 'Finalize',
|
||||
AgentName: '实验材料学家',
|
||||
Description: '进行系统集成测试',
|
||||
ImportantInput: ['agent5'],
|
||||
},
|
||||
],
|
||||
// 第二个任务分支方案
|
||||
[
|
||||
{
|
||||
ID: 'agent7',
|
||||
ActionType: 'Critique',
|
||||
AgentName: '实验材料学家',
|
||||
Description: '深入分析用户需求和技术约束',
|
||||
ImportantInput: ['agent2'],
|
||||
},
|
||||
{
|
||||
ID: 'agent8',
|
||||
ActionType: 'Critique',
|
||||
AgentName: '防护工程专家',
|
||||
Description: '设计系统技术架构和数据流',
|
||||
ImportantInput: ['agent8'],
|
||||
},
|
||||
{
|
||||
ID: 'agent9',
|
||||
ActionType: 'Improve',
|
||||
AgentName: '腐蚀机理研究员',
|
||||
Description: '评估系统安全性',
|
||||
ImportantInput: ['agent4'],
|
||||
},
|
||||
{
|
||||
ID: 'agent10',
|
||||
ActionType: 'Finalize',
|
||||
AgentName: '实验材料学家',
|
||||
Description: '完成系统安全测试',
|
||||
ImportantInput: ['agent9'],
|
||||
},
|
||||
],
|
||||
|
||||
//第三个任务分支方案
|
||||
[
|
||||
{
|
||||
ID: 'agent12',
|
||||
ActionType: 'Critique',
|
||||
AgentName: '腐蚀机理研究员',
|
||||
Description: '设计系统整体架构',
|
||||
ImportantInput: ['agent11'],
|
||||
},
|
||||
{
|
||||
ID: 'agent13',
|
||||
ActionType: 'Improve',
|
||||
AgentName: '防护工程专家',
|
||||
Description: '实现系统核心功能',
|
||||
ImportantInput: ['agent12'],
|
||||
},
|
||||
{
|
||||
ID: 'agent14',
|
||||
ActionType: 'Finalize',
|
||||
AgentName: '实验材料学家',
|
||||
Description: '进行系统集成测试',
|
||||
ImportantInput: ['agent13'],
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
/**
|
||||
* Mock API:模拟后端 branch_TaskProcess 接口调用
|
||||
*
|
||||
* @param branch_Number - 分支数量
|
||||
* @param Modification_Requirement - 修改需求
|
||||
* @param Existing_Steps - 现有步骤列表(包含完整信息的对象数组)
|
||||
* @param Baseline_Completion - 基线完成度
|
||||
* @param stepTaskExisting - 现有任务
|
||||
* @param General_Goal - 总体目标
|
||||
* @returns Promise<BranchAction[][]> - 返回 2D 数组,与后端格式完全一致
|
||||
*/
|
||||
export const mockBranchTaskProcessAPI = async (params: {
|
||||
branch_Number: number
|
||||
Modification_Requirement: string
|
||||
Existing_Steps: BranchAction[]
|
||||
Baseline_Completion: number
|
||||
stepTaskExisting: any
|
||||
General_Goal: string
|
||||
}): Promise<BranchAction[][]> => {
|
||||
// 模拟网络延迟 800ms
|
||||
await new Promise((resolve) => setTimeout(resolve, 800))
|
||||
|
||||
console.log('[Mock API] branch_TaskProcess 调用参数:', params)
|
||||
|
||||
// 🆕 使用轮询方式选择分支方案(依次循环使用所有分支方案)
|
||||
const totalBranches = mockBranchTaskProcessDataRaw.length
|
||||
const sessionKey = `branch-task-process-index-${params.stepTaskExisting?.Id || 'default'}`
|
||||
|
||||
// 获取上一次的选择索引
|
||||
let lastIndex = parseInt(sessionStorage.getItem(sessionKey) || '0')
|
||||
|
||||
// 计算本次的选择索引(轮询到下一个分支)
|
||||
const selectedBranchIndex = (lastIndex + 1) % totalBranches
|
||||
|
||||
// 保存本次的选择索引
|
||||
sessionStorage.setItem(sessionKey, selectedBranchIndex.toString())
|
||||
|
||||
const rawBranchData = mockBranchTaskProcessDataRaw[selectedBranchIndex] || []
|
||||
|
||||
console.log(
|
||||
'[Mock API] branch_TaskProcess 选择分支方案:',
|
||||
selectedBranchIndex + 1,
|
||||
'/',
|
||||
totalBranches,
|
||||
)
|
||||
console.log('[Mock API] branch_TaskProcess 返回数据:', rawBranchData)
|
||||
|
||||
// 直接返回 2D 数组,与后端格式完全一致
|
||||
return [rawBranchData]
|
||||
}
|
||||
|
||||
export default mockBranchTaskProcessAPI
|
||||
@@ -83,8 +83,23 @@ const handleSubmit = async () => {
|
||||
}
|
||||
try {
|
||||
isAddingDimension.value = true
|
||||
|
||||
// 获取大任务ID和小任务信息
|
||||
const dbTaskId = (window as any).__CURRENT_TASK_ID__
|
||||
const stepTask = currentTask.value
|
||||
? {
|
||||
Id: currentTask.value.Id,
|
||||
StepName: currentTask.value.StepName,
|
||||
TaskContent: currentTask.value.TaskContent,
|
||||
InputObject_List: currentTask.value.InputObject_List,
|
||||
OutputObject: currentTask.value.OutputObject
|
||||
}
|
||||
: undefined
|
||||
|
||||
const response = await api.agentSelectModifyAddAspect({
|
||||
aspectList: [...scoreDimensions.value, newDimension]
|
||||
aspectList: [...scoreDimensions.value, newDimension],
|
||||
stepTask: stepTask,
|
||||
TaskID: dbTaskId
|
||||
})
|
||||
|
||||
scoreDimensions.value.push(response.aspectName)
|
||||
@@ -103,9 +118,10 @@ const handleSubmit = async () => {
|
||||
})
|
||||
//异步更新 store(等前端显示完成后再更新,避免触发重新初始化)
|
||||
await nextTick()
|
||||
// 使用 Id 作为 key
|
||||
const taskId = currentTask.value?.Id
|
||||
|
||||
//更新按任务ID的存储
|
||||
//更新按任务Id的存储
|
||||
if (taskId) {
|
||||
const existingTaskData = agentsStore.getTaskScoreData(taskId)
|
||||
if (existingTaskData) {
|
||||
@@ -172,7 +188,28 @@ const confirmAgentSelection = async () => {
|
||||
selectedAgents.value = new Set(existingGroup)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取大任务ID
|
||||
const dbTaskId = (window as any).__CURRENT_TASK_ID__
|
||||
|
||||
// 添加到内存 store
|
||||
agentsStore.addConfirmedAgentGroup(currentTask.value.Id, agentArray)
|
||||
|
||||
// 🆕 保存 confirmed_groups 到数据库
|
||||
if (dbTaskId && currentTask.value.Id) {
|
||||
try {
|
||||
const updatedGroups = agentsStore.getConfirmedAgentGroups(currentTask.value.Id)
|
||||
await api.updateAssignedAgents({
|
||||
task_id: dbTaskId,
|
||||
step_id: currentTask.value.Id,
|
||||
agents: agentArray,
|
||||
confirmed_groups: updatedGroups
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('❌ 保存 confirmed_groups 失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
isLoadingConfirm.value = true
|
||||
const stepTaskForApi = agentsStore.createStepTaskForApi(agentArray)
|
||||
@@ -186,7 +223,8 @@ const confirmAgentSelection = async () => {
|
||||
const filledTask = await api.fillStepTaskTaskProcess({
|
||||
goal,
|
||||
stepTask: stepTaskForApi,
|
||||
agents: agentArray
|
||||
agents: agentArray,
|
||||
TaskID: dbTaskId
|
||||
})
|
||||
selectionStore.setAgentTaskProcess(currentTask.value.Id, agentArray, filledTask)
|
||||
} catch (error) {
|
||||
@@ -212,6 +250,7 @@ const selectAgentGroup = async (agentNames: string[]) => {
|
||||
if (currentTask.value?.Id && agentNames.length > 0) {
|
||||
let taskProcessData = selectionStore.getAgentTaskProcess(currentTask.value.Id, agentNames)
|
||||
|
||||
// 如果 store 中没有数据,调用 API 生成
|
||||
if (!taskProcessData) {
|
||||
try {
|
||||
isLoadingSelectGroup.value = true
|
||||
@@ -225,9 +264,17 @@ const selectAgentGroup = async (agentNames: string[]) => {
|
||||
const filledTask = await api.fillStepTaskTaskProcess({
|
||||
goal,
|
||||
stepTask: stepTaskForApi,
|
||||
agents: agentNames
|
||||
agents: agentNames,
|
||||
TaskID: (window as any).__CURRENT_TASK_ID__
|
||||
})
|
||||
|
||||
// 🆕 先存储到 store,确保 getAgentCombinations 能获取到
|
||||
// 注意:需要转换为后端期望的格式 { process, brief }
|
||||
const groupKey = selectionStore.getAgentGroupKey(agentNames)
|
||||
selectionStore.setAgentTaskProcess(currentTask.value.Id, agentNames, {
|
||||
process: filledTask.process || [],
|
||||
brief: filledTask.brief || {}
|
||||
})
|
||||
selectionStore.setAgentTaskProcess(currentTask.value.Id, agentNames, filledTask)
|
||||
taskProcessData = filledTask
|
||||
} catch (error) {
|
||||
console.error('❌ 加载 TaskProcess 数据失败:', error)
|
||||
@@ -239,10 +286,16 @@ const selectAgentGroup = async (agentNames: string[]) => {
|
||||
|
||||
if (taskProcessData) {
|
||||
const convertedTaskProcess = convertToTaskProcess(taskProcessData.process || [])
|
||||
agentsStore.updateCurrentAgentSelection(
|
||||
|
||||
// 🆕 获取所有 agent combinations(包含新存储的数据)
|
||||
// getAgentCombinations 现在使用 stepId 作为第一层 key
|
||||
const agentCombinations = selectionStore.getAgentCombinations(currentTask.value.Id)
|
||||
|
||||
await agentsStore.updateCurrentAgentSelection(
|
||||
[...agentNames],
|
||||
convertedTaskProcess,
|
||||
taskProcessData.brief || currentTask.value.Collaboration_Brief_frontEnd
|
||||
taskProcessData.brief || currentTask.value.Collaboration_Brief_frontEnd,
|
||||
agentCombinations
|
||||
)
|
||||
}
|
||||
|
||||
@@ -345,9 +398,9 @@ const calculateAgentAverage = (agentData: AgentHeatmapData, selectedDimensions?:
|
||||
|
||||
// API调用 - 获取智能体评分数据
|
||||
const fetchAgentScores = async () => {
|
||||
// 使用 Id 作为 key
|
||||
const taskId = currentTask.value?.Id
|
||||
if (!taskId) {
|
||||
console.warn('⚠️ fetchAgentScores: 当前任务没有 Id')
|
||||
return null
|
||||
}
|
||||
//先检查 store 中是否有该任务的评分数据
|
||||
@@ -369,14 +422,15 @@ const fetchAgentScores = async () => {
|
||||
|
||||
// 检查是否已停止
|
||||
if (agentsStore.isStopping || agentsStore.hasStoppedFilling) {
|
||||
console.log('检测到停止信号,跳过获取智能体评分')
|
||||
return null
|
||||
}
|
||||
|
||||
// 调用 API 获取评分(如果没有缓存或预加载)
|
||||
const dbTaskId = (window as any).__CURRENT_TASK_ID__
|
||||
const agentScores = await api.agentSelectModifyInit({
|
||||
goal: agentsStore.agentRawPlan.data?.['General Goal'] || '',
|
||||
stepTask: currentTask.value
|
||||
stepTask: currentTask.value,
|
||||
TaskID: dbTaskId
|
||||
})
|
||||
|
||||
// 再次检查是否已停止(API 调用后)
|
||||
@@ -388,9 +442,7 @@ const fetchAgentScores = async () => {
|
||||
const firstAgent = Object.keys(agentScores)[0]
|
||||
const aspectList = firstAgent ? Object.keys(agentScores[firstAgent] || {}) : []
|
||||
|
||||
console.log('✅ 获取到的维度列表:', aspectList)
|
||||
|
||||
// 🆕 保存到 store(按任务ID存储)
|
||||
// 🆕 保存到 store(按 Id 存储)
|
||||
agentsStore.setTaskScoreData(taskId, {
|
||||
aspectList,
|
||||
agentScores
|
||||
@@ -438,7 +490,6 @@ const initHeatmapData = async () => {
|
||||
// 获取接口数据
|
||||
const scoreData = await fetchAgentScores()
|
||||
if (!scoreData) {
|
||||
console.warn('⚠️ initHeatmapData: 没有获取到评分数据')
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
// Mock数据 - 用于agentSelectModifyAddAspect接口
|
||||
// 模拟用户输入新维度后,所有agent在该维度上的评分数据
|
||||
|
||||
import { vueAgentList } from './AgentAssignmentMock'
|
||||
|
||||
// 类型定义
|
||||
export interface NewDimensionScore {
|
||||
score: number
|
||||
reason: string
|
||||
}
|
||||
|
||||
export type NewDimensionScoreData = Record<string, NewDimensionScore>
|
||||
|
||||
// 模拟接口返回的数据结构
|
||||
export interface AgentAddAspectResponse {
|
||||
aspectName: string // 新添加的维度名称
|
||||
agentScores: NewDimensionScoreData // 所有agent在该维度上的评分
|
||||
}
|
||||
|
||||
// 生成指定维度名称的mock评分数据
|
||||
export const generateMockDimensionScores = (dimensionName: string): AgentAddAspectResponse => {
|
||||
const agentScores: NewDimensionScoreData = {}
|
||||
|
||||
vueAgentList.forEach((agent) => {
|
||||
// 随机生成1-5的评分
|
||||
const score = Math.floor(Math.random() * 5) + 1
|
||||
|
||||
// 根据评分生成不同的原因描述
|
||||
let reason = ''
|
||||
switch (score) {
|
||||
case 5:
|
||||
reason = `在"${dimensionName}"方面表现卓越,展现出杰出的能力和深刻的理解`
|
||||
break
|
||||
case 4:
|
||||
reason = `在"${dimensionName}"方面表现优秀,具有良好的专业能力和执行力`
|
||||
break
|
||||
case 3:
|
||||
reason = `在"${dimensionName}"方面表现合格,能够完成相关任务`
|
||||
break
|
||||
case 2:
|
||||
reason = `在"${dimensionName}"方面表现一般,仍有提升空间`
|
||||
break
|
||||
case 1:
|
||||
reason = `在"${dimensionName}"方面需要加强,建议进一步提升相关能力`
|
||||
break
|
||||
}
|
||||
|
||||
agentScores[agent] = { score, reason }
|
||||
})
|
||||
|
||||
return {
|
||||
aspectName: dimensionName,
|
||||
agentScores,
|
||||
}
|
||||
}
|
||||
|
||||
// 预设的一些常用维度及其评分数据
|
||||
export const presetDimensionScores: Record<string, AgentAddAspectResponse> = {
|
||||
创新性: generateMockDimensionScores('创新性'),
|
||||
技术能力: generateMockDimensionScores('技术能力'),
|
||||
沟通技巧: generateMockDimensionScores('沟通技巧'),
|
||||
问题解决: generateMockDimensionScores('问题解决'),
|
||||
团队协作: generateMockDimensionScores('团队协作'),
|
||||
学习能力: generateMockDimensionScores('学习能力'),
|
||||
执行力: generateMockDimensionScores('执行力'),
|
||||
责任心: generateMockDimensionScores('责任心'),
|
||||
适应性: generateMockDimensionScores('适应性'),
|
||||
领导力: generateMockDimensionScores('领导力'),
|
||||
}
|
||||
|
||||
// 模拟API调用函数(用于前端测试)
|
||||
export const mockAgentAddAspectApi = async (
|
||||
aspectList: string[],
|
||||
): Promise<AgentAddAspectResponse[]> => {
|
||||
// 获取新增的维度(最后一个)
|
||||
const newAspect = aspectList[aspectList.length - 1]
|
||||
|
||||
// 模拟网络延迟 500ms
|
||||
await new Promise((resolve) => setTimeout(resolve, 20000))
|
||||
|
||||
// 如果是预设维度,返回预设数据
|
||||
if (presetDimensionScores[newAspect]) {
|
||||
return [presetDimensionScores[newAspect]]
|
||||
}
|
||||
|
||||
// 否则动态生成新的评分数据
|
||||
return [generateMockDimensionScores(newAspect)]
|
||||
}
|
||||
|
||||
// Vue Composition API 兼容的hook
|
||||
export const useAgentAddAspectMock = () => {
|
||||
const addNewDimension = async (dimensionName: string) => {
|
||||
const response = await mockAgentAddAspectApi([dimensionName])
|
||||
return response[0]
|
||||
}
|
||||
|
||||
const getMultipleDimensions = async (dimensionNames: string[]) => {
|
||||
const responses: AgentAddAspectResponse[] = []
|
||||
|
||||
for (const dimension of dimensionNames) {
|
||||
if (presetDimensionScores[dimension]) {
|
||||
responses.push(presetDimensionScores[dimension])
|
||||
} else {
|
||||
responses.push(generateMockDimensionScores(dimension))
|
||||
}
|
||||
}
|
||||
|
||||
return responses
|
||||
}
|
||||
|
||||
return {
|
||||
addNewDimension,
|
||||
getMultipleDimensions,
|
||||
generateMockDimensionScores,
|
||||
}
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
// 模拟后端原始返回格式的Mock数据 - 维度 -> agent -> { Reason, Score }
|
||||
import { vueAgentList, vueAspectList } from './AgentAssignmentMock'
|
||||
|
||||
// 后端返回的评分项格式
|
||||
export interface BackendScoreItem {
|
||||
Reason: string
|
||||
Score: number
|
||||
}
|
||||
|
||||
// 后端返回的完整数据格式
|
||||
export type BackendAgentScoreResponse = Record<string, Record<string, BackendScoreItem>>
|
||||
|
||||
// 模拟后端返回的原始数据结构(维度 -> agent -> { Reason, Score })
|
||||
export const mockBackendAgentScoreData: BackendAgentScoreResponse = {
|
||||
能力: {
|
||||
船舶设计师: { Reason: '展现出卓越的创造力和创新思维', Score: 4 },
|
||||
防护工程专家: { Reason: '展现出杰出的创造性问题解决能力', Score: 5 },
|
||||
病理生理学家: { Reason: '具有中等创造技能,有待提升', Score: 3 },
|
||||
药物化学家: { Reason: '在大多数情况下展现较强的创造性思维', Score: 4 },
|
||||
制剂工程师: { Reason: '展现出胜任的创造能力', Score: 3 },
|
||||
监管事务专家: { Reason: '具有较强的创造性表达能力', Score: 4 },
|
||||
物理学家: { Reason: '擅长创新性思维方法', Score: 5 },
|
||||
实验材料学家: { Reason: '展现出卓越的创造性思维和创新能力', Score: 5 },
|
||||
计算模拟专家: { Reason: '展现出良好的创造性问题解决能力', Score: 4 },
|
||||
腐蚀机理研究员: { Reason: '展现出卓越的创造性问题解决能力', Score: 5 },
|
||||
先进材料研发员: { Reason: '展现出平衡的创造能力', Score: 4 },
|
||||
肾脏病学家: { Reason: '展现出卓越的创造天赋', Score: 5 },
|
||||
临床研究协调员: { Reason: '展现出胜任的创造性思维', Score: 3 },
|
||||
中医药专家: { Reason: '展现出较强的创造性主动性', Score: 4 },
|
||||
药物安全专家: { Reason: '具有发展中的创造技能', Score: 3 },
|
||||
二维材料科学家: { Reason: '展现出卓越的创造愿景', Score: 5 },
|
||||
光电物理学家: { Reason: '展现出卓越的创造性执行力', Score: 4 },
|
||||
机器学习专家: { Reason: '具有较强的创造性问题解决能力', Score: 4 },
|
||||
流体动力学专家: { Reason: '展现出胜任的创造能力', Score: 3 },
|
||||
},
|
||||
可用性: {
|
||||
船舶设计师: { Reason: '展现出卓越的共情能力和社会意识', Score: 5 },
|
||||
防护工程专家: { Reason: '具有较强的情绪调节和人际交往技能', Score: 4 },
|
||||
病理生理学家: { Reason: '展现出卓越的情感智力', Score: 5 },
|
||||
药物化学家: { Reason: '在大多数情况下展现平均的情感智力', Score: 3 },
|
||||
制剂工程师: { Reason: '具有良好的情绪意识和沟通能力', Score: 4 },
|
||||
监管事务专家: { Reason: '在情绪意识方面偶尔表现不足', Score: 3 },
|
||||
物理学家: { Reason: '具有较强的情绪理解能力', Score: 4 },
|
||||
实验材料学家: { Reason: '展现出卓越的共情能力和社交技能', Score: 5 },
|
||||
计算模拟专家: { Reason: '具有良好的情绪调节能力', Score: 4 },
|
||||
腐蚀机理研究员: { Reason: '展现出卓越的情感智力和社会意识', Score: 5 },
|
||||
先进材料研发员: { Reason: '具有发展中的情绪意识', Score: 3 },
|
||||
肾脏病学家: { Reason: '擅长人际交往和建立关系', Score: 5 },
|
||||
临床研究协调员: { Reason: '展现出平衡的情感智力', Score: 4 },
|
||||
中医药专家: { Reason: '具有基本的情绪理解能力', Score: 3 },
|
||||
药物安全专家: { Reason: '展现出良好的情绪调节能力', Score: 4 },
|
||||
二维材料科学家: { Reason: '展现出卓越的社会意识', Score: 5 },
|
||||
光电物理学家: { Reason: '在情感智力方面需要提升', Score: 3 },
|
||||
机器学习专家: { Reason: '具有较强的共情能力', Score: 4 },
|
||||
流体动力学专家: { Reason: '具有良好的情绪沟通技能', Score: 4 },
|
||||
},
|
||||
专业性: {
|
||||
船舶设计师: { Reason: '展现出胜任的哲学推理技能', Score: 3 },
|
||||
防护工程专家: { Reason: '展现出卓越的逻辑推理和分析能力', Score: 5 },
|
||||
病理生理学家: { Reason: '展现出深刻的哲学洞察力和批判性思维', Score: 2 },
|
||||
药物化学家: { Reason: '展现出良好的哲学理解能力', Score: 1 },
|
||||
制剂工程师: { Reason: '具有基础哲学推理能力,存在一些局限', Score: 3 },
|
||||
监管事务专家: { Reason: '展现出较强的分析思维能力', Score: 4 },
|
||||
物理学家: { Reason: '展现出卓越的哲学深度', Score: 5 },
|
||||
实验材料学家: { Reason: '展现出卓越的专业分析和推理能力', Score: 5 },
|
||||
计算模拟专家: { Reason: '具有良好的批判性思维能力', Score: 4 },
|
||||
腐蚀机理研究员: { Reason: '具有较强的专业性分析和推理能力', Score: 4 },
|
||||
先进材料研发员: { Reason: '展现出卓越的逻辑推理能力', Score: 5 },
|
||||
肾脏病学家: { Reason: '具有基础的哲学理解能力', Score: 3 },
|
||||
临床研究协调员: { Reason: '展现出平衡的哲学推理能力', Score: 4 },
|
||||
中医药专家: { Reason: '需要在哲学思维方面发展', Score: 3 },
|
||||
药物安全专家: { Reason: '展现出良好的分析技能', Score: 4 },
|
||||
二维材料科学家: { Reason: '具有较强的哲学洞察力', Score: 4 },
|
||||
光电物理学家: { Reason: '擅长批判性思维和分析', Score: 5 },
|
||||
机器学习专家: { Reason: '具有基础哲学推理能力', Score: 3 },
|
||||
流体动力学专家: { Reason: '展现出卓越的哲学才能', Score: 5 },
|
||||
},
|
||||
效率: {
|
||||
船舶设计师: { Reason: '在任务完成方面展现出卓越的效率', Score: 4 },
|
||||
防护工程专家: { Reason: '擅长高效的工作流程管理', Score: 5 },
|
||||
病理生理学家: { Reason: '展现出平均的效率,有提升空间', Score: 3 },
|
||||
药物化学家: { Reason: '具有良好的时间管理技能', Score: 4 },
|
||||
制剂工程师: { Reason: '展现出胜任的效率', Score: 3 },
|
||||
监管事务专家: { Reason: '展现出卓越的生产力', Score: 5 },
|
||||
物理学家: { Reason: '具有强大的任务执行能力', Score: 4 },
|
||||
实验材料学家: { Reason: '具有良好的工作效率和时间管理', Score: 4 },
|
||||
计算模拟专家: { Reason: '展现出良好的工作流程优化能力', Score: 4 },
|
||||
腐蚀机理研究员: { Reason: '展现出卓越的效率和工作流程管理', Score: 5 },
|
||||
先进材料研发员: { Reason: '展现出足够的效率', Score: 3 },
|
||||
肾脏病学家: { Reason: '擅长快速完成任务', Score: 5 },
|
||||
临床研究协调员: { Reason: '展现出良好的生产力', Score: 4 },
|
||||
中医药专家: { Reason: '具有中等的效率水平', Score: 3 },
|
||||
药物安全专家: { Reason: '具有较强的任务效率', Score: 4 },
|
||||
二维材料科学家: { Reason: '具有良好的执行速度', Score: 4 },
|
||||
光电物理学家: { Reason: '展现出卓越的效率', Score: 5 },
|
||||
机器学习专家: { Reason: '展现出平均的生产力', Score: 3 },
|
||||
流体动力学专家: { Reason: '在执行方面具有良好的效率', Score: 4 },
|
||||
},
|
||||
准确性: {
|
||||
船舶设计师: { Reason: '展现出卓越的细节关注度', Score: 5 },
|
||||
防护工程专家: { Reason: '展现出卓越的准确性和精确度', Score: 5 },
|
||||
病理生理学家: { Reason: '展现出卓越的精确度', Score: 5 },
|
||||
药物化学家: { Reason: '展现出良好的准确性', Score: 4 },
|
||||
制剂工程师: { Reason: '展现出中等的准确性,有提升空间', Score: 3 },
|
||||
监管事务专家: { Reason: '具有较强的细节关注度', Score: 4 },
|
||||
物理学家: { Reason: '在精确度和准确性方面表现卓越', Score: 5 },
|
||||
实验材料学家: { Reason: '展现出卓越的细节导向和精确度', Score: 5 },
|
||||
计算模拟专家: { Reason: '展现出平均的准确性', Score: 3 },
|
||||
腐蚀机理研究员: { Reason: '展现出卓越的准确性和精确技能', Score: 5 },
|
||||
先进材料研发员: { Reason: '展现出卓越的准确性', Score: 5 },
|
||||
肾脏病学家: { Reason: '展现出较强的精确度', Score: 4 },
|
||||
临床研究协调员: { Reason: '展现出中等的准确性', Score: 3 },
|
||||
中医药专家: { Reason: '具有良好的细节导向能力', Score: 4 },
|
||||
药物安全专家: { Reason: '在准确性和精确度方面表现卓越', Score: 5 },
|
||||
二维材料科学家: { Reason: '展现出较强的细节关注度', Score: 4 },
|
||||
光电物理学家: { Reason: '展现出平均的准确性水平', Score: 3 },
|
||||
机器学习专家: { Reason: '在工作中具有良好的精确度', Score: 4 },
|
||||
流体动力学专家: { Reason: '展现出卓越的准确性', Score: 5 },
|
||||
},
|
||||
协作性: {
|
||||
船舶设计师: { Reason: '展现出卓越的协作技能', Score: 4 },
|
||||
防护工程专家: { Reason: '在团队合作和协作方面表现卓越', Score: 5 },
|
||||
病理生理学家: { Reason: '具有较强的协作能力', Score: 4 },
|
||||
药物化学家: { Reason: '具有中等的协作技能', Score: 3 },
|
||||
制剂工程师: { Reason: '展现出良好的团队合作精神', Score: 4 },
|
||||
监管事务专家: { Reason: '具有较强的合作能力', Score: 4 },
|
||||
物理学家: { Reason: '展现出平均的协作技能', Score: 3 },
|
||||
实验材料学家: { Reason: '在团队协作方面表现卓越', Score: 5 },
|
||||
计算模拟专家: { Reason: '展现出良好的合作工作能力', Score: 4 },
|
||||
腐蚀机理研究员: { Reason: '在团队协作和合作方面表现卓越', Score: 5 },
|
||||
先进材料研发员: { Reason: '具有中等的协作水平', Score: 3 },
|
||||
肾脏病学家: { Reason: '展现出良好的协作技能', Score: 4 },
|
||||
临床研究协调员: { Reason: '在协调和团队合作方面表现卓越', Score: 5 },
|
||||
中医药专家: { Reason: '具有较强的合作能力', Score: 4 },
|
||||
药物安全专家: { Reason: '展现出平均的协作水平', Score: 3 },
|
||||
二维材料科学家: { Reason: '展现出良好的团队合作精神', Score: 4 },
|
||||
光电物理学家: { Reason: '具有较强的协作技能', Score: 4 },
|
||||
机器学习专家: { Reason: '在团队协作方面表现卓越', Score: 5 },
|
||||
流体动力学专家: { Reason: '具有中等的协作能力', Score: 3 },
|
||||
},
|
||||
}
|
||||
|
||||
// 模拟后端API调用 - agentSelectModifyInit
|
||||
export const mockBackendAgentSelectModifyInit = async (): Promise<BackendAgentScoreResponse> => {
|
||||
// 模拟网络延迟 300ms
|
||||
await new Promise(resolve => setTimeout(resolve, 300))
|
||||
return mockBackendAgentScoreData
|
||||
}
|
||||
|
||||
// 模拟后端API调用 - agentSelectModifyAddAspect(添加新维度)
|
||||
export const mockBackendAgentSelectModifyAddAspect = async (
|
||||
aspectList: string[]
|
||||
): Promise<BackendAgentScoreResponse> => {
|
||||
// 模拟网络延迟 500ms
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
|
||||
// 获取新添加的维度(最后一个)
|
||||
const newAspect = aspectList[aspectList.length - 1]
|
||||
if (!newAspect) {
|
||||
return {}
|
||||
}
|
||||
|
||||
// 生成该维度下所有agent的评分
|
||||
const aspectData: Record<string, BackendScoreItem> = {}
|
||||
|
||||
vueAgentList.forEach(agent => {
|
||||
const score = Math.floor(Math.random() * 5) + 1
|
||||
let reason = ''
|
||||
switch (score) {
|
||||
case 5:
|
||||
reason = `在"${newAspect}"方面表现卓越,展现出杰出的能力和深刻的理解`
|
||||
break
|
||||
case 4:
|
||||
reason = `在"${newAspect}"方面表现优秀,具有良好的专业能力和执行力`
|
||||
break
|
||||
case 3:
|
||||
reason = `在"${newAspect}"方面表现合格,能够完成相关任务`
|
||||
break
|
||||
case 2:
|
||||
reason = `在"${newAspect}"方面表现一般,仍有提升空间`
|
||||
break
|
||||
case 1:
|
||||
reason = `在"${newAspect}"方面需要加强,建议进一步提升相关能力`
|
||||
break
|
||||
}
|
||||
aspectData[agent] = { Reason: reason, Score: score }
|
||||
})
|
||||
|
||||
return {
|
||||
[newAspect]: aspectData
|
||||
}
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
// Vue兼容的mock数据 - 6个维度,19个智能体
|
||||
export const vueAgentList = [
|
||||
'船舶设计师',
|
||||
'防护工程专家',
|
||||
'病理生理学家',
|
||||
'药物化学家',
|
||||
'制剂工程师',
|
||||
'监管事务专家',
|
||||
'物理学家',
|
||||
'实验材料学家',
|
||||
'计算模拟专家',
|
||||
'腐蚀机理研究员',
|
||||
'先进材料研发员',
|
||||
'肾脏病学家',
|
||||
'临床研究协调员',
|
||||
'中医药专家',
|
||||
'药物安全专家',
|
||||
'二维材料科学家',
|
||||
'光电物理学家',
|
||||
'机器学习专家',
|
||||
'流体动力学专家',
|
||||
]
|
||||
|
||||
export const vueAspectList = ['能力', '可用性', '专业性', '效率', '准确性', '协作性']
|
||||
|
||||
// 类型定义
|
||||
export type AgentName = (typeof vueAgentList)[number]
|
||||
export type AspectName = (typeof vueAspectList)[number]
|
||||
|
||||
export interface AgentScore {
|
||||
score: number
|
||||
reason: string
|
||||
}
|
||||
|
||||
export type IAgentSelectModifyAddRequest = Record<AspectName, Record<AgentName, AgentScore>>
|
||||
|
||||
// Vue友好的数据结构 - agent -> 维度 -> 评分(与后端返回格式一致)
|
||||
export const vueAgentScoreData: Record<AgentName, Record<AspectName, AgentScore>> = {
|
||||
船舶设计师: {
|
||||
能力: { score: 4, reason: '展现出卓越的创造力和创新思维' },
|
||||
可用性: { score: 5, reason: '展现出卓越的共情能力和社会意识' },
|
||||
专业性: { score: 3, reason: '展现出胜任的哲学推理技能' },
|
||||
效率: { score: 4, reason: '在任务完成方面展现出卓越的效率' },
|
||||
准确性: { score: 5, reason: '展现出卓越的细节关注度' },
|
||||
协作性: { score: 4, reason: '展现出卓越的协作技能' },
|
||||
},
|
||||
防护工程专家: {
|
||||
能力: { score: 5, reason: '展现出杰出的创造性问题解决能力' },
|
||||
可用性: { score: 4, reason: '具有较强的情绪调节和人际交往技能' },
|
||||
专业性: { score: 5, reason: '展现出卓越的逻辑推理和分析能力' },
|
||||
效率: { score: 5, reason: '擅长高效的工作流程管理' },
|
||||
准确性: { score: 5, reason: '展现出卓越的准确性和精确度' },
|
||||
协作性: { score: 5, reason: '在团队合作和协作方面表现卓越' },
|
||||
},
|
||||
病理生理学家: {
|
||||
能力: { score: 3, reason: '具有中等创造技能,有待提升' },
|
||||
可用性: { score: 5, reason: '展现出卓越的情感智力' },
|
||||
专业性: { score: 2, reason: '展现出深刻的哲学洞察力和批判性思维' },
|
||||
效率: { score: 3, reason: '展现出平均的效率,有提升空间' },
|
||||
准确性: { score: 5, reason: '展现出卓越的精确度' },
|
||||
协作性: { score: 4, reason: '具有较强的协作能力' },
|
||||
},
|
||||
药物化学家: {
|
||||
能力: { score: 4, reason: '在大多数情况下展现较强的创造性思维' },
|
||||
可用性: { score: 3, reason: '在大多数情况下展现平均的情感智力' },
|
||||
专业性: { score: 1, reason: '展现出良好的哲学理解能力' },
|
||||
效率: { score: 4, reason: '具有良好的时间管理技能' },
|
||||
准确性: { score: 4, reason: '展现出良好的准确性' },
|
||||
协作性: { score: 3, reason: '具有中等的协作技能' },
|
||||
},
|
||||
制剂工程师: {
|
||||
能力: { score: 3, reason: '展现出胜任的创造能力' },
|
||||
可用性: { score: 4, reason: '具有良好的情绪意识和沟通能力' },
|
||||
专业性: { score: 3, reason: '具有基础哲学推理能力,存在一些局限' },
|
||||
效率: { score: 3, reason: '展现出胜任的效率' },
|
||||
准确性: { score: 3, reason: '展现出中等的准确性,有提升空间' },
|
||||
协作性: { score: 4, reason: '展现出良好的团队合作精神' },
|
||||
},
|
||||
监管事务专家: {
|
||||
能力: { score: 4, reason: '具有较强的创造性表达能力' },
|
||||
可用性: { score: 3, reason: '在情绪意识方面偶尔表现不足' },
|
||||
专业性: { score: 4, reason: '展现出较强的分析思维能力' },
|
||||
效率: { score: 5, reason: '展现出卓越的生产力' },
|
||||
准确性: { score: 4, reason: '具有较强的细节关注度' },
|
||||
协作性: { score: 4, reason: '具有较强的合作能力' },
|
||||
},
|
||||
物理学家: {
|
||||
能力: { score: 5, reason: '擅长创新性思维方法' },
|
||||
可用性: { score: 4, reason: '具有较强的情绪理解能力' },
|
||||
专业性: { score: 5, reason: '展现出卓越的哲学深度' },
|
||||
效率: { score: 4, reason: '具有强大的任务执行能力' },
|
||||
准确性: { score: 5, reason: '在精确度和准确性方面表现卓越' },
|
||||
协作性: { score: 3, reason: '展现出平均的协作技能' },
|
||||
},
|
||||
实验材料学家: {
|
||||
能力: { score: 5, reason: '展现出卓越的创造性思维和创新能力' },
|
||||
可用性: { score: 5, reason: '展现出卓越的共情能力和社交技能' },
|
||||
专业性: { score: 5, reason: '展现出卓越的专业分析和推理能力' },
|
||||
效率: { score: 4, reason: '具有良好的工作效率和时间管理' },
|
||||
准确性: { score: 5, reason: '展现出卓越的细节导向和精确度' },
|
||||
协作性: { score: 5, reason: '在团队协作方面表现卓越' },
|
||||
},
|
||||
计算模拟专家: {
|
||||
能力: { score: 4, reason: '展现出良好的创造性问题解决能力' },
|
||||
可用性: { score: 4, reason: '具有良好的情绪调节能力' },
|
||||
专业性: { score: 4, reason: '具有良好的批判性思维能力' },
|
||||
效率: { score: 4, reason: '展现出良好的工作流程优化能力' },
|
||||
准确性: { score: 3, reason: '展现出平均的准确性' },
|
||||
协作性: { score: 4, reason: '展现出良好的合作工作能力' },
|
||||
},
|
||||
腐蚀机理研究员: {
|
||||
能力: { score: 5, reason: '展现出卓越的创造性问题解决能力' },
|
||||
可用性: { score: 5, reason: '展现出卓越的情感智力和社会意识' },
|
||||
专业性: { score: 4, reason: '具有较强的专业性分析和推理能力' },
|
||||
效率: { score: 5, reason: '展现出卓越的效率和工作流程管理' },
|
||||
准确性: { score: 5, reason: '展现出卓越的准确性和精确技能' },
|
||||
协作性: { score: 5, reason: '在团队协作和合作方面表现卓越' },
|
||||
},
|
||||
先进材料研发员: {
|
||||
能力: { score: 4, reason: '展现出平衡的创造能力' },
|
||||
可用性: { score: 3, reason: '具有发展中的情绪意识' },
|
||||
专业性: { score: 5, reason: '展现出卓越的逻辑推理能力' },
|
||||
效率: { score: 3, reason: '展现出足够的效率' },
|
||||
准确性: { score: 5, reason: '展现出卓越的准确性' },
|
||||
协作性: { score: 3, reason: '具有中等的协作水平' },
|
||||
},
|
||||
肾脏病学家: {
|
||||
能力: { score: 5, reason: '展现出卓越的创造天赋' },
|
||||
可用性: { score: 5, reason: '擅长人际交往和建立关系' },
|
||||
专业性: { score: 3, reason: '具有基础的哲学理解能力' },
|
||||
效率: { score: 5, reason: '擅长快速完成任务' },
|
||||
准确性: { score: 4, reason: '展现出较强的精确度' },
|
||||
协作性: { score: 4, reason: '展现出良好的协作技能' },
|
||||
},
|
||||
临床研究协调员: {
|
||||
能力: { score: 3, reason: '展现出胜任的创造性思维' },
|
||||
可用性: { score: 4, reason: '展现出平衡的情感智力' },
|
||||
专业性: { score: 4, reason: '展现出平衡的哲学推理能力' },
|
||||
效率: { score: 4, reason: '展现出良好的生产力' },
|
||||
准确性: { score: 3, reason: '展现出中等的准确性' },
|
||||
协作性: { score: 5, reason: '在协调和团队合作方面表现卓越' },
|
||||
},
|
||||
中医药专家: {
|
||||
能力: { score: 4, reason: '展现出较强的创造性主动性' },
|
||||
可用性: { score: 3, reason: '具有基本的情绪理解能力' },
|
||||
专业性: { score: 3, reason: '需要在哲学思维方面发展' },
|
||||
效率: { score: 3, reason: '具有中等的效率水平' },
|
||||
准确性: { score: 4, reason: '具有良好的细节导向能力' },
|
||||
协作性: { score: 4, reason: '具有较强的合作能力' },
|
||||
},
|
||||
药物安全专家: {
|
||||
能力: { score: 3, reason: '具有发展中的创造技能' },
|
||||
可用性: { score: 4, reason: '展现出良好的情绪调节能力' },
|
||||
专业性: { score: 4, reason: '展现出良好的分析技能' },
|
||||
效率: { score: 4, reason: '具有较强的任务效率' },
|
||||
准确性: { score: 5, reason: '在准确性和精确度方面表现卓越' },
|
||||
协作性: { score: 3, reason: '展现出平均的协作水平' },
|
||||
},
|
||||
二维材料科学家: {
|
||||
能力: { score: 5, reason: '展现出卓越的创造愿景' },
|
||||
可用性: { score: 5, reason: '展现出卓越的社会意识' },
|
||||
专业性: { score: 4, reason: '具有较强的哲学洞察力' },
|
||||
效率: { score: 4, reason: '具有良好的执行速度' },
|
||||
准确性: { score: 4, reason: '展现出较强的细节关注度' },
|
||||
协作性: { score: 4, reason: '展现出良好的团队合作精神' },
|
||||
},
|
||||
光电物理学家: {
|
||||
能力: { score: 4, reason: '展现出卓越的创造性执行力' },
|
||||
可用性: { score: 3, reason: '在情感智力方面需要提升' },
|
||||
专业性: { score: 5, reason: '擅长批判性思维和分析' },
|
||||
效率: { score: 5, reason: '展现出卓越的效率' },
|
||||
准确性: { score: 3, reason: '展现出平均的准确性水平' },
|
||||
协作性: { score: 4, reason: '具有较强的协作技能' },
|
||||
},
|
||||
机器学习专家: {
|
||||
能力: { score: 4, reason: '具有较强的创造性问题解决能力' },
|
||||
可用性: { score: 4, reason: '具有较强的共情能力' },
|
||||
专业性: { score: 3, reason: '具有基础哲学推理能力' },
|
||||
效率: { score: 3, reason: '展现出平均的生产力' },
|
||||
准确性: { score: 4, reason: '在工作中具有良好的精确度' },
|
||||
协作性: { score: 5, reason: '在团队协作方面表现卓越' },
|
||||
},
|
||||
流体动力学专家: {
|
||||
能力: { score: 3, reason: '展现出胜任的创造能力' },
|
||||
可用性: { score: 4, reason: '具有良好的情绪沟通技能' },
|
||||
专业性: { score: 5, reason: '展现出卓越的哲学才能' },
|
||||
效率: { score: 4, reason: '在执行方面具有良好的效率' },
|
||||
准确性: { score: 5, reason: '展现出卓越的准确性' },
|
||||
协作性: { score: 3, reason: '具有中等的协作能力' },
|
||||
},
|
||||
}
|
||||
|
||||
// Vue友好的智能体选择配置
|
||||
export const vueAgentSelections = {
|
||||
balanced: { agents: ['船舶设计师', '防护工程专家', '病理生理学家'] },
|
||||
creative: { agents: ['防护工程专家', '物理学家', '二维材料科学家'] },
|
||||
emotional: { agents: ['船舶设计师', '病理生理学家', '实验材料学家'] },
|
||||
philosophical: { agents: ['病理生理学家', '物理学家', '光电物理学家'] },
|
||||
mixed: { agents: ['药物化学家', '先进材料研发员', '肾脏病学家', '机器学习专家'] },
|
||||
}
|
||||
|
||||
export const vueCurrentAgentSelection = 'balanced'
|
||||
|
||||
// Vue兼容的工具函数
|
||||
export const vueCalculateAgentAverages = () => {
|
||||
const averages: Record<string, number> = {}
|
||||
|
||||
vueAgentList.forEach((agent) => {
|
||||
let total = 0
|
||||
let count = 0
|
||||
|
||||
vueAspectList.forEach((aspect) => {
|
||||
// 数据结构:agentScores[agent][aspect]
|
||||
const scoreData = vueAgentScoreData[agent]?.[aspect]
|
||||
if (scoreData) {
|
||||
total += scoreData.score
|
||||
count++
|
||||
}
|
||||
})
|
||||
|
||||
averages[agent] = count > 0 ? Number((total / count).toFixed(2)) : 0
|
||||
})
|
||||
|
||||
return averages
|
||||
}
|
||||
|
||||
// 获取按平均分排序的智能体列表
|
||||
export const vueGetSortedAgentsByAverage = () => {
|
||||
const averages = vueCalculateAgentAverages()
|
||||
return [...vueAgentList].sort((a, b) => {
|
||||
return averages[b] - averages[a]
|
||||
})
|
||||
}
|
||||
|
||||
// Vue Composition API 兼容的hook
|
||||
export const useAgentMockData = () => {
|
||||
// 在Vue中可以使用ref或reactive包装数据
|
||||
const agentScores = vueAgentScoreData
|
||||
const agentSelections = vueAgentSelections
|
||||
const currentSelection = vueCurrentAgentSelection
|
||||
|
||||
// 计算平均分的响应式函数
|
||||
const calculateAverages = () => {
|
||||
return vueCalculateAgentAverages()
|
||||
}
|
||||
|
||||
// 获取特定维度的评分(返回该维度下所有智能体的评分)
|
||||
const getScoresByAspect = (aspect: AspectName) => {
|
||||
const result: Record<AgentName, AgentScore> = {}
|
||||
// 数据结构:agentScores[agent][aspect],需要遍历所有agent提取指定aspect
|
||||
vueAgentList.forEach((agent) => {
|
||||
if (agentScores[agent]?.[aspect]) {
|
||||
result[agent] = agentScores[agent][aspect]!
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
// 获取特定智能体的所有维度评分
|
||||
const getScoresByAgent = (agent: AgentName) => {
|
||||
// 数据结构:agentScores[agent][aspect],直接返回agent的所有维度评分
|
||||
return agentScores[agent] || {}
|
||||
}
|
||||
|
||||
return {
|
||||
agentScores,
|
||||
agentSelections,
|
||||
currentSelection,
|
||||
calculateAverages,
|
||||
getScoresByAspect,
|
||||
getScoresByAgent,
|
||||
getSortedAgents: vueGetSortedAgentsByAverage,
|
||||
}
|
||||
}
|
||||
|
||||
// Vue 2.x 兼容的选项式API版本
|
||||
export const vueMockMixin = {
|
||||
data() {
|
||||
return {
|
||||
vueAgentScores: vueAgentScoreData,
|
||||
vueAgentSelections: vueAgentSelections,
|
||||
vueCurrentSelection: vueCurrentAgentSelection,
|
||||
vueAgentList: vueAgentList,
|
||||
vueAspectList: vueAspectList,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
vueAgentAverages() {
|
||||
return vueCalculateAgentAverages()
|
||||
},
|
||||
vueSortedAgents() {
|
||||
return vueGetSortedAgentsByAverage()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
vueGetScoresByAspect(aspect: AspectName) {
|
||||
const agentScores = (this as any).vueAgentScores
|
||||
const agentList = (this as any).vueAgentList
|
||||
// 数据结构:agentScores[agent][aspect],遍历所有agent提取指定aspect
|
||||
const result: Record<string, { score: number; reason: string }> = {}
|
||||
agentList.forEach((agent: string) => {
|
||||
if (agentScores[agent]?.[aspect]) {
|
||||
result[agent] = agentScores[agent][aspect]
|
||||
}
|
||||
})
|
||||
return result
|
||||
},
|
||||
vueGetScoresByAgent(agent: AgentName) {
|
||||
const agentScores = (this as any).vueAgentScores
|
||||
// 数据结构:agentScores[agent][aspect],直接返回agent的所有维度评分
|
||||
return agentScores[agent] || {}
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import SvgIcon from '@/components/SvgIcon/index.vue'
|
||||
import { getAgentMapIcon } from '@/layout/components/config.ts'
|
||||
import { type ConnectArg, Jsplumb } from '@/layout/components/Main/TaskTemplate/utils.ts'
|
||||
import { type IRawStepTask, useAgentsStore } from '@/stores'
|
||||
// import api from '@/api'
|
||||
import { computed, nextTick, watch, onMounted } from 'vue'
|
||||
import { AnchorLocations } from '@jsplumb/browser-ui'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
@@ -109,7 +110,7 @@ watch(
|
||||
)
|
||||
|
||||
// 保存编辑内容
|
||||
const handleContentSave = (taskId: string, content: string) => {
|
||||
const handleContentSave = async (taskId: string, content: string) => {
|
||||
const taskToUpdate = collaborationProcess.value.find(item => item.Id === taskId)
|
||||
if (taskToUpdate && content !== taskToUpdate.TaskContent) {
|
||||
taskToUpdate.TaskContent = content
|
||||
@@ -118,6 +119,18 @@ const handleContentSave = (taskId: string, content: string) => {
|
||||
if (stepIndex >= 0) {
|
||||
agentsStore.addModifiedStep(stepIndex)
|
||||
}
|
||||
|
||||
//暂时注释掉直接保存 task_outline 的操作,避免覆盖整个主流程
|
||||
// 如果需要持久化,应该只更新变化的字段或使用专门的 API
|
||||
// const dbTaskId = (window as any).__CURRENT_TASK_ID__
|
||||
// if (dbTaskId && agentsStore.agentRawPlan.data) {
|
||||
// try {
|
||||
// await api.updateTaskOutline(dbTaskId, agentsStore.agentRawPlan.data)
|
||||
// console.log('[handleContentSave] 主流程已保存到数据库')
|
||||
// } catch (error) {
|
||||
// console.error('[handleContentSave] 保存主流程失败:', error)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,12 @@ import { Jsplumb } from './utils.ts'
|
||||
import { type IRawStepTask, useAgentsStore } from '@/stores'
|
||||
import { BezierConnector } from '@jsplumb/browser-ui'
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 定义组件 props
|
||||
const props = defineProps<{
|
||||
TaskID?: string // 任务唯一标识,用于写入数据库
|
||||
}>()
|
||||
|
||||
const agentsStore = useAgentsStore()
|
||||
|
||||
// 智能体库
|
||||
@@ -100,6 +106,7 @@ defineExpose({
|
||||
<div class="flex-1 h-full">
|
||||
<TaskResult
|
||||
ref="taskResultRef"
|
||||
:TaskID="props.TaskID"
|
||||
@refresh-line="taskResultJsplumb.repaintEverything"
|
||||
@set-current-task="handleTaskResultCurrentTask"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user