feat:代码优化与Mock数据清理
This commit is contained in:
@@ -3,7 +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 { computed, ref, nextTick, watch, onMounted } from 'vue'
|
||||
import { computed, nextTick, watch, onMounted } from 'vue'
|
||||
import { AnchorLocations } from '@jsplumb/browser-ui'
|
||||
import { Loading } from '@element-plus/icons-vue'
|
||||
import MultiLineTooltip from '@/components/MultiLineTooltip/index.vue'
|
||||
@@ -11,6 +11,7 @@ import Bg from './Bg.vue'
|
||||
import BranchButton from './components/BranchButton.vue'
|
||||
import Notification from '@/components/Notification/Notification.vue'
|
||||
import { useNotification } from '@/composables/useNotification'
|
||||
import TaskContentEditor from '@/components/TaskContentEditor/index.vue'
|
||||
|
||||
// 判断计划是否就绪
|
||||
const planReady = computed(() => {
|
||||
@@ -24,8 +25,6 @@ const openPlanModification = () => {
|
||||
const emit = defineEmits<{
|
||||
(el: 'resetAgentRepoLine'): void
|
||||
(el: 'setCurrentTask', task: IRawStepTask): void
|
||||
(el: 'add-output', outputName: string): void
|
||||
(el: 'click-branch'): void
|
||||
}>()
|
||||
|
||||
const jsplumb = new Jsplumb('task-syllabus')
|
||||
@@ -40,7 +39,7 @@ const collaborationProcess = computed(() => {
|
||||
return agentsStore.agentRawPlan.data?.['Collaboration Process'] ?? []
|
||||
})
|
||||
|
||||
// 检测是否正在填充详情(有步骤但没有 AgentSelection)
|
||||
// 检测是否正在填充详情
|
||||
const isFillingDetails = computed(() => {
|
||||
const process = agentsStore.agentRawPlan.data?.['Collaboration Process'] || []
|
||||
return (
|
||||
@@ -59,8 +58,13 @@ const totalSteps = computed(() => {
|
||||
return agentsStore.agentRawPlan.data?.['Collaboration Process']?.length || 0
|
||||
})
|
||||
|
||||
// Notification system
|
||||
const { notifications, progress: showProgress, updateProgressDetail, removeNotification } = useNotification()
|
||||
// Notification 通知
|
||||
const {
|
||||
notifications,
|
||||
progress: showProgress,
|
||||
updateProgressDetail,
|
||||
removeNotification
|
||||
} = useNotification()
|
||||
const fillingProgressNotificationId = ref<string | null>(null)
|
||||
|
||||
// 监听填充进度,显示通知
|
||||
@@ -77,11 +81,7 @@ watch(
|
||||
if (filling && total > 0) {
|
||||
if (!fillingProgressNotificationId.value) {
|
||||
// 创建进度通知
|
||||
fillingProgressNotificationId.value = showProgress(
|
||||
'生成协作流程',
|
||||
completed,
|
||||
total
|
||||
)
|
||||
fillingProgressNotificationId.value = showProgress('生成协作流程', completed, total)
|
||||
updateProgressDetail(
|
||||
fillingProgressNotificationId.value,
|
||||
`${completed}/${total}`,
|
||||
@@ -108,138 +108,19 @@ watch(
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// 编辑状态管理
|
||||
const editingTaskId = ref<string | null>(null)
|
||||
const editingContent = ref('')
|
||||
|
||||
// 添加新产物状态管理
|
||||
const isAddingOutput = ref(false)
|
||||
const newOutputInputRef = ref<HTMLElement>()
|
||||
const newOutputName = ref('')
|
||||
|
||||
// 处理加号点击
|
||||
const handleAddOutputClick = () => {
|
||||
isAddingOutput.value = true
|
||||
newOutputName.value = ''
|
||||
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
if (newOutputInputRef.value) {
|
||||
newOutputInputRef.value?.focus()
|
||||
}
|
||||
jsplumb.instance.repaintEverything()
|
||||
}, 50)
|
||||
})
|
||||
}
|
||||
|
||||
// 保存新产物
|
||||
const saveNewOutput = () => {
|
||||
if (newOutputName.value.trim()) {
|
||||
const outputName = newOutputName.value.trim()
|
||||
const success = agentsStore.addNewOutput(outputName)
|
||||
if (success) {
|
||||
emit('add-output', outputName)
|
||||
isAddingOutput.value = false
|
||||
newOutputName.value = ''
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
jsplumb.instance.repaintEverything()
|
||||
}, 50)
|
||||
})
|
||||
console.log('添加新产物成功', outputName)
|
||||
} else {
|
||||
// 退出编辑状态
|
||||
isAddingOutput.value = false
|
||||
newOutputName.value = ''
|
||||
// 保存编辑内容
|
||||
const handleContentSave = (taskId: string, content: string) => {
|
||||
const taskToUpdate = collaborationProcess.value.find(item => item.Id === taskId)
|
||||
if (taskToUpdate && content !== taskToUpdate.TaskContent) {
|
||||
taskToUpdate.TaskContent = content
|
||||
// 记录修改过的步骤索引到store用于重新执行
|
||||
const stepIndex = collaborationProcess.value.findIndex(item => item.Id === taskId)
|
||||
if (stepIndex >= 0) {
|
||||
agentsStore.addModifiedStep(stepIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 取消添加产物
|
||||
const cancelAddOutput = () => {
|
||||
isAddingOutput.value = false
|
||||
newOutputName.value = ''
|
||||
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
jsplumb.instance.repaintEverything()
|
||||
}, 50)
|
||||
})
|
||||
}
|
||||
|
||||
// 处理新产物的键盘事件
|
||||
const handleNewOutputKeydown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault()
|
||||
saveNewOutput()
|
||||
} else if (event.key === 'Escape') {
|
||||
cancelAddOutput()
|
||||
}
|
||||
}
|
||||
|
||||
// 新产物输入框失去焦点处理
|
||||
const handleNewOutputBlur = () => {
|
||||
setTimeout(() => {
|
||||
if (newOutputName.value.trim() === '') {
|
||||
cancelAddOutput()
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
|
||||
// 开始编辑
|
||||
const startEditing = (task: IRawStepTask) => {
|
||||
if (!task.Id) {
|
||||
console.warn('Task ID is missing, cannot start editing')
|
||||
return
|
||||
}
|
||||
editingTaskId.value = task.Id
|
||||
editingContent.value = task.TaskContent || ''
|
||||
}
|
||||
|
||||
// 保存编辑
|
||||
const saveEditing = () => {
|
||||
if (editingTaskId.value && editingContent.value.trim()) {
|
||||
const taskToUpdate = collaborationProcess.value.find(item => item.Id === editingTaskId.value)
|
||||
if (taskToUpdate) {
|
||||
// 保存旧值用于比较
|
||||
const oldValue = taskToUpdate.TaskContent
|
||||
const newValue = editingContent.value.trim()
|
||||
|
||||
// 只有内容真正变化时才更新和记录修改
|
||||
if (newValue !== oldValue) {
|
||||
taskToUpdate.TaskContent = newValue
|
||||
|
||||
// 记录修改过的步骤索引到 store(用于重新执行)
|
||||
const stepIndex = collaborationProcess.value.findIndex(item => item.Id === editingTaskId.value)
|
||||
if (stepIndex >= 0) {
|
||||
agentsStore.addModifiedStep(stepIndex)
|
||||
console.log(`📝 步骤 ${stepIndex + 1} (${taskToUpdate.StepName}) 的 TaskContent 已被修改,将从该步骤重新执行`)
|
||||
}
|
||||
} else {
|
||||
console.log(`ℹ️ 步骤 ${taskToUpdate.StepName} 的 TaskContent 未发生变化,不记录修改`)
|
||||
}
|
||||
}
|
||||
}
|
||||
editingTaskId.value = null
|
||||
editingContent.value = ''
|
||||
}
|
||||
|
||||
// 取消编辑
|
||||
const cancelEditing = () => {
|
||||
editingTaskId.value = null
|
||||
editingContent.value = ''
|
||||
}
|
||||
|
||||
// 处理键盘事件
|
||||
const handleKeydown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault()
|
||||
saveEditing()
|
||||
} else if (event.key === 'Escape') {
|
||||
cancelEditing()
|
||||
}
|
||||
}
|
||||
|
||||
function handleCurrentTask(task: IRawStepTask, transparent: boolean): ConnectArg[] {
|
||||
// 创建当前流程与产出的连线
|
||||
const arr: ConnectArg[] = [
|
||||
@@ -290,21 +171,14 @@ function clear() {
|
||||
|
||||
// 封装连线重绘方法
|
||||
const redrawConnections = () => {
|
||||
// 等待 DOM 更新完成
|
||||
nextTick(() => {
|
||||
// 清除旧连线
|
||||
jsplumb.reset()
|
||||
|
||||
// 等待 DOM 稳定后重新绘制
|
||||
setTimeout(() => {
|
||||
const arr: ConnectArg[] = []
|
||||
const currentTaskId = agentsStore.currentTask?.Id
|
||||
|
||||
// 重新绘制所有连线
|
||||
collaborationProcess.value.forEach(item => {
|
||||
arr.push(...handleCurrentTask(item, item.Id !== currentTaskId))
|
||||
})
|
||||
|
||||
jsplumb.connects(arr)
|
||||
}, 100)
|
||||
})
|
||||
@@ -321,7 +195,6 @@ watch(
|
||||
|
||||
// 组件挂载后初始化连线
|
||||
onMounted(() => {
|
||||
// 初始化时绘制连线
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
const arr: ConnectArg[] = []
|
||||
@@ -341,11 +214,8 @@ defineExpose({
|
||||
|
||||
<template>
|
||||
<div class="h-full flex flex-col">
|
||||
<!-- Notification 通知系统 -->
|
||||
<Notification
|
||||
:notifications="notifications"
|
||||
@close="(id) => removeNotification(id)"
|
||||
/>
|
||||
<!-- Notification 通知 -->
|
||||
<Notification :notifications="notifications" @close="id => removeNotification(id)" />
|
||||
|
||||
<div class="text-[18px] font-bold mb-[18px] text-[var(--color-text-title-header)]">
|
||||
任务大纲
|
||||
@@ -361,8 +231,7 @@ defineExpose({
|
||||
class="w-full relative min-h-full"
|
||||
id="task-syllabus"
|
||||
>
|
||||
<Bg :is-adding="isAddingOutput" @start-add-output="handleAddOutputClick" />
|
||||
|
||||
<Bg />
|
||||
<div class="w-full flex items-center gap-[14%] mb-[35px]">
|
||||
<div class="flex-1 flex justify-center">
|
||||
<div
|
||||
@@ -380,47 +249,6 @@ defineExpose({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加新产物卡片 -->
|
||||
<div
|
||||
v-if="isAddingOutput"
|
||||
class="card-it w-full flex items-center gap-[14%] bg-[var(--color-card-bg)] add-output-form mb-[100px]"
|
||||
>
|
||||
<!-- 左侧空白的流程卡片占位 -->
|
||||
<div class="w-[43%] relative z-99" style="height: 20px"></div>
|
||||
|
||||
<!-- 右侧可编辑的产物卡片 -->
|
||||
<el-card
|
||||
class="w-[43%] relative task-syllabus-output-object-card border-dashed border-2 border-[var(--color-primary)]"
|
||||
>
|
||||
<div class="h-full flex items-center justify-center">
|
||||
<!-- 输入框 -->
|
||||
<el-input
|
||||
ref="newOutputInputRef"
|
||||
v-model="newOutputName"
|
||||
placeholder="Enter保存,ESC取消"
|
||||
@keydown="handleNewOutputKeydown"
|
||||
@blur="handleNewOutputBlur"
|
||||
size="large"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 显示临时产物卡片 -->
|
||||
<div
|
||||
v-for="output in agentsStore.additionalOutputs"
|
||||
:key="output"
|
||||
class="card-it w-full flex items-center gap-[14%] bg-[var(--color-card-bg)] mb-[100px]"
|
||||
>
|
||||
<!-- 左侧空白的流程卡片占位 -->
|
||||
<div class="w-[43%] relative z-99" style="height: 100px"></div>
|
||||
|
||||
<!-- 右侧产物卡片 -->
|
||||
<el-card class="w-[43%] relative task-syllabus-output-object-card" :shadow="true">
|
||||
<div class="text-[18px] font-bold text-center">{{ output }}</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<div
|
||||
v-for="item in collaborationProcess"
|
||||
:key="item.Id"
|
||||
@@ -440,49 +268,25 @@ defineExpose({
|
||||
<div class="h-[1px] w-full bg-[var(--color-border-separate)] my-[8px]"></div>
|
||||
|
||||
<!-- 任务内容区域 - 支持双击编辑 -->
|
||||
<div v-if="editingTaskId === item.Id" class="w-full">
|
||||
<div class="flex flex-col gap-3">
|
||||
<el-input
|
||||
v-model="editingContent"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 4 }"
|
||||
placeholder="请输入任务内容"
|
||||
@keydown="handleKeydown"
|
||||
class="task-content-editor"
|
||||
size="small"
|
||||
/>
|
||||
<div class="flex justify-end">
|
||||
<svg-icon
|
||||
icon-class="Check"
|
||||
size="20px"
|
||||
color="#328621"
|
||||
class="cursor-pointer mr-4"
|
||||
@click="saveEditing"
|
||||
title="保存"
|
||||
/>
|
||||
<svg-icon
|
||||
icon-class="Cancel"
|
||||
size="20px"
|
||||
color="#8e0707"
|
||||
class="cursor-pointer mr-1"
|
||||
@click="cancelEditing"
|
||||
title="取消"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else @dblclick="startEditing(item)" class="w-full cursor-pointer">
|
||||
<MultiLineTooltip placement="right" :text="item.TaskContent" :lines="3">
|
||||
<div class="text-[14px] text-[var(--color-text-secondary)] task-content-display">
|
||||
{{ item.TaskContent }}
|
||||
</div>
|
||||
</MultiLineTooltip>
|
||||
</div>
|
||||
<TaskContentEditor :task="item" @save="handleContentSave">
|
||||
<template #display>
|
||||
<MultiLineTooltip placement="right" :text="item.TaskContent" :lines="3">
|
||||
<div class="text-[14px] text-[var(--color-text-secondary)] task-content-display">
|
||||
{{ item.TaskContent }}
|
||||
</div>
|
||||
</MultiLineTooltip>
|
||||
</template>
|
||||
</TaskContentEditor>
|
||||
|
||||
<div class="h-[1px] w-full bg-[var(--color-border-separate)] my-[8px]"></div>
|
||||
|
||||
<div
|
||||
class="flex items-center gap-2 flex-wrap relative w-full"
|
||||
:class="!item.AgentSelection || item.AgentSelection.length === 0 ? 'min-h-[40px]' : 'overflow-y-auto max-h-[72px]'"
|
||||
:class="
|
||||
!item.AgentSelection || item.AgentSelection.length === 0
|
||||
? 'min-h-[40px]'
|
||||
: 'overflow-y-auto max-h-[72px]'
|
||||
"
|
||||
>
|
||||
<!-- 连接到智能体库的连接点 -->
|
||||
<div
|
||||
@@ -492,13 +296,16 @@ defineExpose({
|
||||
|
||||
<!-- 未填充智能体时显示Loading -->
|
||||
<div
|
||||
v-if="(!item.AgentSelection || item.AgentSelection.length === 0) && !agentsStore.hasStoppedFilling"
|
||||
v-if="
|
||||
(!item.AgentSelection || item.AgentSelection.length === 0) &&
|
||||
!agentsStore.hasStoppedFilling
|
||||
"
|
||||
class="flex items-center gap-2 text-[var(--color-text-secondary)] text-[14px]"
|
||||
>
|
||||
<el-icon class="is-loading" :size="20">
|
||||
<Loading />
|
||||
</el-icon>
|
||||
<span>正在分配智能体...</span>
|
||||
<span>正在分配智能体<span class="loading-dots"></span></span>
|
||||
</div>
|
||||
|
||||
<!-- 已填充智能体时显示智能体列表 -->
|
||||
@@ -607,66 +414,6 @@ defineExpose({
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.add-output-btn {
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(59, 130, 246, 0.05);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-output-form {
|
||||
animation: slideDown 0.3s ease-out;
|
||||
:deep(.el-card__body) {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
:deep(.el-input__wrapper) {
|
||||
border: 1px solid var(--color-text);
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
|
||||
&.is-focus {
|
||||
border-color: var(--color-text);
|
||||
box-shadow: 0 0 0 1px var(--color-primary-light);
|
||||
}
|
||||
:deep(.el-input__inner) {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
// 输入框样式
|
||||
:deep(.el-input__wrapper) {
|
||||
background: transparent;
|
||||
@@ -730,4 +477,33 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 加载动画省略号
|
||||
.loading-dots {
|
||||
display: inline-block;
|
||||
width: 1.2em;
|
||||
text-align: left;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
animation: dots 1.5s steps(4, end) infinite;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes dots {
|
||||
0%,
|
||||
20% {
|
||||
content: '';
|
||||
}
|
||||
40% {
|
||||
content: '.';
|
||||
}
|
||||
60% {
|
||||
content: '..';
|
||||
}
|
||||
80%,
|
||||
100% {
|
||||
content: '...';
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user