Files
AgentCoord/frontend/src/layout/components/Main/TaskTemplate/TaskProcess/ProcessCard.vue
2026-01-14 17:54:00 +08:00

325 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { ref, computed } from 'vue'
import { getActionTypeDisplay } from '@/layout/components/config.ts'
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
}>()
//从 currentTask 中获取数据
const currentTaskProcess = computed(() => {
const currentTask = agentsStore.currentTask
if (currentTask && currentTask.Id === props.step.Id && currentTask.TaskProcess) {
return currentTask.TaskProcess
}
//从 agentRawPlan 中获取原始数据
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)
// 处理卡片点击事件
function handleCardClick() {
// 如果正在编辑,不处理点击
if (editingProcessId.value) return
// 设置当前任务,与任务大纲联动
if (props.step.Id) {
agentsStore.setCurrentTask(props.step as any)
}
}
// 检测当前是否是深色模式
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')}`
}
// 获取颜色深两号的函数
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>
<div class="process-card" @click="handleCardClick">
<div class="process-content">
<!-- 显示模式 -->
<div class="display-content">
<span
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">
<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
? getAdjustedColor(getActionTypeDisplay(process.ActionType)?.color || '#909399')
: 'transparent'
}"
@dblclick="handleDblClick(process.ID, process.Description)"
>
{{ process.Description }}
</span>
<span class="separator" v-if="process.Description && !process.Description.endsWith('。')"
></span
>
</span>
</div>
</div>
<!-- 按钮点击不会冒泡到卡片 -->
<BranchButton :step="step" />
</div>
</template>
<style scoped lang="scss">
.process-card {
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);
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;
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>