ZZJ
2021-12-20 832896ccaf8ac6a8ca31394e55577f064bc5eacf
src/components/treeMenu/index.vue
@@ -1,430 +1,491 @@
<template>
  <div class="tree-menu" :style="`max-height:${height - 200}px;`">
    <v-jstree
      :data="node"
      :item-events="itemClickEvents"
      :show-checkbox="TreeDataPool.multiple"
      :multiple="TreeDataPool.multiple"
      allow-batch
      collapse
      :draggable="!gb28181"
      @item-click="itemClick"
      @item-toggle="itemToggle"
      @item-drop="dropNode"
      text-field-name="name"
      ref="jstree"
    >
      <template slot-scope="_">
        <div
          style="display: inherit; width:calc(100% + 120px) "
          @mouseover="selectStyle(_)"
          @mouseout="outStyle(_)"
        >
          <i
            :class="_.vm.themeIconClasses"
            role="presentation"
            v-if="!_.model.loading && _.model.type !== '4'"
          ></i>
          <!-- 摄像机状态图标 -->
          <i
            class="iconfont iconjiankongshexiangji"
            style="padding-left:4px;font-size:13px;line-height: 28px;"
            role="presentation"
            v-if="!_.model.loading && _.model.type === '4' && !_.model.isAI"
          ></i>
          <i
            class="iconfont iconfenxishexiangji"
            style="padding-left:4px;color:#3D68E1; font-size:13px;line-height: 28px;"
            role="presentation"
            v-if="!_.model.loading && _.model.isAI"
          ></i>
          <!-- 正在处理的摄像机名称显示为蓝色 -->
          <span
            class="tree-name"
            :style="_.model.isRunning ? `color:#3d68e1` : '' "
          >{{ _.model.name }}</span>
          <div
            v-if="gb28181"
            v-show="
              hoverNodeId === _.model.id &&
                !TreeDataPool.gbReadonly &&
                '4' !== _.model.type
            "
            class="tree-item-handle"
          >
            <el-tooltip content="编辑区域" placement="bottom" popper-class="atooltip">
              <button @click="editNode($event, _.model, gb28181)">
                <i class="el-icon-edit"></i>
              </button>
            </el-tooltip>
          </div>
          <div
            v-else
            v-show="
              hoverNodeId === _.model.id &&
                !TreeDataPool.readonly &&
                '4' !== _.model.type
            "
            class="tree-item-handle"
          >
            <el-tooltip content="添加区域" placement="bottom" popper-class="atooltip">
              <button @click="addNode($event, _.model)">
                <i class="el-icon-circle-plus-outline"></i>
              </button>
            </el-tooltip>
            <el-tooltip content="删除区域" placement="bottom" popper-class="atooltip">
              <button @click="delNode(_.model)" v-show="!_.model.children" style="color:#f53d3d">
                <i class="el-icon-remove-outline"></i>
              </button>
            </el-tooltip>
            <el-tooltip content="编辑区域" placement="bottom" popper-class="atooltip">
              <button @click="editNode($event, _.model, gb28181)">
                <i class="el-icon-edit"></i>
              </button>
            </el-tooltip>
            <el-tooltip content="添加设备" placement="bottom" popper-class="atooltip">
              <button @click="addCamera(_.model.id)">
                <span
                  class="iconfont iconshishishipin"
                  style="font-size:15px; margin-left:3px; position:relative; top:2px;"
                ></span>
              </button>
            </el-tooltip>
            <el-tooltip content="导入设备" placement="bottom" popper-class="atooltip">
              <button @click="importCameras(_.model.id)">
                <span
                  class="iconfont icondaoru"
                  style="font-size:17px; margin-left:9px; position:relative; top:2px;"
                ></span>
              </button>
            </el-tooltip>
          </div>
        </div>
      </template>
    </v-jstree>
    <div class="dialog-box-bg" v-show="showDialog" @click="hideDialogBox"></div>
    <div
      class="dialog-box"
      v-show="showDialog"
      :style="{ left: clientX + 'px', top: clientY + 'px' }"
    >
      <el-card :body-style="{ padding: '10px' }">
        <el-form :model="dialogForm" size="mini" :rules="rules" ref="dialogForm" label-width="70px">
          <el-form-item label="名称:" prop="name">
            <el-input v-model="dialogForm.text"></el-input>
          </el-form-item>
          <div class="text-center pb-2">
            <el-button size="mini" type="primary" @click="submitForm">保存</el-button>
            <el-button size="mini" @click="hideDialogBox">取消</el-button>
          </div>
        </el-form>
      </el-card>
    </div>
  </div>
