<template>
  <div class="leftTree" ref="leftTree">
    <div>
      <!-- zTree Start -->
      <ul id="leftTree" class="ztree"/>
      <!-- zTree End -->

      <!-- 模态框 Start -->
      <DragModal
          :visible="modalVisible"
          :title="title"
          :width="1000"
          :destroyOnClose="true"
          :maskClosable="false"
          @cancel="modalVisible = false"
          :footer="null">
        <!-- 结构 -->
        <AddStructure
            v-if="actionName === 'addStructure'"
            :struTypeCode="struTypeCode"
            :checkedNode="checkedNode"
            @closeModal="closeModal"
            @initLeftTree="initLeftTree"
            @initRightTree="initRightTree"/>
        <!-- 多级结构 -->
        <AddMultistageStructure
            v-if="actionName === 'addMultistageStructure'"
            :checkedNode="checkedNode"
            @closeModal="closeModal"
            @initLeftTree="initLeftTree"
            @initRightTree="initRightTree"/>
        <!-- 功能 -->
        <AddFunction
            v-if="actionName === 'addFunction'"
            :struTypeCode="struTypeCode"
            :checkedNode="checkedNode"
            @closeModal="closeModal"
            @initRightTree="initRightTree"/>
        <!-- 产品特性 -->
        <AddProductFeature
            v-if="actionName === 'addProductFeature'"
            :struTypeCode="struTypeCode"
            :checkedNode="checkedNode"
            @closeModal="closeModal"
            @initRightTree="initRightTree"/>
        <!-- 结构合并 -->
        <MergeStructure
            v-if="actionName === 'mergeStructure'"
            :checkedNode="checkedNode"
            @closeModal="closeModal"
            @initLeftTree="initLeftTree"
            @initRightTree="initRightTree"/>
        <!-- 结构属性 -->
        <PropertyStructure
            v-if="actionName === 'propertyStructure'"
            :checkedNode="checkedNode"
            :tabKey="tabKey"
            @closeModal="closeModal"
            @initLeftTree="initLeftTree"
            @initRightTree="initRightTree"/>
        <!-- 接口属性 -->
        <PropertyInterface
            v-if="actionName === 'propertyInterface'"
            :checkedNode="checkedNode"
            :tabKey="tabKey"
            @closeModal="closeModal"
            @initLeftTree="initLeftTree"
            @initRightTree="initRightTree"/>
        <!-- 评审意见 -->
        <AddReviewComments
            v-if="actionName === 'addReviewComments'"
            :checkedNode="checkedNode"
            @initLeftTree="initLeftTree"
            @initRightTree="initRightTree"
            @closeModal="closeModal"/>
      </DragModal>
      <!-- 模态框 End -->
    </div>
  </div>
</template>
<script>

import DragModal from "@/components/DragModal";
import AddStructure from "../AddModal/AddStructure";
import AddMultistageStructure from "../AddModal/AddMultistageStructure";
import AddFunction from "../AddModal/AddFunction";
import AddProductFeature from "../AddModal/AddProductFeature";
import MergeStructure from "../MergeModal/MergeStructure";
import PropertyStructure from "../PropertyModal/PropertyStructure";
import PropertyInterface from "../PropertyModal/PropertyInterface";
import AddReviewComments from "../AddModal/AddReviewComments";
import {filterNode, replaceNullName, selectNodeById} from "@/utils/tree";
import {showMergeBtn, showMoveDownBtn, showMoveUpBtn, showPasteBtn} from "@/utils/treeMenuBtn";
import AntSpinDot from "@/components/AntSpinDot/index.vue";
import {addClass, removeClass} from '@/utils'
import {getUrlParam} from "@/common/common"

