<template>
    <div id="initClientHeight">
        <el-container class="flow-container">
            <el-container>
                <el-header class="header-view-option">
                    <div class="header-option__buttons" style="color: #409EFF;font-size: 12px; font-weight: 500">
                        <el-button type="success" size="small" circle style="width: 16px; height: 16px"/> 已执行
                        <el-button type="primary" size="small" circle color="#0057FF" style="width: 16px; height: 16px"/> 执行中
                        <el-button type="info" size="small" circle style="width: 16px; height: 16px"/> 未执行
                    </div>
                    <div class="header-option__buttons" v-if="data.globalConfig.isHideShortcut !== '1'">
                        <el-button v-if="!other.isMobile()"
                                style="color: #409EFF;font-size: 12px"
                                @click="methods.exportPNG"
                                class="header-option-button"
                                icon="Download"
                        >下载流程图
                        </el-button>
                        <el-button
                                style="color: #409EFF;font-size: 12px"
                                @click="methods.shortcutHelper"
                                class="header-option-button"
                                icon="QuestionFilled"
                        >快捷键
                        </el-button>
                    </div>
                </el-header>
                <el-main>
                    <flow-area-view ref="flowArea"
                                    @initJsonFlowView="initJsonFlowView"
                                    :currSelect="data.currSelect">
                    </flow-area-view>
                </el-main>
            </el-container>
        </el-container>
        <!-- 快捷入门 -->
        <shortcut-modal :shortcut="data.shortcut" ref="shortcutModal"></shortcut-modal>
    </div>
</template>

