Files
AgentCoord/frontend/src/layout/components/Main/TaskTemplate/TaskProcess/ProcessCard.vue

325 lines
9.0 KiB
Vue
Raw Normal View History

<script setup lang="ts">
2026-01-09 13:54:32 +08:00
import { ref, computed } from 'vue'
import { getActionTypeDisplay } from '@/layout/components/config.ts'
2025-12-31 19:04:58 +08:00
import { useAgentsStore } from '@/stores'
import BranchButton from './components/TaskButton.vue'
const agentsStore = useAgentsStore()
const props = defineProps<{
step: {
Id?: string
TaskProcess: Array<{
ID: string
ActionType: string
AgentName: string
Description: string
}>
}
}>()
const emit = defineEmits<{
(e: 'open-edit', stepId: string, processId: string): void
(e: 'save-edit', stepId: string, processId: string, value: string): void
}>()
2026-01-14 17:54:00 +08:00
//从 currentTask 中获取数据
2026-01-09 13:54:32 +08:00
const currentTaskProcess = computed(() => {
const currentTask = agentsStore.currentTask
if (currentTask && currentTask.Id === props.step.Id && currentTask.TaskProcess) {
return currentTask.TaskProcess
}
2026-01-14 17:54:00 +08:00
//从 agentRawPlan 中获取原始数据
2026-01-09 13:54:32 +08:00
const collaborationProcess = agentsStore.agentRawPlan.data?.['Collaboration Process'] || []
const rawData = collaborationProcess.find((task: any) => task.Id === props.step.Id)
return rawData?.TaskProcess || []
})
// 当前正在编辑的process ID
const editingProcessId = ref<string | null>(null)
const editValue = ref('')
// 鼠标悬停的process ID
const hoverProcessId = ref<string | null>(null)
2026-01-14 17:54:00 +08:00
// 处理卡片点击事件
2026-01-09 13:54:32 +08:00
function handleCardClick() {
// 如果正在编辑,不处理点击
if (editingProcessId.value) return
// 设置当前任务,与任务大纲联动
if (props.step.Id) {
2026-01-14 17:54:00 +08:00
agentsStore.setCurrentTask(props.step as any)
2026-01-09 13:54:32 +08:00
}
}
2025-12-31 19:04:58 +08:00
// 检测当前是否是深色模式
function isDarkMode(): boolean {
return document.documentElement.classList.contains('dark')
}
// 获取颜色浅两号的函数
function getLightColor(color: string, level: number = 2): string {
if (!color || color.length !== 7 || color[0] !== '#') return color
const r = parseInt(color.substr(1, 2), 16)
const g = parseInt(color.substr(3, 2), 16)
const b = parseInt(color.substr(5, 2), 16)
// 增加亮度(浅两号)
const lightenAmount = level * 20
const newR = Math.min(255, r + lightenAmount)
const newG = Math.min(255, g + lightenAmount)
const newB = Math.min(255, b + lightenAmount)
return `#${Math.round(newR).toString(16).padStart(2, '0')}${Math.round(newG)
.toString(16)
.padStart(2, '0')}${Math.round(newB).toString(16).padStart(2, '0')}`
}
2025-12-31 19:04:58 +08:00
// 获取颜色深两号的函数
function getDarkColor(color: string, level: number = 2): string {
if (!color || color.length !== 7 || color[0] !== '#') return color
const r = parseInt(color.substr(1, 2), 16)
const g = parseInt(color.substr(3, 2), 16)
const b = parseInt(color.substr(5, 2), 16)
// 降低亮度(深两号)
const darkenAmount = level * 20
const newR = Math.max(0, r - darkenAmount)
const newG = Math.max(0, g - darkenAmount)
const newB = Math.max(0, b - darkenAmount)
return `#${Math.round(newR).toString(16).padStart(2, '0')}${Math.round(newG)
.toString(16)
.padStart(2, '0')}${Math.round(newB).toString(16).padStart(2, '0')}`
}
// 根据主题模式获取调整后的颜色
function getAdjustedColor(color: string, level: number = 2): string {
if (isDarkMode()) {
return getDarkColor(color, level)
} else {
return getLightColor(color, level)
}
}
// 处理鼠标进入
function handleMouseEnter(processId: string) {
hoverProcessId.value = processId
}
// 处理鼠标离开
function handleMouseLeave() {
hoverProcessId.value = null
}
// 处理双击编辑针对单个process
function handleDblClick(processId: string, currentDescription: string) {
editingProcessId.value = processId
editValue.value = currentDescription
emit('open-edit', props.step.Id || '', processId)
}
// 处理保存编辑
function handleSave(processId: string) {
if (!editingProcessId.value) return
emit('save-edit', props.step.Id || '', processId, editValue.value)
editingProcessId.value = null
editValue.value = ''
}
// 处理取消编辑
function handleCancel() {
editingProcessId.value = null
editValue.value = ''
}
</script>
<template>
2026-01-09 13:54:32 +08:00
<div class="process-card" @click="handleCardClick">
<div class="process-content">
<!-- 显示模式 -->
<div class="display-content">
<span
2026-01-09 13:54:32 +08:00
v-for="process in currentTaskProcess"
:key="process.ID"
class="process-segment"
@mouseenter="handleMouseEnter(process.ID)"
@mouseleave="handleMouseLeave"
>
<span
class="agent-name"
:style="{
backgroundColor: getActionTypeDisplay(process.ActionType)?.color || '#909399',
color: '#fff',
padding: '2px 6px',
borderRadius: '3px',
marginRight: '4px'
}"
>
{{ process.AgentName }}
</span>
<!-- 编辑模式 - 修改为卡片样式 -->
<div v-if="editingProcessId === process.ID" class="edit-container">
<div class="edit-card">
2025-12-31 19:04:58 +08:00
<div class="flex flex-col gap-3">
<el-input
v-model="editValue"
type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }"
placeholder="请输入描述内容"
autofocus
/>
<div class="flex justify-end">
<svg-icon
icon-class="Check"
size="20px"
color="#328621"
class="cursor-pointer mr-4"
@click="handleSave(process.ID)"
title="保存"
/>
<svg-icon
icon-class="Cancel"
size="20px"
color="#8e0707"
class="cursor-pointer mr-1"
@click="handleCancel"
title="取消"
/>
</div>
</div>
</div>
</div>
<!-- 显示模式 -->
<span
v-else
class="process-description"
:class="{ hovered: hoverProcessId === process.ID }"
:style="{
border: `1px solid ${getActionTypeDisplay(process.ActionType)?.border}`,
backgroundColor:
hoverProcessId === process.ID
2025-12-31 19:04:58 +08:00
? getAdjustedColor(getActionTypeDisplay(process.ActionType)?.color || '#909399')
: 'transparent'
}"
@dblclick="handleDblClick(process.ID, process.Description)"
>
{{ process.Description }}
</span>
2026-01-09 13:54:32 +08:00
<span class="separator" v-if="process.Description && !process.Description.endsWith('。')"
></span
>
</span>
</div>
</div>
2026-01-09 13:54:32 +08:00
<!-- 按钮点击不会冒泡到卡片 -->
2025-12-31 19:04:58 +08:00
<BranchButton :step="step" />
</div>
</template>
<style scoped lang="scss">
.process-card {
2025-12-31 19:04:58 +08:00
position: relative;
margin-bottom: 16px;
padding: 16px;
border-radius: 8px;
background: var(--color-bg-list);
border: 1px solid var(--color-border-default);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
2026-01-09 13:54:32 +08:00
cursor: pointer;
transition: all 0.2s ease;
.process-content {
min-height: 20px;
.display-content {
line-height: 1.6;
font-size: 14px;
color: var(--el-text-color-primary);
.process-segment {
display: inline;
position: relative;
.agent-name {
display: inline-block;
font-weight: 500;
font-size: 13px;
margin-right: 4px;
cursor: default;
}
.edit-container {
display: block; // 改为块级元素,使其换行显示
margin-top: 8px;
margin-bottom: 8px;
.edit-card {
//background: #f0f2f5;
border-radius: 8px;
padding: 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
width: 100%;
max-width: 600px;
:deep(.el-textarea) {
width: 100%;
.el-textarea__inner {
font-size: 14px;
line-height: 1.6;
padding: 8px 12px;
border-radius: 4px;
resize: vertical;
min-height: 60px;
color: var(--color-text-taskbar);
}
}
.edit-buttons {
display: flex;
gap: 8px;
2025-12-31 19:04:58 +08:00
justify-content: flex-end;
margin-top: 8px;
}
}
}
.process-description {
display: inline;
white-space: normal;
cursor: pointer;
padding: 2px 4px;
border-radius: 3px;
transition: background-color 0.2s ease;
&.hovered {
transition: background-color 0.2s ease;
}
}
.separator {
margin-right: 8px;
}
&:last-child .separator {
display: none;
}
}
}
}
}
.process-card:hover {
border-color: var(--el-border-color);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
</style>