<template>
  <div class="FlowChartComponent">
    <!-- <Alert show-icon closable v-if="currentSteps === 1">双击空白区域即可直接新增一个中间节点,双击节点可编辑</Alert> -->
    <div class="chartContent">
      <div id="paletteDiv"></div>
      <div id="goChart" v-show="currentSteps === 1">
      </div>
      <div id="showChart" v-show="currentSteps === 2">
      </div>
    </div>

    <!-- 全局侧滑模块 -->
    <Drawer
      v-model="drawerObject.show"
      transfer
      :title="drawerObject.title"
      :width="472"
      :mask-closable="false"
      :closable="false"
      scrollable
    >
      <components
        v-if="drawerObject.show"
        :configData="drawerObject.configData"
        :data="drawerObject.configData"
        :is="drawerObject.component"
        :TABLE_ID="drawerObject.TABLE_ID"
        :node="drawerObject.node"
        :status="drawerObject.status"
        :rejectedNodes="rejectedNodes"
        :assignedNodes="assignedNodes"
        :readOnly="readOnly"
        :moduleType="data.moduleType"
        @closeDrawer="closeDrawer"
      >
      </components>
    </Drawer>
  </div>
</template>
<script>
import '@/utils/go'
import FlowDesinger from '@/utils/flow-desinger';
import startNodeInfo from '@/components/startNodeInfo'
import endNodeInfo from '@/components/endNodeInfo'
import linkInfo from '@/components/linkInfo'
import ProcessNodeConfig from '@/components/ProcessNodeConfig'
import DynamicProcessNodeConfig from '@/components/DynamicProcessNodeConfig'
import ServiceNodeConfig from '@/components/ServiceNodeConfig'
import FlowDisplay from '@/utils/flow-display';
export default {
  components:{
    startNodeInfo, endNodeInfo, linkInfo, ProcessNodeConfig, DynamicProcessNodeConfig, ServiceNodeConfig
  },
  props:{
    editable:{  //是否可编辑
      type:Boolean,
      default:true
    },
    fresh:{
      type:Boolean,
      default:false
    },
    currentSteps:{
      type:Number,
      default:null
    },
    noFreshFlag:{
      type:Boolean,
      default:false
    },
    readOnly:{
      type:Boolean,
      default:false
    },
    data:{
      type:Object,
      default () {
        return {
            }
      }
    }
  },
  data () {
    return {
      myDesigner:null,  //画布实例
      drawerObject:{
        show:false
      },
      nodeMsg:{},  //存放节点数据
      pathMsg:{},  //存放路径数据
      rejectedNodes:[],  //驳回节点
      assignedNodes: [],  //指派节点
    }
  },
  activated () {
    if(!this.noFreshFlag){
      this.init()
    }
  },
  deactivated () { //keep-alive 组件停用时调用
    if(this.currentSteps === 1 && this.myDesigner){
      this.data.guiStyle = JSON.parse(this.myDesigner.getFlowData())
    }
  },
  methods:{
    init () {
        if(!Array.isArray(this.data.nodeMsg)){
            let nodeMsg = []
            Object.keys(this.data.nodeMsg).map(item => {
              nodeMsg.push(this.data.nodeMsg[item])
              return item
            })

            this.data.nodeMsg = nodeMsg

            let pathMsg = []
            Object.keys(this.data.pathMsg).map(item => {
              pathMsg.push(this.data.pathMsg[item])
              return item
            })
            this.data.pathMsg = pathMsg
        }

        this.dataProcessing()
        if(this.currentSteps === 1){
          // 流程图设计器
          if(!this.myDesigner){
            this.myDesigner= new FlowDesinger('goChart',{
              showEditNode:this.showEditNode,  //节点双击编辑
              SelectionDeleted:this.SelectionDeleted,  //删除事件
              LinkDrawn:this.LinkDrawn,  //线的生成
              externalobjectsdropped:this.externalobjectsdropped,  //节点生成
              LinkRelinked: this.LinkRelinked  //连线修改
            });

          }

          this.initToolbar = this.myDesigner.initToolbar('paletteDiv',this.data.moduleType)
          this.myDesigner.displayFlow(JSON.parse(JSON.stringify(this.data.guiStyle)));// 在设计面板中显示流程图
          this.data.myDisplay = this.myDesigner.diagram
        }else{
          if(this.myDisplay){
            this.myDisplay.loadFlow(JSON.parse(JSON.stringify(this.data.guiStyle)))
          }else{
            this.myDisplay = new FlowDisplay('showChart',{
              showEditNode:this.showEditNode,  //节点双击编辑
            });
            this.myDisplay.loadFlow(JSON.parse(JSON.stringify(this.data.guiStyle)))
          }

          // this.data.myDisplay = this.myDisplay.diagram

        }


    },
    compare (property) {
      return function(a,b) {
        var value1 = a[property];
        var value2 = b[property];
        return value1 - value2
      }
    },
    dataProcessing () {  //处理后端返回节点数据和路径数据
      if(this.data.nodeMsg){

        this.data.nodeMsg.forEach(item => {
          this.nodeMsg[item.key] = item
          if(item.type === 2){  //结束节点对数据排序,区分执行程序还是抄送人
            this.nodeMsg[item.key].actionConfig.sort(this.compare('handleType'))
          }
        })
        this.data.nodeMsg = this.nodeMsg
      }

      if(this.data.pathMsg){
        this.data.pathMsg.forEach(item => {
          this.pathMsg[item.key] = item
        })
        this.data.pathMsg = this.pathMsg
      }

      this.data.removePath = []
      this.data.removeNode = []

    },
    showEditNode (node) {  //双击编辑

      // node.findNodesOutOf()
      if(node.data.type === 1){
        let defaultObj = {
          conditionType: 0,
          ruleList: [],
          priority: null,
          defaultPriority: null,
          modifyId: null,
          id:null,
          triggerBt:[],
          visibleBt:[]
        }
        if(!node.data.id){
          this.nodeMsg[node.data.key] = Object.assign(defaultObj,this.nodeMsg[node.data.key])
        }

        this.drawerObject = {
          show: true,
          component: 'startNodeInfo',
          configData: this.nodeMsg[node.data.key],
          title:'开始节点配置'
        }
      }
      if(node.data.type === 2){
        let defaultObj = {
          id:null,
          manualConfig:null,
          actionConfig:[]
        }
        if(!node.data.id){
          this.nodeMsg[node.data.key] = Object.assign(defaultObj,this.nodeMsg[node.data.key])
        }
        this.drawerObject = {
          show: true,
          component: 'endNodeInfo',
          configData: this.nodeMsg[node.data.key],
          title:'结束节点配置'
        }
      }

      // 审批节点和操作节点用同一个配置界面，根据参数控制展示项
      if(node.data.category === "Approval" || node.data.category === "Operation"){
        this.rejectedNodes = []
        this.assignedNodes = []
        this.findNodesInto(node)
        this.findNodesOutOf(node)
        // 默认节点配置
        let defaultObj = {
          actServiceS:[],
          actionConfig:[],
          approvelList:[],
          backId:null,
          id:null,
          manualConfig:0,
          modifiableField:[],
          moduleId:null,
          name:'中间节点',
          nodeType:0,
          ruleList:[],
          inevitable: 1,  //节点必经
          approveCondition: 0,  //审批条件
          assignBack: 0,  //驳回操作
          whetherBack: 0, //可为驳回节点
          nodeCancle: 0,  //作废操作
          assignNext: 1, //指派流转节点
          assignNode: 1,  //节点是否是必需指派
          assignApprover: 1,  //是否动态指派操作人
          visibleBt:[],  //可见按钮
          nodeBack: 0,  //驳回按钮开关
          nodeAgree: 0, //同意按钮

        }

        if(this.data.moduleType === 0){
          defaultObj = {
            actServiceS:[],
            actionConfig:[],
            approvelList:[],
            backId:null,
            id:null,
            manualConfig:0,
            modifiableField:'',
            modifiableFieldName:'',
            moduleId:null,
            name:'审批节点',
            nodeType:0,
            ruleList:[]
          }
        }

        if(!node.data.id){
          this.nodeMsg[node.data.key] = Object.assign(defaultObj,this.nodeMsg[node.data.key])
        }
        this.drawerObject = {
          show: true,
          component: this.data.moduleType === 0?'ProcessNodeConfig':'DynamicProcessNodeConfig',
          configData: this.nodeMsg[node.data.key],
          node: node,
          title:node.data.category === "Approval"?'审批节点配置':'操作节点'
        }
      }

      // 服务节点
      if(node.data.category === 'Service'){
        let defaultObj = {
          id:null,
          actionConfig:[{
            "id":null,	    //新增不传，修改传
            "handleValue":null,	    //具体的关于请求状态，url之类的json
            "handleType":null,	//51：rest服务实现，52：消息系统
            "extraMsg":null	//相关参数
          }]
        }
        if(!node.data.id){
          this.nodeMsg[node.data.key] = Object.assign(defaultObj,this.nodeMsg[node.data.key])
        }
        this.drawerObject = {
          show: true,
          component: 'ServiceNodeConfig',
          configData: this.nodeMsg[node.data.key],
          title:'服务节点配置'
        }
      }

      if(node.data.from !== undefined){
        if(this.nodeMsg[node.data.from].category === 'Service' && this.data.moduleType === 1){
          return
        }
        // 默认连线配置
        let defaultObj = {
          endNode:null,
          moduleId:null,
          name:null,
          ruleList:[],
          sources:null,
          startNode:null,
          status:null
        }
        if(!node.data.moduleId){
          this.pathMsg[node.data.key] = Object.assign(defaultObj,this.pathMsg[node.data.key])
        }

        let tableConfig = [{
            ID: this.nodeMsg[node.data.from].nodeFormId,
            value: this.nodeMsg[node.data.from].nodeForm
          }]

        if(this.nodeMsg[node.data.from].category === 'Start'){
          tableConfig = [{
            ID: this.nodeMsg[node.data.from].businessType,
            value: this.nodeMsg[node.data.from].businessTypeName
          }]
        }

        this.drawerObject = {
          show: true,
          component: 'linkInfo',
          configData: this.pathMsg[node.data.key],
          TABLE_ID: this.data.moduleType === 1?tableConfig:this.data.businessType,
          title:'连接线配置'
        }
      }
    },
    findNodesInto (node) {  //查找父节点
      let parents = node.findNodesInto()

      if(parents.count > 0){
        node.findNodesInto().map(item => {
          this.rejectedNodes.push({
            value:item.data.key,
            label:item.data.text
          })
          this.findNodesInto(item)
        })
      }else{
        return
      }
    },
    findNodesOutOf (node) {  //查找子节点
      let childrens = node.findNodesOutOf()

      if(childrens.count > 0){
        node.findNodesOutOf().map(item => {
          if(item.data.key != -2){
            this.assignedNodes.push({
              value:item.data.key,
              label:item.data.text
            })
            this.findNodesOutOf(item)
          }

        })
      }else{
        return
      }
    },
    SelectionDeleted (node) {  //删除节点或者线

      if(node.fromPort !== undefined){  //线的删除
        delete this.pathMsg[node.key]
        if(node.id){  //已保存的线
          this.data.removePath.push(node.id)
        }
      }else{  //节点删除
        delete this.nodeMsg[node.key]
        if(node.id){
          this.data.removeNode.push({
            id:node.id,
            type:node.type
          })
        }
      }
    },
    LinkDrawn (node) {  //连线生成
      if(!this.judgeLoop()){
        this.$Modal.fcWarning({
          title:'警告',
          content:'流程图中存在回路，请重新设置!!',
          mask:true
        })

        this.data.guiStyle = JSON.parse(this.myDesigner.getFlowData())
        let linkDataArray = this.data.guiStyle.linkDataArray
        linkDataArray = linkDataArray.filter(item => {
          return item.key !== node.key
        })

        this.data.guiStyle.linkDataArray = linkDataArray
        this.init()
        // reject()
        return
      }else{
        this.pathMsg[node.key] = node
        this.pathMsg[node.key].ruleList = []
      }

    },
    LinkRelinked (node) {  //连线修改
      this.pathMsg[node.key].from = node.from
      this.pathMsg[node.key].to = node.to
      this.pathMsg[node.key].fromPort = node.fromPort
      this.pathMsg[node.key].toPort = node.toPort
    },
    judgeLoop () {  //判断是否存在闭环  true为没有闭环  false有闭环
        // 获取所有的节点
        let data = JSON.parse(this.myDesigner.getFlowData())
        const edges = data.linkDataArray?data.linkDataArray:JSON.parse(data).linkDataArray;
        const nodes = [];
        const list = {}; // 邻接表
        const queue = []; // 入度为0的节点集合
        const indegree = {};
        edges.forEach(e => {
            const { from, to } = e;
            if (!nodes.includes(from)) {
                nodes.push(from);
            }
            if (!nodes.includes(to)) {
                nodes.push(to);
            }
            addEdge(from, to);
        });
        const V = nodes.length;

        nodes.forEach(node => {
            if (!indegree[node]) indegree[node] = 0;
            if (!list[node]) list[node] = [];
        });

        function addEdge(source, target) {
            if (!list[source]) list[source] = [];
            if (!indegree[target]) indegree[target] = 0;
            list[source].push(target);
            indegree[target] += 1;
        }
        function sort() {
            Object.keys(indegree).forEach(id => {
                if (indegree[id] === 0) {
                    queue.push(id);
                }
            });
            let count = 0;
            while (queue.length) {
                ++count;
                const currentNode = queue.pop();
                const nodeTargets = list[currentNode];
                for (let i = 0; i < nodeTargets.length; i++) {
                    const target = nodeTargets[i];
                    indegree[target] -= 1;
                    if (indegree[target] === 0) {
                        queue.push(target);
                    }
                }
            }
            // false 没有输出全部顶点，有向图中有回路
            return !(count < V);
        }

        return sort();
    },
    externalobjectsdropped (node) {  //节点生成

      if(node.category === 'Service' || node.category === 'Subprocesses'){
        this.nodeMsg[node.key] = node
        this.nodeMsg[node.key].name = node.text
        return
      }
      this.nodeMsg[node.key] = node
      this.nodeMsg[node.key].ruleList = []
      this.nodeMsg[node.key].actServiceS =[
        {
          status:1,
          handleValue:null,
          handleType:11
        },
        {
          status:1,
          handleValue:null,
          handleType:20
        }
      ]
      this.nodeMsg[node.key].actionConfig =[]
      this.nodeMsg[node.key].approvelList = []
      this.nodeMsg[node.key].approverStyle = 0
      this.nodeMsg[node.key].name = node.text
    },
    closeDrawer () {  //关闭策划块
      this.drawerObject = {
        show: false
      }
    }
  }
}
</script>
<style lang=scss" >
.FlowChartComponent{
  width: 100%;
  height: 100%;
  overflow: hidden;
  display: flex;
  position: relative;
  flex-direction: column;

  .burgeon-alert{
    margin-bottom: 0;
  }

  .chartContent{
    flex: 1;
    display: flex;
  }

  #paletteDiv{
    padding: 5px;
    width: 160px;
    height: 100%;
    display: inline-block;
    border-right: 1px solid #dcdee2;
  }


  canvas{
    outline: none;
  }

  #goChart,#showChart{
    flex-grow: 1;
    flex: 1;
    // border: solid 1px black
  }
}
</style>
