<template>
  <div>
    <el-table
      ref="BTable"
      :data="localDataSource"
      :border="border"
      v-bind="args"
      :show-summary="totalPrice"
      :summary-method="getSummaries"
      class="b-table"
      @selection-change="handleSelectionChange"
      @select="handleSelect"
      @sort-change="handleSortChange"
      @current-change="handleCurrentChange"
      v-loading="loading"
      :header-row-style="{ background: '#E5EEED' }"
      :header-cell-style="{ background: '#E5EEED' }"
    >
      <!-- 多选 -->
      <el-table-column
        v-if="isShowSelection"
        type="selection"
        :selectable="selectable"
        width="55"
      ></el-table-column>
      <!-- index -->
      <el-table-column
        v-if="isShowIndex"
        :index="getIndex"
        align="center"
        label="序号"
        type="index"
        width="50"
      ></el-table-column>
      <!-- 普通列 -->
      <template v-for="(item, i) in columns">
        <!-- 自定义渲染 -->
        <el-table-column
          v-if="item.customRender"
          show-overflow-tooltip
          v-bind="item"
          :key="i + (item.key || '')"
        >
          <template #default="scope">
            <slot :name="item.customRender" v-bind="scope"></slot>
          </template>
        </el-table-column>
        <el-table-column v-else v-bind="item" :key="i" />
      </template>
    </el-table>
    <div v-if="showPagination" class="pagination">
      <el-pagination
        background
        layout="total, prev, pager, next"
        :current-page.sync="localPagination.page"
        :page-size="localPagination.perPage"
        :total="localPagination.total"
        @current-change="handlePageChange"
      ></el-pagination>
    </div>
  </div>
</template>
<script>
import { assign } from 'lodash-es';

export default {
  name: 'BTable',
  props: {
    data: {
      type: Function,
      required: true
    },
    columns: {
      type: Array,
      required: true
    },
    page: {
      type: Number,
      default: 1
    },
    perPage: {
      type: Number,
      default: 10
    },
    showPagination: {
      type: Boolean,
      default: true
    },
    isShowIndex: {
      type: Boolean,
      default: false
    },
    isShowSelection: {
      type: Boolean,
      default: false
    },
    args: {
      type: Object,
      default: () => ({})
    },
    amount: {
      type: Boolean,
      default: false
    },
    selectable: {
      type: Function,
      default: () => true
    },
    border: {
      type: Boolean,
      default: () => false
    }
  },
  data() {
    return {
      totalPrice: false,
      loading: false,
      localPagination: {
        page: this.page,
        perPage: this.perPage,
        total: 0
      },
      localDataSource: [],
      selectedData: [],
      // 默认排序
      defaultSort: { prop: 'loginTime', order: 'descending' }
    };
  },
  watch: {
    'localPagination.page': {
      handler() {}
    }
  },
  mounted() {
    this.loadData();
  },
  methods: {
    // 只计算最后一列的合计
    getSummaries(param) {
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = '合计';
          //只计算最后一列
        } else if (index === columns.length - 1) {
          const values = data.map((item) => Number(item[column.property]));
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => {
              const value = Number(curr);
              if (!isNaN(value)) {
                return prev + curr;
              } else {
                return prev;
              }
            }, 0);
            sums[index] += ' ';
          } else {
            sums[index] = '';
          }
        } else {
          sums[index] = '';
        }
      });
      return sums;
    },
    getIndex(index) {
      return (this.localPagination.page - 1) * this.perPage + index + 1;
    },
    loadData(pagination) {
      const { page, perPage } = this.localPagination;
      const parameter = this.showPagination
        ? assign({}, { pageNum: page, pageSize: perPage }, pagination)
        : null;

      const result = this.data(parameter);
      if (
        (typeof result === 'object' || typeof result === 'function') &&
        typeof result.then === 'function'
      ) {
        this.loading = true;

        result
          .then((r) => {
            if (r.total == undefined) {
              r.total = r.data.length;
            }
            const {
              // eslint-disable-next-line camelcase
              total,
              data
            } = r;

            if (this.showPagination) {
              this.localPagination = assign({}, this.localPagination, {
                total: total // 返回结果中的总记录数
              });
              // eslint-disable-next-line camelcase
              this.localDataSource = data || [];
            } else {
              this.localDataSource = r.data;
            }

            this.$emit('data-change', this.localDataSource);

            // 动态显示隐藏合计
            this.totalPrice = this.amount;

            this.loading = false;
          })
          .finally(() => {
            this.loading = false;
          });
      }
    },
    handlePageChange() {
      this.$emit('page-change');
      this.loadData({ pageNum: this.localPagination.page });
    },
    handleSelectionChange(val) {
      this.selectedData = val;
      this.$emit('selection-change', val);
    },
    handleSelect(val, row) {
      this.$emit('select', val, row);
    },
    handleSortChange(row) {
      this.$emit('sort-change', row);
    },
    handleCurrentChange(row) {
      this.$emit('current-change', row);
    },
    /**
     * 表格重新加载方法
     * 如果参数为 true, 则强制刷新到第一页
     * @param Boolean bool
     */
    refresh(bool = false) {
      if (bool) {
        this.localPagination = {
          page: 1,
          perPage: this.perPage,
          total: 0
        };
      }

      this.loadData();
    }
  }
};
</script>

<style lang="scss" scoped>
.pagination {
  margin: 20px 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}
</style>
