<template lang="pug">
.smart-table
  el-table.smart-table(
    :data="data"
    :stripe="isStripe"
    :row-class-name="rowClassName"
    :size="size"
    @sort-change="sortChange"
    @row-click="rowClick")
    el-table-column(
      v-for="(item, index) in realConfig.normal"
      :key="`normal_${index}`"
      :width="item.width"
      :height="item.height"
      :min-width="item.minWidth"
      :prop="item.prop"
      :sortable="item.sort"
      :class-name="item.className"
      :label="item.label")
      template(#default="{row, column}")
        slot(v-if="item.type === 'slot'" :name="column.property" :data="row")
        el-progress(v-else-if="item.type === 'progress'" :percentage="row[item.prop]")
        template(v-else-if="realValue")
          el-tooltip(v-if="item.inline" :content="realValue.bind(this, row, item)()" placement="top-start")
            span.inline(:style="{maxWidth: `${item.width}px`}" v-html="realValue.bind(this, row, item)()")
          span(v-else v-html="realValue.bind(this, row, item)()")
    el-table-column(
      v-for="(item, index) in realConfig.expand"
      :key="`expand_${index}`"
      :width="item.width"
      :min-width="item.minWidth"
      type="expand"
      :label="item.label"
      :class-name="item.className")
      template(#default="{row, column}")
        SmartTable(:data='realValue.bind(this, row, item)()' :config="item.config")
    el-table-column(
      :label="operationsTitle"
      :width="operationsWidth"
      v-if="operations.length")
      template(#default="scope")
        el-popover(
          v-for="(btn, index) in operations"
          :disabled="!btn.check"
          placement="top"
          trigger="hover"
          width="160"
          :key="index")
          p {{btn.check}}
          div(style="text-align: right; margin: 0")
            el-button(type="primary", size="mini", @click="btn.action.bind(this, scope)()") 确定
          el-button(
            slot="reference"
            :size="btn.size"
            :type="btn.type"
            :disabled="typeof btn.disabled === 'function' ? btn.disabled.bind(this, scope)() : btn.disabled"
            v-show="typeof btn.visible === 'function' ? btn.visible.bind(this, scope)() : true"
            @click="!btn.check && btn.action.bind(this, scope)()"
          ) {{typeof btn.label === 'function' ? btn.label.bind(this, scope)() : btn.label}}
  el-pagination(
    v-if="total"
    @size-change="handleSizeChange"
    @current-change="handleCurrentChange"
    :page-sizes="sizes"
    :page-size.sync="step"
    :current-page.sync="current"
    :layout="layout"
    :total="total")
</template>
<script>
import dayjs from 'dayjs'

export default {
  name: 'SmartTable',
  components: {},
  props: {
    isStripe: {
      type: Boolean,
      default: true,
    },
    data: {
      type: Array,
      required: true,
    },
    config: {
      type: [Array, Object],
      required: true,
    },
    operations: {
      type: Array,
      required: false,
      default: () => ([]),
    },
    operationsTitle: {
      type: String,
      default: '操作',
    },
    size: {
      type: String,
      required: false,
      default: 'medium',
    },
    total: {
      type: Number,
      required: false,
    },
    sizes: {
      type: Array,
      required: false,
      default: () => ([20]),
    },
    sortChange: {
      type: Function,
      default: () => {},
    },
  },
  data () {
    return {
      step: 20,
      current: 1,
    }
  },
  computed: {
    layout () {
      let res = ['total', 'prev', 'pager', 'next']
      if (this.sizes.length > 1) {
        res.unshift('sizes')
      }
      return res.join(',')
    },
    realConfig () {
      let config
      if (Array.isArray(this.config)) {
        config = this.config
      } else {
        config = Object.entries(this.config).map(([prop, label]) => {
          if (typeof label === 'string') {
            return {
              label,
              prop,
            }
          } else {
            return {
              prop,
              ...label,
            }
          }
        })
      }
      return config.reduce((obj, item) => {
        if (item.expand) {
          obj.expand.push(item)
        } else {
          obj.normal.push(item)
        }
        return obj
      }, { expand: [], normal: [] })
    },
    operationsWidth () {
      let length = this.operations.length
      let words = this.operations.reduce((num, item) => {
        num += item.label.length
        return num
      }, 0)
      return words * 12 + length * 40 + 20
    },
  },
  created () {
    this.step = this.sizes[0]
  },
  mounted () {},
  methods: {
    handleSizeChange () {
      this.$emit('change', this.current - 1, this.step)
    },
    handleCurrentChange () {
      this.$emit('change', this.current - 1, this.step)
    },
    realValue (row, item) {
      let value = row[item.prop]
      if (item.type) {
        switch (item.type) {
          case 'date':
            if (value) {
              value = dayjs(value).format('YYYY-MM-DD')
            } else {
              return ''
            }
            break
          case 'dateTime':
            if (value) {
              value = dayjs(value).format('YYYY-MM-DD HH:mm:ss')
            } else {
              return ''
            }
            break
          default:
            break
        }
      }

      if (item.slot) {
        return ''
      }
      if (typeof item.formatter === 'function') {
        return item.formatter(row, item)
      } else {
        return value
      }
    },
    rowClassName ({ row, rowIndex }) {
      if (row._status) {
        return `${row._status}-row`
      }
      return ''
    },
    rowClick (row, col, e) {
      this.$emit('rowClick', row, col, e)
    },
  },
}
</script>
<style lang="stylus" rel="stylesheet/stylus" scoped>
.el-button {
  margin 0 4px
}
>>> .success-row {
  color #67C23A
  background-color #f0f9eb
}
>>> .warning-row {
  color #E6A23C
  background-color #fdf6ec
}
>>> .danger-row {
  color #F56C6C
  background-color #fef0f0
}
>>>.el-table .cell span {
  display inline-block
}
.el-pagination {
  margin-top 10px
  display: flex;
  justify-content: center;
}
.inline {
  word-break keep-all
  text-overflow ellipsis
  overflow-x hidden
  white-space nowrap
}
</style>
