// 树形下拉框
<template>
  <div class="sp-tree-select" :style="{ width: width }">
    <!-- 选中框区 -->
    <el-popover
      v-model="options_show"
      placement="bottom"
      :width="width"
      :trigger="trigger"
      :disabled="disabled"
      transition="fade-in"
    >
      <el-scrollbar class="sp-treeselect-popover">
        <el-input
          v-if="filterable"
          v-model="filterText"
          :size="size"
          placeholder="请输入关键词"
        ></el-input>
        <el-tree
          ref="tree-select"
          class="sp-options-tree"
          highlight-current
          :data="selfData"
          :props="selfProps"
          :node-key="nodeKey"
          :show-checkbox="checkbox"
          :expand-on-click-node="false"
          :filter-node-method="filterNode"
          :default-checked-keys="checked_keys"
          :default-expand-all="defaultExpandAll"
          :default-expanded-keys="defaultExpandedKeys"
          @check="handleCheckChange"
          @node-click="treeItemClick"
        ></el-tree>
      </el-scrollbar>
      <!---->
      <div
        slot="reference"
        class="selected-box"
        :class="[{ 'sp-disabled': disabled, 'no-wrap': nowrap }, sizeClass]"
      >
        <div class="tag-box">
          <div v-show="selecteds.length > 0">
            <template v-if="!collapseTags">
              <el-tag
                v-for="item in selecteds"
                :key="item[nodeKey]"
                closable
                :size="size"
                class="sp-select-tag"
                :title="item[selfProps.label]"
                @close="tabClose(item[nodeKey])"
              >{{ item[selfProps.label] }}</el-tag
              >
            </template>
            <template v-else>
              <el-tag
                closable
                :size="size"
                class="sp-select-tag"
                :title="collapseTagsItem[selfProps.label]"
                @close="tabClose(collapseTagsItem[nodeKey])"
              >{{ collapseTagsItem[selfProps.label] }}</el-tag
              >
              <el-tag
                v-if="selecteds.length > 1"
                :size="size"
                class="sp-select-tag"
              >+{{ selecteds.length - 1 }}</el-tag
              >
            </template>
          </div>
          <p v-show="selecteds.length == 0" class="sp-placeholder-box">
            {{ placeholder }}
          </p>
        </div>
        <div class="icon-box">
          <transition name="fade-rotate" mode="out-in">
            <i v-if="!options_show" key="top" class="el-icon-arrow-down"></i>
            <i v-else key="btm" class="el-icon-arrow-up"></i>
          </transition>
        </div>
      </div>
    </el-popover>
  </div>
</template>

<script>
/**
 * https://github.com/hql7/wl-vue-select
 */
