<!--
 * @Description:
 * @Autor: renchao
 * @LastEditTime: 2023-05-17 10:41:15
-->
<template>
  <div>
    <div class="process-viewer">
      <div
        v-show="!isLoading"
        ref="processCanvas"
        class="process-canvas"
        style="height: 280px" />
      <!-- 自定义箭头样式,用于成功状态下流程连线箭头 -->
      <defs ref="customSuccessDefs">
        <marker
          id="sequenceflow-end-white-success"
          view-box="0 0 20 20"
          ref-x="11"
          ref-y="10"
          marker-width="10"
          marker-height="10"
          orient="auto">
          <path
            class="success-arrow"
            d="M 1 5 L 11 10 L 1 15 Z"
            style="
              stroke-width: 1px;
              stroke-linecap: round;
              stroke-dasharray: 10000, 1;
            " />
        </marker>
        <marker
          id="conditional-flow-marker-white-success"
          view-box="0 0 20 20"
          ref-x="-1"
          ref-y="10"
          marker-width="10"
          marker-height="10"
          orient="auto">
          <path
            class="success-conditional"
            d="M 0 10 L 8 6 L 16 10 L 8 14 Z"
            style="
              stroke-width: 1px;
              stroke-linecap: round;
              stroke-dasharray: 10000, 1;
            " />
        </marker>
      </defs>
      <!-- 自定义箭头样式,用于失败状态下流程连线箭头 -->
      <defs ref="customFailDefs">
        <marker
          id="sequenceflow-end-white-fail"
          view-box="0 0 20 20"
          ref-x="11"
          ref-y="10"
          marker-width="10"
          marker-height="10"
          orient="auto">
          <path
            class="fail-arrow"
            d="M 1 5 L 11 10 L 1 15 Z"
            style="
              stroke-width: 1px;
              stroke-linecap: round;
              stroke-dasharray: 10000, 1;
            " />
        </marker>
        <marker
          id="conditional-flow-marker-white-fail"
          view-box="0 0 20 20"
          ref-x="-1"
          ref-y="10"
          marker-width="10"
          marker-height="10"
          orient="auto">
          <path
            class="fail-conditional"
            d="M 0 10 L 8 6 L 16 10 L 8 14 Z"
            style="
              stroke-width: 1px;
              stroke-linecap: round;
              stroke-dasharray: 10000, 1;
            " />
        </marker>
      </defs>

      <div style="position: absolute; top: 0px; left: 0px; width: 100%">
        <el-row type="flex" justify="end">
          <el-button-group key="scale-control" size="medium">
            <el-button
              size="medium"
              type="default"
              :plain="true"
              :disabled="defaultZoom <= 0.3"
              icon="el-icon-zoom-out"
              @click="processZoomOut()" />
            <el-button size="medium" type="default" style="width: 90px">{{
              Math.floor(this.defaultZoom * 10 * 10) + "%"
            }}</el-button>
            <el-button
              size="medium"
              type="default"
              :plain="true"
              :disabled="defaultZoom >= 3.9"
              icon="el-icon-zoom-in"
              @click="processZoomIn()" />
            <el-button
              size="medium"
              type="default"
              icon="el-icon-c-scale-to-original"
              @click="processReZoom()" />
            <slot />
          </el-button-group>
        </el-row>
      </div>
    </div>
    <!-- 已完成节点悬浮弹窗 -->
    <div class="information-list">
      <el-select v-model="selectValue" @change="handleSelect">
        <el-option
          v-for="item in selectOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value">
        </el-option>
      </el-select>
      <el-table
        height="190"
        :data="taskCommentList"
        size="mini"
        border
        header-cell-class-name="table-header-gray">
        <el-table-column
          label="序号"
          header-align="center"
          align="center"
          type="index"
          width="55px" />
        <el-table-column label="流程状态" header-align="center" align="center">
          <template slot-scope="scope">
            <div v-if="scope.row.endTime">已完结</div>
            <div v-else>正在办理</div>
          </template>
        </el-table-column>
        <el-table-column
          label="环节名称"
          prop="name"
          minWidth="100"
          align="center" />
        <el-table-column
          label="办理人"
          prop="agent"
          minWidth="120"
          align="center" />
        <el-table-column
          label="转入时间"
          prop="createTime"
          :formatter="formatDate"
          width="160"
          align="center" />
        <el-table-column
          label="认领时间"
          prop="claimTime"
          :formatter="formatDate"
          width="160"
          align="center" />
        <el-table-column
          label="转出时间"
          prop="endTime"
          :formatter="formatDate"
          width="160"
          align="center" />
        <el-table-column label="操作方式" prop="controls" align="center" />
        <el-table-column label="意见" prop="idea" align="center" />
      </el-table>
    </div>
  </div>
