feat:额外产物添加
This commit is contained in:
20
frontend/src/assets/icons/Cancel.svg
Normal file
20
frontend/src/assets/icons/Cancel.svg
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||||
|
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg t="1766247549273" class="icon"
|
||||||
|
viewBox="0 0 1024 1024" version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
p-id="10050" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
width="16" height="16">
|
||||||
|
<path d="M512 1024C229.248 1024
|
||||||
|
0 794.752 0 512S229.248 0 512 0s512
|
||||||
|
229.248 512 512-229.248 512-512 512z
|
||||||
|
m0-938.666667C276.352 85.333333 85.333333
|
||||||
|
276.352 85.333333 512s191.018667 426.666667
|
||||||
|
426.666667 426.666667 426.666667-191.018667
|
||||||
|
426.666667-426.666667S747.648 85.333333 512
|
||||||
|
85.333333z m198.698667 625.365334a42.666667
|
||||||
|
42.666667 0 0 1-60.330667
|
||||||
|
0L512 572.330667l-138.368 138.368a42.666667 42.666667 0 0 1-60.330667-60.330667L451.669333 512 313.301333 373.632a42.666667 42.666667 0 0 1 60.330667-60.330667L512 451.669333l138.368-138.368a42.624 42.624 0 1 1 60.330667 60.330667L572.330667 512l138.368 138.368a42.666667 42.666667 0 0 1 0 60.330667z"
|
||||||
|
fill="#8e0707" p-id="10051">
|
||||||
|
</path></svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
1
frontend/src/assets/icons/Check.svg
Normal file
1
frontend/src/assets/icons/Check.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1766247454540" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9049" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M512 1024C230.4 1024 0 793.6 0 512S230.4 0 512 0s512 230.4 512 512-230.4 512-512 512z m0-938.666667C277.333333 85.333333 85.333333 277.333333 85.333333 512s192 426.666667 426.666667 426.666667 426.666667-192 426.666667-426.666667S746.666667 85.333333 512 85.333333z" p-id="9050"></path><path d="M708.266667 375.466667c-17.066667-17.066667-44.8-17.066667-59.733334 0l-181.333333 181.333333-91.733333-91.733333c-14.933333-14.933333-40.533333-14.933333-55.466667 0l-6.4 4.266666c-14.933333 14.933333-14.933333 40.533333 0 55.466667l125.866667 125.866667c14.933333 14.933333 40.533333 14.933333 55.466666 0l4.266667-4.266667 209.066667-209.066667c17.066667-17.066667 17.066667-44.8 0-61.866666z" p-id="9051"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
1
frontend/src/assets/icons/Edit.svg
Normal file
1
frontend/src/assets/icons/Edit.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1766136633767" class="icon" viewBox="0 0 1028 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7819" width="32.125" height="32" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M1018.319924 112.117535q4.093748 9.210934 6.652341 21.492179t2.558593 25.585928-5.117186 26.609365-16.374994 25.585928q-12.281245 12.281245-22.003898 21.492179t-16.886712 16.374994q-8.187497 8.187497-15.351557 14.32812l-191.382739-191.382739q12.281245-11.257808 29.167958-27.121083t28.144521-25.074209q14.32812-11.257808 29.679676-15.863275t30.191395-4.093748 28.656239 4.605467 24.050772 9.210934q21.492179 11.257808 47.589826 39.402329t40.425766 58.847634zM221.062416 611.554845q6.140623-6.140623 28.656239-29.167958t56.289041-56.80076l74.710909-74.710909 82.898406-82.898406 220.038979-220.038979 191.382739 192.406177-220.038979 220.038979-81.874969 82.898406q-40.937484 39.914047-73.687472 73.175753t-54.242167 54.753885-25.585928 24.562491q-10.234371 9.210934-23.539054 19.445305t-27.632802 16.374994q-14.32812 7.16406-41.960921 17.398431t-57.824197 19.957024-57.312478 16.886712-40.425766 9.210934q-27.632802 3.070311-36.843736-8.187497t-5.117186-37.867173q2.046874-14.32812 9.722653-41.449203t16.374994-56.289041 16.886712-53.730448 13.304682-33.773425q6.140623-14.32812 13.816401-26.097646t22.003898-26.097646z" p-id="7820" fill="#000000"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
@@ -97,6 +97,38 @@ const agentsStore = useAgentsStore()
|
|||||||
class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"
|
class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="item.apiUrl"
|
||||||
|
class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"
|
||||||
|
></div>
|
||||||
|
<!-- 使用 v-if 判断 item 中是否存在 apiUrl -->
|
||||||
|
<div v-if="item.apiUrl" class="text-[12px] break-all">
|
||||||
|
<span class="text-[12px] text-[red]">apiUrl:</span>
|
||||||
|
<span class="text-[12px] text-[var(--color-text-quaternary)] break-all ml-2">{{
|
||||||
|
item.apiUrl
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 只有当 item.apiUrl 存在时才显示上面的分隔线 -->
|
||||||
|
<div
|
||||||
|
v-if="item.apiUrl"
|
||||||
|
class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<!-- 使用 v-if 判断 item 中是否存在 apiModel -->
|
||||||
|
<div v-if="item.apiModel" class="text-[12px]">
|
||||||
|
<span class="text-[12px] text-[blue]">apiModel:</span>
|
||||||
|
<span class="text-[12px] text-[var(--color-text-quaternary)] ml-2">{{
|
||||||
|
item.apiModel
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 只有当 item.apiModel 存在时才显示下面的分隔线 -->
|
||||||
|
<div
|
||||||
|
v-if="item.apiModel"
|
||||||
|
class="h-[1px] w-full bg-[var(--color-border-default)] my-[8px]"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onUnmounted, ref } from 'vue'
|
import { computed, onUnmounted, ref, reactive, nextTick } from 'vue'
|
||||||
import { throttle } from 'lodash'
|
import { throttle } from 'lodash'
|
||||||
import { AnchorLocations, BezierConnector } from '@jsplumb/browser-ui'
|
import { AnchorLocations, BezierConnector } from '@jsplumb/browser-ui'
|
||||||
|
import AdditionalOutputCard from './AdditionalOutputCard.vue'
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue'
|
import SvgIcon from '@/components/SvgIcon/index.vue'
|
||||||
import { getActionTypeDisplay, getAgentMapIcon } from '@/layout/components/config.ts'
|
import { getActionTypeDisplay, getAgentMapIcon } from '@/layout/components/config.ts'
|
||||||
import { type ConnectArg, Jsplumb } from '@/layout/components/Main/TaskTemplate/utils.ts'
|
import { type ConnectArg, Jsplumb } from '@/layout/components/Main/TaskTemplate/utils.ts'
|
||||||
@@ -23,11 +23,24 @@ const collaborationProcess = computed(() => {
|
|||||||
return agentsStore.agentRawPlan.data?.['Collaboration Process'] ?? []
|
return agentsStore.agentRawPlan.data?.['Collaboration Process'] ?? []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 监听额外产物变化
|
||||||
|
watch(
|
||||||
|
() => agentsStore.additionalOutputs,
|
||||||
|
() => {
|
||||||
|
nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
jsplumb.repaintEverything()
|
||||||
|
}, 0)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
// 编辑逻辑
|
// 编辑逻辑
|
||||||
const editMode = ref(false) //全局编辑开关
|
const editMode = ref(false) //全局编辑开关
|
||||||
const editMap = reactive<Record<string, boolean>>({}) //行级编辑状态
|
const editMap = reactive<Record<string, boolean>>({}) //行级编辑状态
|
||||||
const editBuffer = reactive<Record<string, string | undefined>>({}) //临时输入
|
const editBuffer = reactive<Record<string, string | undefined>>({}) //临时输入
|
||||||
|
const showPopover = ref(false)
|
||||||
function getProcessDescription(stepId: string, processId: string) {
|
function getProcessDescription(stepId: string, processId: string) {
|
||||||
const step = collaborationProcess.value.find(s => s.Id === stepId)
|
const step = collaborationProcess.value.find(s => s.Id === stepId)
|
||||||
if (step) {
|
if (step) {
|
||||||
@@ -37,21 +50,6 @@ function getProcessDescription(stepId: string, processId: string) {
|
|||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
|
||||||
Object.keys(editMap).forEach(key => {
|
|
||||||
if (editMap[key]) {
|
|
||||||
const [stepId, processId] = key.split('-')
|
|
||||||
const value = editBuffer[key]
|
|
||||||
// 确保 value 是字符串类型
|
|
||||||
if (value !== undefined && value !== null) {
|
|
||||||
// @ts-ignore - TypeScript 无法正确推断类型,但运行时是安全的
|
|
||||||
handleSaveEdit(stepId, processId, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
editMode.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleOpenEdit(stepId: string, processId: string) {
|
function handleOpenEdit(stepId: string, processId: string) {
|
||||||
if (!editMode.value) return
|
if (!editMode.value) return
|
||||||
const key = `${stepId}-${processId}`
|
const key = `${stepId}-${processId}`
|
||||||
@@ -69,7 +67,6 @@ function handleSaveEdit(stepId: string, processId: string, value: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
editMap[key] = false
|
editMap[key] = false
|
||||||
ElMessage.success('已保存(前端内存)')
|
|
||||||
}
|
}
|
||||||
const jsplumb = new Jsplumb('task-results-main', {
|
const jsplumb = new Jsplumb('task-results-main', {
|
||||||
connector: {
|
connector: {
|
||||||
@@ -185,13 +182,6 @@ function createInternalLine(id?: string) {
|
|||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
// 额外产物编辑状态
|
|
||||||
const editingOutputId = ref<string | null>(null)
|
|
||||||
const editingOutputContent = ref('')
|
|
||||||
|
|
||||||
// 额外产物内容存储
|
|
||||||
const additionalOutputContents = ref<Record<string, string>>({})
|
|
||||||
|
|
||||||
async function handleRun() {
|
async function handleRun() {
|
||||||
try {
|
try {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@@ -207,43 +197,6 @@ async function handleTaskProcess() {
|
|||||||
drawerVisible.value = true
|
drawerVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始编辑额外产物内容
|
|
||||||
function startOutputEditing(output: string) {
|
|
||||||
editingOutputId.value = output
|
|
||||||
editingOutputContent.value = getAdditionalOutputContent(output) || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存额外产物内容
|
|
||||||
function saveOutputEditing() {
|
|
||||||
if (editingOutputId.value && editingOutputContent.value.trim()) {
|
|
||||||
additionalOutputContents.value[editingOutputId.value] = editingOutputContent.value.trim()
|
|
||||||
}
|
|
||||||
editingOutputId.value = null
|
|
||||||
editingOutputContent.value = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取消编辑额外产物内容
|
|
||||||
function cancelOutputEditing() {
|
|
||||||
editingOutputId.value = null
|
|
||||||
editingOutputContent.value = ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取额外产物内容
|
|
||||||
function getAdditionalOutputContent(output: string) {
|
|
||||||
return additionalOutputContents.value[output] || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理额外产物的键盘事件
|
|
||||||
function handleOutputKeydown(event: KeyboardEvent) {
|
|
||||||
if (event.key === 'Enter') {
|
|
||||||
event.preventDefault()
|
|
||||||
saveOutputEditing()
|
|
||||||
} else if (event.key === 'Escape') {
|
|
||||||
editingOutputId.value = null
|
|
||||||
editingOutputContent.value = ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加滚动状态标识
|
// 添加滚动状态标识
|
||||||
const isScrolling = ref(false)
|
const isScrolling = ref(false)
|
||||||
let scrollTimer: ReturnType<typeof setTimeout> | null = null
|
let scrollTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
@@ -281,7 +234,7 @@ function clear() {
|
|||||||
jsplumb.reset()
|
jsplumb.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 按钮交互状态管理 ==========
|
//按钮交互状态管理
|
||||||
const buttonHoverState = ref<'process' | 'execute' | null>(null)
|
const buttonHoverState = ref<'process' | 'execute' | null>(null)
|
||||||
let buttonHoverTimer: ReturnType<typeof setTimeout> | null = null
|
let buttonHoverTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
const handleProcessMouseEnter = () => {
|
const handleProcessMouseEnter = () => {
|
||||||
@@ -328,7 +281,7 @@ const executeBtnClass = computed(() => {
|
|||||||
if (buttonHoverState.value === 'process') {
|
if (buttonHoverState.value === 'process') {
|
||||||
return 'circle'
|
return 'circle'
|
||||||
}
|
}
|
||||||
// 其他情况:如果有任务数据就显示椭圆形,否则显示圆形
|
//如果有任务数据就显示椭圆形,否则显示圆形
|
||||||
return agentsStore.agentRawPlan.data ? 'ellipse' : 'circle'
|
return agentsStore.agentRawPlan.data ? 'ellipse' : 'circle'
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -444,6 +397,20 @@ defineExpose({
|
|||||||
@scroll="handleScroll"
|
@scroll="handleScroll"
|
||||||
>
|
>
|
||||||
<div id="task-results-main" class="px-[40px] relative">
|
<div id="task-results-main" class="px-[40px] relative">
|
||||||
|
<!-- 额外产物卡片 -->
|
||||||
|
<div
|
||||||
|
v-if="agentsStore.additionalOutputs && agentsStore.additionalOutputs.length > 0"
|
||||||
|
class="mt-6"
|
||||||
|
:key="`additional-outputs-${agentsStore.additionalOutputs.length}`"
|
||||||
|
>
|
||||||
|
<div class="space-y-4 mb-4">
|
||||||
|
<AdditionalOutputCard
|
||||||
|
v-for="(_, index) in agentsStore.additionalOutputs"
|
||||||
|
:key="`additional-${index}-${agentsStore.additionalOutputs[index]}`"
|
||||||
|
:index="index"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 原有的流程和产物 -->
|
<!-- 原有的流程和产物 -->
|
||||||
<div v-for="item in collaborationProcess" :key="item.Id" class="card-item">
|
<div v-for="item in collaborationProcess" :key="item.Id" class="card-item">
|
||||||
<el-card
|
<el-card
|
||||||
@@ -556,76 +523,6 @@ defineExpose({
|
|||||||
</el-collapse>
|
</el-collapse>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 额外产物的编辑卡片 -->
|
|
||||||
<div
|
|
||||||
v-for="(output, index) in agentsStore.additionalOutputs"
|
|
||||||
:key="`additional-output-${index}`"
|
|
||||||
class="card-item"
|
|
||||||
>
|
|
||||||
<!-- 空的流程卡片位置 -->
|
|
||||||
<div class="w-full"></div>
|
|
||||||
|
|
||||||
<!-- 额外产物的编辑卡片 -->
|
|
||||||
<el-card
|
|
||||||
class="card-item w-full relative output-object-card additional-output-card"
|
|
||||||
:shadow="false"
|
|
||||||
:id="`additional-output-results-${index}`"
|
|
||||||
>
|
|
||||||
<!-- 产物名称行 -->
|
|
||||||
<div class="text-[18px] mb-3">
|
|
||||||
{{ output }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 编辑区域行 -->
|
|
||||||
<div class="additional-output-editor">
|
|
||||||
<div v-if="editingOutputId === output" class="w-full">
|
|
||||||
<!-- 编辑状态:输入框 + 按钮 -->
|
|
||||||
<div class="flex flex-col gap-3">
|
|
||||||
<el-input
|
|
||||||
v-model="editingOutputContent"
|
|
||||||
type="textarea"
|
|
||||||
:autosize="{ minRows: 3, maxRows: 6 }"
|
|
||||||
placeholder="请输入产物内容"
|
|
||||||
@keydown="handleOutputKeydown"
|
|
||||||
class="output-editor"
|
|
||||||
size="small"
|
|
||||||
/>
|
|
||||||
<div class="flex justify-end gap-2">
|
|
||||||
<el-button @click="saveOutputEditing" type="primary" size="small" class="px-3">
|
|
||||||
√
|
|
||||||
</el-button>
|
|
||||||
<el-button @click="cancelOutputEditing" size="small" class="px-3">
|
|
||||||
×
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else class="w-full">
|
|
||||||
<!-- 非编辑状态:折叠区域 + 编辑按钮 -->
|
|
||||||
<div
|
|
||||||
class="flex items-center justify-between p-3 bg-[var(--color-bg-quinary)] rounded-[8px]"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="text-[14px] text-[var(--color-text-secondary)] output-content-display"
|
|
||||||
>
|
|
||||||
{{ getAdditionalOutputContent(output) || '暂无内容,点击编辑' }}
|
|
||||||
</div>
|
|
||||||
<el-button
|
|
||||||
@click="startOutputEditing(output)"
|
|
||||||
size="small"
|
|
||||||
type="primary"
|
|
||||||
plain
|
|
||||||
class="flex items-center gap-1"
|
|
||||||
>
|
|
||||||
<svg-icon icon-class="action" size="12px" />
|
|
||||||
<span>编辑</span>
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -771,45 +668,6 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 额外产物编辑区域样式
|
|
||||||
.additional-output-editor {
|
|
||||||
.output-editor {
|
|
||||||
:deep(.el-textarea__inner) {
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--color-text-primary);
|
|
||||||
background: var(--color-bg-detail);
|
|
||||||
border: 1px solid #dcdfe6;
|
|
||||||
resize: none;
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.output-content-display {
|
|
||||||
word-break: break-word;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
line-height: 1.5;
|
|
||||||
min-height: 20px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
|
||||||
border-color: #409eff;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 编辑按钮样式
|
|
||||||
.el-button {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 16px;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&.el-button--small {
|
|
||||||
padding: 4px 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========== 新增:按钮交互样式 ==========
|
// ========== 新增:按钮交互样式 ==========
|
||||||
.task-button-group {
|
.task-button-group {
|
||||||
.el-button {
|
.el-button {
|
||||||
|
|||||||
@@ -1,20 +1,44 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
defineProps<{
|
||||||
|
isAdding?: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
defineEmits<{
|
||||||
|
(e: 'start-add-output'): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="absolute inset-0 flex items-start gap-[14%]">
|
<div class="absolute inset-0 flex items-start gap-[14%]">
|
||||||
<!-- 左侧元素 -->
|
<!-- 左侧元素 -->
|
||||||
<div class="flex-1 relative h-full flex justify-center">
|
<div class="flex-1 relative h-full flex justify-center">
|
||||||
<!-- 背景那一根线 -->
|
<!-- 背景那一根线 -->
|
||||||
<div class="h-full bg-[var(--color-bg-flow)] w-[5px]">
|
<div class="h-full bg-[var(--color-bg-flow)] w-[5px]">
|
||||||
<!-- 线底部的小圆球 -->
|
<!-- 线底部的小圆球 -->
|
||||||
<div
|
<div
|
||||||
class="absolute bottom-0 left-1/2 transform -translate-x-1/2 bg-[var(--color-bg-flow)] w-[15px] h-[15px] rounded-full"
|
class="absolute bottom-0 left-1/2 transform -translate-x-1/2 bg-[var(--color-bg-flow)] w-[15px] h-[15px] rounded-full"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右侧元素 -->
|
|
||||||
|
<!-- 右侧元素 -->
|
||||||
<div class="flex-1 relative h-full flex justify-center">
|
<div class="flex-1 relative h-full flex justify-center">
|
||||||
<!-- 背景那一根线 -->
|
<!-- 背景那一根线 -->
|
||||||
<div class="h-full bg-[var(--color-bg-flow)] w-[5px]">
|
<div class="h-full bg-[var(--color-bg-flow)] w-[5px]">
|
||||||
<!-- 线底部的小圆球 -->
|
<!-- 顶部加号区域 -->
|
||||||
|
<div
|
||||||
|
v-if="!isAdding"
|
||||||
|
class="plus-area mt-[35px] ml-[-15px] w-[34px] h-[34px] flex items-center justify-center cursor-pointer rounded-full"
|
||||||
|
@click="$emit('start-add-output')"
|
||||||
|
>
|
||||||
|
<!-- 加号图标 -->
|
||||||
|
<svg-icon
|
||||||
|
icon-class="plus"
|
||||||
|
color="var(--color-text)"
|
||||||
|
size="20px"
|
||||||
|
class="plus-icon opacity-0 transition-opacity duration-200"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- 线底部的小圆球 -->
|
||||||
<div
|
<div
|
||||||
class="absolute bottom-0 left-1/2 transform -translate-x-1/2 bg-[var(--color-bg-flow)] w-[15px] h-[15px] rounded-full"
|
class="absolute bottom-0 left-1/2 transform -translate-x-1/2 bg-[var(--color-bg-flow)] w-[15px] h-[15px] rounded-full"
|
||||||
></div>
|
></div>
|
||||||
@@ -23,4 +47,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts"></script>
|
<style scoped>
|
||||||
|
.plus-area:hover .plus-icon {
|
||||||
|
opacity: 1;
|
||||||
|
border: 1px dashed var(--color-text);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,284 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { computed, ref } from 'vue'
|
|
||||||
import { useAgentsStore } from '@/stores/modules/agents'
|
|
||||||
import { getAgentMapIcon } from '@/layout/components/config.ts'
|
|
||||||
import SvgIcon from '@/components/SvgIcon/index.vue'
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
|
||||||
(e: 'close'): void
|
|
||||||
}>()
|
|
||||||
|
|
||||||
const agentsStore = useAgentsStore()
|
|
||||||
|
|
||||||
// 获取当前选中任务的智能体列表
|
|
||||||
const currentTaskAgents = computed(() => {
|
|
||||||
return agentsStore.currentTask?.AgentSelection || []
|
|
||||||
})
|
|
||||||
|
|
||||||
// 获取智能体列表
|
|
||||||
const agents = computed(() => agentsStore.agents)
|
|
||||||
|
|
||||||
// 选中状态管理 - 初始选中当前任务的智能体
|
|
||||||
const selectedAgents = ref<string[]>([])
|
|
||||||
|
|
||||||
// 初始化选中当前任务的智能体
|
|
||||||
const initializeSelectedAgents = () => {
|
|
||||||
selectedAgents.value = [...currentTaskAgents.value]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 切换选中状态
|
|
||||||
const toggleSelectAgent = (agentName: string) => {
|
|
||||||
const index = selectedAgents.value.indexOf(agentName)
|
|
||||||
if (index > -1) {
|
|
||||||
// 如果已选中,则取消选中
|
|
||||||
selectedAgents.value.splice(index, 1)
|
|
||||||
} else {
|
|
||||||
// 如果未选中,则添加到选中列表末尾
|
|
||||||
selectedAgents.value.push(agentName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否选中
|
|
||||||
const isAgentSelected = (agentName: string) => {
|
|
||||||
return selectedAgents.value.includes(agentName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取排序后的智能体列表 - 选中的智能体排在前面,保持原有顺序
|
|
||||||
const sortedAgents = computed(() => {
|
|
||||||
const selected = agents.value.filter(agent => selectedAgents.value.includes(agent.Name))
|
|
||||||
const unselected = agents.value.filter(agent => !selectedAgents.value.includes(agent.Name))
|
|
||||||
return [...selected, ...unselected]
|
|
||||||
})
|
|
||||||
|
|
||||||
// 颜色等级配置 - 从蓝色到白色的5个等级
|
|
||||||
const colorLevels = [
|
|
||||||
{ level: 5, color: '#1d59dc', textColor: '#FFFFFF' }, // 深蓝色
|
|
||||||
{ level: 4, color: '#4a71c7', textColor: '#FFFFFF' }, // 中蓝色
|
|
||||||
{ level: 3, color: '#6c8ed7', textColor: '#333333' }, // 浅蓝色
|
|
||||||
{ level: 2, color: '#9cb7f0', textColor: '#333333' }, // 更浅蓝
|
|
||||||
{ level: 1, color: '#c8d9fc', textColor: '#333333' } // 接近白色
|
|
||||||
]
|
|
||||||
|
|
||||||
// 为每个智能体分配随机等级(实际应用中应该根据业务逻辑分配)
|
|
||||||
const getAgentLevel = (agentIndex: number) => {
|
|
||||||
// 这里使用简单的算法分配等级,实际应用中应该根据智能体的能力、经验等分配
|
|
||||||
return ((agentIndex % 5) + 1) % 6
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取对应等级的颜色配置
|
|
||||||
const getLevelConfig = (level: number) => {
|
|
||||||
return colorLevels.find(config => config.level === level) || colorLevels[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 组件挂载时初始化选中状态
|
|
||||||
onMounted(() => {
|
|
||||||
initializeSelectedAgents()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 关闭弹窗
|
|
||||||
const handleClose = () => {
|
|
||||||
emit('close')
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="agent-allocation">
|
|
||||||
<!-- 头部 -->
|
|
||||||
<div class="allocation-header">
|
|
||||||
<span class="header-title">智能体分配</span>
|
|
||||||
<el-button class="close-button" text circle @click="handleClose" title="关闭">
|
|
||||||
<span class="close-icon">❌️</span>
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 分割线 -->
|
|
||||||
<el-divider class="header-divider" />
|
|
||||||
|
|
||||||
<!-- 内容区 -->
|
|
||||||
<div class="allocation-content">
|
|
||||||
<!-- 智能体整体容器 -->
|
|
||||||
<div class="agents-container selectagent">
|
|
||||||
<div
|
|
||||||
v-for="(agent, index) in agents"
|
|
||||||
:key="agent.Name"
|
|
||||||
class="agent-item"
|
|
||||||
:title="agent.Name"
|
|
||||||
@click="toggleSelectAgent(agent.Name)"
|
|
||||||
>
|
|
||||||
<!-- 头像部分(独立元素) -->
|
|
||||||
<div class="agent-avatar" :style="{ background: getAgentMapIcon(agent.Name).color }">
|
|
||||||
<SvgIcon :icon-class="getAgentMapIcon(agent.Name).icon" size="24px" color="#fff" />
|
|
||||||
</div>
|
|
||||||
<!-- 等级色值部分(独立元素,通过CSS定位跟随头像) -->
|
|
||||||
<div
|
|
||||||
class="color-level"
|
|
||||||
:style="{
|
|
||||||
backgroundColor: getLevelConfig(getAgentLevel(index)).color,
|
|
||||||
color: getLevelConfig(getAgentLevel(index)).textColor
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ getAgentLevel(index) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 空状态 -->
|
|
||||||
<div v-if="agents.length === 0" class="empty-state">
|
|
||||||
<el-empty description="暂无智能体数据" />
|
|
||||||
<div class="empty-tip">请先在智能体库中上传智能体信息</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.agent-allocation {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.allocation-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 16px 20px;
|
|
||||||
|
|
||||||
.header-title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--color-text-title);
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-button {
|
|
||||||
padding: 4px;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--color-bg-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-divider {
|
|
||||||
margin: 0;
|
|
||||||
border-color: var(--color-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.allocation-content {
|
|
||||||
flex: 1;
|
|
||||||
padding: 30px 20px;
|
|
||||||
overflow-y: auto;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start; // 改为靠左对齐
|
|
||||||
gap: 20px;
|
|
||||||
|
|
||||||
.agents-container {
|
|
||||||
display: flex;
|
|
||||||
gap: 0; // 确保容器内元素之间没有间隙
|
|
||||||
justify-content: flex-start; // 靠左对齐
|
|
||||||
align-items: flex-start; // 改为顶部对齐
|
|
||||||
flex-wrap: wrap;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow-x: auto;
|
|
||||||
|
|
||||||
.agent-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0 0px; // 确保item之间没有水平间距
|
|
||||||
padding: 0; // 移除内边距
|
|
||||||
|
|
||||||
.agent-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
border-radius: 50%;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border: 2px solid var(--color-border);
|
|
||||||
transition: transform 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-level {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
margin-top: 8px; // 头像和等级卡片之间的垂直间距
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-state {
|
|
||||||
text-align: center;
|
|
||||||
padding: 40px 0;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.empty-tip {
|
|
||||||
margin-top: 16px;
|
|
||||||
color: var(--color-text-secondary);
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 响应式设计
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.agent-allocation {
|
|
||||||
.allocation-content {
|
|
||||||
padding: 20px 16px;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
.agents-container {
|
|
||||||
.agent-item {
|
|
||||||
margin: 0 6px;
|
|
||||||
|
|
||||||
.agent-avatar {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-level {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
font-size: 14px;
|
|
||||||
margin-top: 8px; // 保持一致的垂直间距
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 小屏幕适配
|
|
||||||
@media (max-width: 480px) {
|
|
||||||
.agent-allocation {
|
|
||||||
.allocation-content {
|
|
||||||
.agents-container {
|
|
||||||
.agent-item {
|
|
||||||
margin: 0 4px;
|
|
||||||
|
|
||||||
.agent-avatar {
|
|
||||||
width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-level {
|
|
||||||
width: 35px;
|
|
||||||
height: 35px;
|
|
||||||
font-size: 12px;
|
|
||||||
margin-top: 8px; // 保持一致的垂直间距
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -3,7 +3,7 @@ import SvgIcon from '@/components/SvgIcon/index.vue'
|
|||||||
import { getAgentMapIcon } from '@/layout/components/config.ts'
|
import { getAgentMapIcon } from '@/layout/components/config.ts'
|
||||||
import { type ConnectArg, Jsplumb } from '@/layout/components/Main/TaskTemplate/utils.ts'
|
import { type ConnectArg, Jsplumb } from '@/layout/components/Main/TaskTemplate/utils.ts'
|
||||||
import { type IRawStepTask, useAgentsStore } from '@/stores'
|
import { type IRawStepTask, useAgentsStore } from '@/stores'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref, nextTick } from 'vue'
|
||||||
import { AnchorLocations } from '@jsplumb/browser-ui'
|
import { AnchorLocations } from '@jsplumb/browser-ui'
|
||||||
import MultiLineTooltip from '@/components/MultiLineTooltip/index.vue'
|
import MultiLineTooltip from '@/components/MultiLineTooltip/index.vue'
|
||||||
import Bg from './Bg.vue'
|
import Bg from './Bg.vue'
|
||||||
@@ -11,8 +11,12 @@ import Bg from './Bg.vue'
|
|||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(el: 'resetAgentRepoLine'): void
|
(el: 'resetAgentRepoLine'): void
|
||||||
(el: 'setCurrentTask', task: IRawStepTask): void
|
(el: 'setCurrentTask', task: IRawStepTask): void
|
||||||
|
(el: 'add-output', outputName: string): void
|
||||||
|
(el: 'click-branch'): void
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
// 分支数量
|
||||||
|
|
||||||
const jsplumb = new Jsplumb('task-syllabus')
|
const jsplumb = new Jsplumb('task-syllabus')
|
||||||
|
|
||||||
const handleScroll = () => {
|
const handleScroll = () => {
|
||||||
@@ -30,9 +34,79 @@ const editingTaskId = ref<string | null>(null)
|
|||||||
const editingContent = ref('')
|
const editingContent = ref('')
|
||||||
|
|
||||||
// 添加新产物状态管理
|
// 添加新产物状态管理
|
||||||
const showAddOutputForm = ref(false)
|
const isAddingOutput = ref(false)
|
||||||
|
const newOutputInputRef = ref<HTMLElement>()
|
||||||
const newOutputName = ref('')
|
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) => {
|
const startEditing = (task: IRawStepTask) => {
|
||||||
if (!task.Id) {
|
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[] {
|
function handleCurrentTask(task: IRawStepTask, transparent: boolean): ConnectArg[] {
|
||||||
// 创建当前流程与产出的连线
|
// 创建当前流程与产出的连线
|
||||||
const arr: ConnectArg[] = [
|
const arr: ConnectArg[] = [
|
||||||
@@ -179,7 +215,7 @@ defineExpose({
|
|||||||
class="w-full relative min-h-full"
|
class="w-full relative min-h-full"
|
||||||
id="task-syllabus"
|
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="w-full flex items-center gap-[14%] mb-[35px]">
|
||||||
<div class="flex-1 flex justify-center">
|
<div class="flex-1 flex justify-center">
|
||||||
@@ -198,7 +234,47 @@ defineExpose({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</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
|
<div
|
||||||
v-for="item in collaborationProcess"
|
v-for="item in collaborationProcess"
|
||||||
:key="item.Id"
|
:key="item.Id"
|
||||||
@@ -292,72 +368,12 @@ defineExpose({
|
|||||||
<div class="text-[18px] font-bold text-center">{{ item.OutputObject }}</div>
|
<div class="text-[18px] font-bold text-center">{{ item.OutputObject }}</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 额外的产物列表 -->
|
<div class="branch-button" @click="handleBranchClick">
|
||||||
<!-- <div
|
<div class="branch-icon">
|
||||||
v-for="(output, index) in agentsStore.additionalOutputs"
|
<svg-icon icon-class="branch" color="#000" size="24px" />
|
||||||
:key="`additional-${index}`"
|
</div>
|
||||||
class="card-item w-full flex items-center gap-[14%]"
|
<span>{{ branchCount }}</span>
|
||||||
> -->
|
|
||||||
<!-- 空的流程卡片位置 -->
|
|
||||||
<!-- <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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -368,7 +384,6 @@ defineExpose({
|
|||||||
border: 1px solid var(--color-card-border-task);
|
border: 1px solid var(--color-card-border-task);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
transition: border-color 0.2s ease;
|
transition: border-color 0.2s ease;
|
||||||
// box-shadow: var(--color-card-shadow);
|
|
||||||
margin-bottom: 100px;
|
margin-bottom: 100px;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-card-bg-task-hover);
|
background-color: var(--color-card-bg-task-hover);
|
||||||
@@ -390,7 +405,6 @@ defineExpose({
|
|||||||
border: 1px solid var(--color-card-border-task);
|
border: 1px solid var(--color-card-border-task);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
transition: border-color 0.2s ease;
|
transition: border-color 0.2s ease;
|
||||||
// box-shadow: var(--color-card-shadow-hover);
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: var(--color-card-bg-task-hover);
|
background-color: var(--color-card-bg-task-hover);
|
||||||
border-color: var(--color-card-border-hover);
|
border-color: var(--color-card-border-hover);
|
||||||
@@ -449,6 +463,27 @@ defineExpose({
|
|||||||
|
|
||||||
.add-output-form {
|
.add-output-form {
|
||||||
animation: slideDown 0.3s ease-out;
|
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 {
|
@keyframes slideDown {
|
||||||
@@ -462,11 +497,6 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加产物表单样式
|
|
||||||
:deep(.el-card__body) {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 输入框样式
|
// 输入框样式
|
||||||
:deep(.el-input__wrapper) {
|
:deep(.el-input__wrapper) {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ function clear() {
|
|||||||
taskResultJsplumb.repaintEverything()
|
taskResultJsplumb.repaintEverything()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const additionalOutputs = ref<string[]>([])
|
||||||
|
const handleAddOutput = (outputName: string) => {
|
||||||
|
additionalOutputs.value.unshift(outputName)
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
changeTask,
|
changeTask,
|
||||||
resetAgentRepoLine,
|
resetAgentRepoLine,
|
||||||
@@ -94,6 +99,7 @@ defineExpose({
|
|||||||
ref="taskSyllabusRef"
|
ref="taskSyllabusRef"
|
||||||
@resetAgentRepoLine="resetAgentRepoLine"
|
@resetAgentRepoLine="resetAgentRepoLine"
|
||||||
@set-current-task="handleTaskSyllabusCurrentTask"
|
@set-current-task="handleTaskSyllabusCurrentTask"
|
||||||
|
@add-output="handleAddOutput"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- 执行结果 -->
|
<!-- 执行结果 -->
|
||||||
@@ -102,6 +108,7 @@ defineExpose({
|
|||||||
ref="taskResultRef"
|
ref="taskResultRef"
|
||||||
@refresh-line="taskResultJsplumb.repaintEverything"
|
@refresh-line="taskResultJsplumb.repaintEverything"
|
||||||
@set-current-task="handleTaskResultCurrentTask"
|
@set-current-task="handleTaskResultCurrentTask"
|
||||||
|
:additional-outputs="additionalOutputs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { store } from '../index'
|
|||||||
import { useStorage } from '@vueuse/core'
|
import { useStorage } from '@vueuse/core'
|
||||||
import type { IExecuteRawResponse } from '@/api'
|
import type { IExecuteRawResponse } from '@/api'
|
||||||
import { useConfigStore } from '@/stores/modules/config.ts'
|
import { useConfigStore } from '@/stores/modules/config.ts'
|
||||||
|
|
||||||
export interface Agent {
|
export interface Agent {
|
||||||
Name: string
|
Name: string
|
||||||
Profile: string
|
Profile: string
|
||||||
@@ -141,7 +140,7 @@ export const useAgentsStore = defineStore('agents', () => {
|
|||||||
|
|
||||||
const trimmedOutput = outputObject.trim()
|
const trimmedOutput = outputObject.trim()
|
||||||
if (!additionalOutputs.value.includes(trimmedOutput)) {
|
if (!additionalOutputs.value.includes(trimmedOutput)) {
|
||||||
additionalOutputs.value.push(trimmedOutput)
|
additionalOutputs.value.unshift(trimmedOutput)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const pathSrc = resolve(__dirname, 'src')
|
|||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
base: '',
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
@@ -46,12 +47,12 @@ export default defineConfig({
|
|||||||
'/api': {
|
'/api': {
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
// 接口地址
|
// 接口地址
|
||||||
// target: 'http://82.157.183.212:21092',
|
target: 'http://82.157.183.212:21092',
|
||||||
target: 'http://localhost:8000',
|
// target: 'http://localhost:8000',
|
||||||
rewrite: (path: string) => path.replace(/^\/api/, ''),
|
// rewrite: (path: string) => path.replace(/^\/api/, ''),
|
||||||
configure: (proxy, options) => {
|
// configure: (proxy, options) => {
|
||||||
console.log('Proxy configured:', options)
|
// console.log('Proxy configured:', options)
|
||||||
},
|
// },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user