<!--多选下拉树-->
<!--默认 checkStrictly:true,checkWeakly:false 实现父与子完全不联动-->
<!--checkStrictly:false实现父与子完全强联动，有子才有父，饿了么ui默认效果-->
<!--checkStrictly:true,checkWeakly:true 实现父与子完全弱联动，处理父子关系，子取消不影响父，弗取消要取消子，子选中要选中所有父，父选中不影响子-->
<template>
  <el-popover placement="bottom-start" width="315" @hide="popoverHide" trigger="click" v-model="isShowSelect" class="select-tree"   :disabled="disabled">
    <el-input
      placeholder="输入关键字进行过滤"
      v-model="filterText">
    </el-input>
    <el-tree
      style="height:300px;overflow-y: scroll;margin-top:10px;"
      v-show="isShowSelect"
      :data="treeData"
      :node-key="nodeKey"
      :show-checkbox="multiple"
      :expand-on-click-node="multiple"
      :default-expanded-keys="defaultExpandedKeys"
      :default-checked-keys="defaultCheckedKeys"
      :default-expand-all="defaultExpandAll"
      :check-strictly="checkStrictly"
      highlight-current
      @check="getKeys"
      :props="defaultProps"
      :filter-node-method="filterNode"
      ref="tree"
      :render-content="renderContent"
    ></el-tree>
    <template slot="reference" >
      <el-select :class="'select-tree '+className" ref="select" v-model="selectedIdArr" :clearable="false" :multiple="multiple" :placeholder="tipText"   :disabled="disabled" >
        <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
      </el-select>
    </template>
  </el-popover>
</template>
<script>
  import { isNull  } from '@/utils/util'
  export default {
    props: {
      //　是否默认展开所有
      className: {
        type: String,
        default: ''
      },
      //　是否默认展开所有
      disabled: {
        type: Boolean,
        default: false
      },
      // 是否取消强关联
      checkStrictly:{
        type: Boolean,
        default: true
      },
      // 弱关联
      checkWeakly:{
        type: Boolean,
        default: false
      },
      //　下拉树的数据
      treeData: {
        type: Array,
        required: true,
        default: ()=>[] },
      //　是否默认展开所有
      defaultExpandAll: {
        type: Boolean,
        default: false
      },
      //　下拉菜单隐藏回调
      popoverHide: {
        type: Function,
        default: function () { }
      },
      //　已选
      selectedId: {
        type: Array,
        default: ()=>[]
      },
      //　作为下拉树节点ｋｅｙ的属性
      nodeKey: { type: String, default: 'id' },
      //　默认提示信息
      tipText: { type: String, default: '请选择' }
    },
    data () {
      return {
        //　设定当前为多选
        multiple: true,
        //　过滤树的参数
        filterText: '',
        // 是否显示树状选择器
        isShowSelect: false,
        //　ｓｅｌｅｃｔ组件的ｏｐｔｉｏｎ
        options: [],
        //　默认展开的节点
        defaultExpandedKeys: [],
        //　默认选中的节点
        defaultCheckedKeys: [],
        //　树组件默认参数
        defaultProps: {
          children: 'children',
          label: 'name'
        },
        //　树组件返回的选中结果集
        treeValue:[]
      }
    },
    computed: {
      selectedIdArr: {
        // getter
        get: function(){
          return [...this.selectedId]
        },
        // setter
        set: function (newValue) {
        }
      }
    },
    watch: {
      treeData(val){
        this.$nextTick(function(){
          this.setTreeCheckNode(this.selectedIdArr)
        })
      },
      selectedId(val){
        this.$nextTick(function(){
          this.setTreeCheckNode(this.selectedIdArr)
        })
      },
      // 切换下拉框显隐
      isShowSelect (val) {
        // 隐藏select自带的下拉框
        this.$refs.select.blur()
        if (val) {
          // 下拉面板展开-选中节点-展开节点
          this.setTreeCheckNode(this.selectedIdArr)
          this.defaultCheckedKeys = this.selectedIdArr
          this.defaultExpandedKeys = this.selectedIdArr
        }
      },
      // 树组件的check事件触发后把选中值更新到这里
      treeValue (val) {
        console.log(val)
        this.$emit('update:selectedId', val)
      },
      filterText(val) {
        this.$refs.tree.filter(val);
      }
    },
    mounted () {
    },
    methods: {
      // 修改节点文本，自定义图标，return内是jsx语法
      renderContent(h, { node, data, store }) {
        return (
          <span>
          <i class={data.className||''}></i>
        <span>{node.label}</span>
        </span>
      );
      },
      // 树筛选
      filterNode(value, data) {
        if (!value) return true;
        return data[this.defaultProps.label].indexOf(value) !== -1;
      },
      // 树复选框勾选时，触发该方法，更新本地选中值treeValue及select组件的option
      getKeys (data, checked) {

        if(!this.checkStrictly || !this.checkWeakly){
          this.treeValue=[...this.$refs.tree.getCheckedKeys()]
        }else{
          this.weakCheck(data, checked)
        }

        // 多选
        let checkedNodes=this.$refs.tree.getCheckedNodes()
        let tmp = []
        checkedNodes.forEach(node => {
          let tmpMap = {}
          tmpMap.value = node.id
          tmpMap.label = node[this.defaultProps.label]
          tmp.push(tmpMap)
        })
        this.options = tmp
      },
      // 通过遍历数内选中节点，初始化select组件的option
      setTreeCheckNode (ids) {
        this.options=[]
        ids.forEach(id => {
          this.findTreeNode(this.treeData, id)
        })
        this.$forceUpdate()
      },
      // 递归查询树形节点
      findTreeNode (tree, id) {
        if ((!isNull(tree)) && (!isNull(id))) {
          for (var i = 0; i < tree.length; i++) {
            if (tree[i].id === id) {
              this.options.push({
                label:tree[i][this.defaultProps.label],
                value:tree[i].id
              })
            } else if (tree[i].children != null && tree[i].children.length > 0) {
              this.findTreeNode(tree[i].children, id)
            }
          }
        }
      },


      // 非强关联下，处理父子关系，子取消不影响父，弗取消要取消子，子选中要选中所有父，父选中不影响子
      weakCheck(data, checked){
        let currentId=data.id
        let currentChecked=checked.checkedKeys
        let currentNode=this.$refs.tree.getNode(data)

        if(currentChecked.indexOf(currentId)>=0){
          //  此处为选中某个节点
          //  需同步勾选该节点的全部父节点
          this.parentNodesChange(currentNode);
        }else{
          //  此处为取消某个节点
          //  需同步取消该节点下的全部子节点
          this.childNodesChange(currentNode);
        }

        this.treeValue=[...this.$refs.tree.getCheckedKeys()]
      },
      childNodesChange(node){
        let len = node.childNodes.length;
        for(let i = 0; i < len; i++){
          node.childNodes[i].checked = false;
          this.childNodesChange(node.childNodes[i]);
        }
      },
      parentNodesChange(node){
        if(node.parent){
          for(let key in node){
            if(key == "parent"){
              node[key].checked = true;
              this.parentNodesChange(node[key]);
            }
          }
        }
      },
    }
  }
</script>
<style>
  .select-tree .el-select .el-tag__close.el-icon-close{
    display: none;
  }
</style>
