<template>
  <a-modal
      class="funcNetDialog"
      :title="this.$t('functional-analysis.net.failure-net-colon') + title"
      :visible="dialogFormVisible"
      :maskClosable="false"
      @cancel="close"
      :keyboard="false"
      width="100%"
      destroy-on-close
      :footer="false"
      @afterClose="close">
    <div class="funcNetContent">
      <splitPane
          :min-percent="2"
          split="vertical"
          :default-percent="25">
        <template slot="paneL">
          <div class="net-left beauty-Scroll height100">
            <div style="min-width: 250px;">
              <a-tabs
                  v-model="leftTabName"
                  @change="leftTabChange"
                  :style="{height: '100%'}"
                  type="card"
                  :destroyInactiveTabPane="true">
                <a-tab-pane
                    :tab="$t('functional-analysis.net.function-net')"
                    key="leftFunctionNet">
                  <a-spin
                      :tip="spinTip"
                      :spinning="leftTreeLoading">
                    <FaultNetTree
                        class="leftTree"
                        ref="leftTree"
                        treeKey="leftTree"
                        :treeData="leftTreeData"
                        :directFlag="0"
                        @addNetNode="addNetNode"
                        @initTree="initFaultNetLrTree"
                        @deleteNetNode="deleteNetNode"
                        @deleteNode="deleteNode"
                        @updateFaultNetNode="updateFaultNetNode"
                        @keyListenerChange="keyListenerChange"/>
                  </a-spin>
                </a-tab-pane>
                <a-tab-pane
                    :tab="$t('functional-analysis.net.superstructure')"
                    key="superStructure">
                  <TreeSelect
                      ref="leftTreeSelect"
                      :treeData="treeData"
                      :directFlag="0"
                      @treeSelectChange="treeSelectChange"/>
                  <a-spin
                      :tip="spinTip"
                      :spinning="leftTreeLoading">
                    <FaultNetTree
                        class="mt5 ml15 leftTree"
                        ref="leftTree"
                        treeKey="leftTree"
                        :treeData="leftTreeData"
                        :directFlag="0"
                        @addNetNode="addNetNode"
                        @initTree="initFaultNetLrTree"
                        @deleteNetNode="deleteNetNode"
                        @deleteNode="deleteNode"
                        @updateFaultNetNode="updateFaultNetNode"
                        @keyListenerChange="keyListenerChange"/>
                  </a-spin>
                </a-tab-pane>
              </a-tabs>
            </div>
          </div>
        </template>
        <template slot="paneR">
          <splitPane split="vertical" :default-percent="70" :min-percent="2">
            <template slot="paneL">
              <div class="net-center beauty-Scroll pr over-hide">
                <a-form-model class="switchArea">
                  <a-form-model-item>
                    <span class="ml10">
                      <label>{{ $t('functional-analysis.net.note-colon') }}</label>
                      <span>
                        <i class="iconfont icondantupailie parent"/>
                        <label class="ml5">{{ $t('functional-analysis.net.super') }}</label>
                      </span>
                      <span class="ml5">
                        <i class="iconfont icondantupailie current"/>
                        <label class="ml5">{{ $t('functional-analysis.net.current') }}</label>
                      </span>
                      <span class="ml5">
                        <i class="iconfont icondantupailie children"/>
                        <label class="ml5">{{ $t('functional-analysis.net.lower-level') }}</label>
                      </span>
                      <span class="ml5">
                        <i class="iconfont iconshubiaojiantou"/>
                        <label class="ml5">{{ $t('functional-analysis.net.double-tap-focus') }}</label>
                      </span>
                    </span>
                    <span class="ml10">
                      <label>{{ $t('functional-analysis.net.show-structure') }}</label>
                      <a-switch
                          class="ml5"
                          size="small"
                          :disabled="!isOperation"
                          v-model="structureSwitch"
                          @change="structureSwitchChange"
                          active-color="#13ce66"
                          inactive-color="#ff4949"/>
                    </span>
                    <span class="ml10">
                      <label>{{ $t('functional-analysis.net.show-function') }}</label>
                      <a-switch
                          class="ml5"
                          size="small"
                          :disabled="!isOperation"
                          v-model="functionSwitch"
                          @change="functionSwitchChange"
                          active-color="#13ce66"
                          inactive-color="#ff4949"/>
                    </span>
                    <span class="ml10">
                      <a-tooltip :title="$t('functional-analysis.net.refresh')">
                        <a-button
                            type="primary"
                            size="small"
                            :disabled="!isOperation"
                            @click="refreshFaultNet()"
                        >
                            <i class="iconfont iconshuaxin"/>
                        </a-button>
                      </a-tooltip>
                    </span>
                    <span class="ml10">
                      <a-tooltip :title="$t('functional-analysis.net.download')">
                        <a-button
                            type="primary"
                            size="small"
                            @click="downloadHtml()"
                        >
                            <i class="iconfont iconxiazai2"/>
                        </a-button>
                      </a-tooltip>
                    </span>
                    <!-- 故障树 -->
                    <span class="ml10 mr10">
                      <label>{{ $t('functional-analysis.net.fault-tree-diagram') }}</label>
                      <a-switch
                          class="ml5"
                          size="small"
                          :loading="faultTreeDiagramSwitchLoading"
                          v-model="faultTreeDiagramSwitch"
                          @change="faultTreeDiagramSwitchChange"
                      />
                    </span>
                  </a-form-model-item>
                </a-form-model>
                <template>
                  <a-spin
                      :tip="spinTip"
                      :spinning="faultNetLoading">
                    <div class="pr net-container" style="height: calc(100vh - 100px)">
                      <table id="fault-net-tree" ref="faultNetTree" class="ml10 table htree"></table>
                      <div id="faultTreeContainer" style="width: 100%; height: 100%; overflow: hidden;"></div>
                    </div>
                  </a-spin>
                </template>
              </div>
            </template>
            <template slot="paneR">
              <div class="net-right beauty-Scroll height100">
                <div style="min-width: 250px;">
                  <a-tabs
                      v-model="rightTabName"
                      @change="rightTabChange"
                      class="ml24"
                      :style="{height: '100%'}"
                      type="card"
                      :destroyInactiveTabPane="true">
                    <a-tab-pane
                        :tab="$t('functional-analysis.net.function-net')"
                        key="rightFunctionNet">
                      <a-spin
                          :tip="spinTip"
                          :spinning="rightTreeLoading">
                        <FaultNetTree
                            class="rightTree"
                            ref="rightTree"
                            treeKey="rightTree"
                            :treeData="rightTreeData"
                            :directFlag="1"
                            @addNetNode="addNetNode"
                            @initTree="initFaultNetLrTree"
                            @deleteNetNode="deleteNetNode"
                            @deleteNode="deleteNode"
                            @updateFaultNetNode="updateFaultNetNode"
                            @keyListenerChange="keyListenerChange"/>
                      </a-spin>
                    </a-tab-pane>
                    <a-tab-pane
                        :tab="$t('functional-analysis.net.substructure')"
                        key="subStructure">
                      <TreeSelect
                          ref="rightTreeSelect"
                          :treeData="treeData"
                          :directFlag="1"
                          @treeSelectChange="treeSelectChange"/>
                      <a-spin
                          :tip="spinTip"
                          :spinning="rightTreeLoading">
                        <FaultNetTree
                            class="mt5 ml15 rightTree"
                            ref="rightTree"
                            treeKey="rightTree"
                            :treeData="rightTreeData"
                            :directFlag="1"
                            @addNetNode="addNetNode"
                            @initTree="initFaultNetLrTree"
                            @deleteNetNode="deleteNetNode"
                            @deleteNode="deleteNode"
                            @updateFaultNetNode="updateFaultNetNode"
                            @keyListenerChange="keyListenerChange"/>
                      </a-spin>
                    </a-tab-pane>
                  </a-tabs>
                </div>
              </div>
            </template>
          </splitPane>
        </template>
      </splitPane>
    </div>
  </a-modal>
