demo-es6.html 11.7 KB
<html>
<head>
    <meta charset="utf-8">
    <title>vue-flow-editor demo</title>
    <link type="text/css" rel="stylesheet" href="http://martsforever-pot.gitee.io/vue-flow-editor/dist/vue-flow-editor.css">
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">

    <style>
        html, body {
            padding: 0;
            margin: 0;
        }
    </style>
</head>
<body>
<div id="app">

</div>
<script src="./lib/g6.umd.min.js"></script>
<script src="http://martsforever-pot.gitee.io/vue-flow-editor/lib/vue.min.js"></script>
<script src="https://unpkg.com/@vue/composition-api/dist/vue-composition-api.umd.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="http://martsforever-pot.gitee.io/vue-flow-editor/dist/vue-flow-editor.js"></script>
<script>

    console.log(window)
    Vue.use(window.vueCompositionApi.default)
    Vue.use(window.VueFlowEditor)
    const Ele = window.ELEMENT
    const G6 = window.G6.default
    const reactive = window.vueCompositionApi.reactive

    function delay(time) {
        return new Promise((resolve) => setTimeout(resolve, time))
    }

    const AppData = {
        "nodes": [{"data": {}, "id": "start-node", "label": "开始", "shape": "ellipse", "size": [120, 40], "x": 380, "y": 100}, {"data": {}, "id": "1588848310120", "label": "主管审批", "shape": "rect", "size": [120, 40], "x": 380, "y": 180}, {"data": {}, "id": "1588848322179", "label": "经理审批", "shape": "rect", "size": [120, 40], "x": 380, "y": 260}, {
            "data": {},
            "id": "1588848338211",
            "label": "金额>2万",
            "shape": "diamond",
            "size": [120, 40],
            "x": 380,
            "y": 340
        }, {"data": {}, "id": "1588848351476", "label": "财务打款", "shape": "rect", "size": [120, 40], "x": 380, "y": 460}, {"data": {}, "id": "end-node", "label": "结束", "shape": "ellipse", "size": [120, 40], "x": 380, "y": 540}, {"data": {}, "id": "1588848397511", "label": "VIP审批", "shape": "rect", "size": [120, 40], "x": 620, "y": 340}, {
            "data": {},
            "id": "1588848436694",
            "label": "金额>10万",
            "shape": "diamond",
            "size": [120, 40],
            "x": 780,
            "y": 340
        }, {"data": {}, "id": "1588848449431", "label": "CEO审批", "shape": "rect", "size": [120, 40], "x": 980, "y": 460}],
        "edges": [{"shape": "flow-polyline-round", "source": "start-node", "sourceAnchor": 2, "target": "1588848310120", "targetAnchor": 0}, {"shape": "flow-polyline-round", "source": "1588848310120", "sourceAnchor": 2, "target": "1588848322179", "targetAnchor": 0}, {
            "shape": "flow-polyline-round",
            "source": "1588848322179",
            "sourceAnchor": 2,
            "target": "1588848338211",
            "targetAnchor": 0
        }, {"shape": "flow-polyline-round", "source": "1588848338211", "sourceAnchor": 2, "target": "1588848351476", "targetAnchor": 0, "label": "否"}, {"shape": "flow-polyline-round", "source": "1588848351476", "sourceAnchor": 2, "target": "end-node", "targetAnchor": 0}, {
            "shape": "flow-polyline-round",
            "source": "1588848338211",
            "sourceAnchor": 3,
            "target": "1588848397511",
            "targetAnchor": 1,
            "label": "是"
        }, {"shape": "flow-polyline-round", "source": "1588848436694", "sourceAnchor": 3, "target": "1588848449431", "targetAnchor": 0, "label": "是"}, {"shape": "flow-polyline-round", "source": "1588848449431", "sourceAnchor": 1, "target": "1588848351476", "targetAnchor": 3}, {
            "shape": "flow-polyline-round",
            "source": "1588848436694",
            "sourceAnchor": 2,
            "target": "1588848351476",
            "targetAnchor": 3,
            "label": "否"
        }, {"shape": "flow-polyline-round", "source": "1588848397511", "sourceAnchor": 3, "target": "1588848436694", "targetAnchor": 1}]
    }

    new Vue({
        el: '#app',
        template: `
        <div class="app" style="height: 100vh">
            <vue-flow-editor
                    ref="editor"
                    :data="state.data"
                    :grid="showGrid"
                    :miniMap="showMiniMap"
                    :onRef="onRef"
                    :multipleSelect="true"
                    :loading="state.editorLoading"

                    :disabledUndo="false"
                    :disabledDragEdge="true"

                    :beforeDelete="handleBeforeDelete"
                    :afterDelete="handleAfterDelete"
                    :beforeAdd="handleBeforeAdd"
                    :afterAdd="handleAfterAdd"

                    @dblclick-node="onDblclickNode"
                    @dblclick-edge="onDblClickEdge"
            >
                <div slot="menu">
                    <vue-flow-edit-menu-group v-for="(group,groupIndex) in state.menuData" :label="group.label" :key="groupIndex">
                        <vue-flow-edit-menu v-for="(menu,menuIndex) in group.menus" :key="menuIndex" :model="menu"/>
                    </vue-flow-edit-menu-group>
                </div>
                <div slot="model" style="padding: 16px">
                    <el-form v-if="!!state.detailModel" ref="form" :model="state.detailModel" label-width="100px">

                        <el-form-item label="节点名称" prop="label">
                            <el-input v-model="state.detailModel.label"/>
                        </el-form-item>

                        <template v-if="state.detailModel.type !== 'edge'">
                            <el-form-item label="节点背景色" prop="style.fill">
                                <el-color-picker v-model="state.detailModel.style.fill"/>
                            </el-form-item>
                            <el-form-item label="节点边框色" prop="style.stroke">
                                <el-color-picker v-model="state.detailModel.style.stroke"/>
                            </el-form-item>
                            <el-form-item label="节点文字色" prop="labelCfg.style.stroke">
                                <el-color-picker v-model="state.detailModel.labelCfg.style.fill"/>
                            </el-form-item>
                        </template>

                    </el-form>
                </div>

                <template slot="toolbar">
                    <el-tooltip content="测试工具栏插槽">
                        <div class="vue-flow-editor-toolbar-item">
                            <i class="el-icon-search"/>
                        </div>
                    </el-tooltip>
                </template>

                <template slot="foot">
                    <el-button type="primary" @click="save">保存</el-button>
                    <el-button @click="cancel">取消</el-button>
                </template>
            </vue-flow-editor>
        </div>
        `,
        setup() {
            const state = reactive({
                data: AppData,
                detailModel: null,
                editorLoading: false,

                selectOptions: [
                    {label: '待确认', value: '0'},
                    {label: '填写表单', value: '1'},
                    {label: '部门负责人审批', value: '2'},
                    {label: '总经理审批', value: '3'},
                ],
                menuData: [
                    {
                        label: '流程节点',
                        menus: [
                            {label: '开始', shape: 'ellipse', id: 'start-node'},
                            {label: '结束', shape: 'ellipse', id: 'end-node'},
                            {label: '审批节点', busType: '123'},
                            {label: '判断节点'},
                        ],
                    },
                    {
                        label: '其他形状节点',
                        menus: [
                            {label: '矩形节点', shape: 'rect'},
                            {label: '圆形节点', shape: 'circle'},
                            {label: '椭圆节点', shape: 'ellipse'},
                            {label: '菱形节点', shape: 'diamond'},
                            {label: '三角形节点', shape: 'triangle'},
                            {label: '星形节点', shape: 'star'},
                        ]
                    }
                ]
            })

            let editor;

            function onDblclickNode(e) {

                const model = G6.Util.clone(e.item.get('model'))
                model.style = model.style || {}
                model.labelCfg = model.labelCfg || {style: {}}

                state.detailModel = model
                editor.openModel()
            }

            function onDblClickEdge(e) {
                const {source, target, style, labelCfg, label} = e.item.get('model')
                const model = {label, source, target, style: style || {}, labelCfg: labelCfg || {style: {}}, type: null, id: null}
                model.type = e.item.get('type')
                model.id = e.item.get('id')

                state.detailModel = model
                editor.openModel()
            }

            function cancel() {
                editor.closeModel()
            }

            function save() {
                editor.updateModel(state.detailModel)
                editor.closeModel()
            }

            async function handleBeforeDelete(model, type) {
                if (type === 'node') {
                    if (model.label === '开始') {
                        state.editorLoading = true
                        await delay(1000)
                        state.editorLoading = false
                        Ele.Notification.error('不可以删除【开始】节点')
                        return Promise.reject('reject')
                    }
                }
            }

            function handleAfterDelete(model, type) {
                if (type === 'edge') {
                    console.log('delete edge')
                } else {
                    console.log('after delete', model.label, {...model})
                }
            }

            function handleBeforeAdd(model, type) {
                if (type === 'edge') {
                    if (model.source === 'end-node') {
                        Ele.Notification.error('结束节点不能输出连线其他节点')
                        return Promise.reject('reject')
                    }
                }
                if (type === 'node') {
                    if (model.id === 'start-node' || model.id === 'end-node') {
                        const data = editor.editorState.graph.save()
                        for (let i = 0; i < data.nodes.length; i++) {
                            const node = data.nodes[i];
                            if (node.id === model.id) {
                                Ele.Notification.error(`只能有一个${model.id === 'start-node' ? '开始' : '结束'}节点`)
                                return Promise.reject('reject')
                            }
                        }
                    }
                }
            }

            function handleAfterAdd(model, type) {
                if (type === 'edge') {
                    console.log(`新增连接线`)
                }
            }

            return {
                state,

                showGrid: true,
                showMiniMap: false,

                onDblclickNode,
                onDblClickEdge,
                cancel,
                save,
                handleBeforeDelete,
                handleAfterDelete,
                handleBeforeAdd,
                handleAfterAdd,

                onRef: e => editor = e,
            }
        },
    }).$mount()

</script>
</body>
</html>