<template>
    <div style="height: 100%;" :class="props.currFlowForm? '': 'layout-padding'">
        <el-container class="flow-container">
            <el-aside class="select-area">
                <el-row>
                    <div class="el-row-tab">基础</div>
                    <node-menu
                            :menuList="data.menuList.commonNodes"
                            type="commonNodes"
                            @setDragInfo="methods.setDragInfo"
                    />
                </el-row>
                <el-row>
                    <div class="el-row-tab">高级</div>
                    <node-menu
                            :menuList="data.menuList.highNodes"
                            type="highNodes"
                            @setDragInfo="methods.setDragInfo"
                            :flowData="data.flowData"
                    />
                </el-row>
                <el-row>
                    <div class="el-row-tab">泳道</div>
                    <node-menu
                            :menuList="data.menuList.laneNodes"
                            type="laneNodes"
                            @setDragInfo="methods.setDragInfo"
                    />
                </el-row>
            </el-aside>
            <el-container>
                <el-header class="header-option">
                    <div class="header-option__tools">
                        <el-tooltip content="点击可切换简单模式与专业模式" placement="right">
                            <el-button id="isSimpleMode"
                                    icon="Pointer"
                                    type="primary" plain
                                    @click="methods.showFlowMode"
                            > {{ data.globalConfig.isSimpleMode === '1' ? '简单模式' : '专业模式'}}
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="设置流程属性" placement="right">
                            <el-button
                                    icon="Tools"
                                    type="primary" plain
                                    @click="methods.showAttrConfig(true, '1')"
                            >流程属性
                            </el-button>
                        </el-tooltip>
                        <el-select v-model="data.globalValue.connector" @change="methods.changeConnector" clearable
                                   placeholder="连线">
                            <el-option
                                    v-for="(item, index) in data.globalConfig.connectors"
                                    :key="index"
                                    :label="item.label"
                                    :value="item.value">
                            </el-option>
                        </el-select>
                        <el-select v-model="data.globalValue.router" @change="methods.changeRouter" clearable
                                   placeholder="路由">
                            <el-option
                                    v-for="(item, index) in data.globalConfig.routers"
                                    :key="index"
                                    :label="item.label"
                                    :value="item.value">
                            </el-option>
                        </el-select>
                        <el-select v-model="data.globalValue.rankDir" @change="methods.layout" clearable
                                   placeholder="布局">
                            <el-option
                                    v-for="(item, index) in data.globalConfig.rankDirs"
                                    :key="index"
                                    :label="item.label"
                                    :value="item.value">
                            </el-option>
                        </el-select>
                    </div>
                    <div class="header-option__buttons">
                        <el-tooltip content="升版本" placement="bottom" v-if="!props.currFlowForm && !validateRunFlow(data)">
                            <el-button
                                    @click="methods.upgradeVersion()"
                                    class="header-option-button"
                                    icon="Upload"
                            >升版本
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="暂存" placement="bottom" v-if="!props.currFlowForm && !validateRunFlow(data)">
                            <el-button
                                    @click="methods.publishFlow(null, '-1')"
                                    class="header-option-button"
                                    icon="CirclePlus"
                            >暂存
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="发布" placement="bottom" v-if="!props.currFlowForm">
                            <el-button
                                    @click="methods.publishFlow(null, '1')"
                                    class="header-option-button"
                                    icon="Promotion"
                            >发布
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="撤销" placement="bottom">
                            <el-button
                                    @click="methods.undoFlow()"
                                    class="header-option-button"
                                    icon="RefreshLeft"
                            >撤销
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="重做" placement="bottom">
                            <el-button
                                    @click="methods.redoFlow()"
                                    class="header-option-button"
                                    icon="RefreshRight"
                            >重做
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="清空" placement="bottom">
                            <span>
                                <el-popconfirm
                                        title="是否确认重新绘制?"
                                        @confirm="methods.clearAll"
                                        width="200"
                                >
                                    <template #reference>
                                        <el-button
                                                class="header-option-button"
                                                icon="Delete"
                                        >清空
                                        </el-button>
                                    </template>
                                </el-popconfirm>
                            </span>
                        </el-tooltip>
                        <!--<el-tooltip :content="data.gridConfig.showGridText" placement="bottom">
                            <el-button
                                    @click="methods.toggleShowGrid"
                                    class="header-option-button"
                                    :icon="data.gridConfig.showGridIcon"
                            >{{ data.gridConfig.showGridText }}
                            </el-button>
                        </el-tooltip>-->
                        <el-tooltip content="画布设置" placement="bottom">
                            <el-button
                                    @click="methods.setting"
                                    class="header-option-button"
                                    icon="SetUp"
                            >画布设置
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="导入导出" placement="bottom">
                            <el-button
                                    @click="methods.openViewJson"
                                    class="header-option-button"
                                    icon="UploadFilled"
                            >导入导出
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="下载流程图" placement="bottom">
                            <el-button style="color: #409EFF;"
                                       @click="methods.exportPNG"
                                       class="header-option-button"
                                       icon="Download"
                            >下载流程图
                            </el-button>
                        </el-tooltip>
                        <el-tooltip content="查看快捷键或文档" placement="bottom">
                            <span>
                                <el-popconfirm
                                        title="快速入门选项"
                                        placement="bottom"
                                        confirm-button-text="快捷入门"
                                        cancel-button-text="使用文档"
                                        @confirm="methods.shortcutHelper"
                                        @cancel="methods.usingDoc"
                                        icon="QuestionFilled"
                                        width="200"
                                >
                                <template #reference>
                                    <el-button
                                            style="color: #409EFF;font-size: 12px"
                                            class="header-option-button"
                                            icon="QuestionFilled"
                                    >快速入门
                                    </el-button>
                                </template>
                            </el-popconfirm>
                            </span>
                        </el-tooltip>
                    </div>
                </el-header>
                <el-main class="flow-content">
                    <flow-area
                            ref="flowArea"
                            :dragInfo="data.dragInfo"
                            :currSelect="data.currSelect"
                            @removeEleTools="methods.removeEleTools"
                            @showAttrConfig="methods.showAttrConfig"
                            @initJsonFlow="initJsonFlow"
                    >
                    </flow-area>
                </el-main>
            </el-container>
            <flow-attr
                    ref="flowAttr"
                    :flowData="data.flowData"
                    :currFlowForm="props.currFlowForm"
                    :currSelect="data.currSelect"
                    @showAttrConfig="methods.showAttrConfig"
                    @initFlow="methods.initFlow"
            ></flow-attr>
        </el-container>
        <!-- 画布设置 -->
        <setting-modal ref="settingModal" @flowSeparated="methods.flowSeparated"></setting-modal>
        <!-- 快捷入门 -->
        <shortcut-modal :shortcut="data.shortcut" ref="shortcutModal"></shortcut-modal>
        <!-- 导入导出 -->
        <json-modal ref="jsonModal" @loadFlow="methods.loadFlow"></json-modal>
    </div>
