zhangzengfei
2022-08-23 e37e45cfe1123928dba5d9c5a427b0ee497b7ad6
src/components/giantTree/zTree/ztree.vue
@@ -1,319 +1,457 @@
<template>
  <div class="ztree" :id="ztreeId"></div>
  <div>
    <div class="searchTree">
      <el-input placeholder="搜索" v-model="keyWord" size="mini" v-show="search">
        <i slot="suffix" class="el-input__icon el-icon-search" :id="searchBtnId"></i>
      </el-input>
    </div>
    <div class="ztree" :id="ztreeId"></div>
  </div>
</template>
<script>
import * as $ from "jquery";
import * as $ from "jquery"
import { Loading } from "element-ui"
if (!window.jQuery) {
  window.jQuery = $;
  window.jQuery = $
}
// require("@ztree/ztree_v3/js/jquery.ztree.all");
require("./ztree_v3/jquery.ztree.all");
require("./ztree_v3/jquery.ztree.all")
require("./ztree_v3/jquery.ztree.exhide")
export default {
  props: {
    showCheckbox: { type: Boolean, default: false },
    readonly: { type: Boolean, default: true },
    gb28181: { type: Boolean, default: false },
    search: { type: Boolean, default: false },
    setting: {
      type: Object,
      require: false,
      default: function () {
        return {};
      },
      default: function() {
        return {}
      }
    },
    nodes: {
      type: Array,
      require: true,
      default: function () {
        return [];
      },
    },
      default: function() {
        return []
      }
    }
  },
  data() {
    return {
      ztreeId: "ztree_" + parseInt(Math.random() * 1e10),
      searchBtnId: "search_" + parseInt(Math.random() * 1e10),
      ztreeObj: null,
      list: [],
      loading: false,
      ztreeSetting: {
        view: {
          showLine: true,
          showIcon: true, // default to hide icon
          addHoverDom: this.addHoverDom,
          removeHoverDom: this.removeHoverDom,
          removeHoverDom: this.removeHoverDom
        },
        check: {
          chkboxType: { Y: "", N: "" },
          enable: this.showCheckbox,
          chkboxType: { Y: "ps", N: "ps" },
          enable: this.showCheckbox
        },
        callback: {
          onAsyncError: (...arg) => {
            this.$emit("onAsyncError", ...arg);
            this.$emit("onAsyncError", ...arg)
          },
          onAsyncSuccess: (...arg) => {
            this.$emit("onAsyncSuccess", ...arg);
            this.$emit("onAsyncSuccess", ...arg)
          },
          onCheck: (...arg) => {
            this.$emit("onCheck", ...arg);
            this.$emit("onCheck", ...arg)
          },
          onClick: (...arg) => {
            this.$emit("onClick", ...arg);
            //this.removeHoverIcon(...arg);
            this.$emit("onClick", ...arg)
            this.removeHoverIcon(...arg)
          },
          onCollapse: (...arg) => {
            this.$emit("onCollapse", ...arg);
            this.$emit("onCollapse", ...arg)
          },
          onDblClick: (...arg) => {
            this.$emit("onDblClick", ...arg);
            this.$emit("onDblClick", ...arg)
          },
          onDrag: (...arg) => {
            this.$emit("onDrag", ...arg);
            this.$emit("onDrag", ...arg)
          },
          onDragMove: (...arg) => {
            this.$emit("onDragMove", ...arg);
            this.$emit("onDragMove", ...arg)
          },
          onDrop: (...arg) => {
            this.$emit("onDrop", ...arg);
            this.$emit("onDrop", ...arg)
          },
          onExpand: (...arg) => {
            this.$emit("onExpand", ...arg);
            this.$emit("onExpand", ...arg)
          },
          onMouseDown: (...arg) => {
            this.$emit("onMouseDown", ...arg);
            this.$emit("onMouseDown", ...arg)
          },
          onMouseUp: (...arg) => {
            this.$emit("onMouseUp", ...arg);
            this.$emit("onMouseUp", ...arg)
          },
          onRemove: (...arg) => {
            this.$emit("onRemove", ...arg);
            this.$emit("onRemove", ...arg)
          },
          onRename: (...arg) => {
            this.$emit("onRename", ...arg);
            this.$emit("onRename", ...arg)
          },
          onRightClick: (...arg) => {
            this.$emit("onRightClick", ...arg);
          },
        },
            this.$emit("onRightClick", ...arg)
          }
        }
      },
    };
      keyWord: "",
      options: {
        target: ""
      }
    }
  },
  watch: {
    nodes: {
      handler: function (nodes) {
        this.list = nodes;
      handler: function(nodes) {
        this.list = nodes
        // update tree
        if (this.ztreeObj) {
          this.ztreeObj.destroy();
          this.ztreeObj.destroy()
        }
        this.$nextTick(() => {
          this.ztreeObj = $.fn.zTree.init(
            $("#" + this.ztreeId),
            Object.assign({}, this.ztreeSetting, this.setting),
            this.list
          );
          this.$emit("onCreated", this.ztreeObj);
        });
          )
          this.fuzzySearch(this.ztreeObj, this.searchBtnId, false, true) //初始化模糊搜索方法
          this.$emit("onCreated", this.ztreeObj)
        })
      },
      deep: true,
      immediate: true,
      immediate: true
    },
    showCheckbox: {
      handler: function () {
        this.ztreeSetting.check.enable = this.showCheckbox;
      handler: function() {
        let top = $("#" + this.ztreeId)
          .parent()
          .scrollTop()
        this.ztreeSetting.check.enable = this.showCheckbox
        if (this.ztreeObj) {
          this.list = this.ztreeObj.getNodes();
          this.ztreeObj.destroy();
          this.list = this.ztreeObj.getNodes()
          this.ztreeObj.destroy()
        }
        this.$nextTick(() => {
          this.ztreeObj = $.fn.zTree.init(
            $("#" + this.ztreeId),
            Object.assign({}, this.ztreeSetting, this.setting),
            this.list
          );
          this.$emit("onCreated", this.ztreeObj);
        });
          )
          $("#" + this.ztreeId)
            .parent()
            .scrollTop(top)
          this.$emit("onCreated", this.ztreeObj)
        })
      },
      immediate: true,
    },
      immediate: true
    }
  },
  methods: {
    addHoverDom(treeid, treeNode) {
      let _vue = this;
      const item = document.getElementById(`${treeNode.tId}_a`);
      let _vue = this
      const item = document.getElementById(`${treeNode.tId}_a`)
      // 文件夹新增按钮
      if (
        item &&
        !item.querySelector(".addIcon") &&
        !item.querySelector(".el-icon-circle-plus-outline") &&
        treeNode.isParent &&
        !this.readonly &&
        !this.gb28181
      ) {
        const btn = document.createElement("i");
        btn.id = `${treeid}_${treeNode.id}_btn`;
        btn.classList.add("addIcon");
        btn.classList.add("iconfont");
        const btn = document.createElement("i")
        btn.id = `${treeid}_${treeNode.id}_btn`
        btn.classList.add("el-icon-circle-plus-outline")
        btn.classList.add("primary")
        // btn.innerText = '删除';
        btn.addEventListener("click", (e) => {
          e.stopPropagation();
          e.stopPropagation()
          // this.clickRemove(treeNode)
          _vue.$emit("onAddNode", treeNode);
        });
          _vue.$emit("onAddNode", treeNode)
        })
        item.appendChild(btn);
        item.appendChild(btn)
      }
      // 文件夹删除按钮
      if (
        item &&
        !item.querySelector(".delIcon") &&
        !item.querySelector(".el-icon-remove-outline") &&
        treeNode.isParent &&
        !this.readonly &&
        !treeNode.children &&
        !this.gb28181
      ) {
        const btn = document.createElement("i");
        btn.id = `${treeid}_${treeNode.id}_btn`;
        btn.classList.add("delIcon");
        btn.classList.add("iconfont");
        const btn = document.createElement("i")
        btn.id = `${treeid}_${treeNode.id}_btn`
        btn.classList.add("el-icon-remove-outline")
        btn.classList.add("danger")
        // btn.innerText = '删除';
        btn.addEventListener("click", (e) => {
          e.stopPropagation();
          e.stopPropagation()
          // this.clickRemove(treeNode)
          _vue.$emit("onRemoveNode", treeNode);
        });
          _vue.$emit("onRemoveNode", treeNode)
        })
        item.appendChild(btn);
        item.appendChild(btn)
      }
      // 文件夹编辑按钮
      if (
        item &&
        !item.querySelector(".editIcon") &&
        treeNode.isParent &&
        !this.readonly
      ) {
        const btn = document.createElement("i");
        btn.id = `${treeid}_${treeNode.id}_btn`;
        btn.classList.add("editIcon");
        btn.classList.add("iconfont");
      if (item && !item.querySelector(".el-icon-edit") && treeNode.isParent && !this.readonly) {
        const btn = document.createElement("i")
        btn.id = `${treeid}_${treeNode.id}_btn`
        btn.classList.add("el-icon-edit")
        btn.classList.add("primary")
        // btn.innerText = '删除';
        btn.addEventListener("click", (e) => {
          e.stopPropagation();
          e.stopPropagation()
          // this.clickRemove(treeNode)
          _vue.$emit("onRenameNode", treeNode);
        });
          _vue.$emit("onRenameNode", treeNode)
        })
        item.appendChild(btn);
        item.appendChild(btn)
      }
      // 添加摄像机按钮
      if (
        item &&
        !item.querySelector(".addCameraIcon") &&
        treeNode.isParent &&
        !this.readonly &&
        !this.gb28181
      ) {
        const btn = document.createElement("i");
        btn.id = `${treeid}_${treeNode.id}_btn`;
        btn.classList.add("iconfont");
        btn.classList.add("addCameraIcon");
      if (item && !item.querySelector(".iconshishishipin") && treeNode.isParent && !this.readonly && !this.gb28181) {
        const btn = document.createElement("i")
        btn.id = `${treeid}_${treeNode.id}_btn`
        btn.classList.add("iconfont")
        btn.classList.add("iconshishishipin")
        btn.classList.add("primary")
        btn.classList.add("icon-fix")
        // btn.innerText = '删除';
        btn.addEventListener("click", (e) => {
          e.stopPropagation();
          e.stopPropagation()
          // this.clickRemove(treeNode)
          _vue.$emit("onAddDevice", treeNode.id);
        });
          _vue.$emit("onAddDevice", treeNode.id)
        })
        btn.innerHTML = "&#xe642;"
        item.appendChild(btn);
        item.appendChild(btn)
      }
      // 导入摄像机按钮
      if (
        item &&
        !item.querySelector(".importIcon") &&
        treeNode.isParent &&
        !this.readonly &&
        !this.gb28181
      ) {
        const btn = document.createElement("i");
        btn.id = `${treeid}_${treeNode.id}_btn`;
        btn.classList.add("iconfont");
        btn.classList.add("importIcon");
      if (item && !item.querySelector(".icondaoru") && treeNode.isParent && !this.readonly && !this.gb28181) {
        const btn = document.createElement("i")
        btn.id = `${treeid}_${treeNode.id}_btn`
        btn.classList.add("iconfont")
        btn.classList.add("icondaoru")
        btn.classList.add("primary")
        btn.classList.add("icon-fix")
        // btn.innerText = '删除';
        btn.addEventListener("click", (e) => {
          e.stopPropagation();
          e.stopPropagation()
          // this.clickRemove(treeNode)
          _vue.$emit("onImport", treeNode.id);
        });
          _vue.$emit("onImport", treeNode.id)
        })
        btn.innerHTML = "&#xe643;"
        item.appendChild(btn);
        item.appendChild(btn)
      }
      // 查看底图按钮
      if (
        item &&
        !item.querySelector(".icontupian1") &&
        treeNode.type == "camera"
      ) {
        const btn = document.createElement("i");
        btn.id = `${treeid}_${treeNode.id}_btn`;
        btn.classList.add("iconfont");
        btn.classList.add("icontupian1");
        btn.classList.add("primary");
        btn.classList.add("icon-fix");
      if (item && !item.querySelector(".el-icon-picture") && treeNode.type == "camera") {
        const btn = document.createElement("i")
        btn.id = `${treeid}_${treeNode.id}_btn`
        btn.classList.add("iconfont")
        btn.classList.add("el-icon-picture")
        btn.classList.add("primary")
        btn.classList.add("icon-fix")
        // btn.innerText = '删除';
        btn.addEventListener("click", (e) => {
          e.stopPropagation();
          e.stopPropagation()
          // this.clickRemove(treeNode)
          _vue.$emit("onShowPic", treeNode);
        });
          _vue.$emit("onShowPic", treeNode)
        })
        item.appendChild(btn);
        item.appendChild(btn)
      }
    },
    removeHoverIcon(evt, treeId, item) {
      this.removeHoverDom(treeId, item);
      this.removeHoverDom(treeId, item)
    },
    removeHoverDom(treeid, treeNode) {
      const item = document.getElementById(`${treeNode.tId}_a`);
      const item = document.getElementById(`${treeNode.tId}_a`)
      if (item) {
        let btn = item.querySelector(".addIcon");
        let btn = item.querySelector(".el-icon-circle-plus-outline")
        if (btn) {
          item.removeChild(item.querySelector(".addIcon"));
          item.removeChild(item.querySelector(".el-icon-circle-plus-outline"))
        }
        btn = item.querySelector(".delIcon");
        btn = item.querySelector(".el-icon-remove-outline")
        if (btn) {
          item.removeChild(item.querySelector(".delIcon"));
          item.removeChild(item.querySelector(".el-icon-remove-outline"))
        }
        btn = item.querySelector(".editIcon");
        btn = item.querySelector(".el-icon-edit")
        if (btn) {
          item.removeChild(item.querySelector(".editIcon"));
          item.removeChild(item.querySelector(".el-icon-edit"))
        }
        btn = item.querySelector(".addCameraIcon");
        btn = item.querySelector(".iconshishishipin")
        if (btn) {
          item.removeChild(item.querySelector(".addCameraIcon"));
          item.removeChild(item.querySelector(".iconshishishipin"))
        }
        btn = item.querySelector(".importIcon");
        btn = item.querySelector(".icondaoru")
        if (btn) {
          item.removeChild(item.querySelector(".importIcon"));
          item.removeChild(item.querySelector(".icondaoru"))
        }
        btn = item.querySelector(".icontupian1");
        btn = item.querySelector(".el-icon-picture")
        if (btn) {
          item.removeChild(item.querySelector(".icontupian1"));
          item.removeChild(item.querySelector(".el-icon-picture"))
        }
      }
    },
  },
};
    fuzzySearch(zTreeObj, searchField, isHighLight, isExpand) {
      const _this = this
      if (!zTreeObj) {
        alert("fail to get ztree object")
      }
      var nameKey = zTreeObj.setting.data.key.name //get the key of the node name
      isHighLight = isHighLight === false ? false : true //default true, only use false to disable highlight
      isExpand = isExpand ? true : false // not to expand in default
      zTreeObj.setting.view.nameIsHTML = isHighLight //allow use html in node name for highlight use
      var metaChar = "[\\[\\]\\\\^\\$\\.\\|\\?\\*\\+\\(\\)]" //js meta characters
      var rexMeta = new RegExp(metaChar, "gi") //regular expression to match meta characters
      // keywords filter function
      function ztreeFilter(zTreeObj, _keywords, callBackFunc) {
        if (!_keywords) {
          _keywords = "" //default blank for _keywords
        }
        // function to find the matching node
        function filterFunc(node) {
          if (node && node.oldname && node.oldname.length > 0) {
            node[nameKey] = node.oldname //recover oldname of the node if exist
          }
          zTreeObj.updateNode(node) //update node to for modifications take effect
          if (_keywords.length == 0) {
            //return true to show all nodes if the keyword is blank
            zTreeObj.showNode(node)
            zTreeObj.expandNode(node, isExpand)
            return true
          }
          //transform node name and keywords to lowercase
          if (node[nameKey] && node[nameKey].toLowerCase().indexOf(_keywords.toLowerCase()) != -1) {
            if (isHighLight) {
              //highlight process
              //a new variable 'newKeywords' created to store the keywords information
              //keep the parameter '_keywords' as initial and it will be used in next node
              //process the meta characters in _keywords thus the RegExp can be correctly used in str.replace
              var newKeywords = _keywords.replace(rexMeta, function(matchStr) {
                //add escape character before meta characters
                return "\\" + matchStr
              })
              node.oldname = node[nameKey] //store the old name
              var rexGlobal = new RegExp(newKeywords, "gi") //'g' for global,'i' for ignore case
              //use replace(RegExp,replacement) since replace(/substr/g,replacement) cannot be used here
              node[nameKey] = node.oldname.replace(rexGlobal, function(originalText) {
                //highlight the matching words in node name
                var highLightText =
                  '<span style="color: whitesmoke;background-color: darkred;">' + originalText + "</span>"
                return highLightText
              })
              zTreeObj.updateNode(node) //update node for modifications take effect
            }
            zTreeObj.showNode(node) //show node with matching keywords
            return true //return true and show this node
          }
          zTreeObj.hideNode(node) // hide node that not matched
          return false //return false for node not matched
        }
        var nodesShow = zTreeObj.getNodesByFilter(filterFunc) //get all nodes that would be shown
        processShowNodes(nodesShow, _keywords) //nodes should be reprocessed to show correctly
        _this.$emit("onAfterSearch", null)
      }
      /**
       * reprocess of nodes before showing
       */
      function processShowNodes(nodesShow, _keywords) {
        if (nodesShow && nodesShow.length > 0) {
          //process the ancient nodes if _keywords is not blank
          if (_keywords.length > 0) {
            $.each(nodesShow, function(n, obj) {
              var pathOfOne = obj.getPath() //get all the ancient nodes including current node
              if (pathOfOne && pathOfOne.length > 0) {
                //i < pathOfOne.length-1 process every node in path except self
                for (var i = 0; i < pathOfOne.length - 1; i++) {
                  zTreeObj.showNode(pathOfOne[i]) //show node
                  zTreeObj.expandNode(pathOfOne[i], true) //expand node
                }
              }
            })
          } else {
            //show all nodes when _keywords is blank and expand the root nodes
            var rootNodes = zTreeObj.getNodesByParam("level", "0") //get all root nodes
            $.each(rootNodes, function(n, obj) {
              zTreeObj.expandNode(obj, true) //expand all root nodes
            })
          }
        }
      }
      //listen to change in input element
      $("#" + searchField).bind("click", function() {
        // _this.options.target = document.querySelector("#" + _this.ztreeId).parentNode.parentNode
        // console.log(_this.options.target);
        // let loadingInstance = Loading.service(_this.options)
        // console.log(_this.keyWord);
        // var _keywords = $(this).val();
        $("#" + searchField).removeClass("el-icon-search")
        $("#" + searchField).addClass("el-icon-loading")
        searchNodeLazy(_this.keyWord) //call lazy load
        // loadingInstance.close()
        setTimeout(() => {
          $("#" + searchField).removeClass("el-icon-loading")
          $("#" + searchField).addClass("el-icon-search")
        }, 300)
      })
      var lastKeyword = ""
      // excute lazy load once after input change, the last pending task will be cancled
      function searchNodeLazy(_keywords) {
        if (lastKeyword === _keywords) {
          return
        }
        ztreeFilter(zTreeObj, _keywords) //lazy load ztreeFilter function
        // $(searchField).focus();//focus input field again after filtering
        lastKeyword = _keywords
      }
    },
    handleSearch() {
      this.loading = true
      searchNodeLazy(this.keyWord) //call lazy load
      this.loading = false
    }
  }
}
</script>
<style lang="scss">
@@ -405,6 +543,11 @@
  text-align: left;
  white-space: nowrap;
  outline: 0;
  .iconfont {
    padding: 0;
    padding-top: 3px;
  }
}
.ztree li ul {
  margin: 0;
@@ -412,8 +555,7 @@
}
.ztree li ul.line {
  /* background: url(/images/line_conn.gif) 0 0 repeat-y; */
  background: url(data:image/gif;base64,R0lGODlhCQACAIAAAMzMzP///yH5BAEAAAEALAAAAAAJAAIAAAIEjI9pUAA7)
    0 0 repeat-y;
  background: url(data:image/gif;base64,R0lGODlhCQACAIAAAMzMzP///yH5BAEAAAEALAAAAAAJAAIAAAIEjI9pUAA7) 0 0 repeat-y;
}
.ztree li a {
@@ -474,7 +616,7 @@
  color: #5f5f5f;
}
.ztree li i.icon-fix {
.ztree li a.icon-fix {
  font-size: 15px;
  margin-left: 3px;
  margin-right: 5px;
@@ -482,10 +624,19 @@
  top: 2px;
}
.ztree li i.primary {
.ztree i.iconshishishipin,
.ztree i.icondaoru {
  margin-right: 8px;
  font-size: 18px;
  vertical-align: middle;
  width: 24px;
  text-align: left;
}
.ztree li a.primary {
  color: #3d68e1;
}
.ztree li i.danger {
.ztree li a.danger {
  color: #f7493c;
}
@@ -522,7 +673,7 @@
  background-position: 0 -14px;
}
.ztree li span.button.chk.checkbox_false_part {
  background-position: 0 -28px;
  background-position: -14px 0;
}
.ztree li span.button.chk.checkbox_false_part_focus {
  background-position: 0 -42px;
@@ -537,7 +688,7 @@
  background-position: -14px -14px;
}
.ztree li span.button.chk.checkbox_true_part {
  background-position: -14px -28px;
  background-position: -14px 0;
}
.ztree li span.button.chk.checkbox_true_part_focus {
  background-position: -14px -42px;
@@ -734,4 +885,37 @@
  filter: alpha(opacity=0);
  position: absolute;
}
.iconfont.el-icon-picture.primary.icon-fix {
  margin-left: 10px;
  margin-right: 10px;
  font-size: 16px;
  color: #0065ff;
}
</style>
<style scoped lang="scss">
.searchTree {
  margin: 5px 5px;
  display: flex;
  justify-content: center;
  .el-input {
    margin: 0 auto;
    width: 350px;
  }
  ::v-deep .el-input__suffix {
    right: 0;
    width: 50px;
    background: skyblue;
    color: #fff;
    cursor: pointer;
    background-color: rgb(61, 104, 255);
  }
  .el-icon-search:before {
    content: "搜索";
  }
}
</style>