<!--
 * @pageName: 'tree-grid  树型表格'
 * @events  @on-row-click 单击行或者单击操作按钮方法
            @on-selection-change  多选模式下 选中项变化时触发
            @on-sort-change  排序时有效，当点击排序时触发
   @props   items 显示的结构化数据
            columns 表格列的配置描述 sortable:true 开启排序功能
            type: 'selection'为多选功能 type: 'action' 为操作功能 actions:[{}] 操作按钮
 -->
<template>
  <div class='tree-grid-table'>
    <table class="tree-table table-bordered" id='hl-tree-table'>
      <thead>
      <tr>
        <th v-for="(column,index) in cloneColumns" :key="index">
          <label style="text-align: center;" v-if="column.type === 'selection'">
            <!--            <input type="checkbox" v-model="checks" @click="handleCheckAll">-->
          </label>
          <label v-else>
            {{ renderHeader(column, index) }}
            <!--            当前列可以排序-->
            <!--            <span class="ivu-table-sort" v-if="column.sortable">-->
            <!--              <Icon type="md-arrow-dropup" :class="{on: column._sortType === 'asc'}" @click.native="handleSort(index, 'asc')" />-->
            <!--              <Icon type="md-arrow-dropdown" :class="{on: column._sortType === 'desc'}" @click.native="handleSort(index, 'desc')" />-->
            <!--            </span>-->
          </label>
        </th>
      </tr>
      </thead>
      <tbody>
      <tr v-for="(item,index) in initItems" v-show="item.isShow == true || item.level == 1" :class="{'child-tr': item.level == 2, 'child-tr2': item.level == 3,'child-tr3': item.level == 4}">
        <td style="text-align: left;" v-for="(column,snum) in columns">
          <label v-if="column.type === 'selection'">
            <Checkbox v-model="item.isChecked" @on-change="(event) => handleCheckClick(event, item)"></Checkbox>
          </label>
          <p @click="toggle(index,item)">
                        <span v-if='snum==iconRow()'>
                            <span v-if="item.children && item.children.length >0">
                                <Icon  v-if="item.expanded" type="ios-remove-circle-outline" />
                                <Icon  v-else type="ios-add-circle-outline" />
                            </span>
                        </span>
            {{renderBody(item,column) }}
          </p>
        </td>
      </tr>
      </tbody>
    </table>
  </div>
