feat:1.任务大纲编排删除功能新增2.编辑窗口放大缩小功能

This commit is contained in:
liailing1026
2026-02-28 13:40:58 +08:00
parent 8b9c493393
commit f267462e70
4 changed files with 128 additions and 16 deletions

View File

@@ -42,6 +42,14 @@
/>
</template>
</VueFlow>
<!-- 删除分支确认对话框 -->
<DeleteConfirmDialog
v-model="deleteDialogVisible"
title="确认删除该分支 ?"
content="删除后,该分支无法恢复 !"
@confirm="confirmDeleteBranch"
/>
</div>
</div>
</template>
@@ -59,6 +67,7 @@ import '@vue-flow/core/dist/theme-default.css'
import '@vue-flow/minimap/dist/style.css'
import '@vue-flow/controls/dist/style.css'
import TaskNode from './components/TaskNode.vue'
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog/index.vue'
const agentsStore = useAgentsStore()
const selectionStore = useSelectionStore()
@@ -98,6 +107,13 @@ const styledEdges = computed(() => {
stroke: isHighlighted ? 'var(--color-node-active)' : 'var(--color-node-border)',
strokeWidth: 2
},
markerEnd: {
type: 'arrow' as any,
color: isHighlighted ? 'var(--color-node-active)' : 'var(--color-node-border)',
width: 20,
height: 20,
strokeWidth: 2
},
animated: isHighlighted,
class: isHighlighted ? 'edge-highlighted' : 'edge-normal'
}
@@ -381,7 +397,7 @@ const initializeFlow = () => {
style: { stroke: '#e6a23c', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
color: '#e6a23c',
width: 20,
height: 20,
strokeWidth: 2
@@ -405,7 +421,7 @@ const initializeFlow = () => {
style: { stroke: '#409eff', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
color: '#409eff',
width: 20,
height: 20,
strokeWidth: 2
@@ -714,10 +730,62 @@ const getNodeDeletable = (nodeId: string): { isDeletable: boolean; branchId: str
}
}
// 删除分支
// 删除分支弹窗相关状态
const deleteDialogVisible = ref(false)
const branchIdToDelete = ref<string | null>(null)
// 删除分支(显示确认对话框)
const handleDeleteBranch = (branchId: string) => {
console.log('删除分支:', branchId)
// 后续实现删除逻辑
branchIdToDelete.value = branchId
deleteDialogVisible.value = true
}
// 确认删除分支
const confirmDeleteBranch = async () => {
if (!branchIdToDelete.value) return
const branchId = branchIdToDelete.value
// 1. 从store中获取该分支的信息
const allBranches = selectionStore.getAllFlowBranches()
// branchId是timestamp格式需要通过edges中的data.branchId来匹配
const branchToDelete = allBranches.find(b =>
b.edges.some(e => e.data?.branchId === branchId)
)
if (!branchToDelete) {
ElMessage.error('未找到该分支')
deleteDialogVisible.value = false
return
}
// 2. 从nodes中删除该分支的所有节点排除根节点和主流程节点
const branchNodeIds = branchToDelete.nodes
.filter(n => n.id !== 'root-goal' && !n.id.startsWith('task-'))
.map(n => n.id)
nodes.value = nodes.value.filter(n => !branchNodeIds.includes(n.id))
// 3. 从edges中删除该分支的所有边
const branchEdgeIds = branchToDelete.edges.map(e => e.id)
edges.value = edges.value.filter(e => !branchEdgeIds.includes(e.id))
// 4. 从selectionStore中删除该分支
selectionStore.removeFlowBranch(branchToDelete.id)
// 5. 保存到数据库
await saveBranchesToDB()
// 6. 关闭对话框并清理状态
deleteDialogVisible.value = false
branchIdToDelete.value = null
// 7. 刷新视图
nextTick(() => {
fit({ padding: 0.15, duration: 300 })
})
ElMessage.success('分支删除成功')
}
// 开始编辑任务
@@ -895,6 +963,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
// 创建连接边
if (index === 0) {
const strokeColor = taskId === 'root-goal' ? '#409eff' : '#67c23a'
const newEdge: Edge = {
id: `edge-${taskId}-${taskNodeId}`,
source: taskId,
@@ -903,10 +972,10 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
targetHandle: 'left',
type: 'smoothstep',
animated: true,
style: { stroke: '#409eff', strokeWidth: 2, strokeDasharray: '5,5' },
style: { stroke: strokeColor, strokeWidth: 2, strokeDasharray: '5,5' },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
color: strokeColor,
width: 20,
height: 20,
strokeWidth: 2
@@ -930,7 +999,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
style: { stroke: '#409eff', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
color: '#409eff',
width: 20,
height: 20,
strokeWidth: 2
@@ -1172,7 +1241,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
style: { stroke: '#67c23a', strokeWidth: 2, strokeDasharray: '5,5' },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
color: '#67c23a',
width: 20,
height: 20,
strokeWidth: 2
@@ -1197,7 +1266,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
style: { stroke: '#67c23a', strokeWidth: 2 },
markerEnd: {
type: 'arrow' as any,
color: '#43a8aa',
color: '#67c23a',
width: 20,
height: 20,
strokeWidth: 2

View File

@@ -11,6 +11,7 @@ const agentsStore = useAgentsStore()
// 面板显示状态
const visible = ref(false)
const activeTab = ref('outline')
const isMaximized = ref(false)
// 判断是否有流程数据
const planReady = computed(() => {
@@ -65,6 +66,11 @@ const handleTabChange = (tabKey: string) => {
activeTab.value = tabKey
}
// 切换最大化/还原
const toggleMaximize = () => {
isMaximized.value = !isMaximized.value
}
// 暴露给父组件
defineExpose({
open,
@@ -76,7 +82,7 @@ defineExpose({
<Teleport to="body">
<!-- 面板主体 -->
<Transition name="slide-up">
<div v-if="visible" class="settings-panel">
<div v-if="visible" :class="['settings-panel', { 'is-maximized': isMaximized }]">
<!-- 标签栏 -->
<div class="panel-header">
<div class="tabs-container">
@@ -98,6 +104,9 @@ defineExpose({
</span>
</div>
</div>
<button class="maximize-btn" @click="toggleMaximize">
<SvgIcon :icon-class="isMaximized ? 'SuoXiao' : 'FangDa'" size="20px" />
</button>
<button class="close-btn" @click="close">
<SvgIcon icon-class="close" size="20px" />
</button>
@@ -129,11 +138,12 @@ defineExpose({
// 面板主体
.settings-panel {
position: fixed;
bottom: 20px;
left: 50%;
margin-left: -40%;
bottom: 6%;
left: 0;
right: 0;
width: 80%;
max-width: 1200px;
margin: 0 auto;
height: 70vh;
background: var(--color-bg-three);
border-radius: 20px;
@@ -142,6 +152,17 @@ defineExpose({
display: flex;
flex-direction: column;
overflow: hidden;
transition: width 0.4s ease, height 0.4s ease, bottom 0.4s ease, border-radius 0.4s ease;
&.is-maximized {
max-width: none;
left: 24px;
right: 24px;
width: auto;
height: calc(100% - 194px);
bottom: 24px;
border-radius: 20px;
}
}
// 标题栏(包含标签栏)
@@ -161,6 +182,26 @@ defineExpose({
gap: 8px;
}
.maximize-btn {
background: none;
border: none;
cursor: pointer;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
color: var(--color-text-secondary);
transition: all 0.3s;
position: absolute;
right: 60px;
&:hover {
transform: rotate(180deg);
}
}
.close-btn {
background: none;
border: none;
@@ -177,7 +218,7 @@ defineExpose({
right: 20px;
&:hover {
transform: rotate(360deg);
transform: rotate(180deg);
}
}
@@ -297,7 +338,7 @@ defineExpose({
// 动画效果
.slide-up-enter-active,
.slide-up-leave-active {
transition: all 0.5s ease;
transition: opacity 0.5s ease, transform 0.5s ease;
}
.slide-up-enter-from,