<style>
.eagle-scheme {
  padding: 0px;
}
.eagle-scheme__card {
  border: 1px solid #F5F5F5;
  border-radius: 2px;
  background-color: #fff;
  padding: 10px;
  transition: all .3s ease;
  margin-bottom: 10px;
}
.eagle-scheme__card  .eagle-search {
  padding-top: 20px;
  padding-bottom: 10px;
}
.eagle-scheme__action {
  display: flex;
  align-items: center;
  padding-bottom: 10px;
}
.eagle-scheme__action .eagle-scheme__action-btn:not(:first-child) {
  margin-left: 10px;
}
.eagle-scheme__text-selection {
  font-size: 14px;
}
.eagle-scheme__text-selection-highlight {
  color: #f5222d;
  padding: 0 5px;
}
.eagle-scheme__table .eagle-scheme__table-operation {
  display: flex;
  align-items: center;
}
.eagle-scheme__table .eagle-scheme__table-btn {
  padding-left: 0px !important;
  padding-right: 10px !important;
  margin-left: 0px !important;
  margin-right: 0px !important;
}
.eagle-scheme__table .eagle-scheme__table-btn:last-child {
  padding-left: 0px !important;
  padding-right: 0px !important;
  margin-left: 0px !important;
  margin-right: 0px !important;
}
.eagle-scheme__pagination {
  text-align: right;
  padding-top: 10px;
}
.eagle-scheme__dialog .el-dialog__body {
  padding: 30px 40px;
}
</style>

