<template>
  <div id="c-table">
    <el-table
      ref="table"
      :row-key="rowKey"
      :data="data"
      border
      stripe
      size="mini"
      :max-height="height !== null ? height : ''"
      @select="handleSelectionChange"
      @select-all="handleSelectAll"
      :show-summary="useSum"
      @row-click="rowClick"
      :summary-method="computedSum"
    >
      <el-table-column type="selection" width="55" v-if="select" :prop="rowKey" :reserve-selection="true"> </el-table-column>
      <template v-for="(item, index) in fields">
        <template v-if="item.custom">
          <el-table-column :key="index" align="center" :label="item.label" v-bind="item.options" :show-overflow-tooltip="item.showTip || true">
            <template v-slot="{ row }">
              <slot :name="item.model" v-bind="{ item, row }"></slot>
            </template>
          </el-table-column>
        </template>
        <template v-else>
          <el-table-column
            :key="index"
            align="center"
            :label="item.label"
            :prop="item.model"
            :formatter="toFormatter"
            :sortable="true"
            v-bind="item.options"
            :show-overflow-tooltip="item.showTip || true"
          >
          </el-table-column>
        </template>
      </template>
      <template v-if="opera.length > 0">
        <el-table-column label="操作" align="center" :width="operaWidth">
          <template v-slot="{ row, $index }">
            <template v-for="(item, index) in opera">
              <template v-if="display(item, row)">
                <template v-if="vOpera">
                  <el-link
                    v-opera="item.method"
                    :key="`${item.model}-column-${index}`"
                    :type="item.type || 'primary'"
                    :icon="item.icon || ''"
                    size="mini"
                    style="padding-right: 10px"
                    :underline="false"
                    @click="handleOpera(row, item.method, item.confirm, item.methodZh, item.label, $index, item.confirmWord)"
                  >
                    {{ item.label }}
                  </el-link>
                </template>
                <template v-else>
                  <el-link
                    :key="`${item.model}-column-${index}`"
                    :type="item.type || 'primary'"
                    :icon="item.icon || ''"
                    size="mini"
                    style="padding-right: 10px"
                    :underline="false"
                    @click="handleOpera(row, item.method, item.confirm, item.methodZh, item.label, $index, item.confirmWord)"
                  >
                    {{ item.label }}
                  </el-link>
                </template>
              </template>
            </template>
          </template>
        </el-table-column>
      </template>
    </el-table>
    <el-row type="flex" align="middle" justify="end" style="padding-top: 1rem" v-if="usePage">
      <el-col :span="24" style="text-align: right">
        <el-pagination
          background
          layout="total, prev, pager, next"
          :page-sizes="[10, 15, 20, 50, 100]"
          :total="total"
          :page-size="limit"
          :current-page.sync="currentPage"
          @current-change="changePage"
          @size-change="sizeChange"
        >
        </el-pagination>
      </el-col>
    </el-row>
  </div>
</template>

