<template>
  <div
    v-loading="dataLoading"
    class="tree-side"
    element-loading-background="rgba(10 ,38 ,61, 0.9)"
  >
    <!-- tab选项 -->
    <el-tabs v-model="activeTab" :type="tabType" @tab-click="handleClick">
      <template v-if="tabList.length">
        <el-tab-pane
          v-for="(item, index) in tabList"
          :key="index"
          :label="item"
          :name="item + ''"
        ></el-tab-pane>
      </template>
      <!-- 筛选框 -->
      <div class="tree-header">
        <el-input
          v-model="filterText"
          clearable
          placeholder="请输入"
          prefix-icon="el-icon-search"
          size="medium"
        ></el-input>
        <div class="tree-button-group">
          <i
            v-if="expand"
            :class="[
              'expand-icon',
              'cqlt-icon',
              `cqlt-icon-${expandAll ? 'shouqi' : 'zhankai'}`,
            ]"
            :title="expandAll ? '收起' : '展开'"
            @click="expandHandle(!expandAll)"
          />
          <i
            v-if="$listeners['refresh']"
            :class="[
              'el-icon-refresh',
              refreshLading ? 'el-icon-refresh-loading' : '',
            ]"
            title="刷新"
            @click="refreshData"
          />
        </div>
      </div>
      <!-- 树形数据 -->
      <el-scrollbar>
        <el-tree
          ref="tree"
          :data="treeData"
          :default-expand-all="defaultExpandAll"
          :expand-on-click-node="false"
          :filter-node-method="filterNode"
          :highlight-current="true"
          :indent="treeIndent"
          :node-key="nodeKey"
          :props="defaultProps"
          class="filter-tree tree-content"
          v-bind="$attrs"
          v-on="$listeners"
          @current-change="currentChange"
        >
          <template #default="{node, data}">
            <div class="tree-item">
              <i
                v-if="!$attrs.customIcon"
                :class="[
                  'el-node-icon',
                  data.children ? 'el-icon-folder' : 'el-icon-tickets',
                ]"
              ></i>
              <template v-else>
                <slot :data="data" name="treeIcon"></slot>
              </template>
              <!--  -->
              <span
                :title="data[defaultProps.label]"
                class="custom-node-text"
                v-html="brightenKeyword(data[defaultProps.label], filterText)"
              >
                {{ data[defaultProps.label] }}
              </span>
              <el-dropdown
                v-if="isOperate"
                class="tree-drop"
                @command="handleCommand"
              >
                <i class="el-icon-more" title="更多操作" />
                <template v-slot:dropdown>
                  <el-dropdown-menu>
                    <!--  区分自定义第一级或其他层级  -->
                    <template v-if="data.id">
                      <el-dropdown-item
                        v-for="(item, index) in dropdownMenu"
                        :key="index"
                        :command="{
                          type: item.type,
                          dropdownItem: data,
                        }"
                        :disabled="!!btnDisableKey && !data[btnDisableKey]"
                        :divided="!!item.divided"
                        :icon="item.icon"
                      >
                        {{ item.type }}
                      </el-dropdown-item>
                    </template>
                    <template v-else>
                      <el-dropdown-item
                        :command="{
                          type: '新增',
                          dropdownItem: data,
                        }"
                        icon="el-icon-edit"
                      >
                        新增
                      </el-dropdown-item>
                    </template>
                  </el-dropdown-menu>
                </template>
              </el-dropdown>
            </div>
          </template>
        </el-tree>
      </el-scrollbar>
    </el-tabs>
  </div>
</template>

<script>
import {calcFontSize} from '@/utils/responsiveUtils'

export default {
  name: 'TreeSide', // 侧边树
  props: {
    expand: {type: Boolean, default: true},
    tabList: {type: Array, default: () => []},
    treeData: {type: Array, default: () => []},
    defaultProps: {
      type: Object,
      default: () => ({label: 'label', children: 'children'})
    },
    activeName: {type: String, default: ''},
    isOperate: {type: Boolean, default: false},
    dropdownMenu: {
      type: Array,
      default: () => [
        {icon: 'el-icon-edit', type: '新增'},
        {
          icon: 'el-icon-edit-outline',
          type: '编辑'
        },
        {icon: 'el-icon-delete', type: '删除'}
      ]
    },
    isDeselect: {type: Boolean, default: false},
    btnDisableKey: {type: String, default: ''},
    defaultExpandAll: {type: Boolean, default: false},
    dataLoading: {type: Boolean, default: false},
    tabType: {type: String, default: ''},
    nodeKey: {type: String, default: 'id'}
  },
  data() {
    return {
      filterText: '',
      activeTab: '',
      currentNode: {},
      expandAll: false,
      refreshLading: false,
      treeIndent: calcFontSize(14)
    }
  },
  watch: {
    filterText(val) {
      this.$refs.tree?.filter(val)
      this.$emit('filterChange', val)
    }
  },
  created() {
    this.expandAll = this.defaultExpandAll
  },
  mounted() {
    this.$root.$on('resize', this.treeIndentMonitoring)
    this.activeTab = this.activeName || this.tabList[0] || ''
  },
  methods: {
    handleClick() {
      this.filterText = ''
      this.$emit('tabChange', this.activeTab)
      this.$emit('update:activeName', this.activeTab)
    },
    filterNode(value, data) {
      if (!value) return true
      return data[this.defaultProps.label].indexOf(value) !== -1
    },
    currentChange(value, data) {
      if (
        this.currentNode[this.defaultProps.label] ===
        value[this.defaultProps.label]
      ) {
        if (this.isDeselect) return
        this.$refs.tree?.setCurrentKey(null)
        this.currentNode = {}
        this.$emit('currentChange', null, data, this.activeTab)
      } else {
        this.currentNode = value
        this.$emit('currentChange', value, data, this.activeTab)
      }
    },
    handleCommand(command) {
      const {type = '', dropdownItem = {}} = command
      this.$emit('operateEvent', type, dropdownItem)
    },
    setCurrentKey(key = '') {
      this.$refs.tree?.setCurrentKey(key)
    },
    treeIndentMonitoring() {
      this.treeIndent = calcFontSize(14)
    },
    expandHandle(type, level = -1) {
      this.expandAll = type
      this.expandNodes(this.$refs.tree.store.root, level, 0)
    },
    expandNodes(node, level, currentLevel) {
      if (level === -1) {
        node.expanded = this.expandAll
      } else {
        node.expanded = currentLevel <= level
      }
      for (let i = 0; i < node.childNodes.length; i++) {
        this.expandNodes(node.childNodes[i], level, currentLevel + 1)
      }
    },
    refreshData() {
      this.refreshLading = true
      const done = () => {
        this.refreshLading = false
      }
      this.$emit('refresh', done)
    },
    brightenKeyword(val, keyword) {
      const escapedKeyword = keyword
        .replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
        .trim()
      if (!escapedKeyword) return val
      const regex = new RegExp(escapedKeyword, 'gi')
      return val.replace(
        regex,
        (match) => `<span style="color: #f56c6c">${match}</span>`
      )
    }
  },
  beforeDestroy() {
    this.$root.$off('resize', this.treeIndentMonitoring)
  }
}
</script>

