325 lines
9.0 KiB
Vue
325 lines
9.0 KiB
Vue
<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>
|