<script>
export default {
  name: 'c-table',
  props: {
    fields: { type: Array, required: true },
    data: { type: Array, required: true },
    opera: { type: Array, default: () => [] },
    rowKey: { type: String, default: '_id' },
    select: { type: Boolean, default: false },
    selected: { type: Array, default: () => [] },
    usePage: { type: Boolean, default: true },
    total: { type: Number, default: 0 },
    useSum: { type: Boolean, default: false },
    sumcol: { type: Array, default: () => [] },
    sumres: { type: String, default: 'total' },
    limit: { type: Number, default: 10 },
    height: null,
    operaWidth: { type: Number, default: 200 },
    vOpera: { type: Boolean, default: false },
  },
  components: {},
  data: function () {
    return {
      pageSelected: [],
      currentPage: 1,
    };
  },
  created() {},
  methods: {
    toFormatter(row, column, cellValue, index) {
      let this_fields = this.fields.filter((fil) => fil.model === column.property);
      if (this_fields.length > 0) {
        let format = _.get(this_fields[0], `format`, false);
        if (format) {
          let res;
          if (_.isFunction(format)) {
            res = format(cellValue);
          } else {
            res = this.toFormat({
              model: this_fields[0].model,
              value: cellValue,
            });
          }
          return res;
        } else return cellValue;
      }
    },
    handleOpera(data, method, confirm = false, methodZh, label, index, confirmWord) {
      let self = true;
      if (_.isFunction(methodZh)) {
        methodZh = methodZh(data);
      } else if (!_.isString(methodZh)) {
        methodZh = label;
        self = false;
      }
      if (confirm) {
        let word = self ? methodZh : `您确认${methodZh}该数据?`;
        if (confirmWord) word = confirmWord;
        this.$confirm(word, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
        })
          .then(() => {
            this.$emit(method, { data, index });
          })
          .catch(() => {});
      } else {
        this.$emit(method, { data, index });
      }
    },
    handleSelectionChange(selection, row) {
      //根据row是否再pageSelected中,判断是添加还是删除
      let isSelecteds = _.cloneDeep(this.pageSelected);
      const is_has = isSelecteds.findIndex((f) => f[this.rowKey] === row[this.rowKey]);
      if (is_has <= -1) {
        // 没有找到,属于添加
        isSelecteds.push(row);
      } else {
        // 找到了,删除
        isSelecteds.splice(is_has, 1);
      }
      this.$set(this, 'pageSelected', isSelecteds);
      this.$emit(`handleSelect`, isSelecteds);
    },
    handleSelectAll(selection) {
      //处于没全选状态,选择之后一定是全选,只有处于全选状态时,才会反选(全取消)
      // console.log(selection);
      let res = [];
      if (selection.length > 0) {
        //全选
        res = _.uniqBy(this.pageSelected.concat(selection), this.rowKey);
      } else {
        //全取消
        res = _.differenceBy(this.pageSelected, this.data, this.rowKey);
      }
      this.$set(this, `pageSelected`, res);
      this.$emit(`handleSelect`, res);
    },
    initSelection() {
      this.$nextTick(() => {
        this.$refs.table.clearSelection();
        this.selected.forEach((info) => {
          let d = this.data.filter((p) => p._id === info._id);
          if (d.length > 0) this.$refs.table.toggleRowSelection(d[0]);
        });
      });
    },
    selectReset() {
      this.$refs.table.clearSelection();
    },
    changePage(page = this.currentPage) {
      this.$emit('query', { skip: (page - 1) * this.limit, limit: this.limit, ...this.searchInfo });
    },
    sizeChange(limit) {
      this.limit = limit;
      this.currentPage = 1;
      this.$emit('query', { skip: 0, limit: this.limit, ...this.searchInfo });
    },
    rowClick(row, column, event) {
      this.$emit(`rowClick`, row);
    },
    display(item, row) {
      let display = _.get(item, `display`, true);
      if (display === true) return true;
      else {
        let res = display(row);
        return res;
      }
    },
    // 计算合计
    computedSum({ columns, data }) {
      if (columns.length <= 0 || data.length <= 0) return '';
      const result = [];
      const reg = new RegExp(/^\d+$/);
      for (const column of columns) {
        // 判断有没有prop属性
        const prop = _.get(column, 'property');
        if (!prop) {
          result.push('');
          continue;
        }
        // 判断是否需要计算
        const inlist = this.sumcol.find((f) => f == prop);
        if (!inlist) {
          result.push('');
          continue;
        }
        let res = 0;
        // 整理出要计算的属性(只取出数字或者可以为数字的值)
        const resetList = data.map((i) => {
          const d = _.get(i, prop);
          const res = reg.test(d);
          if (res) return d * 1;
          else return 0;
        });
        if (this.sumres === 'total') {
          res = this.totalComputed(resetList);
        } else if (this.sumres === 'avg') {
          res = this.avgComputed(resetList);
        } else if (this.sumres === 'max') {
          res = this.maxComputed(resetList);
        } else if (this.sumres === 'min') {
          res = this.minComputed(resetList);
        }
        result.push(res);
      }
      result[0] = '合计';
      return result;
    },
    // 合计计算
    totalComputed(data) {
      const total = data.reduce((p, n) => p + n, 0);
      return total;
    },
    // 平均值计算
    avgComputed(data) {
      const total = this.totalComputed(data);
      return _.round(_.divide(total, data.length), 2);
    },
    // 最大值计算
    maxComputed(data) {
      return _.max(data);
    },
    // 最小值计算
    minComputed(data) {
      return _.min(data);
    },
  },
};
</script>

<style lang="less" scoped></style>
