160 lines
4.3 KiB
Vue
160 lines
4.3 KiB
Vue
<script setup lang="ts">
|
||
import { ref, onMounted, onUnmounted, reactive, nextTick, watch } from "vue";
|
||
import type { Node, Edge } from '@vue-flow/core'
|
||
import { VueFlow, useVueFlow } from '@vue-flow/core'
|
||
import SpecialEdge from './speciaiEdge.vue'
|
||
import InputNode from './InputNode.vue'//主
|
||
import SecondaryNode from './secondaryNode.vue'//分支
|
||
import { useLayout } from '../../tools/tools'
|
||
const props = defineProps({
|
||
selectItem: {
|
||
type: Object,
|
||
default: () => ({})
|
||
} as any,
|
||
treeList: {
|
||
type: Array,
|
||
default: () => []
|
||
}
|
||
})
|
||
const emit = defineEmits([
|
||
'setSelectItem',
|
||
])
|
||
|
||
// 节点类型:input、output、default、custom
|
||
// input:开始点,output:结尾点,default:普通节点,custom:自定义节点
|
||
const position = { x: 0, y: 0 }
|
||
const nodes = ref<Node[]>([
|
||
// { id: '1', type: 'input', label: 'Node 1', class: 'custom-node start', position },
|
||
// { id: '2', type: 'SecondaryNode', class: 'custom-node', data: { id: '主 1' }, position },
|
||
// { id: '2-1', type: 'SecondaryNode', class: 'custom-node', data: { id: '主 2' }, position },
|
||
// { id: '3', type: 'SecondaryNode', class: 'custom-node', data: { id: '主 3' }, position },
|
||
])
|
||
|
||
// 边类型:custom、default
|
||
// custom:自定义边,default:普通边,step:直角边,smoothstep:平滑边
|
||
const edges = ref<Edge[]>([
|
||
// { id: 'e1-3', source: '2', target: '2-1', type: 'smoothstep', },
|
||
// { id: 'e1-4', source: '2', target: '3', type: 'smoothstep', animated: true },
|
||
])
|
||
const { fitView } = useVueFlow()
|
||
const { layout } = useLayout()
|
||
async function layoutGraph(direction) {
|
||
setTimeout(() => {
|
||
nodes.value = layout(nodes.value, edges.value, direction)
|
||
console.log(nodes.value)
|
||
nextTick(() => {
|
||
fitView()
|
||
})
|
||
}, 0)
|
||
}
|
||
|
||
const push = (item)=>{
|
||
if(!item.id){
|
||
nodes.value.push({ id: '0', type: 'InputNode', class: 'custom-node', position })
|
||
}else{
|
||
let className = `custom-node item${item.id.replace(/-/g, "_")}`
|
||
let id = item.id
|
||
let source = edges.value.length == 0?'0':item.id.slice(0, -2)
|
||
nodes.value.push({id,type:'SecondaryNode',class:className,position,data:item})
|
||
edges.value.push({ id, target:id, source, type: 'smoothstep' })
|
||
}
|
||
}
|
||
|
||
const initialized = ()=>{
|
||
layoutGraph('TB')
|
||
}
|
||
|
||
//是否可拖动节点
|
||
const nodesDraggable = ref(false)
|
||
const toggleNodesDraggable = () => {
|
||
nodesDraggable.value = !nodesDraggable.value
|
||
}
|
||
|
||
const handleVueFlowNodeClick = ({node}) => {
|
||
if(node.data.id)emit('setSelectItem', node.data)
|
||
}
|
||
|
||
watch(()=>props.treeList.length, (newVal, oldVal) => {
|
||
nodes.value = []
|
||
edges.value = []
|
||
props.treeList.forEach(item=>{
|
||
push(item)
|
||
})
|
||
},{immediate:true})
|
||
watch(()=>props.selectItem.id, (newVal, oldVal) => {
|
||
})
|
||
|
||
onMounted(()=>{
|
||
})
|
||
onUnmounted(()=>{
|
||
})
|
||
defineExpose({push})
|
||
// const {} = toRefs(data);
|
||
</script>
|
||
<template>
|
||
<div class="view2">
|
||
<div class="vueFlowBox">
|
||
<div @click="toggleNodesDraggable">拖拽节点</div>
|
||
<VueFlow :nodes="nodes" @nodes-initialized="initialized" :edges="edges" @node-click="handleVueFlowNodeClick" :nodes-draggable="nodesDraggable">
|
||
<template #node-InputNode="nodeProps">
|
||
<InputNode v-bind="nodeProps" />
|
||
</template>
|
||
<template #node-SecondaryNode="nodeProps">
|
||
<SecondaryNode
|
||
v-bind="nodeProps"
|
||
:selectItem="props.selectItem"
|
||
/>
|
||
</template>
|
||
|
||
<!-- <template #edge-custom="edgeProps">
|
||
<SpecialEdge v-bind="edgeProps" />
|
||
</template> -->
|
||
</VueFlow>
|
||
</div>
|
||
|
||
</div>
|
||
</template>
|
||
<style lang="less">
|
||
@import "@vue-flow/core/dist/style.css";
|
||
@import "@vue-flow/core/dist/theme-default.css";
|
||
</style>
|
||
<style lang="less" scoped>
|
||
.view2{
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
>.vueFlowBox{
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
}
|
||
:deep(.custom-node){
|
||
.node{
|
||
--vf-handle: #c1c1c1;
|
||
--vf-node-color: #000;
|
||
--vf-box-shadow: #000;
|
||
font-size: 1.2rem;
|
||
width: var(--treeItem-width);
|
||
height: var(--treeItem-height);
|
||
font-weight: 500;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: var(--treeItem-raduis);
|
||
border: var(--treeItem-border);
|
||
color: #000;
|
||
cursor: pointer;
|
||
background-color: var(--treeItem-background);
|
||
box-sizing: border-box;
|
||
&.active{
|
||
background-color: var(--treeItem-active-background);
|
||
}
|
||
&.start{
|
||
background-color: #7A7A7A;
|
||
color: #FFF;
|
||
border: 2px solid #7A7A7A;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style> |