</template>
<script>
import VJstree from "./jsTree";
export default {
  name: "TreeMenu",
  components: {
    VJstree
  },
  props: {
    app: {
      type: String,
      default: "Video"
    },
    node: {
      type: Array
    },
    treeName: {
      type: String,
      default: ""
    },
    gb28181: {
      type: Boolean,
      default: false
    },
    height: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      hoverNodeId: "",
      itemClickEvents: {
        dblclick: (VNode, item, e) => {
          if (item.type !== "4" || this.app !== "Camera") {
            return;
          }
          // console.log('activeForceChoose', this.TreeDataPool.activeForceChoose)
          this.TreeDataPool.activeVideoId = item.id;
          let videoArr = this.TreeDataPool.videoArr;
          let nullVideoIndex = "";
          if (
            this.TreeDataPool.activeForceChoose &&
            this.TreeDataPool.activeVideoIndex !== "" &&
            this.TreeDataPool.activeVideoIndex <= videoArr.length - 1
          ) {
            this.TreeDataPool.setVideoArr(this.TreeDataPool.activeVideoIndex, undefined, this);
            this.$nextTick(() => {
              this.TreeDataPool.setVideoArr(
                this.TreeDataPool.activeVideoIndex,
                item,
                this
              );
            })
            return;
          }
          for (let i = 0; i < videoArr.length; i++) {
            // eslint-disable-next-line
            if (
              videoArr[i] === "" ||
              videoArr[i] === undefined ||
              videoArr[i] === null
            ) {
              nullVideoIndex = i;
              break;
            } else {
              nullVideoIndex = "";
            }
          }
          if (nullVideoIndex === "") {
            this.TreeDataPool.setVideoArr(this.TreeDataPool.activeVideoIndex, undefined, this);
            this.$nextTick(() => {
              this.TreeDataPool.setVideoArr(
                this.TreeDataPool.activeVideoIndex,
                item,
                this
              );
            })
          } else {
            // this.TreeDataPool.setVideoArr(this.TreeDataPool.activeVideoIndex, undefined, this);
            this.$nextTick(() => {
              this.TreeDataPool.setVideoArr(
                this.TreeDataPool.activeVideoIndex,
                item,
                this
              );
            })
            this.TreeDataPool.activeVideoIndex = nullVideoIndex;
          }
          // this.TreeDataPool.setVideoArr(videoArr.length - 1, item, this);
        }
      },
      showDialog: false,
      clientX: 0,
      clientY: 0,
      dialogForm: {
        text: ""
      },
      rules: {
        text: [
          { required: true, message: "请输入节点名称", trigger: "change" },
          { min: 2, max: 10, message: "长度在2到10个字", trigger: "change" }
        ]
      }
    };
  },
  created() {
    // console.log(this.height, '树高度')
    this.TreeDataPool.activeVideoIndex = sessionStorage.activeIndexVideo
      ? Number(sessionStorage.activeIndexVideo)
      : this.TreeDataPool.activeVideoIndex;
  },
  watch: {
    "TreeDataPool.treeType": function (newValue) {
      if (newValue !== this.treeName) {
        this.TreeDataPool.cleanTree(this.treeName);
      }
    },
    node: function (newValue) {
      this.$refs.jstree.initializeData(newValue);
    }
  },
  methods: {
    addCamera(node) {
      this.$emit("addDevice", node);
    },
    importCameras(node) {
      this.$emit("import", node);
    },
    addNode(event, node) {
      this.dialogForm = {
        text: "",
        method: "add",
        node: node.id
      };
      this.showDialogBox(event);
    },
    editNode(event, node, isGb) {
      this.dialogForm = {
        text: node.name,
        method: "edit",
        node: node.id,
        alias: node.alias,
        gb28181: isGb
      };
      this.showDialogBox(event);
    },
    delNode(node) {
      this.TreeDataPool.del(node.id);
    },
    selectStyle(item) {
      this.hoverNodeId = item.model.id;
    },
    outStyle(item) {
      this.hoverNodeId = "";
    },
    submitForm() {
      // 提交新增或者编辑区域节点表单
      this.$refs.dialogForm.validate(valid => {
        if (valid) {
          if (this.dialogForm.method == "add") {
            this.TreeDataPool.add(this.dialogForm.text, this.dialogForm.node);
          } else if (this.dialogForm.method == "edit") {
            this.TreeDataPool.update(
              this.dialogForm.text,
              this.dialogForm.node,
              this.gb28181 ? this.dialogForm.text : "",
              this.dialogForm.gb28181
            );
          }
        } else {
          return false;
        }
      });
      this.hideDialogBox();
    },
    hideDialogBox() {
      this.showDialog = false;
      this.dialogForm = { text: "" };
    },
    showDialogBox(event) {
      let { clientX = 0, offsetY = 0 } = event;
      // this.clientX = clientX - 120;
      this.clientX = 50;
      this.clientY = offsetY;
      this.showDialog = true;
    },
    itemClick(node, item, e) {
      console.log('jsTree index.vue', item)
      this.TreeDataPool.selectedNode = item;
      this.TreeDataPool.updateSelectedNodes();
      this.TreeDataPool.treeType = this.treeName;
    },
    itemToggle(node, item, e) {
      if (item.opened) {
        delete this.TreeDataPool.foldNodeList[item.id]
      } else {
        this.TreeDataPool.foldNodeList[item.id] = true
      }
    },
    dropNode(node, item, draggedItem, e) {
      console.log('dropNode', node, item, draggedItem);
      this.TreeDataPool.dropNode(draggedItem.id, item.id)
    }
  }
};
</script>
<style lang="scss" scoped>
.dialog-box {
  position: absolute;
  width: 220px;
  z-index: 1;
}
.dialog-box-bg {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: rgba(255, 255, 255, 0.6);
}
.tree-item-handle {
  display: inline;
  font-size: 16px;
  margin-left: 6px;
  button {
    position: relative;
    color: #3d68e1;
    border: 0px;
    background-color: transparent;
    cursor: pointer;
    outline: none;
  }
  button:hover {
    color: #2249b4;
  }
  // button:hover:after {
  //   position: fixed;
  //   padding: 5px 10px;
  //   background-color: #00000090;
  //   border-radius: 0px;
  //   color: #fff;
  //   content: attr(labelTooltip);
  //   font-size: 12px;
  //   width: 55px;
  //   margin-left: -50px;
  //   margin-top: 25px;
  //   vertical-align: left;
  // }
}
.tree-name {
  font-family: PingFangSC-Medium;
  font-size: 13px;
  color: #222222;
  // max-width: 100px;
  line-height: 27px;
  margin-left: 4px;
  display: inline-block;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
  vertical-align: top;
}
.tree-menu {
  // max-width: 350px;
  overflow-x: hidden;
  overflow-y: hidden;
  margin-bottom: 4px;
}
.tree-menu::-webkit-scrollbar {
  /*滚动条整体样式*/
  width: 4px; /*高宽分别对应横竖滚动条的尺寸*/
  height: 4px;
}
.tree-menu::-webkit-scrollbar-thumb {
  /*滚动条里面小方块*/
  border-radius: 5px;
  -webkit-box-shadow: inset 0 0 5px rgba(157, 165, 183, 0);
  background: rgb(202, 201, 201);
}
.tree-menu::-webkit-scrollbar-track {
  /*滚动条里面轨道*/
  -webkit-box-shadow: inset 0 0 5px rgba(157, 165, 183, 0);
  border-radius: 0;
  background: rgb(235, 234, 234);
}
.tree-menu::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.4);
}
.tree-menu:hover {
  overflow-x: visible;
  overflow-y: auto;
  margin-bottom: 0px;
}
</style>
<template>
  <div class="tree-menu" :style="`max-height:${height - 200}px;`">
    <v-jstree
      :data="node"
      :item-events="itemClickEvents"
      :show-checkbox="TreeDataPool.multiple"
      :multiple="TreeDataPool.multiple"
      allow-batch
      collapse
      :draggable="!gb28181"
      @item-click="itemClick"
      @item-toggle="itemToggle"
      @item-drop="dropNode"
      text-field-name="name"
      ref="jstree"
    >
      <template slot-scope="_">
        <div
          style="display: inherit; width: calc(100% + 120px)"
          @mouseover="selectStyle(_)"
          @mouseout="outStyle(_)"
        >
          <i
            :class="_.vm.themeIconClasses"
            role="presentation"
            v-if="!_.model.loading && _.model.type !== '4'"
          ></i>
          <!-- 摄像机状态图标 -->
          <i
            class="iconfont iconjiankongshexiangji"
            style="padding-left: 4px; font-size: 13px; line-height: 28px"
            role="presentation"
            v-if="!_.model.loading && _.model.type === '4' && !_.model.isAI"
          ></i>
          <i
            class="iconfont iconfenxishexiangji"
            style="
              padding-left: 4px;
              color: #3d68e1;
              font-size: 13px;
              line-height: 28px;
            "
            role="presentation"
            v-if="!_.model.loading && _.model.isAI"
          ></i>
          <!-- 正在处理的摄像机名称显示为蓝色 -->
          <span
            class="tree-name"
            :style="_.model.isRunning ? `color:#3d68e1` : ''"
            >{{ _.model.name }}</span
          >
          <div
            v-if="gb28181"
            v-show="
              hoverNodeId === _.model.id &&
              !TreeDataPool.gbReadonly &&
              '4' !== _.model.type
            "
            class="tree-item-handle"
          >
            <el-tooltip
              content="编辑区域"
              placement="bottom"
              popper-class="atooltip"
            >
              <button @click="editNode($event, _.model, gb28181)">
                <i class="el-icon-edit"></i>
              </button>
            </el-tooltip>
          </div>
          <div
            v-else
            v-show="
              hoverNodeId === _.model.id &&
              !TreeDataPool.readonly &&
              '4' !== _.model.type
            "
            class="tree-item-handle"
          >
            <el-tooltip
              content="添加区域"
              placement="bottom"
              popper-class="atooltip"
            >
              <button @click="addNode($event, _.model)">
                <i class="el-icon-circle-plus-outline"></i>
              </button>
            </el-tooltip>
            <el-tooltip
              content="删除区域"
              placement="bottom"
              popper-class="atooltip"
            >
              <button
                @click="delNode(_.model)"
                v-show="!_.model.children"
                style="color: #f53d3d"
              >
                <i class="el-icon-remove-outline"></i>
              </button>
            </el-tooltip>
            <el-tooltip
              content="编辑区域"
              placement="bottom"
              popper-class="atooltip"
            >
              <button @click="editNode($event, _.model, gb28181)">
                <i class="el-icon-edit"></i>
              </button>
            </el-tooltip>
            <el-tooltip
              content="添加设备"
              placement="bottom"
              popper-class="atooltip"
            >
              <button @click="addCamera(_.model.id)">
                <span
                  class="iconfont iconshishishipin"
                  style="
                    font-size: 15px;
                    margin-left: 3px;
                    position: relative;
                    top: 2px;
                  "
                ></span>
              </button>
            </el-tooltip>
            <el-tooltip
              content="导入设备"
              placement="bottom"
              popper-class="atooltip"
            >
              <button @click="importCameras(_.model.id)">
                <span
                  class="iconfont icondaoru"
                  style="
                    font-size: 17px;
                    margin-left: 9px;
                    position: relative;
                    top: 2px;
                  "
                ></span>
              </button>
            </el-tooltip>
          </div>
        </div>
      </template>
    </v-jstree>
    <div class="dialog-box-bg" v-show="showDialog" @click="hideDialogBox"></div>
    <div
      class="dialog-box"
      v-show="showDialog"
      :style="{ left: clientX + 'px', top: clientY + 'px' }"
    >
      <el-card :body-style="{ padding: '10px' }">
        <el-form
          :model="dialogForm"
          size="mini"
          :rules="rules"
          ref="dialogForm"
          label-width="70px"
        >
          <el-form-item label="名称:" prop="name">
            <el-input v-model="dialogForm.text"></el-input>
          </el-form-item>
          <div class="text-center pb-2">
            <el-button size="mini" type="primary" @click="submitForm"
              >保存</el-button
            >
            <el-button size="mini" @click="hideDialogBox">取消</el-button>
          </div>
        </el-form>
      </el-card>
    </div>
  </div>
