<style lang="scss">
.zee-scheme {
  &__header {
    margin-bottom: 10px;
  }
  &__filter {
    border: 1px solid #ebeef5;
    padding-top: 10px;
    border-radius: 4px;
    margin-bottom: 10px;
  }
  &__action {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
    line-height: 1;
    .el-button + .el-button {
      margin-left: 0;
    }
    .el-button {
      margin-right: 10px;
      margin-bottom: 10px;
    }
  }
  &__table {
    &-operation {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      justify-content: flex-start;
      .el-button + .el-button {
        margin-left: 0;
      }
      .el-button {
        margin-right: 10px;
      }
    }
  }
  &__dialog-button {
    display: flex;
    align-items: center;
    justify-content: center;
    padding-top: 10px;
  }
  &__footer {
    margin-top: 10px;
    text-align: right;
    display: flex;
    justify-content: space-between;
    align-items: center;
    .selection-info {
      word-break: break-all;
      white-space: nowrap;
      font-size: 12px;
      color: #606266;
      .num {
        color: #000;
        font-weight: bold;
        padding: 0 5px;
        font-size: 16px;
      }
      .el-button {
        margin-left: 5px;
      }
    }
    .el-pagination {
      flex: auto;
    }
  }
}
</style>

<template>
  <div class="zee-scheme">
    <div v-if="$scopedSlots.header || $slots.header" class="zee-scheme__header">
      <slot name="header" :filterModel="filterModel" v-bind="_slotScope"></slot>
    </div>
    <div class="zee-scheme__filter">
      <z-filter v-if="filter" :value="_filterModel" :list="list | noRulesFilter" :size="size" @input="onFilterInput" @search="search" :loading="loading"></z-filter>
    </div>
    <div v-if="action" class="zee-scheme__action">
      <slot v-if="hadSlot('action')" name="action" v-bind="_slotScope"></slot>
      <template v-else>
        <el-button :size="size" type="primary" @click="openNew">新增</el-button>
        <slot name="button" :size="size" v-bind="_slotScope"></slot>
      </template>
    </div>
    <div class="zee-scheme__table">
      <z-table
        ref="table"
        v-model="tableData"
        v-loading="loading"
        :list="list"
        :tableProps="{ border: true, 'row-key': 'id', ...tableProps }"
        :size="size"
        @selection-change="onTableSelectionChange"
        @selection="onTableSelection"
      >
        <slot></slot>
        <template #column-end>
          <el-table-column prop="$operation" label="操作" :width="140" fixed="right">
            <div class="zee-scheme__table-operation" slot-scope="slotScope">
              <el-button type="text" icon="el-icon-edit" title="编辑" @click="openEdit(slotScope)"></el-button>
              <el-popconfirm confirmButtonText="确定" cancelButtonText="取消" title="确定删除吗？" placement="top" @onConfirm="handleDelete(slotScope)">
                <el-button slot="reference" type="text" icon="el-icon-delete" title="删除"></el-button>
              </el-popconfirm>
            </div>
          </el-table-column>
        </template>
      </z-table>
    </div>
    <div v-if="pagination" class="zee-scheme__footer">
      <div v-if="selection.length > 0" class="selection-info">
        <span>已选中</span>
        <span class="num">{{ selection.length }}</span>
        <span>项</span>
        <el-popconfirm confirmButtonText="确定" cancelButtonText="取消" title="确定清除吗？" placement="top" @onConfirm="clearSelection">
          <el-button slot="reference" :size="size" type="text">清除</el-button>
        </el-popconfirm>
      </div>
      <el-pagination
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="currentPage"
        :page-sizes="pageSizes"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
      >
      </el-pagination>
    </div>
    <el-dialog :visible.sync="dialogVisible" :title="dialogTitle" destroy-on-close append-to-body :lock-scroll="false" :close-on-click-modal="false" @closed="onDialogClosed">
      <div v-loading="dialogLoading">
        <slot v-if="hadSlot('dialog-title')" slot="title" name="dialog-title" :dialogType="dialogType" v-bind="_slotScope"></slot>
        <template v-if="dialogRender">
          <slot v-if="hadSlot(`dialog-${dialogType}`)" :name="`dialog-${dialogType}`" :model="_formModel" v-bind="_slotScope"></slot>
          <z-form v-else ref="form" :value="_formModel" :list="list" label-width="80px" :span="12" @input="onFormInput" @validate="onFormValidate"></z-form>
          <div class="zee-scheme__dialog-button" v-if="['new', 'edit'].includes(dialogType)">
            <el-button :size="size" type="primary" @click="handleConfirm" :loading="submitting">确定</el-button>
            <el-button :size="size" plain @click="closeDialog">取消</el-button>
          </div>
        </template>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { cloneDeep } from '../form/util';

