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

@@ -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="1772248670725" class="icon" viewBox="0 0 1365 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17188" width="341.25" height="256" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M1140.982158 0C1171.511117 0 1196.259731 24.748613 1196.259731 55.277574L1196.259731 481.802069C1196.259731 512.331031 1171.511117 537.079644 1140.982158 537.079644 1110.453196 537.079644 1085.704583 512.331031 1085.704583 481.802069L1085.704583 55.277574 1140.982158 110.555148 707.290659 110.555148C676.761697 110.555148 652.013084 85.806535 652.013084 55.277574 652.013084 24.748613 676.761697 0 707.290659 0L1140.982158 0ZM223.896216 1024.028434C193.367257 1024.028434 168.618642 999.279821 168.618642 968.75086L168.618642 542.226364C168.618642 511.697403 193.367257 486.94879 223.896216 486.94879 254.425178 486.94879 279.17379 511.697403 279.17379 542.226364L279.17379 968.75086 223.896216 913.473286 657.587715 913.473286C688.116677 913.473286 712.865289 938.221898 712.865289 968.75086 712.865289 999.279821 688.116677 1024.028434 657.587715 1024.028434L223.896216 1024.028434Z" p-id="17189"></path></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View 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="1772247481697" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15251" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M554.666667 405.333333V85.333333h85.333333v298.666667h298.666667v85.333333h-320.085334A63.914667 63.914667 0 0 1 554.666667 405.333333zM85.333333 554.666667h320.085334c35.584 0 63.914667 28.885333 63.914666 64V938.666667H384v-298.666667H85.333333v-85.333333z" p-id="15252"></path></svg>

After

Width:  |  Height:  |  Size: 621 B

View File

@@ -42,6 +42,14 @@
/> />
</template> </template>
</VueFlow> </VueFlow>
<!-- 删除分支确认对话框 -->
<DeleteConfirmDialog
v-model="deleteDialogVisible"
title="确认删除该分支 ?"
content="删除后,该分支无法恢复 !"
@confirm="confirmDeleteBranch"
/>
</div> </div>
</div> </div>
</template> </template>
@@ -59,6 +67,7 @@ import '@vue-flow/core/dist/theme-default.css'
import '@vue-flow/minimap/dist/style.css' import '@vue-flow/minimap/dist/style.css'
import '@vue-flow/controls/dist/style.css' import '@vue-flow/controls/dist/style.css'
import TaskNode from './components/TaskNode.vue' import TaskNode from './components/TaskNode.vue'
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog/index.vue'
const agentsStore = useAgentsStore() const agentsStore = useAgentsStore()
const selectionStore = useSelectionStore() const selectionStore = useSelectionStore()
@@ -98,6 +107,13 @@ const styledEdges = computed(() => {
stroke: isHighlighted ? 'var(--color-node-active)' : 'var(--color-node-border)', stroke: isHighlighted ? 'var(--color-node-active)' : 'var(--color-node-border)',
strokeWidth: 2 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, animated: isHighlighted,
class: isHighlighted ? 'edge-highlighted' : 'edge-normal' class: isHighlighted ? 'edge-highlighted' : 'edge-normal'
} }
@@ -381,7 +397,7 @@ const initializeFlow = () => {
style: { stroke: '#e6a23c', strokeWidth: 2 }, style: { stroke: '#e6a23c', strokeWidth: 2 },
markerEnd: { markerEnd: {
type: 'arrow' as any, type: 'arrow' as any,
color: '#43a8aa', color: '#e6a23c',
width: 20, width: 20,
height: 20, height: 20,
strokeWidth: 2 strokeWidth: 2
@@ -405,7 +421,7 @@ const initializeFlow = () => {
style: { stroke: '#409eff', strokeWidth: 2 }, style: { stroke: '#409eff', strokeWidth: 2 },
markerEnd: { markerEnd: {
type: 'arrow' as any, type: 'arrow' as any,
color: '#43a8aa', color: '#409eff',
width: 20, width: 20,
height: 20, height: 20,
strokeWidth: 2 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) => { 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) { if (index === 0) {
const strokeColor = taskId === 'root-goal' ? '#409eff' : '#67c23a'
const newEdge: Edge = { const newEdge: Edge = {
id: `edge-${taskId}-${taskNodeId}`, id: `edge-${taskId}-${taskNodeId}`,
source: taskId, source: taskId,
@@ -903,10 +972,10 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
targetHandle: 'left', targetHandle: 'left',
type: 'smoothstep', type: 'smoothstep',
animated: true, animated: true,
style: { stroke: '#409eff', strokeWidth: 2, strokeDasharray: '5,5' }, style: { stroke: strokeColor, strokeWidth: 2, strokeDasharray: '5,5' },
markerEnd: { markerEnd: {
type: 'arrow' as any, type: 'arrow' as any,
color: '#43a8aa', color: strokeColor,
width: 20, width: 20,
height: 20, height: 20,
strokeWidth: 2 strokeWidth: 2
@@ -930,7 +999,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
style: { stroke: '#409eff', strokeWidth: 2 }, style: { stroke: '#409eff', strokeWidth: 2 },
markerEnd: { markerEnd: {
type: 'arrow' as any, type: 'arrow' as any,
color: '#43a8aa', color: '#409eff',
width: 20, width: 20,
height: 20, height: 20,
strokeWidth: 2 strokeWidth: 2
@@ -1172,7 +1241,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
style: { stroke: '#67c23a', strokeWidth: 2, strokeDasharray: '5,5' }, style: { stroke: '#67c23a', strokeWidth: 2, strokeDasharray: '5,5' },
markerEnd: { markerEnd: {
type: 'arrow' as any, type: 'arrow' as any,
color: '#43a8aa', color: '#67c23a',
width: 20, width: 20,
height: 20, height: 20,
strokeWidth: 2 strokeWidth: 2
@@ -1197,7 +1266,7 @@ const handleAddBranch = async (taskId: string, branchContent: string) => {
style: { stroke: '#67c23a', strokeWidth: 2 }, style: { stroke: '#67c23a', strokeWidth: 2 },
markerEnd: { markerEnd: {
type: 'arrow' as any, type: 'arrow' as any,
color: '#43a8aa', color: '#67c23a',
width: 20, width: 20,
height: 20, height: 20,
strokeWidth: 2 strokeWidth: 2

View File

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