feat:1.任务大纲编排删除功能新增2.编辑窗口放大缩小功能
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user