<style lang="scss" scoped>
@import '@/assets/css/element-variables';

::v-deep .el-scrollbar__wrap {
  overflow-x: hidden;
}

.tree-side {
  padding: 10px 16px;
  box-sizing: border-box;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  height: 100%;

  ::v-deep .el-tabs {
    display: flex;
    flex-direction: column;

    .el-tabs__item {
      font-size: 13.5px;
      padding: 0 10px;

      &:nth-child(2) {
        padding: 0 10px 0 0;
      }
    }

    .el-tabs__content {
      display: flex;
      flex-direction: column;
      row-gap: 20px;

      .el-tab-pane {
        display: none;
      }

      .el-scrollbar {
        height: 0;
        flex: 1;

        .el-tree {
          background: transparent;

          &.tree-content {
            border: none;
          }
        }
      }
    }
  }

  .tree-header {
    display: flex;
    column-gap: 12px;
    align-items: center;

    .el-input {
      flex: 1;
    }

    .tree-button-group {
      display: flex;
      align-items: center;
      height: 100%;
      column-gap: 10px;

      .el-icon-refresh {
        font-weight: bold;
        font-size: 18px;
        margin-top: 2px;

        &.el-icon-refresh-loading {
          animation: rotate 1.5s linear infinite;
          -webkit-animation: rotate 1.5s linear infinite;

          @keyframes rotate {
            0% {
              transform: rotate(0);
            }
            25% {
              transform: rotate(90deg);
            }
            50% {
              transform: rotate(180deg);
            }
            75% {
              transform: rotate(270deg);
            }
            100% {
              transform: rotate(360deg);
            }
          }
        }
      }

      .expand-icon {
        transform: rotate(45deg);
        font-size: 13px;

        &.cqlt-icon-zhankai {
          transform: rotate(45deg) scale(1.25);
        }
      }

      i {
        cursor: pointer;
        font-size: 16px;
        color: $--color-text-placeholder;

        &:hover {
          color: $--system-hover-active-text;
        }
      }
    }
  }
}

.tree-item {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: start;
}

::v-deep .el-tree-node__content {
  height: 28px;

  &:hover {
    background-color: $--system-box-color5;
  }
}

::v-deep .custom-node-text {
  font-size: 14px;
  margin-left: 5px;
  display: inline-block;
  width: calc(100% - 34px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  vertical-align: middle;

  span {
    font-size: 14px;
  }
}

::v-deep
.el-tree--highlight-current
.el-tree-node.is-current
> .el-tree-node__content {
  background: $--system-box-color3;

  .el-icon-tickets,
  .custom-node-text {
    color: $--system-hover-active-text;
  }
}

::v-deep .el-tree-node:focus > .el-tree-node__content {
  background-color: transparent;
}

::v-deep .el-input__inner {
  font-size: 14px;
}

.el-icon-folder,
.el-icon-tickets {
  width: 14px;
}

.el-icon-more {
  font-size: 14px;
  transform: rotate(90deg);
  height: 25px;
  color: $--color-text-placeholder;
}

::v-deep .el-tree-node__content .tree-item .el-dropdown {
  left: -18px;
}

::v-deep .el-dropdown-menu__item {
  height: 28px;
  display: flex;
  justify-content: center;
  align-items: center;

  div {
    font-size: 14px;
  }
}

::v-deep .el-dropdown-menu__item--divided {
  display: block;
  min-height: 35px;
  line-height: 28px;
  text-align: center;
}

.el-node-icon,
::v-deep .el-icon-search {
  font-size: 15px;
}

::v-deep .el-node-icon {
  color: $--color-text-placeholder;
}
</style>