export default {
  name: 'Scheme',
  props: {
    list: Array,
    filter: {
      type: Boolean,
      default: true,
    },
    action: {
      type: Boolean,
      default: true,
    },
    pagination: {
      type: Boolean,
      default: true,
    },
    size: {
      type: String,
      default: 'mini',
    },
    tableProps: {
      type: Object,
      default: () => ({}),
    },
    formModel: Object,
    filterModel: Object,
    auto: Boolean,
    realSelection: Boolean,
    searchAPI: Function,
    submitAPI: Function,
    getAPI: Function,
    deleteAPI: Function,
  },
  data() {
    return {
      filterForm: {},
      editForm: {},
      dialogVisible: false,
      dialogRender: true,
      dialogType: 'none',
      dialogLoading: false,
      dialogTitle: '',
      currentPage: 1,
      // pageSize: 10,
      pageSize: 5,
      total: 127,
      // pageSizes: [10, 20, 50],
      pageSizes: [1, 2, 5],
      tableData: [],
      submitting: false,
      loading: false,
      selection: [],
    };
  },
  created() {
    if (this.auto) {
      this.search();
    }
  },
  filters: {
    noRulesFilter(val = []) {
      let list = cloneDeep(val);
      const clearRules = list => {
        list.forEach(item => {
          if (item.list) {
            clearRules(item.list);
          } else {
            delete item.rules;
          }
        });
      };
      clearRules(list);
      return list;
    },
  },
  computed: {
    _filterModel() {
      return this.filterModel || this.filterForm || {};
    },
    _formModel() {
      return this.formModel || this.editForm || {};
    },
    _slotScope() {
      return {
        openDialog: this.openDialog,
        closeDialog: this.closeDialog,
      };
    },
  },
  methods: {
    // 空Promise
    emptyPromise() {
      return new Promise(resolve => {
        resolve();
      });
    },
    // 设置第二行选中
    toggleRowSelection() {
      this.tableData.forEach(row => {
        if (this.selection.find(item => item.id === row.id)) {
          this.$refs.table && this.$refs.table.toggleRowSelection(row);
        }
      });
    },
    // 表格选中状态
    onTableSelectionChange(selection, type) {
      if (this.realSelection) {
        if (type === 'check') {
          const result = this.selection || [];
          selection.forEach(item => {
            if (!result.find(i => i.id === item.id)) {
              result.push(item);
            }
          });
          this.selection = result;
        } else if (type === 'uncheck') {
          selection.forEach(i => {
            this.selection = this.selection.filter(item => item.id !== i.id);
          });
        }
      }
    },
    // 表格选中
    onTableSelection(selection) {
      if (!this.realSelection) {
        this.selection = selection;
      }
    },
    // 清除表格选中
    clearSelection() {
      this.$refs.table && this.$refs.table.clearSelection();
      this.selection = [];
    },
    // 搜索
    async search() {
      this.loading = true;
      const params = {
        ...this._filterModel,
        currentPage: this.currentPage,
        pageSize: this.pageSize,
      };
      const searchAPI = this.searchAPI || this.emptyPromise;
      await searchAPI(params)
        .then(response => {
          const { result, totalCount } = response || {};
          this.tableData = result;
          this.total = totalCount;
          this.$nextTick(() => {
            this.toggleRowSelection();
          });
        })
        .catch(() => {
          this.$message.error('失败');
        });
      this.loading = false;
    },
    // 更新筛选model
    onFilterInput(val) {
      this.filterForm = val || {};
      this.$emit('update:filterModel', val || {});
    },
    // 更新表单model
    onFormInput(val) {
      this.editForm = val || {};
      this.$emit('update:formModel', val || {});
    },
    // 表单提交且通过校验
    async onFormValidate(valid, model) {
      if (valid) {
        this.submitting = true;
        const submitAPI = this.submitAPI || this.emptyPromise;
        await submitAPI(model, { type: this.dialogType })
          .then(() => {
            this.closeDialog();
          })
          .catch(() => {
            this.$message.error('失败');
          });
        this.submitting = false;
      }
    },
    // 表单按钮确定
    handleConfirm() {
      this.$refs.form && this.$refs.form.validate();
    },
    // 表单按钮取消
    handleCancel() {
      this.closeDialog();
    },
    // 查询是否有某个插槽
    hadSlot(name) {
      return !!this.$slots[name] || !!this.$scopedSlots[name];
    },
    // 打开新增弹出框
    openNew() {
      this.openDialog('new', '新增');
    },
    // 打开编辑弹出框
    async openEdit({ row }) {
      this.dialogLoading = true;
      this.openDialog('edit', '编辑');
      const getRow = () => {
        this.editForm = { ...row };
      };
      const getAPI = this.getAPI || getRow;
      await getAPI(row).then(result => {
        this.editForm = { ...result };
      });
      this.dialogLoading = false;
    },
    // 删除
    async handleDelete({ row, $index }) {
      const deleteAPI = this.deleteAPI || this.emptyPromise;
      const loading = this.$loading({
        text: '处理中',
        spinner: 'el-icon-loading',
        background: 'rgba(255, 255, 255, 0.5)',
      });
      await deleteAPI(row).then(() => {
        this.tableData.splice($index, 1);
        this.$message.success('删除成功');
      });
      loading.close();
    },
    // 打开弹出框
    openDialog(type, title) {
      this.dialogVisible = true;
      this.dialogRender = true;
      this.dialogType = type;
      this.dialogTitle = title;
    },
    // 关闭弹出框
    closeDialog() {
      this.dialogVisible = false;
    },
    // 清空表单
    clearEditForm() {
      this.editForm = {};
    },
    // 弹出框关闭动画结束
    onDialogClosed() {
      this.clearEditForm();
      this.dialogRender = false;
      this.dialogType = 'none';
    },
    // 分页-每页个数
    handleSizeChange(val) {
      this.pageSize = val;
      this.currentPage = 1;
      this.$nextTick(this.search);
    },
    // 分页-当前页数
    handleCurrentChange(val) {
      this.currentPage = val;
      this.$nextTick(this.search);
    },
  },
};
</script>
