<template>
  <div class="flow-diagram">
    <div
      v-if="statusColorList.length >0"
      class="legend"
    >
      <van-collapse v-model="activeNames">
        <van-collapse-item name="1">
          <div slot="title" style="color: #666666;">
            流程图图示(<span class="red">双击节点查看节点的审批历史</span>)
          </div>
          <van-row gutter="5">
            <van-col v-for="(status,index) in statusColorList" :key="status.value+index" span="8" class="van-ellipsis" style="padding-top:5px;">
              <van-icon :style="{'color':status.color}" class-prefix="ibps-icon" name="square-o" /> {{ status.value }}
            </van-col>
          </van-row>
        </van-collapse-item>
      </van-collapse>
    </div>
    <div :id="id" class="canvas" style="height:100%;padding-top:20px;" />
    <!--工具栏-->
    <div v-if="toolbar" class="io-zoom-controls">
      <ul class="io-zoom-reset io-control io-control-list">
        <li>
          <button title="reset zoom" @click="zoomReset">
            <span class="ibps-icon ibps-icon-crosshairs " />
          </button>
        </li>
      </ul>
      <ul class="io-zoom io-control io-control-list">
        <li>
          <button title="zoom in" jsaction="click:bio.zoomIn" @click="zoomIn">
            <span class="ibps-icon ibps-icon-plus" />
          </button>
        </li>
        <li>
          <hr>
        </li>
        <li>
          <button href title="zoom out" jsaction="click:bio.zoomOut" @click="zoomOut">
            <span class="ibps-icon ibps-icon-minus" />
          </button>
        </li>
      </ul>
    </div>
    <!--审批历史-->
    <van-popup v-model="popup" class="ibps-fullscreen-popup">
      <van-nav-bar
        :title="nodeApproval.title"
        @click-left="closePopup"
      >
        <template #left>
          <van-icon name="cross" class="ibps-nav-bar__close-icon" />
        </template>
      </van-nav-bar>
      <div class="ibps-fixed-navbar">
        <template v-if="nodeApproval.hasApproval">
          <van-cell-group v-for="(approval,index) in nodeApproval.data" :key="index">
            <van-cell v-if="approval.auditor" title="执行人">
              <van-tag
                plain
                type="success"
              >
                {{ approval.auditorName }}
              </van-tag>
            </van-cell>
            <van-cell v-else title="候选人">
              <!-- :value="getCandidate(approval.qualifiedExecutor,nodeApproval.bpmNodeUserShowCount)" -->
              <van-tag
                v-for="(qualifiedExecutor,j) in approval.qualifiedExecutor"
                :key="j"
                plain
                type="primary"
              >
                {{ qualifiedExecutor.executor }}
              </van-tag>
            </van-cell>
            <van-cell
              :value="approval.createTime|dateFormat('yyyy-MM-dd HH:mm:ss')"
              title="开始时间"
            />
            <van-cell
              v-if="approval.completeTime"
              :value="approval.completeTime|dateFormat('yyyy-MM-dd HH:mm:ss')"
              title="结束时间"
            />
            <van-cell
              v-if="approval.completeTime"
              :value="approval.durMs|duration"
              title="审批用时"
            />
            <van-cell
              :value="approval.statusName"
              title="审批状态"
            />
            <van-cell
              v-if="approval.completeTime"
              :value="approval.opinion"
              title="审批意见"
            />
            <div style="height:20px;background: #f8f8f8;" />
          </van-cell-group>
        </template>
        <template v-else>
          <van-cell title="暂定候选人">
            <template v-if="nodeApproval.data && nodeApproval.data.length >0">
              <van-tag
                v-for="(d,j) in nodeApproval.data"
                :key="j"
                plain
                type="primary"
              >
                {{ d.name }}
              </van-tag>
            </template>
            <template v-else>
              暂无审批人
            </template>
          </van-cell>
        </template>
      </div>
    </van-popup>
  </div>
</template>
<script>
import { getFlowDiagram } from '@/api/platform/bpmn/bpmImage'
import { getNodeApproval } from '@/api/platform/bpmn/bpmTask'
import 'bpmn-js/dist/assets/diagram-js.css'
import BpmnViewer from 'bpmn-js'
// import Diagram from 'diagram-js'