</template>

<script setup lang="ts" name="JsonFlow">
    import * as menuConfig from "/@/flow/designer/config/menu-config";
    import * as nodeConfig from "/@/flow/designer/config/node-config";
    import {flowConfig} from "/@/flow/designer/config/flow-config";
    import {utils} from "/@/flow/designer/utils/common";
    import {deepClone} from "/@/utils/other";
    import * as defFlow from '/@/flow/designer/api/jsonflow'
    import {setPropsDataValue, setPropsNull} from "/@/flow/support/common";
    import JsonflowDesign from "@jackrolling/jsonflow3"
    import {useI18n} from "vue-i18n"
    import {initDefFlowFromAttrs, notifyLeft, validateRunFlow} from "/@/flow";
    import {useMessage, useMessageBox} from "/@/hooks/message";
    import {validateNull} from "/@/utils/validate";
    import {confirmCancelAndClose, handleUpgradeVersion, hideVueContextmenuName} from "/@/flow/utils";
    import {listDefFlowByFlowKey} from "/@/flow/designer/api/jsonflow";

    const {t} = useI18n();
    const {proxy} = getCurrentInstance();
    const $route = useRoute();
    const $message = useMessage();
    // 引入组件
    const FlowArea = defineAsyncComponent(() => import('/@/flow/designer/components/flow-area.vue'));
    const FlowAttr = defineAsyncComponent(() => import('/@/flow/designer/components/flow-attr.vue'));
    const SettingModal = defineAsyncComponent(() => import('/@/flow/designer/views/setting.vue'));
    const ShortcutModal = defineAsyncComponent(() => import('/@/flow/designer/views/shortcut.vue'));
    const JsonModal = defineAsyncComponent(() => import('/@/flow/designer/views/json-view.vue'));
    const NodeMenu = defineAsyncComponent(() => import('/@/flow/designer/components/node-menu.vue'));

    const props = defineProps({
        currFlowForm: {
            type: Object,
            default: null,
        }
    });
    const data = reactive({
        menuList: {
            commonNodes: menuConfig.commonNodes,
            highNodes: menuConfig.highNodes,
            laneNodes: menuConfig.laneNodes
        },
        flowData: deepClone(flowConfig.flowData),
        globalConfig: flowConfig.globalConfig,
        gridConfig: flowConfig.gridConfig,
        dragInfo: {
            type: "",
            belongTo: ""
        },
        shortcut: flowConfig.shortcut,
        globalValue: {},
        currSelect: {}
    })

    const methods = {
        // drag
        setDragInfo(info) {
            data.dragInfo = info;
        },
        setElementTools(graph, paper, model) {
            methods.setCurrSelect(model);
            window._eleTools.setElementTools(graph, paper, model)
        },
        removeEleTools() {
            window._jfOperate.removeEleTools()
            methods.clearCurrSelect();
            hideVueContextmenuName()
        },
        // 关闭提示
        listenPage() {
            window.onbeforeunload = function (e) {
                e = e || window.event;
                if (e) {
                    e.returnValue = "关闭提示";
                }
                return "关闭提示";
            };
        },
        // 初始化流程
        initFlow(currFlowId?: any, flowInstId?: any, callback?: Function, isNew?: boolean) {
            let flowType = '0'
            // 判断编辑
            if (!currFlowId) {
                flowType = <string>$route.query.flowType
                currFlowId = $route.query.currFlowId
            } else if (flowInstId) {
                currFlowId = flowInstId
                flowType = '1'
            }
            if (currFlowId) methods.clearAll();
            if (currFlowId) {
                defFlow.getNodesByIdType(currFlowId, flowType, '1').then(resp => {
                    let defFlowData = resp.data
                    if (defFlowData.attrs) {
                        if (!validateNull(defFlowData.nodeList)) methods.loadFlow(defFlowData, callback, isNew);
                        else {
                            let flowData = deepClone(flowConfig.flowData);
                            setPropsDataValue(flowData.attrs, defFlowData.attrs, 'id', 'flowName', 'flowKey', 'groupName', 'status', 'sort', 'remark', 'version')
                            methods.loadFlow(flowData, callback, isNew);
                        }
                    }
                    methods.currFlowFormFlowDesigning(false, false)
                }).catch((e) => {
                    methods.currFlowFormFlowDesigning(false, false)
                    $message.error("获取流程信息失败");
                    console.error(e)
                })
            } else {
                data.flowData.attrs.id = utils.getId();
                if (!props.currFlowForm) window._jfOperate.reAutoInitNodes()
            }
        },
        async initNewFlow(callback, isNew) {
            data.flowData.graph = window._jfGraph.toJSON();
            let resp = await listDefFlowByFlowKey(data.flowData.attrs.flowKey);
            if (validateNull(resp.data)) return
            data.flowData.attrs.version = resp.data[0].version
            methods.loadFlow(data.flowData, callback, isNew);
        },
        flowSeparated(isJobSeparated) {
            data.flowData.graph = window._jfGraph.toJSON();
            data.flowData.attrs.isJobSeparated = isJobSeparated
            // 为了节点自适应布局
            data.flowData.attrs.autoLayout = data.globalConfig.defaultAutoLayoutName
            methods.jfGraphToFlowData(data.flowData, null)
            methods.loadFlow(data.flowData, null, false);
        },
        // 加载流程
        loadFlow(loadData, callback, isNew) {

            window._jfOperate.reInitFlowSetting(data.flowData, loadData, data)
            window._shapes = nodeConfig.initNodeShapes();

            window._jfOperate.handleGraphCells(loadData, 'id');
            if (isNew === true) {
                window._jfOperate.handleNewFromTemp(loadData);
            }
            data.flowData.attrs = loadData.attrs;

            if (!validateNull(loadData.graph) && !validateNull(loadData.graph.cells)) {
                window._jfGraph.fromJSON(loadData.graph)
            }
            if (callback) callback()
        },
        // 检测
        checkFlow() {
            let nodes = window._jfGraph.getElements();
            if (nodes.length <= 0) {
                $message.warning("流程无任何节点");
                return false;
            }
            let links = window._jfGraph.getLinks();
            if (links.length <= 0) {
                $message.warning("流程无任何连线");
                return false;
            }
            return true;
        },
        async upgradeVersion() {
            try {
                let isNew = data.flowData.attrs.isNew;
                if (isNew) {
                    notifyLeft('当前流程版本已最新, 请确认是否已保存')
                    return
                }
                await useMessageBox().confirm('是否确定升级版本?');
            } catch {
                return;
            }
            methods.initNewFlow(() => {
                let confirmObj = {text: "发布流程", callback: () => { methods.publishFlow(null, '1') }}
                let cancelObj = {text: "暂存流程", callback: () => { methods.publishFlow(null, '-1') }}
                confirmCancelAndClose(confirmObj, cancelObj, '流程设计升级版本成功! 是否立即暂存或发布?')
            }, true);
        },
        // 发布流程
        async publishFlow(callback, status) {
            let flowObj = Object.assign({}, data.flowData);
            if (!methods.checkFlow()) return;

            if (!flowObj.attrs.flowKey || !flowObj.attrs.flowName || !flowObj.attrs.groupName) {
                $message.warning("流程属性【流程名称】或【流程KEY】或【分组名称】为空，请点击左上角《流程属性》填写");
                methods.showAttrConfig(true, '1')
                return
            }
            function doPublishFlow(isNew?) {
                // 升版本后取最新
                if (isNew) flowObj = Object.assign({}, data.flowData);
                methods.doPublishFlow(flowObj, callback, status)
            }
            if (!validateRunFlow(data)) {
                let exists = await defFlow.listRunFlowsByDefFlowId(flowObj.attrs.id, flowObj.attrs.version)
                if (!validateNull(exists.data) && exists.data.isIndependent !== '1') {
                    let text = status === '-1' ? "暂存" : "发布";
                    let confirmObj = {text: "无增删节点继续" + text, callback: () => { doPublishFlow() }}
                    let cancelObj = {text: "有增删节点升级" + text, callback: async () => {
                            await handleUpgradeVersion(props)
                            methods.initNewFlow(() => {
                                doPublishFlow(true)
                            }, true);
                        }}
                    confirmCancelAndClose(confirmObj, cancelObj, '当前流程版本已存在流程实例! 若本次修改存在增删节点或连线，请先确认是否已升级版本')
                } else {
                    doPublishFlow()
                }
            } else {
                doPublishFlow()
            }
        },
        doPublishFlow(flowObj, callback, status) {
            // 转换格式
            methods.jfGraphToFlowData(flowObj, status)
            if (methods.validateDistFlowNode(flowObj)) return;

            let addObj = defFlow.addObjByDefFlowId
            let flowType = <string>$route.query.flowType;
            if (validateRunFlow(props) || flowType === '1') {
                addObj = defFlow.addObjByFlowInstId
            }
            addObj(flowObj).then(resp => {
                methods.currFlowFormFlowDesigning(false, true)
                if (status === '-1') notifyLeft('流程设计暂存成功')
                else notifyLeft('流程设计发布成功')
                if (callback) callback()
            }).catch(() => {
                methods.currFlowFormFlowDesigning(false, false)
                $message.error("流程设计发布失败");
            })
        },
        currFlowFormFlowDesigning(flowDesigning, flowDesign) {
            if (props.currFlowForm) {
                props.currFlowForm.flowDesigning = flowDesigning
                props.currFlowForm.flowDesign = flowDesign
            }
        },
        jfGraphToFlowData(flowObj, status) {
            flowObj.graph = window._jfGraph.toJSON();
            if (status) flowObj.attrs.status = status
            initDefFlowFromAttrs(props, flowObj.attrs)
            window._jfOperate.initFlowSetting(flowObj, data)
            window._jfOperate.jfGraphToFlowData(flowObj)
        },
        validateDistFlowNode(flowObj) {
            let notExist = false;
            flowObj.nodeList.forEach(each => {
                if(each.defJob && each.defJob.distFlowNodeId) {
                    let some = flowObj.nodeList.some(s => s.attrs.id === each.defJob.distFlowNodeId);
                    if (!some) {
                        $message.error("当前任务【"+ each.defJob.jobName +"】配置的【待分配参与者节点】不存在, 请重新配置");
                        notExist = true
                    }
                }
            })
            return notExist
        },
        // 连线切换
        changeConnector(name) {
            window._jfOperate.changeConnector(name)
        },
        // 路由切换
        changeRouter(name) {
            window._jfOperate.changeRouter(name)
        },
        // 自动布局
        layout(name) {
            window._jfOperate.layout(name)
        },
        // 显示隐藏网格
        toggleShowGrid() {
            window._jfOperate.toggleShowGrid()
        },
        // 导入导出
        openViewJson() {
            let flowData = Object.assign({}, data.flowData);
            methods.jfGraphToFlowData(flowData, null)
            proxy.$refs.jsonModal.open(flowData);
        },
        showAttrConfig(bool, type) {
            if (type === '1') methods.removeEleTools()
            proxy.$refs.flowAttr.open(bool)
        },
        showFlowMode() {
            let isSimpleMode = data.globalConfig.isSimpleMode === '1' ? '0': '1';
            data.globalConfig.isSimpleMode = isSimpleMode
            flowConfig.globalConfig.isSimpleMode = isSimpleMode
            data.flowData.attrs.isSimpleMode = isSimpleMode
            window._jfOperate.reAutoInitNodes()
        },
        undoFlow() {
            window._jfOperate.undo();
        },
        redoFlow() {
            window._jfOperate.redo();
        },
        clearAll() {
            methods.removeEleTools()
            data.flowData.nodeList = [];
            data.flowData.linkList = [];
            data.flowData.graph = null;
            setPropsNull(data.flowData.attrs, 'remark', 'flowName', 'flowKey', 'groupName', 'version')
            window._jfGraph.clear();
            data.flowData.attrs.status = '-1'
        },
        setCurrSelect(curr) {
            data.currSelect = curr
        },
        resetConfig() {
            data.globalConfig.isSimpleMode = '1'
            flowConfig.globalConfig.isSimpleMode = '1'
            data.flowData.attrs.isSimpleMode = '1'
            data.globalConfig.isJobSeparated = '0'
            data.gridConfig.gridSize = 1
        },
        clearCurrSelect() {
            data.currSelect = {}
        },
        exportPNG() {
            window._jfOperate.exportPNG()
        },
        // 画布设置
        setting() {
            proxy.$refs.settingModal.open();
        },
        // 快捷入门
        shortcutHelper() {
            proxy.$refs.shortcutModal.open();
        },
        // 使用文档
        usingDoc() {
            window.open("http://jsonflow.top:9000/");
        },
        $refs() {
            return proxy.$refs;
        }
    }

    const exposeObj = {
        gridConfig: data.gridConfig,
        globalValue: data.globalValue,
        setCurrSelect: methods.setCurrSelect,
        clearCurrSelect: methods.clearCurrSelect,
        showAttrConfig: methods.showAttrConfig,
        setElementTools: methods.setElementTools,
        removeEleTools: methods.removeEleTools,
        notifyLeft: notifyLeft,
        $refs: methods.$refs
    }

    function initJsonFlow() {
        methods.resetConfig()
        // 实例化
        window._shapes = nodeConfig.initNodeShapes();
        JsonflowDesign.initFlow.initJsonFlow(exposeObj);
        // 初始化流程图
        methods.initFlow();
    }

    onBeforeMount(() => {
        window._flowConfig = flowConfig
        window._eleTools = JsonflowDesign.eleTools.initEleTools(exposeObj);
    });
    onMounted(() => {
        nextTick(() => {
            // 关闭提示
            methods.listenPage();
        })
    });

    // 暴露变量
    defineExpose({
        initFlow: methods.initFlow,
        initNewFlow: methods.initNewFlow,
        publishFlow: methods.publishFlow,
        flowData: data.flowData,
    });
</script>

<style lang="scss">
  @import "../../../flow/designer/assets/style/flow-designer.scss";
  @import "../../../flow/components/style/flow-drawer.scss";
</style>