export default {
  name: 'WlTreeSelect',
  model: {
    prop: 'value', //这里使我们定义的v-model属性
    event: 'change'
  },
  props: {
    // 数据
    data: {
      type: Array,
      default: () => []
    },
    // 树结构配置
    props: {
      type: Object,
      default: () => {
        return {};
      }
    },
    // node-key
    nodeKey: {
      type: String,
      default: 'id'
    },
    // 选中数据
    value: {
      type: [String, Number, Array, Object],
      default: undefined
    },
    // 是否可多选
    checkbox: {
      type: Boolean,
      default: false
    },
    // 多选时是否将选中值按文字的形式展示
    collapseTags: {
      type: Boolean,
      default: false
    },
    // 是否只可选叶子节点
    leaf: {
      type: Boolean,
      default: false
    },
    // 宽度
    width: {
      type: String,
      default: 'auto'
    },
    // 触发方式 click/focus/hover/manual
    trigger: {
      type: String,
      default: 'click'
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // 是否允许多行显示
    nowrap: {
      type: Boolean,
      default: false
    },
    // 多选时，清空选项关闭
    noCheckedClose: {
      type: Boolean,
      default: false
    },
    placeholder: {
      type: String,
      default: '请选择'
    },
    size: {
      type: String,
      default: 'medium'
    },
    //是否展开全部
    defaultExpandAll: {
      type: Boolean,
      default: true
    },
    //默认展开的节点的 key 的数组
    defaultExpandedKeys: {
      type: Array,
      default: () => {
        return [];
      }
    },
    // 是否使用搜索
    filterable: {
      type: Boolean,
      default: false
    },
    // 自定义筛选函数
    filterFnc: {
      type: Function,
      default: undefined
    }
  },
  data() {
    return {
      selecteds: [], // 选中数据
      options_show: false, // 是否显示下拉选项
      checked_keys: [], // 默认选中
      guid: '00000000-0000-0000-0000-000000000000',
      filterText: ''
    };
  },
  computed: {
    selfData() {
      return this.data;
    },
    selfProps() {
      return {
        label: 'label',
        children: 'children',
        disabled: data => {
          return data.disabled;
        },
        ...this.props
      };
    },
    sizeClass() {
      let size_class = 'size-medium';
      switch (this.size) {
      case 'medium':
        size_class = 'size-medium';
        break;
      case 'small':
        size_class = 'size-small';
        break;
      case 'default':
        size_class = 'size-default';
        break;
      case 'mini':
        size_class = 'size-mini';
        break;
      default:
        size_class = 'size-medium';
        break;
      }
      return size_class;
    },
    // 开启collapseTags时首个选中值
    collapseTagsItem() {
      return this.selecteds[0] || {};
    }
  },
  watch: {
    value(val) {
      this.checkDefaultValue();
    },
    // 树节点搜索
    filterText(val) {
      this.$refs['tree-select'].filter(val);
    }
  },
  created() {
    this.checkDefaultValue();
  },
  methods: {
    // 树节点-checkbox选中
    handleCheckChange(val, { checkedNodes, checkedKeys }) {
      let nodes = this.$refs['tree-select'].getCheckedNodes(this.leaf);
      this.selecteds = nodes;
      this.$emit('change', nodes);
      if (checkedKeys.length === 0 && this.noCheckedClose)
        this.options_show = false;
    },
    // 树节点-点击选中
    treeItemClick(item, node) {
      if (this.checkbox || (this.leaf && !node.isLeaf)) {
        return;
      }
      this.selecteds = [item];
      this.options_show = false;
      this.$emit('change', this.selecteds);
    },
    // tag标签关闭
    tabClose(Id) {
      if (this.disabled) return;
      if (this.checkbox) {
        this.$refs['tree-select'].setChecked(Id, false, true);
        this.selecteds = this.$refs['tree-select'].getCheckedNodes();
        if (this.selecteds.length === 0 && this.noCheckedClose)
          this.options_show = false;
      } else {
        this.selecteds = [];
        this.$refs['tree-select'].setCurrentKey(null);
        this.options_show = false;
      }
      this.$emit('change', this.selecteds);
    },
    // 清空数据
    clear() {
      this.selecteds = [];
    },
    // 处理默认选中数据
    checkDefaultValue() {
      let val = this.value;
      if (!val || (Array.isArray(val) && val.length === 0)) {
        this.selecteds = [];
        if (!this.checkbox) return;
        this.checked_keys = [];
        this.$nextTick(() => {
          this.$refs['tree-select'].setCheckedKeys([]);
        });
        return;
      }
      // 多选处理
      if (this.checkbox) {
        this.checked_keys =
          typeof val[0] === 'object' ? val.map(i => i[this.nodeKey]) : val;
        this.$nextTick(() => {
          this.selecteds = this.$refs['tree-select'].getCheckedNodes(this.leaf);
        });
        return;
      }
      // 单选处理
      if (typeof val === 'object') {
        let _val = Array.isArray(val) ? val[0] : val;
        this.selecteds = [_val];
        this.$nextTick(() => {
          this.$refs['tree-select'].setCurrentNode(_val);
        });
      } else {
        this.$nextTick(() => {
          this.$refs['tree-select'].setCurrentKey(val);
          let _node = this.$refs['tree-select'].getCurrentNode();
          this.selecteds = _node ? [_node] : [];
        });
      }
    },
    // 关闭
    closeOptions() {
      this.options_show = false;
    },
    // 树节点筛选
    filterNode(value, data) {
      if (this.filterFnc) return this.filterFnc(value, data);
      if (!value) return true;
      return data[this.selfProps.label].indexOf(value) !== -1;
    }
  }
};
</script>

<style lang="scss">
.sp-tree-select {
  position: relative;
  display: inline-block;
  width: 240px;
  vertical-align: middle;
  outline: none;
  .selected-box {
    display: flex;
    border: 1px solid #dcdfe6;
    padding: 0 5px 0 8px;
    width: 100%;
    min-height: 36px;
    line-height: 34px;
    box-sizing: border-box;
    border-radius: 4px;
    cursor: pointer;
    outline: none;
    &:focus {
      border-color: #409eff;
    }
    > .tag-box {
      display: inline-block;
      width: calc(100% - 20px);
      text-align: left;
    }
    > .icon-box {
      float: right;
      display: flex;
      width: 20px;
      justify-content: center;
      align-items: Center;
      color: #c0c4cc;
    }
  }
  .selected-box.size-small {
    min-height: 32px;
    line-height: 30px;
  }
  .selected-box.size-mini {
    min-height: 28px;
    line-height: 26px;
  }
  .selected-box.size-default {
    min-height: 40px;
    line-height: 38px;
  }
  .no-wrap {
    height: 36px;
    > .tag-box {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }
  .sp-disabled {
    background: #eee;
    cursor: no-drop;
    &:focus {
      border-color: #dcdfe6;
    }
    .el-tag__close {
      cursor: no-drop;
    }
  }
  .sp-select-tag {
    max-width: 100%;
    text-overflow: ellipsis;
    overflow: hidden;
    word-wrap: break-word;
    word-break: break-all;
    vertical-align: middle;
  }
  .sp-select-tag + .sp-select-tag {
    margin-left: 4px;
  }
}
.sp-treeselect-popover {
  height: 360px;
  > .el-scrollbar__wrap {
    overflow-x: hidden;
  }
}
.sp-options-tree {
  display: inline-block !important;
  min-width: 100%;
  .el-tree-node__content {
    height: 34px;
    line-height: 34px;
  }
}
.sp-placeholder-box {
  color: #c0c4cc;
  margin: 0;
}
// 过度效果
.fade-in-enter-active,
.fade-in-leave-active {
  transition: all 0.4s;
}
.fade-in-enter, .fade-in-leave-to /* .fade-leave-active below version 2.1.8 */ {
  opacity: 0;
  transform: translateY(-10px);
}
.fade-rotate-enter-active,
.fade-rotate-leave-active {
  transition: all 0.2s;
}
.fade-rotate-enter, .fade-rotate-leave-to /* .fade-leave-active below version 2.1.8 */ {
  transform: rotateZ(45deg);
}
</style>