import SelectionModule from 'diagram-js/lib/features/selection' // select elements
import TouchModule from 'diagram-js/lib/navigation/touch' // touch
import ZoomScrollModule from 'diagram-js/lib/navigation/zoomscroll' // zoom canvas
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas' // scroll canvas
import ModelingModule from 'diagram-js/lib/features/modeling' // basic modeling (create/move/remove shapes/connections)
// import MoveModule from 'diagram-js/lib/features/move' // move shapes
import OutlineModule from 'diagram-js/lib/features/outline' // show element outlines
// import LassoToolModule from 'diagram-js/lib/features/lasso-tool' // lasso tool for element selection
import PaletteModule from 'diagram-js/lib/features/palette' // palette
// import CreateModule from 'diagram-js/lib/features/create' // create elements
import ContextPadModule from 'diagram-js/lib/features/context-pad' // context pad for elements,
import ConnectModule from 'diagram-js/lib/features/connect' // connect elements
// import RulesModule from 'diagram-js/lib/features/rules' // rules
export default {
  name: 'flow-diagram',
  props: {
    defId: String,
    taskId: String,
    instId: String,
    bizKey: String,
    toolbar: {
      type: Boolean,
      default: true
    },
    height: Number,
    width: Number,
    autoHeight: Boolean,
    init: Boolean
  },
  data() {
    return {
      activeNames: [],
      id: 'ibps-flow-diagram' + this.$utils.guid(), // 随机个id避免一个页面多个流程图
      statusColorList: [],
      viewer: null,
      popup: false,
      nodeApproval: {},
      cacheNodeApproval: {},
      loading: false
    }
  },
  mounted() {
    if (this.init) {
      this.getFormData()
    }
  },
  methods: {
    getFormData() {
      this.$nextTick(() => {
        this.initUI()
        this.loadData()
      })
    },
    initUI() {
      // 当前窗口高度
      const height = this.autoHeight ? '100%' : window.innerHeight
      this.viewer = new BpmnViewer({
        container: '#' + this.id,
        height: height,
        additionalModules: [
          SelectionModule,
          ZoomScrollModule,
          MoveCanvasModule,
          ModelingModule,
          // MoveModule,
          OutlineModule,
          // LassoToolModule,
          PaletteModule,
          // CreateModule,
          ContextPadModule,
          ConnectModule,
          // RulesModule,
          TouchModule
        ]
      })
    },
    loadData() {
      let hasEvent = true
      const parms = {}
      if (this.$utils.isNotEmpty(this.defId)) {
        parms['defId'] = this.defId
        hasEvent = false
      }
      if (this.$utils.isNotEmpty(this.taskId)) {
        parms['taskId'] = this.taskId
      }
      if (this.$utils.isNotEmpty(this.instId)) {
        parms['instId'] = this.instId
      }
      if (this.$utils.isNotEmpty(this.bizKey)) {
        parms['bizKey'] = this.bizKey
      }
      parms['ignoreInstIdNull'] = true
      this.loading = true
      getFlowDiagram(parms).then(response => {
        this.loading = false
        if (response.state === 103) {
          // this.$message.closeAll()
          // this.$message({
          //   message: response.message,
          //   type: 'warning'
          // })
          this.$emit('error', true)
          return
        }
        const data = response.data
        const xml = data.xml
        const styleMap = data.styleMap || {}
        this.statusColorList = this.$utils.isEmpty(styleMap) ? [] : data.statusColorList
        this.initStatusColorList()

        this.loadViewer(xml, styleMap, hasEvent)
      }).catch(() => {
        this.loading = false
      })
    },

    async loadViewer(xml, styleMap, hasEvent) {
      try {
        await this.viewer.importXML(xml)
        this.viewer.get('canvas').zoom('fit-viewport')
        this.handleColor(styleMap)
        if (hasEvent) {
          this.handleEventBus()
        }
      } catch (err) {
        console.error('[flow-diagram] something went wrong:', err)
        this.loading = false
      }
    },
    initStatusColorList() {
      if (this.$utils.isEmpty(this.statusColorList)) {
        return
      }
      const id = 'ibps-flow-diagram'
      let newStyle = ''
      this.statusColorList.forEach(item => {
        newStyle += `.ibps-flow-diagram-${item.key}:not(.djs-connection) .djs-visual > :nth-child(1) {stroke: ${item.color} !important;}  `
      })

      let styleTag = document.getElementById(id)
      if (!styleTag) {
        styleTag = document.createElement('style')
        styleTag.setAttribute('type', 'text/css')
        styleTag.setAttribute('id', id)
        document.head.appendChild(styleTag)
      }
      styleTag.innerText = newStyle
    },
    /**
     * 染色
     */
    handleColor(styleMap) {
      if (this.$utils.isEmpty(styleMap) || this.$utils.isEmpty(this.statusColorList)) {
        return
      }
      const canvas = this.viewer.get('canvas')
      const elementRegistry = this.viewer.get('elementRegistry')
      for (const key in styleMap) {
        if (styleMap[key]) {
          const style = styleMap[key]
          const shape = elementRegistry.get(key)// 存在的节点才上色
          if (shape) {
            canvas.addMarker(key, 'ibps-flow-diagram-' + style.status)
          }
        }
      }
    },
    handleEventBus() {
      const eventBus = this.viewer.get('eventBus')
      // you may hook into any of the following events
      const events = [
        'element.click',
        'element.dblclick',
        'element.tap'
      ]
      events.forEach((event) => {
        eventBus.on(event, (e) => {
          // e.element = the model element
          // e.gfx = the graphical element
          // e.preventDefault()
          // e.stopPropagation()
          if (e.element.type !== 'bpmn:UserTask') {
            return
          }
          const id = e.element.id

          if (this.cacheNodeApproval[id]) {
            this.popup = true
            this.nodeApproval = this.cacheNodeApproval[id]
            return
          }

          getNodeApproval({
            taskId: this.taskId,
            instId: this.instId,
            bizKey: this.bizKey,
            nodeId: id
          }).then(response => {
            var data = response.data
            if (!data.hasApproval && !data.data) {
              this.$notify({
                type: 'warning',
                message: '暂无审批历史'
              })
              return
            }
            this.popup = true
            this.nodeApproval = { ...response.data, title: e.element.businessObject.name }
            this.cacheNodeApproval[id] = this.nodeApproval
          })
        })
      })
    },
    closePopup() {
      this.popup = false
    },
    zoomReset() {
      this.viewer.get('zoomScroll').reset()
    },
    zoomOut() {
      this.viewer.get('zoomScroll').stepZoom(-1)
    },
    zoomIn() {
      this.viewer.get('zoomScroll').stepZoom(1)
    }
  }
}
</script>
<style>
.bjs-powered-by {
  display: none;
}
</style>
<style lang="scss" scoped>
.flow-diagram {
      background: #fff;
  .van-hairline--top-bottom::after {
    border-width: 0;
  }

  .io-control {
    background: #fff;
    border-radius: 2px;
    border: solid 1px #e0e0e0;
    padding: 5px;
  }
  .io-zoom-controls {
    width: auto;
    position: fixed;
    right: 15px;
    bottom: 90px;
  }
  .io-zoom-reset {
    margin-bottom: 10px;
  }

  .io-control-list {
    list-style: none;
    padding: 5px;
    margin: 0;
  }

  .io-control-list a,
  .io-control-list a:visited,
  .io-control-list button {
    padding: 0;
    outline: none;
    cursor: pointer;
    font-size: 22px;
    line-height: 26px;
    color: #555555;
    background: none;
    border: none;
  }

  .io-control-list a:hover,
  .io-control-list a:visited:hover,
  .io-control-list button:hover {
    color: #333333;
  }

  .io-control-list a.inactive,
  .io-control-list a:visited.inactive,
  .io-control-list button.inactive {
    color: #e0e0e0;
    cursor: default;
  }

  .io-control-list.io-horizontal,
  .io-control-list.io-horizontal li {
    display: inline-block;
  }

  .io-control-list.io-horizontal a {
    padding: 2px;
    margin: 0 5px;
  }

  .io-control-list.io-horizontal button {
    margin: 0 5px;
  }

  .io-control hr {
    border: none;
    border-top: solid 1px #eee;
  }
}
</style>