</template>
<script>

import splitPane from "vue-splitpane";
import TreeSelect from "./components/TreeSelect";
import FaultNetTree from "./components/FaultNetTree";
import {arrayToTree} from "@/utils/tree";
import {arrayToNetTree, filterNode} from "@/utils/netTree";
import {getViewPortOffset} from "@/utils";
import {buildNet, dragZoom} from './components/index';
import {downloadHtml} from '@/utils/download-html';
import {buildFaultTreeDiagram, buildGoJsData, exportSvg} from "@/utils/go/go_ui";

/** 节点颜色 */
let nodeColor = {
  "02": {'color': 'rgb(66, 167, 94)'},
  "04": {'color': '#5b9bd5'},
  "05": {'color': '#5b9bd5'},
  "06": {'color': 'rgb(200, 77, 60)'},
};

export default {
  name: "FaultNetModal",
  components: {splitPane, TreeSelect, FaultNetTree},
  props: {
    showFaultNetModal: {
      type: Boolean,
      default: false
    },
    showFaultNetEventListener: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    showFaultNetModal(val) {
      this.dialogFormVisible = val;
      if (val) {
        this.isOperation = true;
        this.faultTreeDiagramSwitch = false;
        this.faultTreeDiagram = undefined;
        this.goJsData = {};
      }
    },
    showFaultNetEventListener: {
      handler(val, oldVal) {
        if (val) {
          window.addEventListener("keydown", this.keyCodeForEvent);
          window.addEventListener("resize", this.watchFaultNetResize);
        } else {
          window.removeEventListener("keydown", this.keyCodeForEvent);
          window.removeEventListener("resize", this.watchFaultNetResize);
        }
      },
      immediate: true
    },
  },
  data() {
    return {
      /** 标题 */
      title: '',
      /** 左侧tab默认选中 */
      leftTabName: "leftFunctionNet",
      /** 右侧tab默认选中 */
      rightTabName: "rightFunctionNet",
      /** 模态框状态 */
      dialogFormVisible: false,
      /** 结构树数据 */
      treeData: [],
      /** 左侧树数据 */
      leftTreeData: [],
      /** 左侧树功能网数据 */
      leftTreeFunctionNetData: [],
      /** 右侧树数据 */
      rightTreeData: [],
      /** 右侧树功能网数据 */
      rightTreeFunctionNetData: [],
      /** 左侧树选中节点 */
      leftTreeCheckedNode: [],
      /** 右侧树选中节点 */
      rightTreeCheckedNode: [],
      /** 缓存树标识 左边=0 右边=1 */
      directFlag: 0,
      /** 是否可以操作 */
      isOperation: true,
      /** 结构switch开关 */
      structureSwitch: true,
      /** 功能switch开关 */
      functionSwitch: true,
      /** 故障树图switch开关 */
      faultTreeDiagramSwitch: false,
      /** 故障树图switch开关Loading */
      faultTreeDiagramSwitchLoading: false,
      /** 故障树图 Diagram*/
      faultTreeDiagram: undefined,
      /** 左侧下拉选中节点ID */
      leftSelectCheckedNodeId: "",
      /** 右侧下拉选中节点ID */
      rightSelectCheckedNodeId: "",
      /** 第一次失效网节点 */
      firstFaultNetNode: {},
      /** 左tree加载中状态 */
      leftTreeLoading: false,
      /** 失效加载中状态 */
      faultNetLoading: false,
      /** 右tree加载中状态 */
      rightTreeLoading: false,
      /** 自定义Loading描述文案 */
      // spinTip: "加载中...",
      spinTip: "",
      /** 中心节点菜单项 */
      centerMenuItems: {},
      /** gojs数据 */
      goJsData: {},
    };
  },
  mounted() {
    this.$once('hook:beforeDestroy', () => {
      this.$emit("closeFaultNetModal");
    });
  },
  methods: {
    /**
     * 下载Html
     */
    downloadHtml() {
      if (!this.isOperation) {
        exportSvg(this.faultTreeDiagram, this.$t('functional-analysis.net.fault-tree-diagram'));
      } else {
        const html = this.$refs.faultNetTree.outerHTML;
        downloadHtml(html, this.$t('functional-analysis.net.failure-net'));
      }
    },
    getLrTreeHeight() {
      this.$nextTick(() => {
        // 模态框头部高度
        let antModalHeaderH = document.querySelector(".ant-modal-header").offsetHeight;
        // 模态框体Padding
        let antModalBodyStyle = window.getComputedStyle(document.querySelector(".ant-modal-body"), null);
        let antModalBodyPadding = parseFloat(antModalBodyStyle.getPropertyValue('padding-top'));
        // 选项卡高度
        let antTabsBarH = document.querySelector(".ant-tabs-bar").offsetHeight;
        // 选项卡margin-bottom
        let antTabsBarStyle = window.getComputedStyle(document.querySelector(".ant-tabs-bar"), null);
        let antTabsBarStyleMarginBottom = parseFloat(antTabsBarStyle.getPropertyValue('margin-bottom'));
        // 下拉搜索框
        let antSelectDom = document.querySelector(".ant-select");
        let antSelectH = 0;
        if (antSelectDom) antSelectH = antSelectDom.offsetHeight;

        // console.log("模态框头部高度:" + antModalHeaderH);
        // console.log("模态框体Padding:" + antModalBodyPadding);
        // console.log("选项卡高度:" + antTabsBarH);
        // console.log("选项卡margin-bottom:" + antTabsBarStyleMarginBottom);
        // console.log("下拉搜索框:" + antSelectH);
        let otherDomH = antModalHeaderH + antModalBodyPadding + antTabsBarH + antTabsBarStyleMarginBottom
            + antSelectH;
        console.log("其他元素高度:" + otherDomH);
        let viewAreaWH = getViewPortOffset();
        let treeHeight = viewAreaWH.h - otherDomH;
        this.$refs.leftTree.$el.style.height = treeHeight + "px";
        this.$refs.rightTree.$el.style.height = treeHeight + "px";
      });
    },
    /**
     * 监听窗口大小调整
     */
    watchFaultNetResize() {
      this.getLrTreeHeight();
    },
    /**
     * 刷新失效网
     */
    refreshFaultNet() {
      let _that = this;
      _that.setCheckedNode(_that.firstFaultNetNode.id, _that.firstFaultNetNode.pid);
      _that.initFaultNet(_that.firstFaultNetNode.id, 1, 1);
      _that.structureSwitch = true;
      _that.functionSwitch = true;
      _that.isOperation = true;
      _that.faultTreeDiagramSwitch = false;
      _that.handleCenterMenuItems(_that.firstFaultNetNode.id);
      _that.title = _that.firstFaultNetNode.name;
    },
    /**
     * 初始化结构树
     * @returns {Promise<void>}
     */
    async initLeftTree() {
      let _that = this;
      await _that.$api.getLeftTree({
        fmeaId: _that.$store.getters.rfmeaId
      }).then((res) => {
        if (res.flag) {
          let resData = res.data.rdfmStruTreeModels;
          let filterNodes = _that.$store.getters.variantFilterNodes;
          let targetNode = resData.filter((item) => {
            return item.pid === '00000000000000000000000000000000';
          })[0];
          this.treeData = arrayToTree(targetNode, filterNode(resData, filterNodes));
          _that.getLrTreeHeight();
        } else {
          _that.$message.error(res.message, 1);
        }
      });
    },
    /**
     * 下拉选择树节点
     * @param checkedNodeId 选中节点ID
     * @param directFlag 0：左侧，1：右侧
     */
    treeSelectChange(checkedNodeId, directFlag) {
      let _that = this;
      // 初始化默认左右侧树
      if (!checkedNodeId) {
        let centerNodeId = _that.$store.getters.lastCheckedNetNode.id;
        if (directFlag === 0) {
          _that.leftSelectCheckedNodeId = undefined;
          _that.initFaultLeftTree(centerNodeId);
        } else {
          _that.rightSelectCheckedNodeId = undefined;
          _that.initFaultRightTree(centerNodeId);
        }
        return;
      }
      // 缓存左右侧选中节点ID
      if (directFlag === 0) {
        _that.leftSelectCheckedNodeId = checkedNodeId;
      } else {
        _that.rightSelectCheckedNodeId = checkedNodeId;
      }
      // 手动下拉选择时,初始化下拉树。
      _that.initDropDownTree(checkedNodeId, directFlag);
    },
    /**
     * 初始化下拉树
     * @param checkedNodeId 选中节点ID
     * @param directFlag 0：左侧，1：右侧
     */
    initDropDownTree(checkedNodeId, directFlag) {
      let _that = this;
      if (0 === directFlag) _that.leftTreeLoading = true;
      if (1 === directFlag) _that.rightTreeLoading = true;
      _that.$api.getFaultNetTree({
        fmeaId: _that.$store.getters.rfmeaId,
        selectStruId: checkedNodeId,
      }).then((res) => {
        if (res.flag) {
          let resData = res.data.rdfmStruTreeModels;
          if (resData && resData.length > 0) {
            // 过滤变体节点
            let filterNodes = _that.$store.getters.variantFilterNodes;
            resData = filterNode(resData, filterNodes);
            let targetNodes = resData.filter((item) => {
              return "01,99".indexOf(item.struTypeCode) !== -1;
            });
            let treeData = [];
            let checkedNode = directFlag === 0 ? _that.leftTreeCheckedNode : _that.rightTreeCheckedNode;
            for (let i = 0, len = targetNodes.length; i < len; i++) {
              treeData.push(arrayToNetTree("", [], targetNodes[i], resData, checkedNode));
            }
            directFlag === 0 ? _that.leftTreeData = treeData : _that.rightTreeData = treeData;
          } else {
            directFlag === 0 ? _that.leftTreeData = [] : _that.rightTreeData = [];
          }
        } else {
          _that.$message.error(res.message, 1);
        }
      }).finally(() => {
        if (0 === directFlag) _that.leftTreeLoading = false;
        if (1 === directFlag) _that.rightTreeLoading = false;
      });
    },
    /**
     * 初始化失效网
     * @param checkedNodeId 选中节点ID
     * @param flag 初期化网时，清空前次对网操作的Session标记
     * @param clearFlag 初期化网时，清空前次对网操作的Session标记
     * @returns {Promise<void>}
     */
    async initFaultNet(checkedNodeId, flag, clearFlag) {
      await this.initFaultNetByFunctionNet(checkedNodeId, flag, clearFlag);
    },
    /**
     * 根据功能网，初始化失效网
     * @param checkedNodeId 选中节点ID
     * @param flag 初期化网时，清空前次对网操作的Session标记
     * @param clearFlag 初期化网时，清空前次对网操作的Session标记
     * @param lrTreeFlag 默认刷新左右树
     * @returns {Promise<void>}
     */
    initFaultNetByFunctionNet(checkedNodeId, flag, clearFlag, lrTreeFlag = true) {
      let _that = this;
      _that.faultNetLoading = true;
      _that.$api.getFaultNetByFunctionNet({
        fmeaId: _that.$store.getters.rfmeaId,
        struId: checkedNodeId,
        flag: flag,
        clearFlag: clearFlag,
      }).then((res) => {
        if (res.flag) {
          // 处理失效网数据
          _that.handleFaultNetData(res.data);
          // 构建左右侧，节点的勾选
          let targetNode = res.data.targetNode;
          _that.leftTreeCheckedNode = [];
          _that.rightTreeCheckedNode = [];
          res.data.parentNode.forEach((item) => {
            if (targetNode.faultId === item.faultId) _that.leftTreeCheckedNode.push(item.parentFaultId);
          });
          res.data.subNode.forEach((item) => {
            if (targetNode.faultId === item.parentFaultId) _that.rightTreeCheckedNode.push(item.faultId);
          });
          // 初始失效网左、右侧树
          if (lrTreeFlag) _that.initFaultNetLrTree(checkedNodeId);
        } else {
          _that.$message.error(res.message, 1);
        }
      }).finally(() => {
        _that.faultNetLoading = false;
        _that.structureSwitchChange(_that.structureSwitch);
        _that.functionSwitchChange(_that.functionSwitch);
      });
    },
    /**
     * 处理失效网数据
     * @param resData 响应数据
     */
    handleFaultNetData(resData) {
      // 过滤变体节点
      let filterNodes = this.$store.getters.variantFilterNodes;
      let targetNode = resData.targetNode;
      let parentNode = filterNode(resData.parentNode, filterNodes, 'parentFaultId');
      let subNode = filterNode(resData.subNode, filterNodes, 'faultId');

      let id = resData.struId;
      let nodeData = {};
      nodeData[targetNode.faultId] = {
        id: targetNode.faultId,
        pid: targetNode.requireId ? targetNode.requireId : targetNode.functionId,
        faultName: targetNode.faultName,
        functionName: targetNode.functionName,
        struCode: targetNode.struCode,
        struName: targetNode.struName,
        requireName: targetNode.requireName,
        funStruTypeCode: targetNode.funStruTypeCode,
      }
      let netData = [];
      parentNode.forEach(pf => {
        nodeData[pf.parentFaultId] = {
          id: pf.parentFaultId,
          pid: pf.requireId ? targetNode.requireId : targetNode.functionId,
          faultName: pf.faultName,
          functionName: pf.functionName,
          struCode: pf.struCode,
          struName: pf.struName,
          requireName: pf.requireName,
          funStruTypeCode: pf.funStruTypeCode,
        };
        netData.push([pf.parentFaultId, pf.faultId]);
      })

      subNode.forEach(pf => {
        nodeData[pf.faultId] = {
          id: pf.faultId,
          pid: pf.requireId ? targetNode.requireId : targetNode.functionId,
          faultName: pf.faultName,
          functionName: pf.functionName,
          struCode: pf.struCode,
          struName: pf.struName,
          requireName: pf.requireName,
          funStruTypeCode: pf.funStruTypeCode,
          linkName: pf.linkName,
        };
        netData.push([pf.parentFaultId, pf.faultId]);
      });
      // 去重
      netData = $.unique(netData);
      this.handleFaultNet(id, nodeData, netData);
      console.log('初始化 ==> 构建故障树图');
      // 处理GoJs数据
      buildGoJsData(netData, nodeData, this.goJsData, targetNode.faultId, 2);
      // 初始化构建故障树图
      // 这里捕获异常，避免在大数据情况下影响左右树加载
      try {
          this.faultTreeDiagram = buildFaultTreeDiagram(this.faultTreeDiagram, this.goJsData, 'faultTreeContainer');
      } catch (error) {
          // console.error(error);
      }
      document.getElementById('faultTreeContainer').style.display = 'none';
    },
    /**
     * 处理失效网
     * @param id 根节点ID
     * @param nodeData 节点数据
     * @param netData 网数据
     */
    handleFaultNet(id, nodeData, netData) {
      const name = this.$t('global-constant.contextmenu.delete');
      let _that = this;
      // 初期化网
      buildNet('table#fault-net-tree', {target: id, nodes: nodeData, net: netData}, {
        htmlNullLeft: '',
        htmlNullRight: '',
        editable: false,
        buildNodeHtmlFunc: function (o) {
          // 结构（零件号）
          let scode = '';
          if (o.struCode) scode = '(' + o.struCode + ')';

          // 要求
          let requireName = "";
          if (o.requireName) {
            requireName = '<span  style="line-height:20px;white-space: normal;color:'
                + nodeColor["05"].color + '">&nbsp;'
                + '(' + o.requireName + ')'
                + '</span>';
          }
          return '<p id="netNameId' + o.id + '" style="line-height:20px;white-space: normal;color:'
              + nodeColor["06"].color + '" title="' + o.faultName + '">'
              + o.faultName
              + '</p>'
              + '<small class="function" style="line-height:20px;white-space: normal;color:'
              + nodeColor[o.funStruTypeCode].color
              + '" title="' + o.functionName + (o.requireName ? '&nbsp;(' + o.requireName + ')' : '') + '">'
              + (o.linkName ? o.linkName + "\xa0\xa0" : '')
              + o.functionName + requireName
              + '</small>'
              + '<small class="structure" style="line-height:20px;white-space: normal;'
              + '" title="' + o.struName + scode + '">'
              + o.struName + scode
              + '</small>';
        },
        // 双击聚焦
        focusNodeFunc: function () {
          let id = $(this).attr("id");
          let pid = $(this).attr("pid");
          let name = $("#netNameId" + id)[0].innerText;
          let checkedNode = {id: id, pid: pid, name: name};
          _that.dblFocus(checkedNode);
        },
        // 右击节点
        rightClickNodeFunc: function () {
          let className = $(this).attr("class");
          // 位置标识
          let position = '';
          if (className.indexOf('center') !== -1) {
            position = 'center';
          } else if (className.indexOf('left') !== -1) {
            position = 'left';
          } else if (className.indexOf('right') !== -1) {
            position = 'right';
          }
          let id = $(this).attr("id");
          $.contextMenu('destroy'); // 销毁所有菜单。
          // 中心节点
          if (position === 'center') {
            if (Object.keys(_that.centerMenuItems).length === 0) return;
            $.contextMenu({
              selector: '#' + id,
              autoHide: true,
              zIndex: 10,
              items: _that.centerMenuItems,
              callback: function (itemKey, opt) {
                let item = opt.items[itemKey];
                let actionInfo = {action: 'toFunctionNet', node: item.node};
                _that.menuAction(actionInfo);
              },
            });
            // 两侧节点
          } else if (position === 'left' || position === 'right') {
            $.contextMenu({
              selector: '#' + id,
              autoHide: true,
              zIndex: 10,
              items: {
                "delete": {
                  name: name,
                  title: name,
                  icon: "fas iconfont iconshanchu",
                  node: {
                    id: id,
                  }
                }
              },
              callback: function (itemKey, opt) {
                let item = opt.items[itemKey];
                let actionInfo = {action: 'delete', node: item.node, position: position};
                _that.menuAction(actionInfo);
              },
            });
          }
        }
      });
      // 元素拖动、缩放
      dragZoom(document.querySelector('#fault-net-tree'));
    },
    /**
     * 处理中心节点菜单项
     * @param id
     */
    handleCenterMenuItems(id) {
      let _that = this;
      let menuBtn = {};
      _that.$api.getFaultNetToFunctionNet({
        fmeaId: _that.$store.getters.rfmeaId,
        struId: id,
      }).then((res) => {
        //刷新结构树
        if (res.flag) {
          let resData = res.data.funcIdsList;
          // 过滤变体节点
          let filterNodes = _that.$store.getters.variantFilterNodes;
          resData = filterNode(resData, filterNodes, 'struId');
          if (resData && resData.length > 0) {
            // 处理右键菜单项
            resData.forEach(item => {
              menuBtn['' + item.struId + ''] = {
                name: item.funcName,
                icon: "fas iconfont icon14",
                className: item.nodeType === '02' ? 'function-color' : 'require-color',
                node: {
                  id: item.struId,
                  pid: id,
                  name: item.funcName,
                }
              };
            });
          }
          _that.centerMenuItems = menuBtn;
        } else {
          _that.$message.error(res.message, 1);
        }
      }).catch((error) => {
        _that.$message.error(error.response.data.message, 1);
      });
    },
    /**
     * 结构开关改变事件
     * @param checked
     * @param event
     */
    structureSwitchChange(checked, event) {
      if (checked) {
        $('.structure').show();
      } else {
        $('.structure').hide();
      }
    },
    /**
     * 功能开关改变事件
     * @param checked
     * @param event
     */
    functionSwitchChange(checked, event) {
      if (checked) {
        $('.function').show();
      } else {
        $('.function').hide();
      }
    },
    /**
     * 故障树图开关改变事件
     * @param checked
     * @param event
     */
    faultTreeDiagramSwitchChange(checked, event) {
      if (checked) {
        document.getElementById('fault-net-tree').style.display = 'none';
        document.getElementById('faultTreeContainer').style.display = '';
      } else {
        document.getElementById('faultTreeContainer').style.display = 'none';
        document.getElementById('fault-net-tree').style.display = '';
      }
      this.isOperation = !checked;
    },
    /**
     * 初始化失效网左侧，右侧的树
     */
    initFaultNetLrTree() {
      let _that = this;
      let centerNodeId = _that.$store.getters.lastCheckedNetNode.id;
      if (_that.leftTabName === 'leftFunctionNet') {
        _that.initFaultLeftTreeByFunctionNet(centerNodeId);
      } else {
        if (_that.leftSelectCheckedNodeId) {
          _that.initDropDownTree(_that.rightSelectCheckedNodeId, 0);
        } else {
          _that.initFaultLeftTree(centerNodeId);
        }
      }
      if (_that.rightTabName === 'rightFunctionNet') {
        _that.initFaultRightTreeByFunctionNet(centerNodeId);
      } else {
        if (_that.rightSelectCheckedNodeId) {
          _that.initDropDownTree(_that.rightSelectCheckedNodeId, 1);
        } else {
          _that.initFaultRightTree(centerNodeId);
        }
      }
    },
    /**
     * 根据功能网，初始失效网左侧树
     * @param checkedNodeId 选中节点ID
     */
    async initFaultLeftTreeByFunctionNet(checkedNodeId) {
      let _that = this;
      _that.leftTreeLoading = true;
      await _that.$api.getFaultNetParentByFunctionNet({
        fmeaId: _that.$store.getters.rfmeaId,
        struId: checkedNodeId,
      }).then((res) => {
        if (res.flag) {
          let resData = res.data.rdfmStruTreeModels;
          if (resData && resData.length > 0) {
            // 过滤变体节点
            let filterNodes = _that.$store.getters.variantFilterNodes;
            resData = filterNode(resData, filterNodes);
            let targetNodes = resData.filter((item) => {
              return "01,99".indexOf(item.struTypeCode) !== -1;
            });
            // 过滤结构没有下级功能、产品特性。
            for (let i = targetNodes.length - 1; i >= 0; i--) {
              let childNodes = resData.filter(item => {
                return "02,04".indexOf(item.struTypeCode) !== -1
                    && targetNodes[i].id === item.pid
              });
              if (childNodes.length === 0) targetNodes.splice(i, 1);
            }
            // 过滤结构、接口。
            resData = resData.filter((item) => {
              return "01,99".indexOf(item.struTypeCode) === -1;
            });
            let treeData = [];
            for (let i = 0, len = targetNodes.length; i < len; i++) {
              treeData.push(arrayToNetTree("", [], targetNodes[i], resData, _that.leftTreeCheckedNode));
            }
            _that.leftTreeData = treeData;
          } else {
            _that.leftTreeData = [];
          }
        } else {
          _that.$message.error(res.message, 1);
        }
      }).finally(() => {
        _that.leftTreeLoading = false;
      });
    },
    /**
     * 根据功能网，初始失效网右侧树
     * @param checkedNodeId 选中节点ID
     */
    async initFaultRightTreeByFunctionNet(checkedNodeId) {
      let _that = this;
      _that.rightTreeLoading = true;
      await _that.$api.getFaultNetChildrenByFunctionNet({
        fmeaId: _that.$store.getters.rfmeaId,
        struId: checkedNodeId,
      }).then((res) => {
        if (res.flag) {
          let resData = res.data.rdfmStruTreeModels;
          if (resData && resData.length > 0) {
            // 过滤变体节点
            let filterNodes = _that.$store.getters.variantFilterNodes;
            resData = filterNode(resData, filterNodes);
            let targetNodes = resData.filter((item) => {
              return "01,99".indexOf(item.struTypeCode) !== -1;
            });
            // 过滤结构没有下级功能、产品特性。
            for (let i = targetNodes.length - 1; i >= 0; i--) {
              let childNodes = resData.filter(item => {
                return "02,04".indexOf(item.struTypeCode) !== -1
                    && targetNodes[i].id === item.pid
              });
              if (childNodes.length === 0) targetNodes.splice(i, 1);
            }
            // 过滤结构、接口。
            resData = resData.filter((item) => {
              return "01,99".indexOf(item.struTypeCode) === -1;
            });
            let treeData = [];
            for (let i = 0, len = targetNodes.length; i < len; i++) {
              treeData.push(arrayToNetTree("", [], targetNodes[i], resData, _that.rightTreeCheckedNode));
            }
            _that.rightTreeData = treeData;
            _that.rightTreeFunctionNetData = treeData;
          } else {
            _that.rightTreeData = [];
            _that.rightTreeFunctionNetData = [];
          }
        } else {
          _that.$message.error(res.message, 1);
        }
      }).finally(() => {
        _that.rightTreeLoading = false;
      });
    },
    /**
     * 初始失效网左侧树
     * @param checkedNodeId 选中节点ID
     */
    async initFaultLeftTree(checkedNodeId) {
      let _that = this;
      _that.leftTreeLoading = true;
      await _that.$api.getFaultNetParent({
        fmeaId: _that.$store.getters.rfmeaId,
        struId: checkedNodeId,
      }).then((res) => {
        if (res.flag) {
          let resData = res.data.rdfmStruTreeModels;
          if (resData && resData.length > 0) {
            // 过滤变体节点
            let filterNodes = _that.$store.getters.variantFilterNodes;
            resData = filterNode(resData, filterNodes);
            let targetNodes = resData.filter((item) => {
              return "01,99".indexOf(item.struTypeCode) !== -1;
            });
            let treeData = [];
            for (let i = 0, len = targetNodes.length; i < len; i++) {
              treeData.push(arrayToNetTree("", [], targetNodes[i], resData, _that.leftTreeCheckedNode));
            }
            _that.leftTreeData = treeData;
          } else {
            _that.leftTreeData = [];
          }
        } else {
          _that.$message.error(res.message, 1);
        }
      }).finally(() => {
        _that.leftTreeLoading = false;
      });
    },
    /**
     * 初始失效网右侧树
     * @param checkedNodeId 选中节点ID
     */
    async initFaultRightTree(checkedNodeId) {
      let _that = this;
      _that.rightTreeLoading = true;
      await _that.$api.getFaultNetChildren({
        fmeaId: _that.$store.getters.rfmeaId,
        struId: checkedNodeId,
      }).then((res) => {
        if (res.flag) {
          let resData = res.data.rdfmStruTreeModels;
          if (resData && resData.length > 0) {
            // 过滤变体节点
            let filterNodes = _that.$store.getters.variantFilterNodes;
            resData = filterNode(resData, filterNodes);
            let targetNodes = resData.filter((item) => {
              return "01,99".indexOf(item.struTypeCode) !== -1;
            });
            let treeData = [];
            for (let i = 0, len = targetNodes.length; i < len; i++) {
              treeData.push(arrayToNetTree("", [], targetNodes[i], resData, _that.rightTreeCheckedNode));
            }
            _that.rightTreeData = treeData;
          } else {
            _that.rightTreeData = [];
          }
        } else {
          _that.$message.error(res.message, 1);
        }
      }).finally(() => {
        _that.rightTreeLoading = false;
      });
    },
    /**
     * 缓存选中节点
     * @param id 选中节点ID
     * @param pid 选中节点PID
     */
    setCheckedNode(id, pid) {
      this.$store.dispatch("fmeaTree/set", {
        key: "lastCheckedNetNode",
        value: {id: id, pid: pid}
      });
    },
    /**
     * 获取菜单节点颜色
     * @param struTypeCode 节点类型CODE
     */
    getMenuNodeColor(struTypeCode) {
      switch (struTypeCode) {
        case '02':
          return 'function-color';
        case '04':
          return 'productFeature-color';
        case '05':
          return 'require-color';
        default:
          break;
      }
    },
    /**
     * 右键菜单事件
     * @param actionInfo 菜单项信息
     */
    menuAction(actionInfo) {
      switch (actionInfo.action) {
        case "delete":  // 删除
          let directFlag = actionInfo.position === 'left' ? 0 : 1;
          this.deleteNetNode(directFlag, actionInfo.node);
          break;
        case 'toFunctionNet': // 处理失效网跳转功能网逻辑
          this.handleFaultNetToFunctionNet(actionInfo.node);
          break;
      }
    },
    /**
     * 处理失效网跳转功能网逻辑
     * @param node 节点
     */
    handleFaultNetToFunctionNet(node) {
      this.$store.dispatch("fmeaTree/clearNet");
      this.$emit("closeFaultNetModal");
      this.$parent.$refs.functionNet.setCheckedNode(node.id);
      this.$parent.$refs.functionNet.initFunctionNet(node.id, 1, 1);
      this.$parent.$refs.functionNet.handleCenterMenuItems(node.id);
      this.$parent.$refs.functionNet.firstFunctionNetNode = {id: node.id, name: node.name};
      this.$parent.$refs.functionNet.initLeftTree();
      this.$parent.$refs.functionNet.title = node.name;
      this.$parent.$refs.functionNet.structureSwitch = true;
      this.$parent.showFunctionNetEventListener = true;
      this.$parent.showFunctionNetModal = true;
      this.$parent.$refs.functionNet.forbiddenRightClick();
    },
    /**
     * 添加网节点
     * @param directFlag 0：左侧，1：右侧
     * @param node 节点
     */
    async addNetNode(directFlag, node) {
      let _that = this;
      if (!_that.isOperation) return;
      let checkedNodeId = node.id;
      let checkedNodePid = node.pid;
      // 1：查看：2：编制
      if (_that.$api.isLook === '1') return;
      let centerNodeId = _that.$store.getters.lastCheckedNetNode.id;
      if (centerNodeId === checkedNodeId) {
        _that.$message.warning(this.$t('global-message.warn.can-not-all-choose-myself'));
        return false;
      }
      await this.addFunctionNetNode(directFlag, checkedNodePid)
      await _that.$api.saveFaultNet({
        fmeaId: _that.$store.getters.rfmeaId,
        directFlag: directFlag,
        selectStruId: checkedNodeId,
        targetStruId: centerNodeId,
      }).then((res) => {
        //刷新结构树
        if (res.flag) {
          _that.$message.success(res.message, 1);
          _that.initFaultNetByFunctionNet(centerNodeId, undefined, undefined, false);
          // 修改左右树节点勾选
          _that.updateLrTreeNodeCheck(directFlag, node, true);
        } else {
          _that.$message.error(res.message, 1);
        }
      });
    },
    /**
     * 校验失效是否关联功能网
     * @param directFlag 0：左侧，1：右侧
     * @param functionId 功能ID
     */
    validateFaultJoinFunctionNet(directFlag, functionId) {
      let flag = false;
      let loops = (data, functionId) => {
        data.forEach((item, index) => {
          if (item.id === functionId) {
            flag = true;
          }
          if (item.children && item.children.length > 0) {
            loops(item.children, functionId);
          }
        })
      }
      let treeData = directFlag === 0 ? this.leftTreeFunctionNetData : this.rightTreeFunctionNetData;
      loops(treeData, functionId);
      return flag;
    },
    /**
     * 添加功能网节点
     * @param directFlag 0：左侧，1：右侧
     * @param functionId 选中节点节点
     */
    addFunctionNetNode(directFlag, functionId) {
      let _that = this;
      // 校验失效是否关联功能网
      if (_that.validateFaultJoinFunctionNet(directFlag, functionId)) return;
      let targetNodeId = _that.$store.getters.lastCheckedNetNode.pid;
      _that.$api.saveFunctionNet({
        fmeaId: _that.$store.getters.rfmeaId,
        directFlag: directFlag,
        selectStruId: functionId,
        targetStruId: targetNodeId,
      }).then((res) => {
        if (!res.flag) {
          console.log("失效网自动追加功能网节点 - message: " + res.message);
        }
      });
    },
    /**
     * 删除网节点
     * @param directFlag 0：左侧，1：右侧
     * @param node 节点
     */
    async deleteNetNode(directFlag, node) {
      let _that = this;
      if (!_that.isOperation) return;
      // 1：查看：2：编制
      if (_that.$api.isLook === '1') return;
      _that.$confirm({
        title: this.$t('global-message.warn'),
        content: this.$t('global-message.warn.sure-delete'),
        icon: "aaoopqa", //图标，不想用就随便写一个
        okText: this.$t('global-btn.ok'),
        cancelText: this.$t('global-btn.cancel'),
        onOk() {
          let centerNodeId = _that.$store.getters.lastCheckedNetNode.id;
          _that.$api.deleteFaultNet({
            fmeaId: _that.$store.getters.rfmeaId,
            struId: centerNodeId,
            delStruId: node.id,
          }).then((res) => {
            if (res.flag) {
              _that.$message.success(res.message, 1);
              _that.initFaultNetByFunctionNet(centerNodeId, undefined, undefined, false);
              // 修改左右树节点勾选
              _that.updateLrTreeNodeCheck(directFlag, node, false);
            } else {
              _that.$message.error(res.message, 1);
            }
          }).catch((error) => {
            _that.$message.error(error.response.data.message, 1);
          }).finally(() => {
            _that.cleanHighLightNode();
          });
        }
      });
    },
    /**
     * 删除节点
     * @param node 节点
     * @param treeKey leftTree：左侧，rightTree：右侧
     */
    deleteNode(node, treeKey) {
      let _that = this;
      let centerNodeId = _that.$store.getters.lastCheckedNetNode.id;
      _that.$confirm({
        title: this.$t('global-message.warn'),
        content: this.$t('global-message.warn.delete-child-node'),
        icon: "aaoopqa", //图标，不想用就随便写一个
        okText: this.$t('global-btn.ok'),
        cancelText: this.$t('global-btn.cancel'),
        onCancel() {
        },
        onOk() {
          _that.$api.deleteNode({
            fmeaId: _that.$store.getters.rfmeaId,
            struId: node.id
          }).then((res) => {
            if (res.flag) {
              _that.$message.success(res.message, 1);
              _that.initFaultNet(centerNodeId, undefined, undefined);
            } else {
              _that.$message.error(res.message, 1);
            }
          }).catch((error) => {
            _that.$message.error(error.response.data.message, 1);
          });
        },
      });
    },
    /**
     * 修改左右树节点勾选
     * @param directFlag 0：左侧，1：右侧
     * @param node 节点
     * @param checked 勾选状态
     */
    updateLrTreeNodeCheck(directFlag, node, checked) {
      let _that = this;
      let lCheckedKeys = _that.$refs.leftTree.checkedKeys;
      let rCheckedKeys = _that.$refs.rightTree.checkedKeys;
      if (checked) {
        directFlag === 0 ? lCheckedKeys.push(node.id) : rCheckedKeys.push(node.id)
      } else {
        directFlag === 0
            ? lCheckedKeys.indexOf(node.id) !== -1 ? lCheckedKeys.splice(lCheckedKeys.indexOf(node.id), 1) : ''
            : rCheckedKeys.indexOf(node.id) !== -1 ? rCheckedKeys.splice(rCheckedKeys.indexOf(node.id), 1) : '';
      }
    },
    /**
     * 清除高亮节点
     */
    cleanHighLightNode() {
      // 清除左侧网选中样式
      let leftClassName = "leftNode-selected";
      let leftCheckedNodes = document.getElementsByClassName(leftClassName);
      if (leftCheckedNodes[0]) leftCheckedNodes[0].classList.remove(leftClassName);
      // 清除右侧网选中样式
      let rightClassName = "rightNode-selected";
      let rightCheckedNodes = document.getElementsByClassName(rightClassName);
      if (rightCheckedNodes[0]) rightCheckedNodes[0].classList.remove(rightClassName);
    },
    /**
     * 左侧选项卡切换事件
     * @param activeKey 面板的key
     */
    leftTabChange(activeKey) {
      let centerNodeId = this.$store.getters.lastCheckedNetNode.id;
      if (activeKey === 'leftFunctionNet') {
        this.initFaultLeftTreeByFunctionNet(centerNodeId);
      } else if (activeKey === 'superStructure') {
        this.initFaultLeftTree(centerNodeId);
      }
      this.leftSelectCheckedNodeId = undefined;
      this.getLrTreeHeight();
    },
    /**
     * 右侧选项卡切换事件
     * @param activeKey 面板的key
     */
    rightTabChange(activeKey) {
      let centerNodeId = this.$store.getters.lastCheckedNetNode.id;
      if (activeKey === 'rightFunctionNet') {
        this.initFaultRightTreeByFunctionNet(centerNodeId);
      } else if (activeKey === 'subStructure') {
        this.initFaultRightTree(centerNodeId);
      }
      this.rightSelectCheckedNodeId = undefined;
      this.getLrTreeHeight();
    },
    /**
     * 修改失效网节点
     * @param node 节点
     */
    updateFaultNetNode(node) {
      let el_arr = document.querySelectorAll('#netNameId' + node.id);
      el_arr.forEach(el => {
        el.innerText = node.name;
      });
      this.updateTreeDataNode(this.$refs.leftTree.treeData, node);
      this.updateTreeDataNode(this.$refs.rightTree.treeData, node);
    },
    /**
     * 修改treeData节点数据（名称）
     * @param treeData
     * @param targetNode 目标节点
     */
    updateTreeDataNode(treeData, targetNode) {
      for (let i = 0, len = treeData.length; i < len; i++) {
        if (treeData[i].id === targetNode.id) {
          treeData[i].name = targetNode.name;
          return true;
        }
        if (treeData[i].children && treeData[i].children.length > 0) {
          let result = this.updateTreeDataNode(treeData[i].children, targetNode);
          if (result) return true;
        }
      }
      return false;
    },
    /**
     * 关闭模态框
     */
    close() {
      this.$store.dispatch("fmeaTree/clearNet");
      this.leftTabName = 'leftFunctionNet';
      this.rightTabName = 'rightFunctionNet';
      this.$emit("closeFaultNetModal");
      this.$emit("initRightTree");
    },
    /**
     * 监听键盘，触发事件
     * @param v true移除，false添加
     */
    keyListenerChange(v) {
      if (v) {
        window.removeEventListener("keydown", this.keyCodeForEvent);
      } else {
        window.addEventListener("keydown", this.keyCodeForEvent);
      }
    },
    /**
     * 监听键盘，触发事件
     * @param e
     */
    keyCodeForEvent(e) {
      // 选中失效网左右侧节点
      let checkedNetLRNode = this.$store.getters.lastCheckedNetLRNode;
      if (!checkedNetLRNode) return;
      switch (e.keyCode) {
        case 46: // Delete
          this.deleteNetNode(checkedNetLRNode.directFlag, checkedNetLRNode.id);
          break;
        default:
          break;
      }
    },
    /**
     * 双击聚焦
     * @param checkedNode 选中节点
     * @returns {Promise<void>}
     */
    async dblFocus(checkedNode) {
      this.setCheckedNode(checkedNode.id, checkedNode.pid);
      this.title = checkedNode.name;
      // 重置左右侧input值
      // this.$refs.leftTreeSelect.searchValue = undefined;
      // this.$refs.rightTreeSelect.searchValue = undefined;
      // 重置缓存下拉选中节点ID
      this.leftSelectCheckedNodeId = undefined;
      this.rightSelectCheckedNodeId = undefined;
      // 重置选项卡"功能网"
      this.leftTabName = 'leftFunctionNet';
      this.rightTabName = 'rightFunctionNet';
      // 清空缓存节点
      this.cleanCheckedNetNode();
      await this.initFaultNet(checkedNode.id, undefined, undefined);
      this.handleCenterMenuItems(checkedNode.id);
    },
    /**
     * 清空缓存节点
     */
    cleanCheckedNetNode() {
      this.$store.dispatch("fmeaTree/set", {
        key: "lastCheckedNetLRNode",
        value: undefined
      });
    },
    /**
     * 禁用浏览器右键菜单
     */
    forbiddenRightClick() {
      document.body.oncontextmenu = function () {
        return false;
      };
    }
  },
};
</script>