</template>
<script>
  export default {
    name: 'treeGrid',
    props: {
      columns: Array,
      items: {
        type: Array,
        default: function() {
          return [];
        }
      },
      // 是否正在加载,为false 则会显示错误信息（如果加载时间较长，最好设置为true,数据返回后设置为false）
      isLoading: {
        type: Boolean,
        default: false
      },
      loadingContent: {
        type: String,
        default: '<span><i class="v-icon-spin5 animate-loading-23" style="font-size: 28px;opacity:0.6;"></i></span>'
      },
      loadingOpacity: {
        type: Number,
        default: 0.6
      },
    },
    data() {
      return {
        // 选中数据
        dataList: [],
        initItems: [], //处理后数据数组
        cloneColumns: [], //处理后的表头数据
        checkGroup: [], //复选框数组
        checks: false, //全选
        screenWidth: document.body.clientWidth, //自适应宽
        tdsWidth: 0, //td总宽
        timer: false, //控制监听时长
        dataLength: 0, //树形数据长度
      }
    },
    computed: {
      tableWidth() {
        return this.tdsWidth > this.screenWidth && this.screenWidth > 0 ? this.screenWidth + 'px' : '100%'
      }
    },
    watch: {
      screenWidth(val) {
        if (!this.timer) {
          this.screenWidth = val
          this.timer = true
          setTimeout(() => {
            this.timer = false
          }, 400)
        }
      },
      'items': {
        handler: function (newVal) {
          if (newVal) {
            this.initItems = this.initData(newVal, 1 )
            this.dataList = []
          }
        },
        deep: true
      },
      columns: {
        handler() {
          this.cloneColumns = this.makeColumns();
        },
        deep: true
      },
      checkGroup(data) {
        this.checkAllGroupChange(data)
      },
    },
    mounted() {
      if (this.items) {
        this.dataLength = this.Length(this.items)
        this.initItems = this.initData(this.items, 1);
        this.cloneColumns = this.makeColumns();
        this.checkGroup = this.renderCheck(this.items)
        if (this.checkGroup.length == this.dataLength) {
          this.checks = true
        } else {
          this.checks = false
        }
      }
    },
    methods: {
      // 有无多选框折叠位置优化
      iconRow() {
        for (var i = 0, len = this.columns.length; i < len; i++) {
          if (this.columns[i].type == 'selection') {
            return 1
          }
        }
        return 0
      },
      // 设置td宽度,td的align
      tdStyle(column) {
        var style = {}
        if (column.align) {
          style["text-align"] = column.align;
        }
        if (column.width) {
          style["min-width"] = column.width + 'px';
        }
        return style;
      },
      // 处理tree-table 返回数据
      translateDataToTree(data) {
        //没有父节点的数据
        let parents = data.filter(value =>  value.parent_guid == 0 || value.parent_guid == null)

        //有父节点的数据
        let children = data.filter(value => value.parent_guid !== 0 && value.parent_guid != null)

        //定义转换方法的具体实现
        let translator = (parents, children) => {
          //遍历父节点数据
          parents.forEach((parent) => {
            //遍历子节点数据
            children.forEach((current, index) => {
              //此时找到父节点对应的一个子节点
              if (current.parent_guid == parent.guid) {
                //对子节点数据进行深复制，这里只支持部分类型的数据深复制，对深复制不了解的童靴可以先去了解下深复制
                let temp = JSON.parse(JSON.stringify(children))
                //让当前子节点从temp中移除，temp作为新的子节点数据，这里是为了让递归时，子节点的遍历次数更少，如果父子关系的层级越多，越有利
                temp.splice(index, 1)
                //让当前子节点作为唯一的父节点，去递归查找其对应的子节点
                translator([current], temp)
                //把找到子节点放入父节点的children属性中
                typeof parent.children !== 'undefined' ? parent.children.push(current) : parent.children = [current]
              }
            })
          })
        }
        //调用转换方法
        translator(parents, children)
        //返回最终的结果
        return parents
      },
      // 排序事件
      handleSort(index, type) {
        this.cloneColumns.forEach((col) => col._sortType = 'normal');
        if (this.cloneColumns[index]._sortType === type) {
          this.cloneColumns[index]._sortType = 'normal'
        } else {
          this.cloneColumns[index]._sortType = type
        }
        this.$emit('on-sort-change', this.cloneColumns[index]['key'], this.cloneColumns[index]['_sortType'])
      },
      // 点击某一行事件
      RowClick(data) {
        let result = this.makeData(data)
        this.$emit('on-row-click',data)
      },
      // 点击事件 返回数据处理
      makeData(data) {
        const t = this.type(data);
        let o;
        if (t === 'array') {
          o = [];
        } else if (t === 'object') {
          o = {};
        } else {
          return data;
        }

        if (t === 'array') {
          for (let i = 0; i < data.length; i++) {
            o.push(this.makeData(data[i]));
          }
        } else if (t === 'object') {
          for (let i in data) {
            if ( i != 'parent' && i != 'level' && i != 'expanded' && i != 'isShow' && i != 'load') {
              o[i] = this.makeData(data[i]);
            }
          }
        }
        return o;
      },
      // 处理表头数据
      makeColumns() {
        let columns = this.deepCopy(this.columns);
        columns.map((column, index) => {
          column.key = column.code
          column._index = index;
          column._width = column.width ? column.width : '';
          column._sortType = 'normal';
        });
        return columns;
      },
      // 数据处理 增加自定义属性监听
      initData(items, level) {
        return items.map((item, index) => {
          item = Object.assign({}, item, {
            "level": level
          });
          item = Object.assign({}, item, {
            "load": (item.expanded ? true : false)
          });
          if(item.children && item.children.length > 0) {
            item.children = this.initData(item.children, level + 1);
          }
          return item
        })
      },
      //  隐藏显示
      show(item) {
        return ((item.level == 1) || (item.isShow && item.load));
      },
      toggle(index, item) {
        let level = item.level + 1;
        if (item.children) {
          if (item.expanded) {
            item.expanded = !item.expanded;
            this.close(index, item);
          } else {
            item.expanded = !item.expanded;
            if (item.load) {
              this.open(index, item);
            } else {
              item.load = true;
              item.children.forEach((child, childIndex) => {
                this.initItems.splice((index + childIndex + 1), 0, child);
                //设置监听属性
                // this.$set(this.initItems[index + childIndex + 1], 'parent', item);
                this.$set(this.initItems[index + childIndex + 1], 'level', level);
                // this.$set(this.initItems[index + childIndex + 1], 'spaceHtml', spaceHtml);
                this.$set(this.initItems[index + childIndex + 1], 'isShow', true);
                this.$set(this.initItems[index + childIndex + 1], 'expanded', false);
              })
            }
          }
        }
      },
      open(index, item) {
        if (item.children) {
          item.children.forEach((child, childIndex) => {
            child.isShow = true;
            if (child.children && child.expanded) {
              this.open(index + childIndex + 1, child);
            }
          })
        }
      },
      close(index, item) {
        if (item.children) {
          item.children.forEach((child, childIndex) => {
            child.isShow = false;
            child.expanded = false;
            if (child.children && child.expanded) {
              this.close(index + childIndex + 1, child);
            }
          })
        }
      },
      //点击check勾选框
      handleCheckClick(event,data){
        data.isChecked = event
        if(data.isChecked == true) {
          this.dataList.push(data)
        } else {
          this.dataList.forEach((val,index) => {
            if(val.guid == data.guid) {
              this.dataList.splice(index, 1)
            }
          })
        }
        console.log(this.dataList, '')
        this.$emit('on-selection-change',this.dataList, this.columns[0])
        //判断是否有children节点 如果有就一并勾选
        // var arr = data.children;
        // if(arr){
        //   if(data.isChecked){
        //     this.checkGroup.push(data.guid);
        //     for (let i=0; i<arr.length; i++){
        //       this.checkGroup.push(arr[i].guid)
        //     }
        //   }else {
        //     for (var i=0; i<this.checkGroup.length; i++){
        //       if(this.checkGroup[i] == data.guid){
        //         this.checkGroup.splice(i,1)
        //       }
        //       for (var j=0; j<arr.length; j++){
        //         if(this.checkGroup[i] == arr[j].guid){
        //           this.checkGroup.splice(i,1);
        //         }
        //       }
        //     }
        //   }
        // }
      },
      //checkbox 全选 选择事件
      handleCheckAll() {
        this.checks = !this.checks;
        if (this.checks) {
          this.checkGroup = this.getArray(this.checkGroup.concat(this.All(this.items)))
        } else {
          this.checkGroup = []
        }
        // this.$emit('on-selection-change', this.checkGroup)
      },
      // 数组去重
      getArray(a) {
        var hash = {},
          len = a.length,
          result = [];
        for (var i = 0; i < len; i++) {
          if (!hash[a[i]]) {
            hash[a[i]] = true;
            result.push(a[i]);
          }
        }
        return result;
      },
      checkAllGroupChange(data) {
        if (this.dataLength > 0 && data.length === this.dataLength) {
          this.checks = true;
        } else {
          this.checks = false;
        }
        // this.$emit('on-selection-change', this.checkGroup)
      },
      All(data) {
        let arr = []
        data.forEach((item) => {
          arr.push(item.id)
          if (item.children && item.children.length > 0) {
            arr = arr.concat(this.All(item.children));
          }
        })
        return arr
      },
      // 返回树形数据长度
      Length(data) {
        let length = data.length
        data.forEach((child) => {
          if (child.children) {
            length += this.Length(child.children)
          }
        })
        return length;
      },
      // 返回表头
      renderHeader(column, $index) {
        if ('renderHeader' in this.columns[$index]) {
          return this.columns[$index].renderHeader(column, $index);
        } else {
          return column.title || '#';
        }
      },

      // 返回内容
      renderBody(row, column, index) {
        return row[column.code]
      },
      // 默认选中
      renderCheck(data) {
        let arr = []
        data.forEach((item) => {
          if (item._checked) {
            arr.push(item.id)
          }
          if (item.children && item.children.length > 0) {
            arr = arr.concat(this.renderCheck(item.children));
          }
        })
        return arr
      },
      // 深度拷贝函数
      deepCopy(data) {
        var t = this.type(data),
          o, i, ni;
        if (t === 'array') {
          o = [];
        } else if (t === 'object') {
          o = {};
        } else {
          return data;
        }
        if (t === 'array') {
          for (i = 0, ni = data.length; i < ni; i++) {
            o.push(this.deepCopy(data[i]));
          }
          return o;
        } else if (t === 'object') {
          for (i in data) {
            o[i] = this.deepCopy(data[i]);
          }
          return o;
        }

      },
      type(obj) {
        var toString = Object.prototype.toString;
        var map = {
          '[object Boolean]': 'boolean',
          '[object Number]': 'number',
          '[object String]': 'string',
          '[object Function]': 'function',
          '[object Array]': 'array',
          '[object Date]': 'date',
          '[object RegExp]': 'regExp',
          '[object Undefined]': 'undefined',
          '[object Null]': 'null',
          '[object Object]': 'object'
        };
        return map[toString.call(obj)];
      }
    },
    beforeDestroy() {
      // window.onresize = null
    }
  }