</template>
<script>
  import "@/styles/package/theme/index.scss";
  import BpmnViewer from "bpmn-js/lib/Viewer";
  import MoveCanvasModule from "diagram-js/lib/navigation/movecanvas";
  export default {
    props: {
      formData: {
        type: Object,
        default: {},
      },
    },
    data () {
      return {
        dlgTitle: undefined,
        defaultZoom: 1,
        // 是否正在加载流程图
        isLoading: true,
        bpmnViewer: undefined,
        // 已完成流程元素
        processNodeInfo: undefined,
        // 当前任务id
        selectTaskId: undefined,
        // 任务节点审批记录
        taskList: [],
        taskCommentList: [],
        // 已完成任务悬浮延迟Timer
        hoverTimer: null,
        // 下拉
        selectValue: "",
        selectOptions: [],
      };
    },
    created () {
      this.$nextTick(() => {
        // 获取流程记录
        this.getCommentList();
        this.setProcessStatus(this.formData.finishedInfo);
        this.importXML(this.formData.xml);
      });
    },
    destroyed () {
      this.clearViewer();
    },
    methods: {
      /**
       * @description: formatDate
       * @param {*} row
       * @param {*} column
       * @author: renchao
       */
      formatDate (row, column) {
        let data = row[column.property];
        if (data == null) {
          return null;
        }
        let dt = new Date(data);
        return (
          dt.getFullYear() +
          "-" +
          (dt.getMonth() + 1) +
          "-" +
          dt.getDate() +
          " " +
          dt.getHours() +
          ":" +
          dt.getMinutes() +
          ":" +
          dt.getSeconds()
        );
      },
      /**
       * @description: processReZoom
       * @author: renchao
       */
      processReZoom () {
        this.defaultZoom = 1;
        this.bpmnViewer.get("canvas").zoom("fit-viewport", "auto");
      },
      /**
       * @description: processZoomIn
       * @param {*} zoomStep
       * @author: renchao
       */
      processZoomIn (zoomStep = 0.1) {
        const newZoom = Math.floor(this.defaultZoom * 100 + zoomStep * 100) / 100;
        if (newZoom > 4) {
          throw new Error(
            "[Process Designer Warn ]: The zoom ratio cannot be greater than 4"
          );
        }
        this.defaultZoom = newZoom;
        this.bpmnViewer.get("canvas").zoom(this.defaultZoom);
      },
      /**
       * @description: processZoomOut
       * @param {*} zoomStep
       * @author: renchao
       */
      processZoomOut (zoomStep = 0.1) {
        const newZoom = Math.floor(this.defaultZoom * 100 - zoomStep * 100) / 100;
        if (newZoom < 0.2) {
          throw new Error(
            "[Process Designer Warn ]: The zoom ratio cannot be scss than 0.2"
          );
        }
        this.defaultZoom = newZoom;
        this.bpmnViewer.get("canvas").zoom(this.defaultZoom);
      },
      /**
       * @description: getOperationTagType
       * @param {*} type
       * @author: renchao
       */
      getOperationTagType (type) {
        return "success";
      },
      // 流程图预览清空
      /**
       * @description: 流程图预览清空
       * @param {*} e
       * @author: renchao
       */
      clearViewer (a) {
        if (this.$refs.processCanvas) {
          this.$refs.processCanvas.innerHTML = "";
        }
        if (this.bpmnViewer) {
          this.bpmnViewer.destroy();
        }
        this.bpmnViewer = null;
      },
      // 添加自定义箭头
      /**
       * @description: 添加自定义箭头
       * @author: renchao
       */
      addCustomDefs () {
        const canvas = this.bpmnViewer.get("canvas");
        const svg = canvas._svg;
        const customSuccessDefs = this.$refs.customSuccessDefs;
        const customFailDefs = this.$refs.customFailDefs;
        svg.appendChild(customSuccessDefs);
        svg.appendChild(customFailDefs);
      },
      // 任务悬浮弹窗
      /**
       * @description: 任务悬浮弹窗
       * @param {*} element
       * @author: renchao
       */
      onSelectElement (element) {
        this.selectTaskId = undefined;
        this.dlgTitle = undefined;
        let allfinishedTaskSet = [
          ...this.processNodeInfo.finishedTaskSet,
          ...this.processNodeInfo.unfinishedTaskSet,
        ];
        if (this.processNodeInfo == null || allfinishedTaskSet == null) return;
        if (element == null || allfinishedTaskSet.indexOf(element.id) === -1) {
          return;
        }
        this.selectTaskId = element.id;
        this.selectValue = element.id;
        this.dlgTitle = element.businessObject
          ? element.businessObject.name
          : undefined;
        // 计算当前悬浮任务审批记录,如果记录为空不显示弹窗
        this.taskCommentList = (this.taskList || []).filter((item) => {
          return item.taskDefinitionKey === this.selectTaskId;
        });
        if (this.taskCommentList.length == 0) {
          this.taskCommentList = this.taskList;
        }
      },
      // 下拉列表切换
      /**
       * @description: 下拉列表切换
       * @param {*} val
       * @author: renchao
       */
      handleSelect (val) {
        this.taskCommentList = (this.taskList || []).filter((item) => {
          return item.taskDefinitionKey === val;
        });
        if (this.taskCommentList.length == 0) {
          this.taskCommentList = this.taskList;
        }
      },
      // 显示流程图
      /**
       * @description: 显示流程图
       * @param {*} xml
       * @author: renchao
       */
      async importXML (xml) {
        let xmlData = this.$x2js.xml2js(xml).definitions.process;
        this.selectOptions = xmlData.userTask.map((item) => {
          return { value: item._id, label: item._name };
        });
        this.selectOptions = [
          { value: xmlData.startEvent._id, label: "浏览记录" },
          ...this.selectOptions,
        ];
        this.selectOptions = this.selectOptions
          .map((item) => {
            if (this.formData.finishedInfo.finishedTaskSet.includes(item.value)) {
              return item;
            }
            if (
              this.formData.finishedInfo.unfinishedTaskSet.includes(item.value)
            ) {
              return item;
            }
          })
          .filter(Boolean);
        this.selectValue = xmlData.startEvent._id;
        this.clearViewer("a");
        if (xml != null && xml !== "") {
          try {
            this.bpmnViewer = new BpmnViewer({
              additionalModules: [
                // 移动整个画布
                MoveCanvasModule,
              ],
              container: this.$refs.processCanvas,
            });
            // 任务节点悬浮事件
            this.bpmnViewer.on("element.click", ({ element }) => {
              this.onSelectElement(element);
            });
            await this.bpmnViewer.importXML(xml);
            this.isLoading = true;
            this.addCustomDefs();
          } catch (e) {
            this.clearViewer("b");
          } finally {
            this.isLoading = false;
            this.setProcessStatus(this.processNodeInfo);
            this.$nextTick(() => {
              this.processReZoom();
            });
          }
        }
      },
      // 获取流程记录
      /**
       * @description: 获取流程记录
       * @author: renchao
       */
      getCommentList () {
        this.formData.allCommentList.forEach(async (item, index) => {
          // item.comments.forEach(element => {
          //   if(element.type=="COMPLETE"){
          //     this.formData.allCommentList[index].idea=element.message
          //      this.formData.allCommentList[index].controls="完成"
          //   }
          // });
          let type = item.comments[item.comments.length - 1].type;
          this.formData.allCommentList[index].idea =
            item.comments[item.comments.length - 1].message;
          // 操作方式
          let controls = "";
          switch (type) {
            case "COMPLETE":
              controls = "完成";
              break;
            case "CLAIM":
              controls = "完成";
              break;
            case "ASSIGN":
              controls = "转办";
              break;
            case "DELEGATE":
              controls = "委派";
              break;
            case "UNCLAIM":
              controls = "取消认领";
              break;
            case "STOP":
              controls = "终止";
              break;
            case "BACK":
              controls = "退回";
              break;
          }
          this.formData.allCommentList[index].controls = controls;
          this.formData.allCommentList[index].agent = item.assignee.name;
        });
        this.formData.handlinglist.forEach(async (item, index) => {
          if (item.assignee.name) {
            this.formData.handlinglist[index].agent = item.assignee.name;
          } else {
            let str = "";
            item.countersign.forEach((item) => {
              str += item.name + ",";
            });
            str = str.slice(0, -1);
            this.formData.allCommentList[index].agent = str;
          }
        });
        this.taskList = [
          ...this.formData.allCommentList,
          ...this.formData.handlinglist,
        ];
        //  this.taskList =this.formData.allCommentList;
        //  处理数据之后赋值
        this.taskCommentList = this.taskList;
      },

      // 设置流程图元素状态
      /**
       * @description: 设置流程图元素状态
       * @param {*} processNodeInfo
       * @author: renchao
       */
      setProcessStatus (processNodeInfo) {
        this.processNodeInfo = processNodeInfo;
        if (
          this.isLoading ||
          this.processNodeInfo == null ||
          this.bpmnViewer == null
        )
          return;
        const {
          finishedTaskSet,
          rejectedTaskSet,
          unfinishedTaskSet,
          finishedSequenceFlowSet,
        } = this.processNodeInfo;
        const canvas = this.bpmnViewer.get("canvas");
        const elementRegistry = this.bpmnViewer.get("elementRegistry");
        if (Array.isArray(finishedSequenceFlowSet)) {
          finishedSequenceFlowSet.forEach((item) => {
            if (item != null) {
              canvas.addMarker(item, "success");
              const element = elementRegistry.get(item);
              const conditionExpression =
                element.businessObject.conditionExpression;
              if (conditionExpression) {
                canvas.addMarker(item, "condition-expression");
              }
            }
          });
        }
        if (Array.isArray(finishedTaskSet)) {
          finishedTaskSet.forEach((item) => canvas.addMarker(item, "success"));
        }
        if (Array.isArray(unfinishedTaskSet)) {
          unfinishedTaskSet.forEach((item) => canvas.addMarker(item, "primary"));
        }
        if (Array.isArray(rejectedTaskSet)) {
          rejectedTaskSet.forEach((item) => {
            if (item != null) {
              const element = elementRegistry.get(item);
              if (element.type.includes("Task")) {
                canvas.addMarker(item, "danger");
              } else {
                canvas.addMarker(item, "warning");
              }
            }
          });
        }
      },
    },
  };
</script>
<style scoped lang="scss">
  .information-list {
    height: 220px;
    margin-top: 10px;

    p {
      font-size: 16px;
      line-height: 24px;
    }
  }
  /deep/.bjs-powered-by {
    display: none;
  }
  // /deep/.information-list {
  //   height: 170px;
  //   overflow: visible;
  // }
</style>