<style lang="less" scoped>

// 设置model 全屏
/deep/ .ant-modal {
  top: 0 !important;
}

// 设置model 全屏
/deep/ .ant-modal-content {
  height: calc(100vh);
}

// 不加上弹窗就会有滚动条;
/deep/ .ant-modal-wrap {
  overflow: hidden !important
}

.funcNetDialog .switchArea {
  position: absolute;
  z-index: 3;
  background-color: #fff;
}

/deep/ .funcNetContent {
  height: calc(100vh);

  .splitter-pane-resizer.vertical {
    margin-top: -24px;
  }

  // 功能网左侧
  .splitter-pane.vertical.splitter-paneL {
    overflow: hidden !important;
  }

  .splitter-pane.vertical.splitter-paneL .leftTree {
    overflow: auto !important;
  }

  // 功能网右边
  .splitter-pane.vertical.splitter-paneR .rightTree {
    overflow: auto !important;
  }
}

/*/deep/ .ant-modal-close-x {
  font-size: 40px;
  color: white;
}

/deep/ .ant-modal-header {
  background: #5170b7;
}

/deep/ .ant-modal-title {
  color: white;
}*/

/deep/ .ant-form-item {
  margin-bottom: 0px;
}

.parent {
  color: #e6a23c;
}

.current {
  color: #409eff;
}

.children {
  color: #c84d3c;
}

.contextmenu {
  background: #FFF;
  border: 1px solid #bebebe;
  border-radius: 0.5em;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
  display: inline-block;
  font-family: inherit;
  font-size: inherit;
  list-style-type: none;
  max-width: 16em;
  min-width: 8em;
  position: absolute;

  ul {
    margin-bottom: 0;
  }

  li:hover {
    background-color: #2980B9 !important;;
    color: #FFF !important;
    cursor: pointer;
    border-radius: 0.5em !important;
  }

  a {
    padding: 2px 12px;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
    display: block;
  }
}
</style>