</script>
<style scoped lang="less">
  .tree-grid-table {
    overflow: auto;
    width: 50%;
    .tree-table {
      width: 100%;
      border-spacing: 0;
      border-collapse: collapse;
    }

    .table-bordered {
      border: 1px solid #EBEBEB;
    }

    .tree-table>tbody>tr>td,
    .tree-table>tbody>tr>th,
    .tree-table>thead>tr>td,
    .tree-table>thead>tr>th {
      font-size: 14px;
      border-top: 1px solid #e7eaec;
      line-height: 1.42857;
      padding: 8px 20px;
      vertical-align: middle;
    }

    .table-bordered>tbody>tr>td,
    .table-bordered>tbody>tr>th,
    .table-bordered>tfoot>tr>td,
    .table-bordered>tfoot>tr>th,
    .table-bordered>thead>tr>td,
    .table-bordered>thead>tr>th {
      border: 1px solid #e7e7e7;
    }
    .tree-table>thead>tr>th {
      border-bottom: 1px solid #DDD;
    }
    .tree-table>tbody>tr>td:first-child{
      width: 30px;
    }
    .table-bordered>thead>tr>td,
    .table-bordered>thead>tr>th {
      background-color: #F5F5F6;
    }
    .child-tr>td{
      padding-left: 40px !important;
    }
    .child-tr>td:first-child{
      padding-left: 20px !important;
    }
    .child-tr2>td{
      padding-left: 60px !important;
    }
    .child-tr2>td:first-child{
      padding-left: 20px !important;
    }
    .child-tr3>td{
      padding-left: 80px !important;
    }
    .child-tr3>td:first-child{
      padding-left: 20px !important;
    }
    #hl-tree-table>tbody>tr {
      background-color: #fbfbfb;
    }

    #hl-tree-table>tbody>.child-tr {
      background-color: #fff;
    }

    .ms-tree-space {
      position: relative;
      top: 1px;
      display: inline-block;
      font-style: normal;
      font-weight: 400;
      line-height: 1;
      width: 14px;
      height: 14px;
    }

    .ms-tree-space::before {
      content: ""
    }

    #hl-tree-table th>label {
      margin: 0;
    }
  }
</style>
