<!--
 * @Descripttion:
 * @Version: 1.0
 * @Author: +C
 * @Date: 2022-02-15 08:47:06
 * @remark: 自定义属性: auto-col-width 是否自适应宽度(默认true) auto-fixed 是否自动操作列固定右侧(默认true)
 * @LastEditors: wufz
 * @LastEditTime: 2022-06-21 14:36:47
-->
<script>
import XEUtils from 'xe-utils'
export default {
  name: `DxxTable`,
  // functional: true, //函数式组件
  inheritAttrs: false, //禁止attrs的属性作为普通的 HTML attribute 应用在子组件的根元素上
  props: ['showOverflow', 'align', 'border', 'highlightHoverRow', 'headerRowClassName', 'headerCellClassName', 'stripe', 'autoResize', 'data'],
  data() {
    return {
      //窄列的判定宽度(px)
      shortWidth: 112,
      //单元格左右间隔和(px)
      cellPadding: 70,
      //自动居左的宽度标准(px)
      alignLeftWidth: 156,
      //单列宽度对于表格可视区域宽度的百分比
      singleColPercent: 33.3,
      //表格宽度(px)
      tableWidth: 0,
      //是否已执行自适应
      initTable: false,
      //表格中每一列的文本宽度
      colTextWidth: []
    };
  },
  mounted() {
    //动态绑定vxetable的函数到this
    for (let key in this.$refs.xTable) {
      if (typeof this.$refs.xTable[key] === "function") {
        this[key] = this.$refs.xTable[key]
      }
    }
  },
  methods: {
    //根据文本和字体大小样式获取具体宽度
    textSize(fontSize, text) {
      var span = document.createElement("span");
      var result = {};
      result.width = span.offsetWidth;
      result.height = span.offsetHeight;
      span.style.visibility = "hidden";
      span.style.fontSize = fontSize;
      span.style.display = "inline-block";
      document.body.appendChild(span);
      if (typeof span.textContent != "undefined") {
        span.textContent = text;
      } else {
        span.innerText = text;
      }
      result.width = parseFloat(window.getComputedStyle(span).width) - result.width;
      result.height = parseFloat(window.getComputedStyle(span).height) - result.height;
      document.body.removeChild(span);
      return result;
    },
    //自适应列宽
    computeColWidth(setting) {
      this.$nextTick(() => {
        let columns = this.$refs.xTable.getColumns()
        //初始列宽
        let initWidthList = columns.map((item) => { return item.width })
        //每一列的最长文本宽度列表
        this.colTextWidth = columns.map((item) => { return this.getColMaxLen(item) })
        //表格宽度
        this.tableWidth = parseInt(this.$el.clientWidth)
        //所有列宽单位转换为px
        let pxList = columns.map((item) => {
          if (item.width && typeof item.width == 'string' && item.width.indexOf('%') > -1) {
            item.width = Math.floor(parseInt(item.width) * this.tableWidth / 100)
          }
          return item
        })
        //设置操作列自动固定右侧
        if (this.$attrs['auto-fixed'] !== false) {
          pxList = this.setFixed(pxList)
        }
        //设置自适应宽度及自动居左
        pxList = this.autoWidth(pxList)
        //计算自适应完后等比列的总宽度
        let setWidth = pxList.reduce((total, cur) => {
          return total += XEUtils.toNumber(cur.width)
        }, 0)
        let newAutoList = pxList.filter((item) => { return !item.width })
        if (newAutoList.length != 0 && this.$attrs['auto-col-width'] !== false) {
          //计算出单列宽度
          let autoColWidth = (this.tableWidth - setWidth) / newAutoList.length
          let singleAutoPercent = (autoColWidth / this.tableWidth) * 100
          //如果剩下的等比列单列宽度大于阈值或小于窄列标准，取消自适应
          if (singleAutoPercent > this.singleColPercent || autoColWidth < this.shortWidth) {
            pxList.forEach((item, index) => {
              item.width = initWidthList[index]
            })
          }
        }
        pxList = this.setFixed(pxList)
        this.$refs.xTable.reloadColumn(pxList)
        this.logError(pxList)
      })
    },
    //检查列表是否含有不合法的设置，并提示
    logError(columns) {
      let index = columns.findIndex((item) => {
        let keys = XEUtils.isObject(item.slots) ? Object.keys(item.slots) : []
        return keys.length != 0 && !item.width && !item.minWidth
      })
      if (index != -1) {
        console.warn('表格列使用slots插槽必须设置width或minWidth！')
      }
    },
    /**
     * @description: 获取当前列最长的文本长度
     * @author: wufz
     * @param {*} column 当前列设置
     * @param {*} includeHeader 是否包含表头
     * @return {*}
     */
    getColMaxLen(column, includeHeader = true) {
      //该列是自定义列，不做计算
      let keys = Object.keys(column.slots)
      if (keys.length != 0) {
        return 0
      }
      //计算该列文本长度
      let lenList = []
      let fontSize = '14px'
      if (column.title && includeHeader) {
        let len = this.textSize(fontSize, column.title).width
        lenList.push(len)
      }
      if (column.property) {
        this.data.forEach((item) => {
          if (item[column.property]) {
            let text = ''
            //如果有格式化设置，获取格式化后的文本
            if (column.formatter) {
              text = column.formatter({ cellValue: item[column.property], row: item, column: column })
            } else {
              text = item[column.property]
            }
            let len = this.textSize(fontSize, text).width
            lenList.push(len)
          }
        })
      }
      let max = lenList.length > 0 ? XEUtils.max(lenList) : 0
      return max
    },
    //设置操作列自动固定右侧
    setFixed(columns) {
      //如果有一列未设置宽度，则退出
      let index = columns.findIndex((item) => {
        return item.width ? false : item.minWidth ? false : true
      })
      if (index != -1) {
        return columns
      }
      //获取总列宽
      let totalWidth = columns.reduce((total, cur) => {
        let width = cur.width ? cur.width : cur.minWidth ? cur.minWidth : 0
        return total + parseInt(width)
      }, 0)
      let lastCol = columns[columns.length - 1]
      //如果总列宽大于表格宽度且最后一列为自定义的操作列,+5是留余量，避免列宽计算出现的误差造成功能错误
      if (totalWidth > this.tableWidth + 5 && lastCol.title == '操作' && lastCol.slots && !lastCol.fixed) {
        columns[columns.length - 1].fixed = 'right'
      }
      return columns
    },
    //自适应宽度及自动居左
    autoWidth(columns) {
      //如果表格的未设宽度单元内文本的长度都不大于窄列标准，不做自适应设置
      let autoList = columns.filter((item) => { return !item.width })
      let overIndex = autoList.findIndex((item, index) => {
        return this.colTextWidth[index] > this.shortWidth
      })
      //设置自适应列宽
      columns.forEach((item, index) => {
        let textWidth = this.colTextWidth[index]
        if (!item.width && textWidth && textWidth <= this.shortWidth && overIndex != -1 && this.$attrs['auto-col-width'] !== false) {
          let width = parseInt(textWidth) + this.cellPadding
          //如果该列已设置最小宽度且计算列宽小于最小宽度，取最小宽度
          item.width = !item.minWidth || XEUtils.toNumber(item.minWidth) <= width ? width : item.minWidth
        }
        //列的最大文本宽度大于8个中文的宽度时，自动居左
        if (!item.align && this.getColMaxLen(item, false) > this.alignLeftWidth) {
          item.align = 'left'
          item.headerAlign = item.headerAlign || 'center'
        }
      })
      return columns
    }
  },
  //建立虚拟 DOM
  render: function (createElement) {
    //默认属性
    let defaultArr = {
      showOverflow: true,
      align: 'center',
      border: 'inner',
      highlightHoverRow: true,
      headerRowClassName: "dxx-table-header",
      headerCellClassName: "dxx-table-header-cell",
      stripe: true,
      autoResize: true
    }
    for (let key in this._props) {
      if (!XEUtils.isNull(this._props[key]) && !XEUtils.isUndefined(this._props[key])) {
        defaultArr[key] = this._props[key]
      }
    }

    //有表数据且未进行自适应时
    if (this.data && this.data.length != 0 && !this.initTable) {
      //自适应列宽
      this.computeColWidth(defaultArr)
      this.initTable = true
    }

    //编辑：dom表单元素
    let drawFromComponents = createElement(
      // 标签名称
      `vxe-table`,
      // 传递数据
      {
        attrs: {
          ...this.$attrs
        },
        props: {
          ...defaultArr
        },
        on: {
          ...this.$listeners
        },
        scopedSlots: {
          ...this.$scopedSlots
        },
        ref: 'xTable'
        /* ...context.data,
        props: {
          ...context.props
        },
        class: (context.data.staticClass || "") + " dxx-select", //自定义class
        style: {
          ...context.data.staticStyle
        } */
      },
      // 子节点数组，createElement...
      [
        this.$slots.default
      ]
    );

    /* // 编辑：dom表单元素
    let drawFromComponents = createElement(
      // 标签名称
      `vxe-table`,
      // 传递数据
      {
        ...context.data,
        props: {
          ...defaultArr
        },
        class: (context.data.staticClass || "") + "", //自定义class
        style: {
          ...context.data.staticStyle
        }
      },
      // 子节点数组，createElement...
      [
        context.slots().default
      ]
    ); */
    return drawFromComponents;
  }
};
</script>

<style scoped>
</style>