<template>
  <div class="eagle-scheme">
    <div v-if="option.showSearch !== false" class="eagle-scheme__card">
      <!-- 搜索表单 -->
      <eagle-search :list="_searchList" v-model="searchModel" :span="searchProps.span || 6" :formProps="searchProps" @search="handleSearch" :searching="tableLoading">
        <!-- 搜索表单项具名插槽 -->
        <template v-for="item in _searchList">
          <slot v-if="$scopedSlots[`search-${item.key}`] || $slots[`search-${item.key}`]" :name="`search-${item.key}`" :slot="item.key" :model="searchModel"></slot>
        </template>
      </eagle-search>
    </div>
    <!-- 操作按钮栏 -->
    <div v-if="option.showActionBar !== false" class="eagle-scheme__action" v-loading="tableLoading" element-loading-spinner="none" element-loading-background="rgba(255, 255, 255, 0.6)">
      <slot v-if="$scopedSlots['action-bar'] || $slots['action-bar']" name="action-bar" v-bind="slotMethod" :model="formModel" :selection="tableSelection"></slot>
      <template v-else>
        <slot v-if="$scopedSlots['action-btn-new'] || $slots['action-btn-new']" name="action-btn-new" v-bind="slotMethod" :model="formModel" :selection="tableSelection"></slot>
        <el-button v-else class="eagle-scheme__action-btn" type="primary" size="small" @click="handleNew">{{ i18n('eagle.scheme.new') || '新增'  }}</el-button>
        <el-button v-if="hasSelectionSlot && option.showActionBtnDelete !== false" :disabled="tableSelection && tableSelection.length <= 0" class="eagle-scheme__action-btn" plain size="small" @click="handleDelete('more')">{{ i18n('eagle.scheme.delete') || '删除'  }}</el-button>
        <slot v-if="$scopedSlots['action-button'] || $slots['action-button']" name="action-button" class="eagle-scheme__action-btn" :model="formModel" :selection="tableSelection" v-bind="slotMethod"></slot>
        <div v-if="hasSelectionSlot && tableSelection && tableSelection.length > 0 && option.showActionBtnDelete !== false" class="eagle-scheme__action-btn eagle-scheme__text-selection">{{ i18n('eagle.scheme.checked') || '已选中'  }}<span class="eagle-scheme__text-selection-highlight">{{ tableSelection.length }}</span>{{ i18n('eagle.scheme.item') || '项'  }}</div>
      </template>
    </div>
    <div class="eagle-scheme__table">
      <!-- 表格 -->
      <eagle-table ref="eagle-table" :list="_tableList" :value="tableData"
        v-loading="tableLoading"
        element-loading-background="rgba(255, 255, 255, 0.6)"
        :tableProps="{ border: true, 'row-key': 'id', ...tableProps }"
        :tableEvents="{
          'selection-change': handleTableSelectionChange,
          ...tableEvents,
        }"
      >
        <slot></slot>
        <!-- 表格具名插槽 -->
        <template v-for="item in _tableList">
          <slot v-if="$scopedSlots[`table-${item.key}`] || $slots[`table-${item.key}`]" :name="`table-${item.key}`" :slot="item.key" v-bind="slotMethod"></slot>
        </template>
        <!-- 表格后置插槽 -->
        <template v-if="$scopedSlots['table-append'] || $slots['table-append']">
          <slot name="table-append" slot="$append"></slot>
        </template>
        <!-- 表格操作栏插槽 - 自定义 -->
        <template v-if="$scopedSlots['table-operation'] || $slots['table-operation']">
          <slot name="table-operation" slot="$end" v-bind="slotMethod"></slot>
        </template>
        <!-- 表格操作栏插槽 - 默认 -->
        <el-table-column v-else slot="$end" prop="$operation" :label="i18n('eagle.scheme.operation') || '操作'" min-width="140" fixed="right">
          <div class="eagle-scheme__table-operation" slot-scope="slotScope">
            <!-- 表格操作栏插槽 - 前置插槽 -->
            <slot v-if="$scopedSlots['table-operation-btn'] || $slots['table-operation-btn']" name="table-operation-btn" :slotScope="slotScope" v-bind="slotMethod"></slot>
            <el-button v-if="option.showViewBtn !== false" class="eagle-scheme__table-btn" type="text" icon="el-icon-view" :title="i18n('eagle.scheme.detail') || '详情'" @click="handleView(slotScope)"></el-button>
            <slot v-if="$scopedSlots['table-operation-btn-edit'] || $slots['table-operation-btn-edit']" name="table-operation-btn-edit" :slotScope="slotScope" v-bind="slotMethod"></slot>
            <el-button v-else-if="option.showEditBtn !== false" class="eagle-scheme__table-btn" type="text" icon="el-icon-edit" :title="i18n('eagle.scheme.edit') || '编辑'" @click="handleEdit(slotScope)"></el-button>
            <eagle-confirm v-if="option.showDeleteBtn !== false" class="eagle-scheme__table-btn" :title="i18n('eagle.scheme.deleteConfirm') || '是否删除？'" @confirm="handleDelete('one', slotScope)">
              <el-button type="text" icon="el-icon-delete" :title="i18n('eagle.scheme.delete') || '删除'"></el-button>
            </eagle-confirm>
            <!-- 表格操作栏插槽 - 后置插槽 -->
            <slot v-if="$scopedSlots['table-operation-btn-append'] || $slots['table-operation-btn-append']" name="table-operation-btn-append" :slotScope="slotScope" v-bind="slotMethod"></slot>
          </div>
        </el-table-column>
      </eagle-table>
      <!-- 分页器 -->
      <div v-if="option.showPagination !== false" class="eagle-scheme__pagination">
        <el-pagination size="small" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" v-loading="tableLoading" element-loading-spinner="none" element-loading-background="rgba(255, 255, 255, 0.6)"
          :page-size="pageSize" :total="totalCount" v-bind="{ 'page-sizes': [10, 20, 50], layout: 'total, sizes, prev, pager, next, jumper', ...paginationProps }"></el-pagination>
      </div>
    </div>
    <el-dialog v-loading="dialogLoading" element-loading-background="rgba(255, 255, 255, 0.3)" :custom-class="dialogProps['custom-class'] || 'eagle-scheme__dialog'" :title="dialogProps.title || dialogTitle" :visible.sync="dialogVisible" v-bind="{ width: '65%', ...dialogProps }">
      <eagle-form v-if="dialogType === 'dialog-form' && !$scopedSlots['dialog-form'] && !$slots['dialog-form']" ref="eagle-form" :list="_formList" v-model="formModel" :params="{ formMode }" :span="formProps.span || 12" :formProps="formProps" @submit="handleSubmit" @cancel="handleCancel">
        <!-- 表单分组具名插槽 -->
        <template v-for="key in formGroupSlotsKeys">
          <slot v-if="$scopedSlots[`form-${key}`] || $slots[`form-${key}`]" :name="`form-${key}`" :slot="key" :model="formModel"></slot>
        </template>
        <!-- 表单项具名插槽 -->
        <template v-for="item in _formList">
          <slot v-if="$scopedSlots[`form-item-${item.key}`] || $slots[`form-item-${item.key}`]" :name="`form-item-${item.key}`" :slot="`item-${item.key}`" :model="formModel"></slot>
        </template>
      </eagle-form>
      <eagle-detail v-else-if="dialogType === 'dialog-view' && !$scopedSlots['dialog-view'] && !$slots['dialog-view']" v-model="formModel" :list="list || detailList || _formList" :span="detailProps.span || 8" :formProps="detailProps">
        <!-- 表单分组具名插槽 -->
        <template v-for="key in formGroupSlotsKeys">
          <slot v-if="$scopedSlots[`view-${key}`] || $slots[`view-${key}`]" :name="`view-${key}`" :slot="key" :model="formModel"></slot>
        </template>
        <!-- 表单项具名插槽 -->
        <template v-for="item in _formList">
          <slot v-if="$scopedSlots[`view-item-${item.key}`] || $slots[`view-item-${item.key}`]" :name="`view-item-${item.key}`" :slot="`item-${item.key}`" :model="formModel"></slot>
        </template>
      </eagle-detail>
      <!-- 自定义弹出框内容插槽 -->
      <slot v-else :name="dialogType" :row="tableCurrentRow" :hideDialog="hideDialog"></slot>
    </el-dialog>
  </div>
