feat:额外产物添加

This commit is contained in:
liailing1026
2025-12-21 15:28:59 +08:00
parent b42ab5aedd
commit b987fe70ad
11 changed files with 281 additions and 587 deletions

View File

@@ -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 } from 'vue'
import { computed, ref, nextTick } from 'vue'
import { AnchorLocations } from '@jsplumb/browser-ui'
import MultiLineTooltip from '@/components/MultiLineTooltip/index.vue'
import Bg from './Bg.vue'
@@ -11,8 +11,12 @@ import Bg from './Bg.vue'
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')
const handleScroll = () => {
@@ -30,9 +34,79 @@ const editingTaskId = ref<string | null>(null)
const editingContent = ref('')
// 添加新产物状态管理
const showAddOutputForm = ref(false)
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 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) {
@@ -71,44 +145,6 @@ const handleKeydown = (event: KeyboardEvent) => {
}
}
// 显示添加产物表单
const showAddOutputDialog = () => {
showAddOutputForm.value = true
newOutputName.value = ''
}
// 添加新产物
const addNewOutput = () => {
if (newOutputName.value.trim()) {
const success = agentsStore.addNewOutput(newOutputName.value.trim())
if (success) {
showAddOutputForm.value = false
newOutputName.value = ''
}
}
}
// 取消添加产物
const cancelAddOutput = () => {
showAddOutputForm.value = false
newOutputName.value = ''
}
// 处理添加产物的键盘事件
const handleAddOutputKeydown = (event: KeyboardEvent) => {
if (event.key === 'Enter') {
event.preventDefault()
addNewOutput()
} else if (event.key === 'Escape') {
cancelAddOutput()
}
}
// 删除额外产物
const removeAdditionalOutput = (output: string) => {
agentsStore.removeAdditionalOutput(output)
}
function handleCurrentTask(task: IRawStepTask, transparent: boolean): ConnectArg[] {
// 创建当前流程与产出的连线
const arr: ConnectArg[] = [
@@ -179,7 +215,7 @@ defineExpose({
class="w-full relative min-h-full"
id="task-syllabus"
>
<Bg />
<Bg :is-adding="isAddingOutput" @start-add-output="handleAddOutputClick" />
<div class="w-full flex items-center gap-[14%] mb-[35px]">
<div class="flex-1 flex justify-center">
@@ -198,7 +234,47 @@ 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"
@@ -292,72 +368,12 @@ defineExpose({
<div class="text-[18px] font-bold text-center">{{ item.OutputObject }}</div>
</el-card>
</div>
<!-- 额外的产物列表 -->
<!-- <div
v-for="(output, index) in agentsStore.additionalOutputs"
:key="`additional-${index}`"
class="card-item w-full flex items-center gap-[14%]"
> -->
<!-- 空的流程卡片位置 -->
<!-- <div class="w-[43%]"></div> -->
<!-- 额外产物卡片 -->
<!-- <el-card class="w-[43%] relative additional-output-card group" :shadow="false">
<div class="flex items-center justify-between">
<div class="text-[18px] font-bold text-center flex-1">{{ output }}</div>
<button
@click="removeAdditionalOutput(output)"
class="opacity-0 group-hover:opacity-100 text-red-500 hover:text-red-700 transition-all duration-200 ml-2 text-lg font-bold w-5 h-5 flex items-center justify-center rounded hover:bg-red-50"
>
×
</button>
</div>
</el-card>
</div> -->
<!-- 添加新产物按钮 -->
<!-- <div class="card-item w-full flex items-center gap-[14%] mt-[20px]"> -->
<!-- 空的流程卡片位置 -->
<!-- <div class="w-[43%]"></div> -->
<!-- 添加新产物按钮 -->
<!-- <div class="w-[43%] relative"> -->
<!-- <div v-if="!showAddOutputForm" class="add-output-btn">
<button
@click="showAddOutputDialog"
class="w-full h-[50px] border-2 border-dashed border-gray-300 rounded-lg flex items-center justify-center text-gray-500 hover:border-blue-500 hover:text-blue-500 transition-all duration-200 group"
>
<svg-icon icon-class="plus" size="20px" class="mr-2" />
<span class="text-sm font-medium"></span>
</button>
</div> -->
<!-- 添加产物表单 -->
<!-- <div v-else class="add-output-form">
<el-card class="w-full" shadow="hover">
<div class="p-3">
<el-input
v-model="newOutputName"
placeholder="输入产物名称"
size="small"
@keydown="handleAddOutputKeydown"
@blur="addNewOutput"
class="w-full mb-3"
/>
<div class="flex gap-2">
<el-button @click="addNewOutput" type="primary" size="small" class="flex-1">
确定
</el-button>
<el-button @click="cancelAddOutput" size="small" class="flex-1">
取消
</el-button>
</div>
</div>
</el-card>
</div> -->
<!-- </div> -->
<!-- </div> -->
<!-- <div>
<el-button type="info" size="medium" class="flex-1"> branch </el-button>
</div> -->
</div>
<div class="branch-button" @click="handleBranchClick">
<div class="branch-icon">
<svg-icon icon-class="branch" color="#000" size="24px" />
</div>
<span>{{ branchCount }}</span>
</div>
</div>
</div>
@@ -368,7 +384,6 @@ defineExpose({
border: 1px solid var(--color-card-border-task);
box-sizing: border-box;
transition: border-color 0.2s ease;
// box-shadow: var(--color-card-shadow);
margin-bottom: 100px;
&:hover {
background-color: var(--color-card-bg-task-hover);
@@ -390,7 +405,6 @@ defineExpose({
border: 1px solid var(--color-card-border-task);
box-sizing: border-box;
transition: border-color 0.2s ease;
// box-shadow: var(--color-card-shadow-hover);
&:hover {
background-color: var(--color-card-bg-task-hover);
border-color: var(--color-card-border-hover);
@@ -449,6 +463,27 @@ defineExpose({
.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 {
@@ -462,11 +497,6 @@ defineExpose({
}
}
// 添加产物表单样式
:deep(.el-card__body) {
padding: 16px;
}
// 输入框样式
:deep(.el-input__wrapper) {
background: transparent;