<script setup lang="ts" name="JsonFlowView">
    import {flowConfig} from "/@/flow/designer/config/flow-config";
    import * as other from "/@/utils/other";
    import {CommonNodeType, HighNodeType, LaneNodeType} from "/@/flow/designer/config/type";
    import * as defFlow from '/@/flow/designer/api/jsonflow'
    import * as nodeConfig from "/@/flow/designer/config/node-config";
    import JsonflowDesign from "@jackrolling/jsonflow3"
    import {nodeJobSvgIcons} from "/@/flow/designer/assets/svges/path";
    import {useI18n} from "vue-i18n"
    import {notifyLeft} from "/@/flow";
    import {useMessage} from "/@/hooks/message";
    import {validateNull} from "/@/utils/validate";
    import {initJsonFlowViewByApp} from "/@/flow/support/extend";
    import {hideVueContextmenuName, initFlowDesignHeight} from "/@/flow/utils";

    const {t} = useI18n();
    const $route = useRoute();
    const {proxy} = getCurrentInstance();
    const $message = useMessage();
    // 引入组件
    const FlowAreaView = defineAsyncComponent(() => import('/@/flow/designer/components/flow-area-view.vue'));
    const ShortcutModal = defineAsyncComponent(() => import('/@/flow/designer/views/shortcut.vue'));

    const props = defineProps({
        currJob: {
            type: Object,
            default: {},
        }
    });
    const data = reactive({
        globalConfig: flowConfig.globalConfig,
        globalValue: {},
        flowData: other.deepClone(flowConfig.flowData),
        gridConfig: flowConfig.gridConfig,
        shortcut: flowConfig.viewShortcut,
        comments: {},
        runJobs: {},
        currSelect: {}
    })

    const methods = {
        removeEleTools() {
            window._jfOperate.removeEleTools()
            methods.clearCurrSelect();
            hideVueContextmenuName()
        },
        initClientHeight() {
            nextTick(() => {
                let browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
                initFlowDesignHeight($route, browserHeight)
            })
        },
        // 初始化流程
        initFlow(currFlowId?: any, callback?: Function) {
            let flowType = '0'
            // 判断编辑
            if (!currFlowId && props.currJob) {
                currFlowId = props.currJob.defFlowId
                let flowInstId = props.currJob.flowInstId;
                if (flowInstId) {
                    currFlowId = flowInstId
                    flowType = '1'
                }
            }
            if (currFlowId) {
                defFlow.getNodesByIdType(currFlowId, flowType, '0').then(resp => {
                    let defFlowData = resp.data
                    if (!defFlowData.attrs) {
                        notifyLeft('当前流程信息不存在')
                    } else  if (!validateNull(defFlowData.nodeList)) {
                        methods.loadFlow(defFlowData, callback);
                    }
                }).catch((e) => {
                    $message.error("获取流程信息失败");
                    console.error(e)
                })
            }
        },
        handleNodeListInfo(loadData) {
            let flowNodes = loadData.graph.cells.filter(f => f.attrs.cdata.type !== CommonNodeType.LINK);
            flowNodes.forEach(node => {
                    if (node.attrs.cdata.type === LaneNodeType.X_LANE || node.attrs.cdata.type === LaneNodeType.Y_LANE) {
                        return
                    }
                    let status = loadData.attrs.status;
                    if (node.ports && node.ports.items.length > 0) {
                        node.ports.items.forEach(each => {
                            methods.doNodeListInfo(each, true, false, status);
                        })
                    }
                    let isJobSeparated = '0'
                    if (loadData.attrs) isJobSeparated = loadData.attrs.isJobSeparated
                    methods.doNodeListInfo(node, false, isJobSeparated, status);
                })
            methods.handleLinkListInfo(loadData, flowNodes)
        },
        handleLinkListInfo(loadData, flowNodes) {
            loadData.graph.cells.filter(f => f.attrs.cdata.type === CommonNodeType.LINK)
                .forEach(link => {
                    let stroke;
                    let source = flowNodes.find(f => f.id === link.source.id);
                    let target = flowNodes.find(f => f.id === link.target.id);
                    let idNodeJob = target.attrs.cdata.type === HighNodeType.JOB;
                    if (!idNodeJob) {
                        let exists = data.runRejects.filter(f => source.attrs.cdata.attrs.runNodeId === f.fromRunNodeId &&
                            target.attrs.cdata.attrs.runNodeId === f.toRunNodeId);
                        if (validateNull(exists)) return
                    }
                    if (source.status === '1' && (target.status === '0' || target.status === '9')) {
                        stroke = '#0057FF'
                    } else if (source.status === '1' && target.status === '1') {
                        stroke = 'green'
                    }
                    if (stroke) {
                        if (link.attrs.line) link.attrs.line.stroke = stroke
                        else link.attrs.line = {'stroke': stroke}
                    }
                })
        },
        doNodeListInfo(node, isPort, isJobSeparated, status) {
            let findComments = data.comments.filter(f => f.flowNodeId === node.id || f.nodeJobId === node.id);
            if (!validateNull(findComments)) {
                methods.updateNodeContMenuData(findComments, isPort ? node.attributes : node, node, isPort, isJobSeparated, true)
            } else {
                let findRunJobs = data.runJobs.filter(f => f.flowNodeId === node.id || f.nodeJobId === node.id);
                if (!validateNull(findRunJobs)) {
                    if (status === '1') {
                        findRunJobs.forEach(each => {
                            if (each.status === '0' || each.status === '2' || each.status === '9') each.status = '-1'
                        })
                    }
                    methods.updateNodeContMenuData(findRunJobs, isPort ? node.attributes : node, node, isPort, isJobSeparated, false)
                } else {
                    node = isPort ? node.attributes : node
                    let startTimeBtnName = flowConfig.contextMenu.nodeView.menulists[1].btnName;
                    node.startTime = startTimeBtnName + '节点信息有误,请核实'
                    let userRoleBtnName = flowConfig.contextMenu.nodeView.menulists[2].btnName;
                    node.userRoleName = userRoleBtnName + ''
                    let userBtnName = flowConfig.contextMenu.nodeView.menulists[3].btnName;
                    node.userName = userBtnName + ''
                    let remarkBtnName = flowConfig.contextMenu.nodeView.menulists[4].btnName;
                    node.remark = remarkBtnName + ''
                }
            }
        },
        updateNodeContMenuData(findNodes, node, source, isPort, isJobSeparated, isComment) {
            let startTimeBtnName = flowConfig.contextMenu.nodeView.menulists[1].btnName;
            let userRoleBtnName = flowConfig.contextMenu.nodeView.menulists[2].btnName;
            let userBtnName = flowConfig.contextMenu.nodeView.menulists[3].btnName;
            let remarkBtnName = flowConfig.contextMenu.nodeView.menulists[4].btnName;

            if (findNodes.find(f => f.status === '-3')) node.status = '-3'
            else if (findNodes.find(f => f.status === '-2')) node.status = '-2'
            else if (findNodes.find(f => f.status === '0' || f.status === '9' || f.subFlowStatus === '0')) node.status = '0'
            else if (findNodes.find(f => f.status === '2')) node.status = '2'
            else if (findNodes.find(f => f.status === '1')) node.status = '1'
            else if (findNodes.find(f => f.status === '3')) node.status = '3'
            else if (findNodes.every(f => f.status === '-1')) node.status = '-1'

            findNodes.sort((a, b) => b.createTime - a.createTime);
            let length = findNodes.length;
            findNodes.forEach((f, index) => {
                let comma = index > 0 ? '，' : '';
                let startTime = node.startTime ? node.startTime : '';
                if (f.status === '3') node.startTime = startTime + comma + (f.startTime ? f.startTime : '已被跳过节点或任务')
                else node.startTime = startTime + comma + (f.startTime ? f.startTime : '未开始')
                if (length === index + 1) node.startTime = startTimeBtnName + node.startTime

                let userName = f.userName, userRoleName = '', userBtnName2 = ''
                if (userName) userBtnName2 += userName
                let roleName = f.roleName;
                if (roleName) userRoleName += roleName
                node.userRoleName = (node.userRoleName ? node.userRoleName : '') + comma + (roleName ? userRoleName : '无')
                node.userName = (node.userName ? node.userName : '') + comma + (userName ? userBtnName2 : '无')
                if (length === index + 1) node.userRoleName = userRoleBtnName + node.userRoleName
                if (length === index + 1) node.userName = userBtnName + node.userName

                let remark = node.remark ? node.remark : '';
                if (f.status === '-3') node.remark = remark + comma + '已终止'
                else if (f.status === '-2') node.remark = remark + comma + '已作废'
                else if (f.status === '0') node.remark = remark + comma + '正在审批中'
                else if (f.subFlowStatus === '0') node.remark = remark + comma + '子流程中'
                else if (f.status === '9') node.remark = remark + comma + '被驳回中'
                else if (f.status === '1' && (!f.userId || !isComment)) node.remark = remark + comma + (f.remark ? f.remark : '由【他人】审批')
                else if (f.status === '1') node.remark = remark + comma + (f.remark ? f.remark : '已审批')
                else if (f.status === '2') node.remark = remark + comma + '驳回中'
                else if (f.status === '-1') node.remark = remark + comma + '未审批'
                else if (f.status === '3') node.remark = remark + comma + '已被跳过'

                if (length === index + 1) node.remark = remarkBtnName + node.remark
            })

            if (node.status === '-1') return
            methods.updateNodeJobSeparated(node.status, node, source, isPort, isJobSeparated)
        },
        updateNodeJobSeparated(status, node, source, isPort, isJobSeparated) {
            let icon;
            let stroke;
            if (status === '-3' || status === '-2' || status === '3') {
                icon = {xlinkHref: nodeJobSvgIcons.warning}
            } else if (status === '0' || status === '9') {
                icon = {xlinkHref: nodeJobSvgIcons.loading}
                stroke = '#0057FF'
            } else if (status === '1') {
                icon = {xlinkHref: nodeJobSvgIcons.success}
                stroke = 'green'
            }
            if (stroke) {
                if (source.attrs.body) source.attrs.body.stroke = stroke
                else source.attrs.body = {'stroke': stroke}
            }
            if (source.attrs.cdata && (source.attrs.cdata.type === CommonNodeType.SERIAL || source.attrs.cdata.type === CommonNodeType.PARALLEL)) {
                if (source.attrs.cdata.attrs.isGateway === '1') return
                if (isJobSeparated !== '1') {
                    if (icon) source.attrs.icon = icon
                } else {
                    if (icon) source.attrs.image = icon
                }
            } else if (icon) {
                isPort ? source.attrs.portImage = icon : source.attrs.image = icon
            }
        },
        // 加载流程
        loadFlow(loadData, callback) {

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

            methods.handleFlowNodeListInfo(loadData, () => {
                data.flowData.attrs = loadData.attrs;
                window._jfGraph.fromJSON(loadData.graph)
                if (callback) callback()
            })
        },
        handleFlowNodeListInfo(loadData, call) {
            // 流程节点实例
            let flowInstId = props.currJob.flowInstId;
            if (!flowInstId) {
                if (call) call(loadData)
                return
            }
            defFlow.fetchComment({flowInstId: flowInstId}).then(resp => {
                data.comments = resp.data
                defFlow.fetchRunJobs(flowInstId).then(resp => {
                    data.runJobs = resp.data
                    defFlow.fetchRunRejects(flowInstId).then(resp => {
                        data.runRejects = resp.data
                        // 处理节点信息
                        methods.handleNodeListInfo(loadData)
                        if (call) call(loadData)
                    })
                })
            })
        },
        // 检测
        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;
        },
        // 清除画布
        clearAll() {
            methods.removeEleTools()
            data.flowData.nodeList = [];
            data.flowData.linkList = [];
            window._jfGraph.clear();
        },
        setCurrSelect(curr) {
            data.currSelect = curr
        },
        exportPNG() {
            window._jfOperate.exportPNG()
        },
        clearCurrSelect() {
            data.currSelect = {}
        },
        // 快捷入门
        shortcutHelper() {
            proxy.$refs.shortcutModal.open();
        },
        $refs() {
            return proxy.$refs;
        }
    }

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

    function initJsonFlowView() {
        // 兼容移动端
        initJsonFlowViewByApp($route, props)
        // 实例化
        window._shapes = nodeConfig.initNodeShapes();
        JsonflowDesign.initFlow.initJsonFlowView(exposeObj);
        // 初始化流程图
        methods.initFlow();
    }

    onBeforeMount(() => {
        window._flowConfig = flowConfig
        window._eleTools = JsonflowDesign.eleTools.initEleTools(exposeObj);
    })
    onMounted(() => {
        methods.initClientHeight();
    })
</script>

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