</template>

<script>
import { generateListSpace } from './parser';
import { stringify } from './utils';

let _$http = null;

export default {
  name: 'Scheme',
  props: {
    // 配置列表
    list: Array,
    // 配置选项
    option: {
      type: Object,
      default() { return {} }
    },
    // 搜索表单配置
    searchList: Array,
    // 表单配置
    formList: Array,
    // 表格配置
    tableList: Array,
    // 详情配置
    detailList: Array,
    // 搜索表单参数
    searchProps: {
      type: Object,
      default() { return {} }
    },
    // 表格参数
    tableProps: {
      type: Object,
      default() { return {} }
    },
    // 表格事件
    tableEvents: {
      type: Object,
      default() { return {} }
    },
    // 表单参数
    formProps: {
      type: Object,
      default() { return {} }
    },
    // 详情参数
    detailProps: {
      type: Object,
      default() { return {} }
    },
    // 分页参数
    paginationProps: {
      type: Object,
      default() { return {} }
    },
    // 弹出框参数
    dialogProps: {
      type: Object,
      default() { return {} }
    },
  },
  data() {
    return {
      // 搜索表单配置
      _searchList: [],
      // 搜索表单值
      searchModel: {},
      // 表单配置
      _formList: [],
      // 表单值
      formModel: {},
      // 表单模式 新增(new)/编辑(edit)/详情(view)
      formMode: 'new',
      // 表格配置
      _tableList: [],
      // 当前页
      currentPage: 1,
      // 每页最大数据量
      pageSize: this.paginationProps.pageSize || 10,
      // 数据总量
      totalCount: 0,
      // 弹出框状态
      dialogVisible: false,
      // 弹出框标题
      dialogTitle: '',
      // 弹出框类型
      dialogType: '',
      // 弹出框加载状态
      dialogLoading: false,
      // 表格数据
      tableData: [],
      // 表格选中项
      tableSelection: [],
      // 表格加载状态
      tableLoading: false,
      // 表格当前操作列
      tableCurrentRow: null,
    };
  },
  created() {
    if (this.list instanceof Array) { // 如果有总配置列表，则根据总配置列表生成作用域数据
      const { search = [], form = [], table = [] } = generateListSpace(this.list);
      this._searchList = search;
      this._formList = form;
      this._tableList = table;
    } else { // 没有总配置列表时，单独传入作用域列表
      this._searchList = this.searchList || [];
      this._formList = this.formList || [];
      this._tableList = this.tableList || [];
    }
    this.totalCount = this.tableData.length;
    // 传入axios标准的http库
    if (this.option.$http) {
      _$http = this.option.$http;
    }
  },
  mounted() {
    // 设置自动加载数据
    if (!this.option.auto) {
      this.handleSearch();
    }
  },
  computed: {
    // 解析表单组件分组具名插槽名称
    formGroupSlotsKeys() {
      const keys = [...new Set([...Object.keys(this.$scopedSlots), ...Object.keys(this.$slots)])];
      return keys.filter(key => key.indexOf('form-group') > -1).map(key => key.substr(5));
    },
    // 判断设置全选插槽
    hasSelectionSlot() {
      const slots = this.$slots || {};
      const defaultSlot = slots.default || [];
      let result = false;
      for (let slot of defaultSlot) {
        if (slot.componentOptions && slot.componentOptions.tag === 'el-table-column' && slot.componentOptions.propsData && slot.componentOptions.propsData.type === 'selection') {
          result = true;
          break;
        }
      }
      return result;
    },
    // 插槽开放方法
    slotMethod() {
      return {
        handleNew: this.handleNew,
        handleView: this.handleView,
        handleEdit: this.handleEdit,
        handleDelete: this.handleDelete,
        setDialog: this.setDialog,
      }
    }
  },
  methods: {
    // 查询数据
    async handleSearch(value) {
      const { currPageAlias = 'currPage', pageSizeAlias = 'pageSize' } = this.option || {};
      const fixedParams = this.option.params || {};
      const param = {
        ...this.searchModel,
        ...value,
        [currPageAlias]: this.currentPage,
        [pageSizeAlias]: this.pageSize,
        ...fixedParams,
      };
      this.doSearch(param);
    },
    // 查询数据逻辑
    async doSearch(param) {
      const { totalCountAlias = 'totalCount' } = this.option || {};
      if (this.option.searchAPI) { // 配置了自定义查询API的情况
        this.tableLoading = true;
        try {
          const response = await this.option.searchAPI(param) || {};
          const { result = [] } = response;
          this.tableData = result;
          this.totalCount = response[totalCountAlias] || 0;
        } catch (error) {
          console.error(error);
        } finally {
          this.tableLoading = false;
        }
      } else if (_$http && this.option.url) { // 给定了http的情况
        this.tableLoading = true;
        _$http.get(`${this.option.url.trim('/')}/${this.option.searchMethod || 'page'}?${stringify(param)}`)
        .then((response) => {
          const { result = {} } = response || {};
          const { list = [] } = result || {};
          this.tableData = list;
          this.totalCount = result[totalCountAlias] || 0;
        })
        .finally(() => {
          this.tableLoading = false;
        });
      } else {
        this.tableLoading = true;
        setTimeout(() => { this.tableLoading = false; }, 1500);
      }
    },
    // 查看按钮
    handleView({ row }) {
      this.dialogTitle = this.i18n('eagle.scheme.detail') || '详情';
      this.dialogType = 'dialog-view';
      this.tableCurrentRow = row;
      this.resetFormModel();
      this.formMode = "view";
      this.$emit('dialog-change', this.dialogType);
      this.showDialog();
      this.doDetail(row);
    },
    // 查询单项数据详情
    async doDetail(param) {
      const { primaryKey = 'id', detailPrimaryKey, detailRow = false } = this.option || {};
      if (this.option.detailAPI && !detailRow) { // 配置了自定义查询API的情况
        this.dialogLoading = true;
        try {
          const result = await this.option.detailAPI(param);
          this.setFormModel(result);
        } catch (error) {
          console.error(error);
        } finally {
          this.dialogLoading = false;
        }
      } else if (_$http && this.option.url && !detailRow) { // 给定了http的情况
        this.dialogLoading = true;
        const defaultDetailMethod = `info/${detailPrimaryKey || primaryKey}/${param[detailPrimaryKey] || param[primaryKey]}`;
        const detailMethodFormat = this.option.detailMethod ? `${this.option.detailMethod.trim('/')}/${param[detailPrimaryKey || primaryKey]}` : undefined;
        _$http.get(`${this.option.url.trim('/')}/${detailMethodFormat || defaultDetailMethod}`)
        .then(response => {
          const { result = {} } = response || {};
          this.setFormModel(result);
        })
        .finally(() => {
          this.dialogLoading = false;
        });
      } else {
        this.setFormModel(param);
      }
    },
    // 新增按钮
    handleNew({ row }) {
      this.dialogTitle = this.i18n('eagle.scheme.new') || '新增';
      this.dialogType = 'dialog-form';
      this.tableCurrentRow = row;
      this.resetFormModel();
      this.formMode = "new";
      this.$emit('dialog-change', this.dialogType);
      this.showDialog();
    },
    // 编辑按钮
    async handleEdit({ row }) {
      this.dialogTitle = this.i18n('eagle.scheme.edit') || '编辑';
      this.dialogType = 'dialog-form';
      this.tableCurrentRow = row;
      this.resetFormModel();
      this.formMode = "edit";
      this.$emit('dialog-change', this.dialogType);
      this.showDialog();
      this.doGet(row);
    },
    // 查询单项数据
    async doGet(param) {
      const { primaryKey = 'id', getPrimaryKey, getRow = false } = this.option || {};
      if (this.option.getAPI) { // 配置了自定义查询API的情况
        this.dialogLoading = true;
        try {
          const result = await this.option.getAPI(param);
          this.setFormModel(result);
        } catch (error) {
          console.error(error);
        } finally {
          this.dialogLoading = false;
        }
      } else if (_$http && this.option.url && !getRow) { // 给定了http的情况
        this.dialogLoading = true;
        const defaultGetMethod = `get/${getPrimaryKey || primaryKey}/${param[getPrimaryKey] || param[primaryKey]}`;
        const getMethodFormat = this.option.getMethod ? `${this.option.getMethod.trim('/')}/${param[getPrimaryKey || primaryKey]}` : undefined;
        _$http.get(`${this.option.url.trim('/')}/${getMethodFormat || defaultGetMethod}`)
        .then(response => {
          const { result = {} } = response || {};
          this.setFormModel(result);
        })
        .finally(() => {
          this.dialogLoading = false;
        });
      } else {
        this.dialogLoading = true;
        this.setFormModel(param);
        setTimeout(() => { this.dialogLoading = false; }, 1500);
      }
    },
    // 删除按钮
    handleDelete(type, scope) {
      if (type === 'one') {
        this.doDelete([scope.row]);
      } else if (type === 'more') {
        this.$confirm(`${this.i18n('eagle.scheme.mulDeleteConfirm') || '是否删除已选中的'} [ ${this.tableSelection.length} ] ${this.i18n('eagle.scheme.item') || '项'}`, this.i18n('eagle.scheme.tip') || '提示', {
          confirmButtonText: this.i18n('eagle.scheme.confirm') || '确定',
          cancelButtonText: this.i18n('eagle.scheme.cancel') || '取消',
          type: 'warning'
        }).then(() => {
          this.doDelete(this.tableSelection || []);
        }).catch(() => {
          // 取消的操作
        });
      }
    },
    // 删除数据
    async doDelete(selection) {
      const { primaryKey = 'id', deletePrimaryKey } = this.option || {};
      const param = selection.map(item => item[deletePrimaryKey || primaryKey]);
      if (this.option.deleteAPI) { // 配置了自定义删除API的情况
        this.dialogLoading = true;
        try {
          const success = await this.option.deleteAPI(param, selection);
          if (success) {
            this.hideDialog();
            this.handleSearch();
            if (this.$message) { this.$message({ message: this.i18n('eagle.scheme.deleteSuccess') || '删除成功', type: 'success' }); }
          }
        } catch (error) {
          console.error(error);
        } finally {
          this.dialogLoading = false;
        }
      } else if (_$http && this.option.url) { // 给定了http的情况
        this.dialogLoading = true;
        const postData = param;
        _$http.post(`${this.option.url.trim('/')}/${this.option.deleteMethod || 'delete'}`, postData)
        .then(response => {
          const { code } = response || {};
          if (`${code}` === '0') {
            this.hideDialog();
            this.handleSearch();
            if (this.$message) { this.$message({ message: this.i18n('eagle.scheme.deleteSuccess') || '删除成功', type: 'success' }); }
          }
        })
        .finally(() => {
          this.dialogLoading = false;
        });
      }
    },
    // 重置表单值
    resetFormModel() {
      this.$nextTick(() => {
        if (this.$refs['eagle-form']) {
          this.$refs['eagle-form'].reset();
        } else {
          Object.keys(this.formModel).forEach(key => {
            this.formModel[key] = undefined;
          });
        }
      });
    },
    // 设置表单值
    setFormModel(value) {
      if (value && value instanceof Object) {
        Object.keys(value).forEach(key => {
          this.formModel[key] = value[key];
        });
      }
    },
    // 改变每页总数大小
    handleSizeChange(val) {
      this.currentPage = 1;
      this.pageSize = val;
      this.handleSearch();
    },
    // 改变当前页数
    handleCurrentChange(val) {
      this.currentPage = val;
      this.handleSearch();
    },
    // 表单提交
    handleSubmit(param) {
      if (this.formMode === 'new') {
        this.doNewSubmit(param);
      } else if (this.formMode === 'edit') {
        this.doEditSubmit(param);
      } else {
        this.hideDialog();
        this.handleSearch();
      }
    },
    // 新增提交逻辑
    async doNewSubmit(param) {
      const { primaryKey = 'id', formPrimaryKey } = this.option || {};
      if (this.option.newAPI) { // 配置了自定义查询API的情况
        this.dialogLoading = true;
        try {
          const success = await this.option.newAPI(param);
          if (success) {
            this.hideDialog();
            this.handleSearch();
            if (this.$message) { this.$message({ message: this.i18n('eagle.scheme.submitSuccess') || '提交成功', type: 'success' }); }
          }
        } catch (error) {
          console.error(error);
        } finally {
          this.dialogLoading = false;
        }
      } else if (_$http && this.option.url) { // 给定了http的情况
        this.dialogLoading = true;
        const postData = { ...param };
        delete postData[formPrimaryKey || primaryKey];
        _$http.post(`${this.option.url.trim('/')}/${this.option.newMethod || 'add'}`, postData)
        .then(response => {
          const { code } = response || {};
          if (`${code}` === '0') {
            this.hideDialog();
            this.handleSearch();
            if (this.$message) { this.$message({ message: this.i18n('eagle.scheme.submitSuccess') || '提交成功', type: 'success' }); }
          }
        })
        .finally(() => {
          this.dialogLoading = false;
        });
      }
    },
    // 编辑提交逻辑
    async doEditSubmit(param) {
      if (this.option.editAPI) { // 配置了自定义查询API的情况
        this.dialogLoading = true;
        try {
          const success = await this.option.editAPI(param);
          if (success) {
            this.hideDialog();
            this.handleSearch();
            if (this.$message) { this.$message({ message: this.i18n('eagle.scheme.editSuccess') || '编辑成功', type: 'success' }); }
          }
        } catch (error) {
          console.error(error);
        } finally {
          this.dialogLoading = false;
        }
      } else if (_$http && this.option.url) { // 给定了http的情况
        this.dialogLoading = true;
        _$http.post(`${this.option.url.trim('/')}/${this.option.editMethod || 'update'}`, param)
        .then(response => {
          const { code } = response || {};
          if (`${code}` === '0') {
            this.hideDialog();
            this.handleSearch();
            if (this.$message) { this.$message({ message: this.i18n('eagle.scheme.editSuccess') || '编辑成功', type: 'success' }); }
          }
        })
        .finally(() => {
          this.dialogLoading = false;
        });
      }
    },
    // 表单取消
    handleCancel() {
      this.hideDialog();
    },
    // 表格选择
    handleTableSelectionChange(selection) {
      this.tableSelection = selection;
      this.$emit('selection', selection);
    },
    // 显示弹出框
    showDialog() {
      this.dialogVisible = true;
    },
    // 隐藏弹出框
    hideDialog() {
      this.dialogVisible = false;
      this.tableSelection = [];
      this.tableLoading = false;
      this.tableCurrentRow = null;
      this.formModel = {};
      this.dialogTitle = '';
      this.dialogType = '';
    },
    // 设置弹出框模式
    setDialog({ title, type, model }) {
      this.dialogTitle = title;
      this.dialogType = type;
      this.$emit('dialog-change', type);
      if (model) {
        Object.keys(model).forEach(key => {
          this.formModel[key] = model[key];
        });
      }
      this.dialogVisible = true;
    }
  }
};
</script>
