| | |
| | | </BasicModal> |
| | | </div> |
| | | </template> |
| | | <script lang="ts"> |
| | | <script lang="ts" setup> |
| | | import type { Ref } from 'vue'; |
| | | import type { Definition } from '@logicflow/core'; |
| | | import { defineComponent, ref, onMounted, unref, nextTick, computed, watch } from 'vue'; |
| | | import { ref, onMounted, unref, nextTick, computed, watch } from 'vue'; |
| | | import FlowChartToolbar from './FlowChartToolbar.vue'; |
| | | import LogicFlow from '@logicflow/core'; |
| | | import { Snapshot, BpmnElement, Menu, DndPanel, SelectionSelect } from '@logicflow/extension'; |
| | | import { useDesign } from '/@/hooks/web/useDesign'; |
| | | import { useAppStore } from '/@/store/modules/app'; |
| | | import { useDesign } from '@/hooks/web/useDesign'; |
| | | import { useAppStore } from '@/store/modules/app'; |
| | | import { createFlowChartContext } from './useFlowContext'; |
| | | // import { toLogicFlowData } from './adpterForTurbo'; |
| | | import { useModal, BasicModal } from '/@/components/Modal'; |
| | | import { JsonPreview } from '/@/components/CodeEditor'; |
| | | import { toLogicFlowData } from './adpterForTurbo'; |
| | | import { useModal, BasicModal } from '@/components/Modal'; |
| | | import { JsonPreview } from '@/components/CodeEditor'; |
| | | import { configDefaultDndPanel } from './config'; |
| | | import '@logicflow/core/dist/style/index.css'; |
| | | import '@logicflow/extension/lib/style/index.css'; |
| | |
| | | import PackingNode from './PackingNode'; |
| | | import RepairNode from './RepairNode'; |
| | | |
| | | const { notification } = useMessage(); |
| | | const { t } = useI18n(); |
| | | defineOptions({ name: 'FlowChart' }); |
| | | |
| | | export default defineComponent({ |
| | | name: 'FlowChart', |
| | | components: { BasicModal, FlowChartToolbar, JsonPreview }, |
| | | props: { |
| | | flowOptions: { |
| | | type: Object as PropType<Definition>, |
| | | default: () => ({}), |
| | | }, |
| | | |
| | | data: { |
| | | type: Object as PropType<any>, |
| | | default: () => ({}), |
| | | }, |
| | | |
| | | toolbar: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | patternItems: { |
| | | type: Array, |
| | | }, |
| | | const props = defineProps({ |
| | | flowOptions: { |
| | | type: Object as PropType<Definition>, |
| | | default: () => ({}), |
| | | }, |
| | | emits: [ |
| | | 'view-data', |
| | | 'save-data', |
| | | 'add-lf', |
| | | 'select-node', |
| | | 'click-blank', |
| | | 'init', |
| | | 'undo', |
| | | 'redo', |
| | | ], |
| | | setup(props, { emit }) { |
| | | const globSetting = useGlobSetting(); |
| | | const lfElRef = ref(null); |
| | | const graphData = ref({}); |
| | | |
| | | const lfInstance = ref(null) as Ref<LogicFlow | null>; |
| | | data: { |
| | | type: Object as PropType<any>, |
| | | default: () => ({}), |
| | | }, |
| | | |
| | | const { prefixCls } = useDesign('flow-chart'); |
| | | const appStore = useAppStore(); |
| | | const [register, { openModal }] = useModal(); |
| | | createFlowChartContext({ |
| | | logicFlow: lfInstance as unknown as LogicFlow, |
| | | }); |
| | | |
| | | const getFlowOptions = computed(() => { |
| | | const { flowOptions } = props; |
| | | |
| | | const defaultOptions: Partial<Definition> = { |
| | | grid: true, |
| | | background: { |
| | | color: appStore.getDarkMode === 'light' ? '#f7f9ff' : '#151515', |
| | | }, |
| | | keyboard: { |
| | | enabled: true, |
| | | }, |
| | | edgeType: 'bezier', |
| | | ...flowOptions, |
| | | }; |
| | | return defaultOptions as Definition; |
| | | }); |
| | | |
| | | watch( |
| | | () => props.data, |
| | | () => { |
| | | onRender(); |
| | | }, |
| | | ); |
| | | |
| | | // TODO |
| | | // watch( |
| | | // () => appStore.getDarkMode, |
| | | // () => { |
| | | // init(); |
| | | // } |
| | | // ); |
| | | |
| | | watch( |
| | | () => unref(getFlowOptions), |
| | | (options) => { |
| | | unref(lfInstance)?.updateEditConfig(options); |
| | | }, |
| | | ); |
| | | |
| | | // init logicFlow |
| | | async function init() { |
| | | await nextTick(); |
| | | |
| | | const lfEl = unref(lfElRef); |
| | | if (!lfEl) { |
| | | return; |
| | | } |
| | | LogicFlow.use(DndPanel); |
| | | |
| | | // Canvas configuration |
| | | LogicFlow.use(Snapshot); |
| | | // Use the bpmn plug-in to introduce bpmn elements, which can be used after conversion in turbo |
| | | LogicFlow.use(BpmnElement); |
| | | // Start the right-click menu |
| | | LogicFlow.use(Menu); |
| | | LogicFlow.use(SelectionSelect); |
| | | |
| | | lfInstance.value = new LogicFlow({ |
| | | ...unref(getFlowOptions), |
| | | container: lfEl, |
| | | edgeGenerator: (sourceNode) => { |
| | | // console.log('a'); |
| | | // 起始节点类型 rect 时使用 自定义的边 custom-edge |
| | | if (sourceNode.properties.isReturn) return 'custom-edge'; |
| | | // if (sourceNode.type === 'rect') return 'custom-edge'; |
| | | // return 'custom-edge'; |
| | | }, |
| | | }); |
| | | const lf = unref(lfInstance)!; |
| | | // lf?.setDefaultEdgeType('line'); |
| | | lf.register(actionRect); |
| | | lf.register(TestNode); |
| | | lf.register(CollectNode); |
| | | lf.register(AssemblyNode); |
| | | lf.register(PackingNode); |
| | | lf.register(RepairNode); |
| | | onRender(); |
| | | lf?.setPatternItems(props.patternItems || configDefaultDndPanel(lf)); |
| | | } |
| | | |
| | | async function onRender() { |
| | | await nextTick(); |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | lf.register(customEdge); |
| | | // const lFData = toLogicFlowData(props.data); |
| | | lf.render(props.data); |
| | | |
| | | lf.on('anchor:drop', (data) => { |
| | | const nodeData = data.nodeModel.getData(); |
| | | if (nodeData.properties.isReturn === true) { |
| | | console.log(11, nodeData.properties.isReturn); |
| | | data.nodeModel.graphModel.edges.forEach((element) => { |
| | | if (element.sourceNodeId === data.nodeModel.id) { |
| | | lf.changeEdgeType(element.id, 'custom-edge'); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | lf.on('node:click,edge:click', (data) => { |
| | | if (data.isSelected) { |
| | | console.log(data.data.text.value, data.isSelected); |
| | | // notification.success({ |
| | | // message: t('点击了节点'), |
| | | // description: `${data.data.text.value}: ${data.isSelected}`, |
| | | // duration: 3, |
| | | // }); |
| | | emit('select-node', data, lf); |
| | | } else { |
| | | console.log(data.data.type); |
| | | } |
| | | }); |
| | | |
| | | lf.on('blank:mousedown', (e) => { |
| | | emit('click-blank'); |
| | | }); |
| | | |
| | | lf.on('node:dnd-add', (data, e) => { |
| | | console.log('node:dnd-add', data); |
| | | emit('select-node', data, lf); |
| | | }); |
| | | |
| | | emit('init', lf); |
| | | } |
| | | |
| | | function handlePreview() { |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | graphData.value = unref(lf).getGraphData(); |
| | | openModal(); |
| | | } |
| | | |
| | | function handleSave() { |
| | | // console.log('handleSave'); |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | emit('save-data', lf); |
| | | } |
| | | |
| | | function handleAdd() { |
| | | const lf = unref(lfInstance); |
| | | console.log('handleAdd'); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | // lf.clearData(); |
| | | lf.render({}); |
| | | } |
| | | |
| | | function handleAddlf() { |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | emit('add-lf', lf); |
| | | } |
| | | |
| | | function handleUndo() { |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | emit('undo', lf); |
| | | } |
| | | |
| | | function handleRedo() { |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | emit('redo', lf); |
| | | } |
| | | |
| | | onMounted(init); |
| | | |
| | | return { |
| | | register, |
| | | prefixCls, |
| | | lfElRef, |
| | | handlePreview, |
| | | graphData, |
| | | handleSave, |
| | | handleAdd, |
| | | handleAddlf, |
| | | handleUndo, |
| | | handleRedo, |
| | | }; |
| | | toolbar: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | patternItems: { |
| | | type: Array, |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits([ |
| | | 'view-data', |
| | | 'save-data', |
| | | 'add-lf', |
| | | 'select-node', |
| | | 'click-blank', |
| | | 'init', |
| | | 'undo', |
| | | 'redo', |
| | | ]); |
| | | const lfElRef = ref(null); |
| | | const graphData = ref({}); |
| | | |
| | | const lfInstance = ref(null) as Ref<LogicFlow | null>; |
| | | |
| | | const { prefixCls } = useDesign('flow-chart'); |
| | | const appStore = useAppStore(); |
| | | const [register, { openModal }] = useModal(); |
| | | createFlowChartContext({ |
| | | logicFlow: lfInstance as unknown as LogicFlow, |
| | | }); |
| | | |
| | | const getFlowOptions = computed(() => { |
| | | const { flowOptions } = props; |
| | | |
| | | const defaultOptions: Partial<Definition> = { |
| | | grid: true, |
| | | background: { |
| | | color: appStore.getDarkMode === 'light' ? '#f7f9ff' : '#151515', |
| | | }, |
| | | keyboard: { |
| | | enabled: true, |
| | | }, |
| | | edgeType: 'polyline', |
| | | ...flowOptions, |
| | | }; |
| | | return defaultOptions as Definition; |
| | | }); |
| | | |
| | | watch( |
| | | () => props.data, |
| | | () => { |
| | | onRender(); |
| | | }, |
| | | ); |
| | | |
| | | // TODO |
| | | // watch( |
| | | // () => appStore.getDarkMode, |
| | | // () => { |
| | | // init(); |
| | | // } |
| | | // ); |
| | | |
| | | watch( |
| | | () => unref(getFlowOptions), |
| | | (options) => { |
| | | unref(lfInstance)?.updateEditConfig(options); |
| | | }, |
| | | ); |
| | | |
| | | // init logicFlow |
| | | async function init() { |
| | | await nextTick(); |
| | | |
| | | const lfEl = unref(lfElRef); |
| | | if (!lfEl) { |
| | | return; |
| | | } |
| | | LogicFlow.use(DndPanel); |
| | | |
| | | // Canvas configuration |
| | | LogicFlow.use(Snapshot); |
| | | // Use the bpmn plug-in to introduce bpmn elements, which can be used after conversion in turbo |
| | | LogicFlow.use(BpmnElement); |
| | | // Start the right-click menu |
| | | LogicFlow.use(Menu); |
| | | LogicFlow.use(SelectionSelect); |
| | | |
| | | lfInstance.value = new LogicFlow({ |
| | | ...unref(getFlowOptions), |
| | | container: lfEl, |
| | | edgeGenerator: (sourceNode) => { |
| | | // console.log('a'); |
| | | // 起始节点类型 rect 时使用 自定义的边 custom-edge |
| | | if (sourceNode.properties.isReturn) return 'custom-edge'; |
| | | // if (sourceNode.type === 'rect') return 'custom-edge'; |
| | | // return 'custom-edge'; |
| | | }, |
| | | }); |
| | | const lf = unref(lfInstance)!; |
| | | lf?.setDefaultEdgeType('polyline'); |
| | | lf.register(actionRect); |
| | | lf.register(TestNode); |
| | | lf.register(CollectNode); |
| | | lf.register(AssemblyNode); |
| | | lf.register(PackingNode); |
| | | lf.register(RepairNode); |
| | | lf.register(customEdge); |
| | | onRender(); |
| | | lf?.setPatternItems(props.patternItems || configDefaultDndPanel(lf)); |
| | | } |
| | | |
| | | async function onRender() { |
| | | await nextTick(); |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | const lFData = toLogicFlowData(props.data); |
| | | lf.render(lFData); |
| | | |
| | | lf.on('anchor:drop', (data) => { |
| | | const nodeData = data.nodeModel.getData(); |
| | | if (nodeData.properties.isReturn === true) { |
| | | console.log(11, nodeData.properties.isReturn); |
| | | data.nodeModel.graphModel.edges.forEach((element) => { |
| | | if (element.sourceNodeId === data.nodeModel.id) { |
| | | lf.changeEdgeType(element.id, 'custom-edge'); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | lf.on('node:click,edge:click', (data) => { |
| | | if (data.isSelected) { |
| | | console.log(data.data.text.value, data.isSelected); |
| | | // notification.success({ |
| | | // message: t('点击了节点'), |
| | | // description: `${data.data.text.value}: ${data.isSelected}`, |
| | | // duration: 3, |
| | | // }); |
| | | emit('select-node', data, lf); |
| | | } else { |
| | | console.log(data.data.type); |
| | | } |
| | | }); |
| | | |
| | | lf.on('blank:mousedown', (e) => { |
| | | emit('click-blank'); |
| | | }); |
| | | |
| | | lf.on('node:dnd-add', (data, e) => { |
| | | console.log('node:dnd-add', data); |
| | | emit('select-node', data, lf); |
| | | }); |
| | | |
| | | emit('init', lf); |
| | | } |
| | | |
| | | function handlePreview() { |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | graphData.value = unref(lf).getGraphData(); |
| | | openModal(); |
| | | } |
| | | |
| | | function handleSave() { |
| | | // console.log('handleSave'); |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | emit('save-data', lf); |
| | | } |
| | | |
| | | function handleAdd() { |
| | | const lf = unref(lfInstance); |
| | | console.log('handleAdd'); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | // lf.clearData(); |
| | | lf.render({}); |
| | | } |
| | | |
| | | function handleAddlf() { |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | emit('add-lf', lf); |
| | | } |
| | | |
| | | function handleUndo() { |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | emit('undo', lf); |
| | | } |
| | | |
| | | function handleRedo() { |
| | | const lf = unref(lfInstance); |
| | | if (!lf) { |
| | | return; |
| | | } |
| | | emit('redo', lf); |
| | | } |
| | | |
| | | onMounted(init); |
| | | </script> |
| | | ./TestNode |