export default {
  name: "LeftTree",
  components: {
    AntSpinDot,
    DragModal,
    AddStructure,
    AddMultistageStructure,
    AddFunction,
    AddProductFeature,
    MergeStructure,
    PropertyStructure,
    PropertyInterface,
    AddReviewComments,
  },
  props: {
    versionDiffCloseFlag: {
      type: Boolean,
      default: false
    },
    versionLibraryDiffCloseFlag: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      oldSelectedNode: undefined,
      /** 功能完整性检查开关 **/
      funInspectionShowHide: false,
      /** 失效完整性检查开关 **/
      failInspectionShowHide: false,
      /** 要求完整性检查开关 **/
      requestInspectionShowHide: false,
      /** sod值完整性检查开关 **/
      sodInspectionShowHide: false,
      /** 高风险项检查开关 **/
      highRiskInspectionShowHide: false,
      /** 关联历史失效显示隐藏：开关 */
      historyShowOrHide: false,
      /** 完整性检查数据 */
      funComp: [],
      reqComp: [],
      faiComp: [],
      sodComp: [],
      riskComp: [],
      historyComp: [],
      /** 初始数据 */
      initData: [],
      /** 模态框状态 */
      modalVisible: false,
      /** 模态框唯一Key */
      actionName: "",
      /** 模态框标题 */
      title: "",
      /** 模态框，选项卡Key */
      tabKey: "",
      /** 节点类型CODE */
      struTypeCode: "",
      /** 选中节点 */
      checkedNode: "",
      /** 加载对象 */
      loader: undefined,
      contextMenu: undefined,
      /** zTree 配置项 */
      setting: {
        data: {
          key: {
            title: "description"
          },
          simpleData: {
            enable: true,
            idKey: "id",
            pIdKey: "pid",
          }
        },
        view: {
          /** 显示 / 不显示 连线 */
          showLine: true,
          /** 显示 / 隐藏 提示信息 */
          showTitle: false,
          /** 支持 / 不支持 HTML 脚本 */
          nameIsHTML: true,
          /** 显示 / 隐藏 图标 */
          showIcon: false,
          /** 双击节点 切换 / 不切换 展开状态 */
          dblClickExpand: false,
          /** 是否允许同时选中多个节点 */
          selectedMulti: false,
          /** 是否允许可以选择 zTree DOM 内的文本 */
          txtSelectedEnable: true,
          /** 显示动画效果 */
          expandSpeed: "fast"
        },
        edit: {
          enable: true,
          drag: {
            isCopy: false,
            isMove: true,
            prev: this.canDragPrev,
            next: this.canDragNext,
            inner: this.canDragInner
          },
          editNameSelectAll: true,
          showRenameBtn: false,
          showRemoveBtn: false,
        },
        async: {
          enable: true,
          url: "/DFMEA/mfmea/funAnalysis/rb0426314/func",
          dataType: "json",
          type: "post",
          dataFilter: this.handleDataFilter
        },
        callback: {
          beforeClick: this.handleBeforeClick,
          beforeRightClick: this.handleBeforeRightClick,
          beforeAsync: this.handleBeforeAsync,
          onAsyncSuccess: this.handleOnAsyncSuccess,
          onDblClick: this.handleOnDblClick,
          onRename: this.handleOnRename,
          onDrop: this.zTreeOnDrop,
          onCollapse: this.treeNodeCollapse,
          onExpand: this.treeNodeExpand,
        }
      },
      // 刷新后选择的节点id
      onAsyncSuccessSelectId: "",
      // 折叠节点ids
      foldNodeIds: [],
    };
  },
  watch: {
    modalVisible(v) {
      this.keyListenerChange(v);
    },
    // 监听差异处理弹框标志
    versionDiffCloseFlag(v) {
      if (v) {
        this.initLeftTree();
      }
    },
    // 监听知识库差异处理弹框标志
    versionLibraryDiffCloseFlag(v) {
      if (v) {
        this.initLeftTree();
      }
    }
  },
  created() {
  },
  mounted() {
    this.forbidRightClick();
    this.initLeftTree();
    this.$nextTick(() => {
      this.initRightTree();
    });
    window.handleAnnexLIconClick = this.handleAnnexIconClick;
  },
  methods: {
    // 将查找内容做变色处理
    changeSelectNodesColor(selectedRows, charToFind) {
      let _that = this;
      // 获取当前左树
      let treeObj = $.fn.zTree.getZTreeObj('leftTree');
      // 把过去的找内容变为初始颜色
      if (_that.oldSelectedNode) {
        let nodeId = `#${_that.oldSelectedNode.tId}_a`;
        if ($(nodeId)[0]) {
          // 获取高亮标签
          let dom = document.getElementById("yellow_span");
          if (dom) {
            // 被替换的字符串
            let beReplacedStr = '<span style="color: yellow" id="yellow_span">' + dom.innerHTML + '</span>';
            // 替换后的字符串
            let replacement = dom.innerHTML;
            // 替换
            $(nodeId)[0].innerHTML = $(nodeId)[0].innerHTML.replaceAll(beReplacedStr, replacement)
            // 从过去高亮的节点列表中移除该节点
            _that.oldSelectedNode = undefined;
          }
        }
      }
      // 现在查找和替换选中的节点的颜色变为黄色
      if (treeObj && selectedRows) {
        let node = treeObj.getNodeByParam("id", selectedRows[0].struId);
        if (node) {
          // 获取节点a标签
          let nodeId = `#${node.tId}_a`;
          // 替换内容
          let description = node.description;
          let replacement = description.replaceAll(charToFind, '<span style="color: yellow" id="yellow_span">' + charToFind + '</span>');
          let beforeStr = $(nodeId)[0].innerHTML.slice(0, $(nodeId)[0].innerHTML.length - 7 - node.description.length);
          // 替换
          $(nodeId)[0].innerHTML = beforeStr + replacement + '</span>';
          _that.oldSelectedNode = node;
          // 右数节点选中
          _that.handleBeforeClick("leftTree", node, 1);
        }
      }
    },
    /******************************************* zTree Start **************************************************/
    /**
     * 初始化左侧树
     */
    initLeftTree(zNodes = []) {
      let _that = this;
      let settings = $.extend({}, _that.setting);
      settings.view.fontCss = _that.setNodeFontCss;
      settings.view.showTitle = true; // 设置鼠标移入显示
      settings.async.contentType = "application/json";
      settings.async.otherParam = {
        fmeaId: _that.$store.getters.rfmeaId,
      };
      // 查看权限不允许拖拽节点
      settings.edit.drag.isMove = this.canMove();
      // 初始化ztree
      $.fn.zTree.init($("#leftTree"), settings, zNodes);

      // 获取左侧zTree
      let treeObj = $.fn.zTree.getZTreeObj('leftTree');
      // 循环所有折叠状态节点将其折叠
      for (let i = 0; i < _that.foldNodeIds.length; i++) {
        treeObj.expandNode(treeObj.getNodeByParam("id", _that.foldNodeIds[i]), false, true, false );
      }
      // 刷新后，清除选中节点
      _that.$store.dispatch('fmeaTree/set', {
        key: 'lastCheckedNode',
        value: undefined
      });
    },
    /**
     * 刷新指定父级的子节点
     */
    reAsyncChildNodes(parentId) {
      // 初始化ztree
      var zTree = $.fn.zTree.getZTreeObj("leftTree"); // 获取zTree对象
      var parentNode = zTree.getNodeByParam("id", parentId); // 获取需要刷新子节点的父节点
      if (parentNode) {
        // 重新异步加载子节点
        zTree.reAsyncChildNodes(parentNode, "refresh", true); // 第三个参数为true表示强制刷新，即使子节点已经加载过
      }
    },
    /**
     * 用于对 Ajax 返回数据进行预处理的函数
     * @param treeId
     * @param parentNode
     * @param responseData
     */
    handleDataFilter(treeId, parentNode, responseData) {
      let childNodes = responseData.data.mfmeaStruTreeModels;
      this.initData = responseData.data.mfmeaStruTreeModels;
      for (let i = 0, l = childNodes.length; i < l; i++) {
        let node = childNodes[i];
        // 设置【description】为节点的title
        node['description'] = replaceNullName(node);
        node.name = this.getNodeName(node);
        // 评审意见跳转高亮节点
        if (this.$store.getters.leftStruIdFromComments && node.id == this.$store.getters.leftStruIdFromComments) {
          this.$store.dispatch("fmeaTree/set", {
            key: "checkedLeftNode",
            value: node
          });
          this.cleanCommentJumpStruNode()
        }
      }
      return childNodes;
    },
    /**
     * 用于捕获单击节点之前的事件回调函数，并且根据返回值确定是否允许单击操作
     * @param treeId
     * @param treeNode
     * @param clickFlag
     */
    handleBeforeClick(treeId, treeNode, clickFlag) {
      let _that = this;
      // 当前节点已选中, 防止右侧树多次刷新
      if (treeNode && _that.$store.getters.checkedLeftNode?.id !== treeNode.id) {
        // 处理选中ZTree节点
        this.handleSelectZTreeNodes(treeId, [treeNode]);
        // 刷新右侧树
        this.initRightTree();
      }
      // 存储当前节点信息
      this.setCheckedNode(treeNode);
    },
    /**
     * 用于捕获 zTree 上鼠标右键点击之前的事件回调函数，并且根据返回值确定触发 onRightClick 事件回调函数
     * @param treeId
     * @param treeNode
     */
    handleBeforeRightClick(treeId, treeNode) {
      // 右键非节点时，忽略
      if (!treeNode) return;
      let _that = this;
      // 当前节点已选中, 防止右侧树多次刷新
      if (_that.$store.getters.checkedLeftNode?.id !== treeNode.id) {
        // 处理选中ZTree节点
        this.handleSelectZTreeNodes(treeId, [treeNode]);
        // 刷新右侧树
        this.initRightTree();
      }
      // 存储当前节点信息
      this.setCheckedNode(treeNode);
      // 获取右键菜单项
      let bthMenuBtn = this.getMenuBtn();
      // 处理右键菜单
      this.handleContextMenu(treeNode, bthMenuBtn);
    },
    /**
     * 用于捕获异步加载之前的事件回调函数，zTree 根据返回值确定是否允许进行异步加载
     * @param treeId
     * @param treeNode
     */
    handleBeforeAsync(treeId, treeNode) {
      // 开启加载...
      this.handleShowHideLoading(true);
    },
    /**
     * 用于捕获异步加载正常结束的事件回调函数
     * 如果设置了 setting.callback.beforeAsync 方法，且返回 false，
     * 将无法触发 onAsyncSuccess / onAsyncError 事件回调函数。
     */
    handleOnAsyncSuccess(event, treeId, treeNode, msg) {
      let _that = this;
      // 处理节点显示/隐藏
      _that.handleShowHideNodes();
      // 处理选中ZTree节点
      let nodes = [_that.$store.getters.checkedLeftNode];
      _that.handleSelectZTreeNodes(treeId, nodes);
      // 刷新移动节点标识状态
      _that.refreshMoveNodeFlag();
      // 刷新顶部按钮状态
      _that.refreshBtnStatus();
      // 恢复高亮复制节点
      _that.restoreHighLightCopyNode();
      // 关闭加载...
      _that.handleShowHideLoading(false);
      // 设置节点选中
      _that.selectNode(treeId)
    },
    /**
     * 用于捕获 zTree 上鼠标双击之后的事件回调函数
     * @param event
     * @param treeId
     * @param treeNode
     */
    handleOnDblClick(event, treeId, treeNode) {
      // 进入编制状态若为查看，禁用双击重命名
      if (getUrlParam("enterState")) return false;
      // 防止，双击展开折叠时报错
      if (treeNode) {
        let treeObj = $.fn.zTree.getZTreeObj(treeId);
        treeNode.name = treeNode.description;
        treeObj.editName(treeNode);
        // 禁用快捷键
        this.keyListenerChange(true)
      }
    },
    /**
     * 用于捕获节点编辑名称结束之后的事件回调函数。
     * @param event
     * @param treeId
     * @param treeNode
     * @param isCancel
     */
    handleOnRename(event, treeId, treeNode, isCancel) {
      let _that = this;
      let treeObj = $.fn.zTree.getZTreeObj(treeId);
      // 非空
      if (!treeNode.name) {
        treeNode.name = treeNode.description;
      }
      // 未更改
      if (treeNode.name === treeNode.description) {
        console.log('未更改' + treeNode.name);
      } else {
        if (treeNode.name.length < 500) {
          // 调接口
          _that.$api.updateNodeName({
            fmeaId: _that.$store.getters.rfmeaId,
            struId: treeNode.id,
            struName: treeNode.name,
          }).then((res) => {
            if (res.flag) {
              _that.$message.success(res.message, 1);
              _that.initRightTree();
            } else {
              _that.$message.error(res.message, 1);
            }
          }).catch((error) => {
            _that.$message.error(error.response.data.message);
          });
        } else {
          _that.$message.warn(_that.$t('global-message.warn.node-name-length'));
          treeNode.name = treeNode.description;
        }
      }
      treeNode.description = treeNode.name;
      treeNode.name = this.getNodeName(treeNode);
      treeObj.updateNode(treeNode);
      // 启用快捷键
      this.keyListenerChange(false)
    },
    /**
     * 取得节点名称
     * @param node
     * @returns {string}
     */
    getNodeName(node) {
      let nodeName = '&nbsp;';
      // 附件标识 0：无，1：有
      if (node.annexFlag === '1') {
        nodeName += "<i class='iconfont iconshuxing1' onclick='handleAnnexLIconClick(\"" + node.id + "\")'></i>" + "&nbsp;";
      }
      // 评审意见
      if (node.hasStruComment) {
        nodeName += `<i class="iconfont iconxiaoxi_right"></i>` + '&nbsp;';
      }
      nodeName += node.description;

      // 完整性检查
      if (this.funInspectionShowHide && this.funComp.indexOf(node.id) != -1) {
        nodeName += '<span style="color: #de0b0b">(' + this.$t("functional-analysis.top-btn.lose-function") + ')</span>';
      } else if (this.failInspectionShowHide && this.faiComp.indexOf(node.id) != -1) {
        nodeName += '<span style="color: #de0b0b">(' + this.$t("functional-analysis.top-btn.lose-failure") + ')</span>';
      } else if (this.requestInspectionShowHide && this.reqComp.indexOf(node.id) != -1) {
        nodeName += '<span style="color: #de0b0b">(' + this.$t("functional-analysis.top-btn.lose-require") + ')</span>';
      } else if (this.sodInspectionShowHide && this.sodComp.indexOf(node.id) != -1) {
        nodeName += '<span style="color: #de0b0b">(' + this.$t("functional-analysis.top-btn.lose-sod") + ')</span>';
      } else if (this.highRiskInspectionShowHide && this.riskComp.indexOf(node.id) != -1) {
        nodeName += '<span style="color: #de0b0b">(' + this.$t("functional-analysis.top-btn.has-high-risk") + ')</span>';
      }
      // 关联历史问题显示/隐藏
      if (this.historyShowOrHide && this.historyComp.indexOf(node.id) != -1) {
        nodeName += '<span style="color: #de0b0b">(' + this.$t("functional-analysis.top-btn.invalid-associated-history") + ')</span>';
      }
      return nodeName;
    },
    /**
     * 完整性检查
     */
    changeCheckNodes() {
      let treeObj = $.fn.zTree.getZTreeObj('leftTree');
      // 还原完整性检查的节点数据，防止切换完整性检查时出现脏数据
      this.cleanCurrentLeftTreeNodes();
      // 功能完整性检查
      if (this.funInspectionShowHide && this.funComp.length > 0) {
        this.funComp.forEach((nodeId) => {
          let funcNode = treeObj.getNodeByParam("id", nodeId);
          if (funcNode && funcNode.struTypeCode !== "01") {
            funcNode.name = this.getNodeName(funcNode);
            treeObj.updateNode(funcNode);
          }
        })
        // 失效完整性检查
      } else if (this.failInspectionShowHide && this.faiComp.length > 0) {
        this.faiComp.forEach((nodeId) => {
          let failNode = treeObj.getNodeByParam("id", nodeId);
          if (failNode && failNode.struTypeCode !== "01") {
            failNode.name = this.getNodeName(failNode);
            treeObj.updateNode(failNode);
          }
        })
        // 要求完整性检查
      } else if (this.requestInspectionShowHide && this.reqComp.length > 0) {
        this.reqComp.forEach((nodeId) => {
          let reqNode = treeObj.getNodeByParam("id", nodeId);
          if (reqNode && reqNode.struTypeCode !== "01") {
            reqNode.name = this.getNodeName(reqNode);
            treeObj.updateNode(reqNode);
          }
        })
        // sod完整性检查
      } else if (this.sodInspectionShowHide && this.sodComp.length > 0) {
        this.sodComp.forEach((nodeId) => {
          let sodNode = treeObj.getNodeByParam("id", nodeId);
          if (sodNode && sodNode.struTypeCode !== "01") {
            sodNode.name = this.getNodeName(sodNode);
            treeObj.updateNode(sodNode);
          }
        })
        // 高风险项完整性检查
      } else if (this.highRiskInspectionShowHide && this.riskComp.length > 0) {
        this.riskComp.forEach((nodeId) => {
          let riskNode = treeObj.getNodeByParam("id", nodeId);
          if (riskNode && riskNode.struTypeCode !== "01") {
            riskNode.name = this.getNodeName(riskNode);
            treeObj.updateNode(riskNode);
          }
        })
      } else if (this.historyShowOrHide && this.historyComp.length > 0) {
        this.historyComp.forEach((nodeId) => {
          let historyNode = treeObj.getNodeByParam("id", nodeId);
          if (historyNode && historyNode.struTypeCode === "01") {
            historyNode.name = this.getNodeName(historyNode);
            treeObj.updateNode(historyNode);
          }
        })
      } else {
        this.reductionCheckNodes();
      }
    },
    /**
     * 清除当前左树的节点完整性检查
     */
    cleanCurrentLeftTreeNodes() {
      let treeObj = $.fn.zTree.getZTreeObj('leftTree');
      if (this.initData.length > 0) {
        this.initData.forEach(node => {
          let leftTreeNode = treeObj.getNodeByParam("id", node.id);
          if (leftTreeNode) {
            leftTreeNode.name = this.getNodeName(leftTreeNode);
            treeObj.updateNode(leftTreeNode);
          }
        })
      }
    },
    /**
     * 还原完整性检查节点
     */
    reductionCheckNodes() {
      let treeObj = $.fn.zTree.getZTreeObj('leftTree');
      this.funComp.forEach((nodeId) => {
        let funcNode = treeObj.getNodeByParam("id", nodeId);
        if (funcNode) {
          funcNode.name = this.getNodeName(funcNode);
          treeObj.updateNode(funcNode);
        }
      })
      this.faiComp.forEach((nodeId) => {
        let failNode = treeObj.getNodeByParam("id", nodeId);
        if (failNode) {
          failNode.name = this.getNodeName(failNode);
          treeObj.updateNode(failNode);
        }
      })
      this.reqComp.forEach((nodeId) => {
        let reqNode = treeObj.getNodeByParam("id", nodeId);
        if (reqNode) {
          reqNode.name = this.getNodeName(reqNode);
          treeObj.updateNode(reqNode);
        }
      })
      this.sodComp.forEach((nodeId) => {
        let sodNode = treeObj.getNodeByParam("id", nodeId);
        if (sodNode) {
          sodNode.name = this.getNodeName(sodNode);
          treeObj.updateNode(sodNode);
        }
      })
      this.riskComp.forEach((nodeId) => {
        let riskNode = treeObj.getNodeByParam("id", nodeId);
        if (riskNode) {
          riskNode.name = this.getNodeName(riskNode);
          treeObj.updateNode(riskNode);
        }
      })
      // this.historyComp.forEach((nodeId) => {
      //   let historyNode = treeObj.getNodeByParam("id", nodeId);
      //   if (historyNode) {
      //     historyNode.name = this.getNodeName(historyNode);
      //     treeObj.updateNode(historyNode);
      //   }
      // })
    },
    /**
     * 设置功能、失效、要求和产品特征字体着色
     * @param treeId
     * @param treeNode
     * @returns {*}
     */
    setNodeFontCss(treeId, treeNode) {
      return this.$store.getters.nodeTypeDict.zTreeLNodeColor[treeNode.struTypeCode];
    },
    /**
     * 选中ztree节点
     * @param treeId
     * @param nodes
     */
    handleSelectZTreeNodes(treeId, nodes) {
      let treeObj = $.fn.zTree.getZTreeObj(treeId);
      for (let i = 0; i < nodes.length; i++) {
        let node = treeObj.getNodeByParam("id", nodes[i]?.id, null);
        if (node) {
          treeObj.selectNode(node);
          // 重新赋值，保持缓存节点数据一致
          this.setCheckedNode(node);
        }
      }
    },
    /**
     * 单级折叠/展开（顶部按钮）
     */
    collapseExpand() {
      let _that = this;
      let checkedNode = _that.$store.getters.lastCheckedNode;
      let treeObj = $.fn.zTree.getZTreeObj('leftTree');
      treeObj.expandNode(checkedNode, !checkedNode?.open, true, true);
      _that.saveFoldNodeIds(checkedNode);
      document.getElementById("leftTree").style.paddingLeft = "15px";
    },
    /**
     * 全部折叠/展开（顶部按钮）
     */
    collapseExpandAll() {
      let _that = this;
      let checkedNode = _that.$store.getters.lastCheckedNode;
      let treeObj = $.fn.zTree.getZTreeObj('leftTree');
      let nodes = treeObj.getNodesByParam("level", checkedNode.level, null);
      let expandFlag = checkedNode?.open;
      for (let i = 0, len = nodes.length; i < len; i++) {
        // 聚焦当前选中节点
        treeObj.expandNode(nodes[i], !expandFlag, true, checkedNode.id === nodes[i].id);
        _that.saveFoldNodeIds(nodes[i]);
      }
      document.getElementById("leftTree").style.paddingLeft = "15px";
    },
    /**
     * 树节点折叠
     */
    treeNodeCollapse(event, treeId, treeNode) {
      this.saveFoldNodeIds(treeNode);
    },
    /**
     * 树节点展开
     */
    treeNodeExpand(event, treeId, treeNode) {
      this.saveFoldNodeIds(treeNode);
    },
    /**
     * 保存节点展开折叠状态
     */
    saveFoldNodeIds(checkedNode) {
      let _that = this;
      // open：f为折叠 t为展开
      if (!checkedNode?.open) {
        // 存储折叠节点ID
        _that.foldNodeIds.push(checkedNode.id)
      } else {
        // 清除节点折叠状态
        _that.foldNodeIds = _that.foldNodeIds.filter(item => item !== checkedNode.id);
      }
    },
    /**
     * 处理节点显示/隐藏
     */
    handleShowHideNodes() {
      let _that = this;
      let showNodes = [];
      let filterNodes = _that.$store.getters.variantFilterNodes;
      jQuery.extend(true, showNodes, _that.initData);
      let rootNode = _that.initData[0];
      if (filterNodes.length > 0) {
        let treeObj = $.fn.zTree.getZTreeObj('leftTree');
        // 过滤节点类型
        filterNode(treeObj.getNodes(), _that.initData, rootNode.pid, '',
            filterNodes, showNodes = []);
      }
      // 左序号升序
      showNodes.sort((a, b) => {
        return a.leftNo - b.leftNo
      });
      _that.initLeftTree(showNodes);
      // 切换下拉选项时右侧树回归根节点
      _that.cleanCheckedLeftNode();
    },
    /**
     * 清除：缓存左侧节点
     */
    cleanCheckedLeftNode() {
      this.$store.dispatch("fmeaTree/set", {
        key: "checkedLeftNode",
        value: undefined
      });
    },
    /**
     * 显示、隐藏 -- 加载Loading
     * @param flag
     */
    handleShowHideLoading(flag) {
      if (flag) {
        if (this.loader) this.loader.hide();
        this.loader = this.$loading.show({
          container: this.$refs.leftTree,
          color: '#1890FF',
        }, {
          // 自定义加载动画组件
          default: this.$createElement('ant-spin-dot'),
        });
      } else {
        this.loader.hide();
      }
    },
    /******************************************* zTree End **************************************************/

    /******************************************* 右键菜单 Start **************************************************/
    /**
     * 取得当前节点的右键菜单项
     */
    getCurrentNodeMenus(node) {
      let data = {};
      this.$emit('getCurrentNodeMenus', node, "leftTree", val => {
        data = val;
      })
      return data;
    },
    /**
     * 获取右键菜单项
     */
    getMenuBtn() {
      // 选中节点
      let checkedNode = this.$store.getters.lastCheckedNode;
      // 复制剪切的节点
      let lastCopyOrCutNode = this.$store.getters.lastCopyOrCutNode;
      // 复制剪切的标识位：copy、cut
      let lastCopyOrCut = this.$store.getters.lastCopyOrCut;
      // 选中节点过滤掉外部结构后的的子节点
      let checkedNodeChildren = [];
      if (checkedNode.children && checkedNode.children.length > 0) {
        checkedNodeChildren = checkedNode.children.filter(item => {
          return item.struTypeCode !== '99';
        })
      }
      // 取得当前节点的右键菜单项
      let cNodeMenus = this.getCurrentNodeMenus(checkedNode);
      let menuBtn = {};
      this.$store.getters.leftTreeMenus.forEach((item) => {
        if (cNodeMenus.indexOf(item.key) !== -1) {
          switch (item.key) {
            case "cut": // 剪切
              // 根节点不能剪切
              if (checkedNode.deep === 1) return false;
              break;
            case "paste": // 粘贴
              if (!lastCopyOrCut) return false; // 没有复制或剪切，不允许粘贴
              // 剪切的节点不能粘贴在它的子节点下(包含自己)
              if (showPasteBtn('leftTree', this.$store.getters.nodeTypeDict.paste,
                  lastCopyOrCutNode, checkedNode, lastCopyOrCut) === 1) return false;
              break;
            case "merge": // 合并
              if (checkedNode.deep === 1) return false;  // 根节点不能合并
              else if (!showMergeBtn('leftTree', checkedNode)) return false;
              break;
            case "delete": // 删除
              if (checkedNode.deep === 1) return false;  // 非根节点删除
              break;
            case "deleteRoot": // 删除根节点
              if (checkedNode.deep !== 1) return false;  // 根节点删除
              // 当大于一个或没有孩子节点时，不允许删除根节点
              if (checkedNodeChildren && checkedNodeChildren.length > 1
                  || checkedNode.children && checkedNode.children.length === 0) return false;
              break;
            case "addParent": // 添加上级
              if (checkedNode.deep !== 1) return false; // 根节点可以添加
              break;
            case "moveUp": // 上移
              if (checkedNode.deep === 1) return false; // 根节点不能移动
              else if (!showMoveUpBtn('leftTree', checkedNode)) return false;
              break;
            case "moveDown": // 下移
              if (checkedNode.deep === 1) return false;  // 根节点不能移动
              else if (!showMoveDownBtn('leftTree', checkedNode)) return false;
              break;
            case "property": // 属性
              if (checkedNode.connectId) return false;  // 连线结构没有属性
              break;
            case "addFunctionInference": // 功能推理
              if (!window.apiObj.isAiSwtich) return false;
              break;
            default:
              break;
          }
          // 追加菜单项
          let menuObj = {name: this.$t('' + item.label + ''), icon: "fas iconfont " + item.icon};
          let children = {};
          if (item.children && item.children.length > 0) {
            for (let i = 0, len = item.children.length; i < len; i++) {
              children['' + item.children[i].key + ''] = {name: this.$t('' + item.children[i].label + '')};
            }
            menuObj['items'] = children;
          }
          menuBtn['' + item.key + ''] = menuObj;
        }
      });
      // 处理右键菜单的分割线
      menuBtn = this.handleContextMenuSep(menuBtn);
      return menuBtn;
    },
    /**
     * 处理右键菜单的分割线
     * @param menuBtn
     */
    handleContextMenuSep(menuBtn) {
      let afterFilter = Object.keys(menuBtn);
      let operationTypes = this.$store.getters.nodeTypeDict.operationType;
      let sepIndex = 1;
      for (let i = 0; i < operationTypes.length; i++) {
        let innerJoinArray = afterFilter.filter((v) => operationTypes[i].includes(v));
        if (innerJoinArray && innerJoinArray.length > 0) {
          let index = afterFilter.findIndex(val => val === innerJoinArray[innerJoinArray.length - 1]);
          // 最后一组分割线不显示
          if (i < operationTypes.length - 1 && afterFilter.length > 1) {
            afterFilter.splice(index + 1, 0, 'sep' + sepIndex++);
          }
        }
      }
      let newMenuBtn = {};
      for (let i = 0; i < afterFilter.length; i++) {
        for (let j in menuBtn) {
          if (afterFilter[i] === j) {
            newMenuBtn['' + afterFilter[i] + ''] = menuBtn[j];
            break;
          } else {
            newMenuBtn['' + afterFilter[i] + ''] = "---------";
          }
        }
      }
      return newMenuBtn;
    },
    /**
     * 处理右键菜单
     * @param node 节点
     * @param items 菜单项
     */
    handleContextMenu(node, items) {
      let _that = this;
      // 隐藏上次菜单
      let selector = '#' + node.tId + '_a'
      jQuery.contextMenu('destroy', selector);
      jQuery.contextMenu({
        selector: selector,
        autoHide: true,
        zIndex: 10,
        items: items,
        callback: function (itemKey, opt) {
          let actionInfo = {key: itemKey};
          _that.menuAction(actionInfo);
        },
      });
    },
    /**
     * 右键菜单事件
     * @param actionInfo 菜单项信息
     */
    menuAction(actionInfo) {
      let checkedNode = this.$store.getters.lastCheckedNode;
      this.checkedNode = checkedNode;
      this.actionName = actionInfo.key;
      switch (actionInfo.key) {
        case "addStructure": // 结构
          this.clearHighLightCopyCutNode();
          this.handleAddModal(checkedNode, actionInfo.key);
          this.modalVisible = true;
          break;
        case "addMultistageStructure": // 多级结构
          this.clearHighLightCopyCutNode();
          this.handleAddModal(checkedNode, actionInfo.key);
          this.modalVisible = true;
          break;
        case "addFunction": // 功能
          this.clearHighLightCopyCutNode();
          this.handleAddModal(checkedNode, actionInfo.key);
          this.modalVisible = true;
          break;
        case "addFunctionInference": // 功能推理
          this.clearHighLightCopyCutNode();
          this.saveNodeAiInference(checkedNode, "02");
          break;
        case "addProductFeature": // 产品特性
          this.clearHighLightCopyCutNode();
          this.handleAddModal(checkedNode, actionInfo.key);
          this.modalVisible = true;
          break;
        case "copy": // 复制
          this.setHighLightCopyCutNode("copy");
          this.refreshBtnStatus();
          break;
        case "cut": // 剪切
          this.setHighLightCopyCutNode("cut");
          this.refreshBtnStatus();
          break;
        case "paste": // 粘贴
          this.paste();
          break;
        case "merge": // 合并
          this.clearHighLightCopyCutNode();
          this.handleMergeModal(checkedNode);
          this.modalVisible = true;
          break;
        case "delete": // 删除
          this.clearHighLightCopyCutNode();
          this.deleteNode(checkedNode);
          break;
        case "deleteRoot": // 删除根节点
          this.clearHighLightCopyCutNode();
          this.deleteRootNode(checkedNode);
          break;
        case "moveUp": // 上移
          this.clearHighLightCopyCutNode();
          this.moveNode(checkedNode, -1);
          break;
        case "moveDown": // 下移
          this.clearHighLightCopyCutNode();
          this.moveNode(checkedNode, 1);
          break;
        case "addParent": // 添加上级
          this.clearHighLightCopyCutNode();
          this.addParent(checkedNode);
          break;
        case "property": // 属性
          this.clearHighLightCopyCutNode();
          this.handlePropertyModal(checkedNode);
          this.modalVisible = true;
          break;
        case "addReviewComments": // 添加评审意见
          this.clearHighLightCopyCutNode();
          this.handleReviewCommentsModal(checkedNode);
          this.modalVisible = true;
          break;
      }
    },
    /**
     * 处理添加
     * @param node 节点
     * @param menuKey 菜单标识
     */
    handleAddModal(node, menuKey) {
      let name = node.description;
      let adds = this.$store.getters.nodeTypeDict.addModals;
      for (let i = 0, len = adds.length; i < len; i++) {
        if (adds[i].menuKey === menuKey) {
          this.title = this.$t('' + adds[i].title + '') + name;
          this.struTypeCode = adds[i].struTypeCode;
          this.tab = this.$t('' + adds[i].label + '');
          return;
        }
      }
    },
    /**
     * 处理合并Modal逻辑
     * @param node 节点
     */
    handleMergeModal(node) {
      let struTypeCode = node.struTypeCode;
      let merges = this.$store.getters.nodeTypeDict.mergeModals;
      for (let i = 0; i < merges.length; i++) {
        if (merges[i].key === struTypeCode) {
          this.actionName = merges[i].action;
          this.title = this.$t('' + merges[i].title + '');
          return;
        }
      }
    },
    /**
     * 处理属性Modal逻辑
     * @param node 节点
     * @param tabKey 选项卡Key
     */
    handlePropertyModal(node, tabKey = "") {
      let name = "14,07".indexOf(node.struTypeCode) !== -1 ? "" : node.description;
      let merges = this.$store.getters.nodeTypeDict.propertyModals;
      let merge = {};
      for (let i = 0; i < merges.length; i++) {
        if ("09,10".indexOf(node.struTypeCode) !== -1
            && merges[i].key === node.curOptTypeCode) {
          merge = merges[i];
          break;
        }
        if (merges[i].key === node.struTypeCode) {
          merge = merges[i];
          break;
        }
      }
      this.actionName = merge.action;
      this.title = this.$t('' + merge.title + '') + name;
      this.tabKey = tabKey;
    },
    /**
     * 处理评审意见Modal逻辑
     * @param node 节点
     */
    handleReviewCommentsModal(node) {
      let name = "14,07".indexOf(node.struTypeCode) !== -1 ? "" : node.description;
      let reviewComments = this.$store.getters.nodeTypeDict.reviewCommentsModals;
      for (let i = 0, len = reviewComments.length; i < len; i++) {
        if ("09,10".indexOf(node.struTypeCode) !== -1
            && reviewComments[i].key === node.curOptTypeCode) {
          this.title = this.$t('' + reviewComments[i].title + '') + name;
          return;
        }
        if (reviewComments[i].key === node.struTypeCode) {
          this.title = this.$t('' + reviewComments[i].title + '') + name;
          return;
        }
      }
    },
    /******************************************* 右键菜单 End **************************************************/

    /******************************************* 父组件方法 Start **************************************************/
    /**
     * 监听快捷键
     * @param flag true、false
     */
    keyListenerChange(flag) {
      this.$emit("keyListenerChange", flag);
    },
    /**
     * 刷新顶部按钮
     */
    refreshBtnStatus() {
      this.$emit("refreshBtnStatus");
    },
    /**
     * 刷新移动节点标识状态
     */
    refreshMoveNodeFlag() {
      this.$emit("refreshMoveNodeFlag");
    },
    /**
     * 初始化：右侧结构树
     */
    initRightTree() {
      this.$emit("initRightTree");
    },
    /**
     * 存储当前节点信息
     */
    setCheckedNode(node) {
      this.$emit("setCheckedNode", node, "leftTree");
    },
    /**
     * 设置：复制/剪切时，节点高亮
     */
    setHighLightCopyCutNode(copyCut) {
      this.$emit("setHighLightCopyCutNode", copyCut, "leftTree");
    },
    /**
     * 清除：复制/剪切时，节点高亮
     */
    clearHighLightCopyCutNode() {
      this.$emit("clearHighLightCopyCutNode", "leftTree");
    },
    /**
     * 恢复高亮复制节点,目的：允许一次复制多次粘贴
     */
    restoreHighLightCopyNode() {
      this.$emit("restoreHighLightCopyNode", "leftTree");
    },
    /**
     * 粘贴
     */
    paste() {
      this.$emit("paste", "leftTree");
    },
    /**
     * 删除节点
     */
    deleteNode(node) {
      this.$emit("deleteNode", node);
    },
    /**
     * 删除根节点
     * @param node 节点
     */
    deleteRootNode(node) {
      this.$emit("deleteRootNode", node);
    },
    /**
     * 移动节点
     */
    moveNode(node, optType) {
      this.$emit("moveNode", node, optType);
    },
    /**
     * 添加上级
     */
    addParent(node) {
      this.$emit("addParent", node);
    },
    /******************************************* 父组件方法 End **************************************************/

    /******************************************* 子组件方法 Start **************************************************/
    /**
     * 关闭模态框
     */
    closeModal() {
      this.modalVisible = false;
    },
    /**
     * 点击附件图标
     */
    handleAnnexIconClick(id) {
      let _that = this;
      _that.clearHighLightCopyCutNode();
      let node = _that.initData.find(item => {
        return item.id === id;
      });
      if (node) {
        _that.checkedNode = node;
        _that.handlePropertyModal(node, "remarks");
        _that.modalVisible = true;
      }
    },
    /******************************************* 子组件方法 End **************************************************/

    /**
     * 清除：评审意见跳转储存id
     */
    cleanCommentJumpStruNode() {
      this.$store.dispatch("fmeaTree/set", {
        key: "leftStruIdFromComments",
        value: undefined
      });
    },
    /**
     * 在区域禁用浏览器右键菜单
     */
    forbidRightClick() {
      document.getElementById("leftTree").oncontextmenu = function (e) {
        return false;
      };
    },
    /*******************************************ztree拖拽Start*************************/
    // 拖拽到目标节点上方
    canDragPrev(treeId, nodes, targetNode) {
      if (!targetNode || !nodes) {
        return false;
      }
      // 判断选择节点是否是从当前树上选取的节点
      if (nodes[0].tId.indexOf(treeId) === -1) {
        return false;
      }
      // 不允许拖拽到根节点上方
      if (!targetNode.pid || targetNode.pid === "00000000000000000000000000000000") {
        return false;
      }
      // 结构节点拖拽目标不允许选择接口节点
      if (nodes[0].struTypeCode !== targetNode.struTypeCode) {
        return false;
      }
      // 只能同级节点拖拽，如果想要随意拖拽请注释该代码
      if (nodes[0].pid !== targetNode.pid) {
        return false;
      }
      return true;
    },
    // 拖拽到目标节点下方
    canDragNext(treeId, nodes, targetNode) {
      if (!targetNode || !nodes) {
        return false;
      }
      // 判断选择节点是否是从当前树上选取的节点
      if (nodes[0].tId.indexOf(treeId) === -1) {
        return false;
      }
      // 结构节点拖拽目标不允许选择接口节点
      if (nodes[0].struTypeCode !== targetNode.struTypeCode) {
        return false;
      }
      // 只能同级节点拖拽，如果想要随意拖拽请注释该代码
      if (nodes[0].pid !== targetNode.pid) {
        return false;
      }
      return true;
    },
    // 拖拽到目标节点里
    canDragInner(treeId, nodes, targetNode) {
      if (!targetNode || !nodes) {
        return false;
      }
      // 判断选择节点是否是从当前树上选取的节点
      if (nodes[0].tId.indexOf(treeId) === -1) {
        return false;
      }
      // 结构节点拖拽目标不允许选择接口节点
      if (nodes[0].struTypeCode !== targetNode.struTypeCode) {
        return false;
      }
      // 只能同级节点拖拽，如果想要随意拖拽请注释该代码
      if (nodes[0].pid !== targetNode.pid) {
        return false;
      }
      // 不允许拖拽到接口里面
      if ("99".indexOf(targetNode.struTypeCode) > -1) {
        return false;
      }
      return true;
    },
    // 拖拽完成后的回调函数
    zTreeOnDrop(event, treeId, treeNodes, targetNode, moveType) {
      if (!targetNode) return false;
      var treeObj = $.fn.zTree.getZTreeObj(treeId);
      var nodes = treeObj.getNodes();
      // 拖拽到根节点的节点全部认为是拖入根节点内
      if (!targetNode.pid || targetNode.pid === "00000000000000000000000000000000" || targetNode.id === nodes[0].id) {
        moveType = "inner";
      }
      let data = {};
      data.struId = targetNode.id;
      data.fmeaId = this.$store.getters.rfmeaId;
      data.source = treeNodes;
      data.target = targetNode;
      data.moveType = moveType;
      this.$api.dropNode(data).then((res) => {
        if (res.flag) {
          this.$message.success(res.message, 1);
          this.onAsyncSuccessSelectId = treeNodes[0].id;
          // 刷新变体数据
          this.$emit("cleanVariantSelect");
          // 刷新树
          this.initLeftTree();
        } else {
          this.$message.error(res.message, 1);
        }
      }).catch((error) => {
        this.$message.error(error.response.data.message, 1);
      })
      nodes = undefined;
    },
    // 设置节点选中
    selectNode(treeId) {
      let treeObj = $.fn.zTree.getZTreeObj(treeId);
      let node = treeObj.getNodeByParam("id", this.onAsyncSuccessSelectId);
      if (node) {
        this.handleBeforeClick(treeId, node, 1);
        this.onAsyncSuccessSelectId = "";
      }
    },
    // 判断权限是否可移动
    canMove() {
      if (getUrlParam("enterState")) {
        return false;
      }
      return true;
    },
    /*******************************************ztree拖拽End*************************/
    // 粘贴回调方法设置目标选中节点id
    setPasteCompletedNodeId(id) {
      this.onAsyncSuccessSelectId = id;
    },
    /**
     * ai推理
     */
    saveNodeAiInference(node, struTypeCode) {
      this.$emit("saveNodeAiInference", node, struTypeCode);
    },
  },
};

/**
 * 左侧树附件点击
 * @param id
 */
window.handleLAnnexIconClick = function (id) {
  handleAnnexLIconClick(id);
}
</script>
<style lang="less" scoped>

@import "~@/styles/zTree";

</style>
