<template>
  <div class="uif-table" :class="classes">
    <!-- header -->
    <div class="uif-table-header-container" :style="{paddingRight: rightScrollBar}">
      <div class="uif-table-header-main" :style="mainContainerStyles" ref="headerScroll">
        <t-header :columns="mainRenderColumns" :data-list="dataList" :has-resize="hasResize"
                  @sort="handleSort" v-on="$listeners"></t-header>
      </div>
      <div ref="headerLeft" class="uif-table-header-left" v-if="leftColumns.length" :style="leftContainerStyles">
        <t-header :columns="leftColumns" :data-list="dataList" :has-resize="hasResize"
                  @sort="handleSort" v-on="$listeners"></t-header>
      </div>
      <u-icon class="uif-table-header-setting" v-if="hasSetting" title="表格设置"
              type="settings" scene="action" @click="$emit('setting')"></u-icon>
    </div>
    <!-- loading -->
    <u-loading-bar :loading="loading"></u-loading-bar>
    <!-- empty -->
    <div v-if="empty" class="uif-table-empty">{{noDataText}}</div>
    <!-- body -->
    <div class="uif-table-body-container" ref="bodyContainer">
      <div class="uif-table-body-main" :style="mainContainerStyles" ref="bodyScroll">
        <t-body :class-index="classIndex" :columns="mainRenderColumns" :data-list="dataList" v-on="$listeners"></t-body>
      </div>
      <div class="uif-table-body-left" v-if="leftColumns.length" :style="leftContainerStyles">
        <t-body :class-index="classIndex" :columns="leftRenderColumns" :data-list="dataList" v-on="$listeners"></t-body>
      </div>
      <slot name="body-slot"></slot>
    </div>
    <!-- scrollBar -->
    <div class="uif-table-scroll" :style="scrollStyles" ref="scrollBar" @scroll="handleScrollHorizontal">
      <t-header class="uif-table-scroll-inner" :columns="mainColumns"></t-header>
    </div>
  </div>
</template>

<script>
import elementResizeDetectorMaker from 'element-resize-detector'
import {oneOf} from '@uif/hq/lib/utils/assist'
import {filter, concat} from '@uif/hq/lib/utils/array'
import {on, off} from '@uif/hq/lib/utils/dom'
import UIcon from '@uif/hq/lib/components/icon'
import ULoadingBar from '@uif/admin/lib/components/loading-bar'
import THeader from './header'
import TBody from './body'
import sort from '@uif/admin/lib/utils/sort'
import {getRenderType} from '@uif/admin/lib/utils/table'

export default {
  name: 'u-table',
  components: {
    ULoadingBar,
    UIcon,
    THeader,
    TBody
  },
  props: {
    dataList: {
      type: Array,
      default () {
        return []
      }
    },
    columns: {
      type: Array,
      default () {
        return []
      }
    },
    loading: {
      type: Boolean,
      default: false
    },
    noData: {
      validator (value) {
        return oneOf(value, ['auto', true, false])
      },
      default: 'auto'
    },
    noDataText: {
      type: String,
      default: '暂无数据'
    },
    hasBorder: {
      type: Boolean,
      default: true
    },
    // 完整渲染 （自动适应高度，但会影响性能）
    fullRender: {
      type: Boolean,
      default: false
    },
    // 列表样式（下标）
    classIndex: {
      type: Object,
      default () {
        return {}
      }
    },
    flex: {
      type: Boolean,
      default: false
    },
    hasResize: {
      type: Boolean,
      default: false
    },
    hasSetting: {
      type: Boolean,
      default: false
    },
    hasSelection: {
      type: Boolean,
      default: true
    },
    fullRenderFixed: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      rightScrollBar: 0,
      bottomScrollBar: 0
    }
  },
  computed: {
    empty () {
      return this.noData === 'auto' ? (!this.loading && this.dataList.length <= 0) : this.noData
    },
    classes () {
      return {
        'uif-table-border': this.hasBorder,
        'uif-table-flex': this.flex
      }
    },
    // 可见列
    visibleColumns () {
      return filter(this.columns, column => !column.h && (getRenderType(column) !== 'selection' || this.hasSelection))
    },
    // main 真实固定列
    mainColumns () {
      return filter(this.visibleColumns, column => !column.fixed)
    },
    // main 渲染列
    mainRenderColumns () {
      if (!this.fullRender) {
        return this.mainColumns
      }
      return concat([], this.leftColumns, this.mainColumns, this.fullRenderFixed ? {} : [])
    },
    // main 样式
    mainContainerStyles () {
      return this.fullRender ? null : {paddingLeft: this.leftColumnsWidth}
    },
    // left 固定列
    leftColumns () {
      return filter(this.visibleColumns, column => column.fixed === 'left')
    },
    // left 渲染列
    leftRenderColumns () {
      if (!this.fullRender) {
        return this.leftColumns
      }
      return concat([], this.leftColumns, this.mainColumns)
    },
    // left 宽度
    leftColumnsWidth () {
      return this.leftColumns.reduce((w, d) => w + d.width, 0) + 'px'
    },
    // left 样式
    leftContainerStyles () {
      return {
        width: this.leftColumnsWidth
      }
    },
    scrollStyles () {
      return {
        height: this.bottomScrollBar,
        right: this.rightScrollBar,
        paddingLeft: this.leftColumnsWidth
      }
    }
  },
  watch: {
  },
  created () {
  },
  mounted () {
    this.handleResize()
    on(window, 'resize', this.handleResize)
    this.observer = elementResizeDetectorMaker()
    this.observer.listenTo(this.$el, this.handleResize)
  },
  updated () {
    this.handleResize()
  },
  beforeDestroy () {
    off(window, 'resize', this.handleResize)
    this.observer.removeListener(this.$el, this.handleResize)
  },
  methods: {
    // 更新 滚动条宽度
    handleResize () {
      if (!this.$el.getBoundingClientRect().width) return
      const {bodyContainer, bodyScroll} = this.$refs
      this.rightScrollBar = bodyContainer.offsetWidth - bodyContainer.clientWidth + 'px'
      this.bottomScrollBar = bodyScroll.offsetHeight - bodyScroll.clientHeight + 'px'
    },
    // 监听横向滚动条
    handleScrollHorizontal ({target}) {
      this.$refs.headerScroll.scrollLeft = target.scrollLeft
      this.$refs.bodyScroll.scrollLeft = target.scrollLeft
    },
    // 同步mainScroll
    syncMainScroll () {
      const scrollLeft = this.$refs.bodyScroll.scrollLeft
      if (this.$refs.scrollBar.scrollLeft !== scrollLeft) {
        this.$refs.scrollBar.scrollLeft = scrollLeft
        this.$refs.headerScroll.scrollLeft = scrollLeft
      }
    },
    refresh () {
      this.refreshSort()
    },
    handleSort (column, type) {
      sort(this.dataList, column)
      this.$emit('sort', column, type)
    },
    // 刷新排序
    refreshSort () {
      const column = this.columns.find(column => column._sort)
      if (column) sort(this.dataList, column)
    }
  }
}
</script>