</template>
<script>
import VJstree from "./jsTree";
export default {
  name: "TreeMenu",
  components: {
    VJstree,
  },
  props: {
    app: {
      type: String,
      default: "Video",
    },
    node: {
      type: Array,
    },
    treeName: {
      type: String,
      default: "",
    },
    gb28181: {
      type: Boolean,
      default: false,
    },
    height: {
      type: Number,
      default: 0,
    },
  },
  data() {
    return {
      hoverNodeId: "",
      itemClickEvents: {
        dblclick: (VNode, item, e) => {
          if (item.type !== "4" || this.app !== "Camera") {
            return;
          }
          // console.log('activeForceChoose', this.TreeDataPool.activeForceChoose)
          this.TreeDataPool.activeVideoId = item.id;
          let videoArr = this.TreeDataPool.videoArr;
          let nullVideoIndex = "";
          if (
            this.TreeDataPool.activeForceChoose &&
            this.TreeDataPool.activeVideoIndex !== "" &&
            this.TreeDataPool.activeVideoIndex <= videoArr.length - 1
          ) {
            this.TreeDataPool.setVideoArr(
              this.TreeDataPool.activeVideoIndex,
              undefined,
              this
            );
            this.$nextTick(() => {
              this.TreeDataPool.setVideoArr(
                this.TreeDataPool.activeVideoIndex,
                item,
                this
              );
            });
            return;
          }
          for (let i = 0; i < videoArr.length; i++) {
            // eslint-disable-next-line
            if (
              videoArr[i] === "" ||
              videoArr[i] === undefined ||
              videoArr[i] === null
            ) {
              nullVideoIndex = i;
              break;
            } else {
              nullVideoIndex = "";
            }
          }
          if (nullVideoIndex === "") {
            this.TreeDataPool.setVideoArr(
              this.TreeDataPool.activeVideoIndex,
              undefined,
              this
            );
            this.$nextTick(() => {
              this.TreeDataPool.setVideoArr(
                this.TreeDataPool.activeVideoIndex,
                item,
                this
              );
            });
          } else {
            // this.TreeDataPool.setVideoArr(this.TreeDataPool.activeVideoIndex, undefined, this);
            this.$nextTick(() => {
              this.TreeDataPool.setVideoArr(
                this.TreeDataPool.activeVideoIndex,
                item,
                this
              );
            });
            this.TreeDataPool.activeVideoIndex = nullVideoIndex;
          }
          // this.TreeDataPool.setVideoArr(videoArr.length - 1, item, this);
        },
      },
      showDialog: false,
      clientX: 0,
      clientY: 0,
      dialogForm: {
        text: "",
      },
      rules: {
        text: [
          { required: true, message: "请输入节点名称", trigger: "change" },
          { min: 2, max: 10, message: "长度在2到10个字", trigger: "change" },
        ],
      },
    };
  },
  created() {
    console.log("------------");
    // console.log(this.height, '树高度')
    this.TreeDataPool.activeVideoIndex = sessionStorage.activeIndexVideo
      ? Number(sessionStorage.activeIndexVideo)
      : this.TreeDataPool.activeVideoIndex;
  },
  watch: {
    "TreeDataPool.treeType": function (newValue) {
      if (newValue !== this.treeName) {
        this.TreeDataPool.cleanTree(this.treeName);
      }
    },
    node: function (newValue) {
      this.$refs.jstree.initializeData(newValue);
    },
  },
  methods: {
    addCamera(node) {
      this.$emit("addDevice", node);
    },
    importCameras(node) {
      this.$emit("import", node);
    },
    addNode(event, node) {
      this.dialogForm = {
        text: "",
        method: "add",
        node: node.id,
      };
      this.showDialogBox(event);
    },
    editNode(event, node, isGb) {
      this.dialogForm = {
        text: node.name,
        method: "edit",
        node: node.id,
        alias: node.alias,
        gb28181: isGb,
      };
      this.showDialogBox(event);
    },
    delNode(node) {
      this.TreeDataPool.del(node.id);
    },
    selectStyle(item) {
      this.hoverNodeId = item.model.id;
    },
    outStyle(item) {
      this.hoverNodeId = "";
    },
    submitForm() {
      // 提交新增或者编辑区域节点表单
      this.$refs.dialogForm.validate((valid) => {
        if (valid) {
          if (this.dialogForm.method == "add") {
            this.TreeDataPool.add(this.dialogForm.text, this.dialogForm.node);
          } else if (this.dialogForm.method == "edit") {
            this.TreeDataPool.update(
              this.dialogForm.text,
              this.dialogForm.node,
              this.gb28181 ? this.dialogForm.text : "",
              this.dialogForm.gb28181
            );
          }
        } else {
          return false;
        }
      });
      this.hideDialogBox();
    },
    hideDialogBox() {
      this.showDialog = false;
      this.dialogForm = { text: "" };
    },
    showDialogBox(event) {
      let { clientX = 0, offsetY = 0 } = event;
      // this.clientX = clientX - 120;
      this.clientX = 50;
      this.clientY = offsetY;
      this.showDialog = true;
    },
    itemClick(node, item, e) {
      console.log("jsTree index.vue", item);
      this.TreeDataPool.selectedNode = item;
      this.TreeDataPool.updateSelectedNodes();
      this.TreeDataPool.treeType = this.treeName;
    },
    itemToggle(node, item, e) {
      if (item.opened) {
        delete this.TreeDataPool.foldNodeList[item.id];
      } else {
        this.TreeDataPool.foldNodeList[item.id] = true;
      }
    },
    dropNode(node, item, draggedItem, e) {
      console.log("dropNode", node, item, draggedItem);
      this.TreeDataPool.dropNode(draggedItem.id, item.id);
    },
  },
};
</script>
<style lang="scss" scoped>
.dialog-box {
  position: absolute;
  width: 220px;
  z-index: 1;
}
.dialog-box-bg {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: rgba(255, 255, 255, 0.6);
}
.tree-item-handle {
  display: inline;
  font-size: 16px;
  margin-left: 6px;
  button {
    position: relative;
    color: #3d68e1;
    border: 0px;
    background-color: transparent;
    cursor: pointer;
    outline: none;
  }
  button:hover {
    color: #2249b4;
  }
  // button:hover:after {
  //   position: fixed;
  //   padding: 5px 10px;
  //   background-color: #00000090;
  //   border-radius: 0px;
  //   color: #fff;
  //   content: attr(labelTooltip);
  //   font-size: 12px;
  //   width: 55px;
  //   margin-left: -50px;
  //   margin-top: 25px;
  //   vertical-align: left;
  // }
}
.tree-name {
  font-family: PingFangSC-Medium;
  font-size: 13px;
  color: #222222;
  // max-width: 100px;
  line-height: 27px;
  margin-left: 4px;
  display: inline-block;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
  vertical-align: top;
}
.tree-menu {
  // max-width: 350px;
  overflow-x: hidden;
  overflow-y: hidden;
  margin-bottom: 4px;
}
.tree-menu::-webkit-scrollbar {
  /*滚动条整体样式*/
  width: 4px; /*高宽分别对应横竖滚动条的尺寸*/
  height: 4px;
}
.tree-menu::-webkit-scrollbar-thumb {
  /*滚动条里面小方块*/
  border-radius: 5px;
  -webkit-box-shadow: inset 0 0 5px rgba(157, 165, 183, 0);
  background: rgb(202, 201, 201);
}
.tree-menu::-webkit-scrollbar-track {
  /*滚动条里面轨道*/
  -webkit-box-shadow: inset 0 0 5px rgba(157, 165, 183, 0);
  border-radius: 0;
  background: rgb(235, 234, 234);
}
.tree-menu::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.4);
}
.tree-menu:hover {
  overflow-x: visible;
  overflow-y: auto;
  margin-bottom: 0px;
}
</style>