<template>
  <div class='base-table-layer' ref='base-table-layer'>
    <!-- 抽屉组件 -->
    <el-drawer title='更多筛选' :visible.sync='drawer' :size='550'>
      <div class='operation-box drawer-box' ref='operation-box'>
        <div class='operation-filter' v-show='search'>
          <el-form inline>
            <slot name='search' v-if='search'></slot>
            <el-form-item>
              <el-button type='primary' icon='el-icon-search' @click='searchFn(true)'>搜索</el-button>
              <el-button plain type='primary' icon='el-icon-refresh' @click='resetFn'>重置</el-button>
            </el-form-item>
          </el-form>
        </div>
      </div>
    </el-drawer>

    <div class='operation-box' ref='operation-box'>
      <div class='operation-filter' v-show='search'>
        <el-form inline>
          <div ref='searchDom' class='searchStyle'>
            <div class='searchStyle-item'>
              <slot name='search' v-if='search'></slot>
            </div>
            <div class='btnDom'>
              <div
                class='unfold'
                v-if='isSearchDom > searchDomMax + 1 && screenType === 1'
                @click='filterShowFn(!isUnfold)'
              >
                {{ isUnfold ? '收起' : '展开' }}<i :class="`el-icon-arrow-${isUnfold ? 'up' : 'down'} `"></i>
              </div>
              <el-form-item style='margin-right: 0'>
                <el-button type='primary' @click='searchFn(true)'>搜索</el-button>
                <el-button plain type='primary' @click='resetFn'>重置</el-button>
                <el-button v-if='isSearchDom > searchDomMax + 1 && screenType === 2' @click='drawer = true' plain type='success'>更多筛选
                </el-button>
              </el-form-item>
            </div>
          </div>
        </el-form>
      </div>
    </div>
    <div class='l-main-box'>
      <div class='operation-control' v-if='control'>
        <p class='operation-control-t'>操作</p>
        <div>
          <slot name='prevBtn'></slot>
          <el-button type='primary' size='medium' @click='addFn' v-if='addBtn'>{{ addBtnText }}</el-button>
          <slot name='nextBtn'></slot>
          <el-dropdown trigger='click' @command='handleCommand' v-if='moreOperation'>
            <el-button size='medium' plain style='margin-left: 12px'>
              更多操作
              <i class='el-icon-arrow-down el-icon--right'></i>
            </el-button>
            <el-dropdown-menu slot='dropdown'>
              <el-dropdown-item v-if='batchDelBtn' command='batchDelFn'>{{ batchDelBtnText }}</el-dropdown-item>
              <slot name='operation'></slot>
              <el-dropdown-item v-if='importBtn' command='importFn'>导入数据</el-dropdown-item>
              <el-dropdown-item v-if='exportBtn' command='exportFn'>导出数据</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </div>
      </div>
      <slot name='showInformation' v-if='showInformation'></slot>
      <div class='table-box'>
        <el-table
          ref='table'
          v-loading='loading'
          stripe
          border
          tooltip-effect='dark'
          :height='tableHeight < 50 ? 300 : tableHeight'
          :data='tableData'
          :row-key='rowKey'
          :tree-props='treeProps'
          :span-method='mergeTable'
          :show-summary='showSummary'
          :summary-method='summaries'
          @selection-change="handleSelectionChange"
        >
          <el-table-column v-if='many' type='selection' align='center' width='50' />
          <el-table-column v-if='index' type='index' label='序号' align='center' width='50'>
            <template slot-scope='scope'>
              <span>{{ (searchParams.current - 1) * searchParams.size + scope.$index + 1 }}</span>
            </template>
          </el-table-column>
          <el-table-column
            v-for='item in tableHeader'
            :key='item.prop'
            :label='item.label'
            :prop='item.prop'
            :fixed='item.fixed || false'
            :width='item.width'
            :min-width='item.minWidth'
            :align='item.align'
            show-overflow-tooltip
            :sortable='item.sortable || false'
            header-align='center'
          >
            <template slot-scope='scope'>
              <span v-if="item.type == 'render'">
                <ex-slot :render='item.render' :row='scope.row' :index='scope.$index' :column='item' />
              </span>
              <span v-else>{{ scope.row[item.prop] || item.defaultValue || '-' }}</span>
            </template>
          </el-table-column>
          <el-table-column
            v-if='tableOperate && tableOperate.length > 0'
            label='操作'
            header-align='center'
            align='center'
            :fixed='fixedFn'
            :width="tableOperate.length === 1 ? '80' : tableOperate.length * 60"
          >
            <template slot-scope='scope'>
              <el-tooltip
                effect='dark'
                placement='top'
                v-for='btn in tableOperate'
                :key='btn.label'
                :content='btn.label'
                :enterable='false'
              >
                <el-button
                  v-show='btnShowFn(btn, scope.row)'
                  size='mini'
                  :type='btn.type'
                  :icon='btn.icon'
                  :disabled='btnDisableFn(btn, scope.row)'
                  @click='btn.func(scope.row, scope.$index)'
                />
              </el-tooltip>
            </template>
          </el-table-column>
        </el-table>
        <el-dialog
          ref='imgDialog'
          width='400px'
          :title='imgDialog.title'
          :visible.sync='imgDialog.visible'
          :close-on-click-modal='false'
        >
          <el-image style='width: 100%; height: 100%' :src='imgDialog.url' fit='fit'></el-image>
        </el-dialog>
      </div>
    </div>
    <div class='pagination-box' ref='pagination-box' v-show='isPage'>
      <el-pagination
        layout='total, prev, pager, sizes, next'
        :total='Number(searchParams.total)'
        :page-size='Number(searchParams.size)'
        :page-sizes='[10, 50, 100, 200]'
        :current-page='Number(searchParams.current)'
        @current-change='currentChangeFn'
        @size-change='sizeChangeFn'
        @prev-click='prevFn'
        @next-click='nextFn'
      />
    </div>
  </div>
</template>

<script>
import { isArray } from '@utils/validate';

export default {
  name: 'BaseTable',
  components: {
    exSlot: {
      functional: true,
      props: {
        row: Object,
        render: Function,
        index: Number,
        column: {
          type: Object,
          default: null
        }
      },
      render: (h, data) => {
        let params = {
          row: data.props.row,
          index: data.props.index
        };
        if (data.props.column) {
          params.column = data.props.column;
        }
        return data.props.render(h, params);
      }
    }
  },
  props: {
    many: {
      type: Boolean,
      default: true
    },
    index: {
      type: Boolean,
      default: true
    },
    search: {
      type: Boolean,
      default: true
    },
    control: {
      type: Boolean,
      default: true
    },
    moreOperation: {
      type: Boolean,
      default: true
    },
    addBtn: {
      type: Boolean,
      default: true
    },
    batchDelBtn: {
      type: Boolean,
      default: true
    },
    batchDelBtnText: {
      type: String,
      default: '批量删除'
    },
    importBtn: {
      type: Boolean,
      default: false
    },
    exportBtn: {
      type: Boolean,
      default: false
    },
    infoBtn: {
      type: Boolean,
      default: true
    },
    rowKey: {
      type: String,
      default: ''
    },
    treeProps: {
      type: Object,
      default: () => {
        return {};
      }
    },
    showSummary: {
      type: Boolean,
      default: false
    },
    showInformation: {
      type: Boolean,
      default: false
    },
    tableData: {
      type: Array,
      default: () => {
        return [];
      }
    },
    tableHeader: {
      type: Array,
      default: () => {
        return [];
      }
    },
    tableOperate: {
      type: Array,
      default: () => {
        return [];
      }
    },
    isPage: {
      type: Boolean,
      default: true
    },
    searchParams: {
      type: Object,
      default: () => {
        return {};
      }
    },
    cutHeight: {
      type: Number,
      default: 0
    },
    tableShowError: {
      type: Boolean,
      default: false
    },
    addBtnText: {
      type: String,
      default: '新增'
    },
    // 是否开启更多筛选的功能
    moreSearch: {
      type: Boolean,
      default: true
    },
    // 筛选类型 1 为展开方式 2 为弹窗方式
    screenType: {
      type: Number,
      default: 1
    },
    // 搜索框最大数量
    searchDomMax: {
      type: Number,
      default: 3
    },
    // 操作栏是否固定
    operateFixed: {
      type: String,
      default: ''
    },
    // 表格加载
    loading: {
      type: Boolean,
      default: false
    }
  },
  computed: {
    fixedFn() {
      let pattern = /^(left|right)$/;
      return pattern.test(this.operateFixed) ? this.operateFixed : false;
    }
  },
  data() {
    return {
      tableHeight: 300,
      imgDialog: {
        visible: false,
        title: '',
        url: ''
      },
      isSearchDom: 0, // 当前搜索框dom数量
      drawer: false, // 是否显示抽屉
      isUnfold: true
    };
  },
  watch: {
    tableData(val) {
      if (val.length !== 0) {
        this.resizeTable();
      }
    },
    'searchParams.total': {
      handler(newVal, oldVal) {
        let vm = this;
        if (vm.searchParams.current !== 1 && vm.searchParams.current > newVal / vm.searchParams.size) {
          vm.searchParams.current = Math.ceil(newVal / vm.searchParams.size);
          this.searchFn(false);
        }
      },
      immediate: true
    }
  },
  mounted() {
    let vm = this;
    this.$nextTick(() => {
      if (this.moreSearch) {
        this.filterShowFn();
      }
      window.addEventListener('resize', () => {
        vm.resizeTable();
      });
    });
  },
  methods: {
    // * 筛选条件展示逻辑
    filterShowFn(isUnfold = true) {
      this.isUnfold = isUnfold;
      let domList = this.$refs.searchDom.getElementsByClassName('el-form-item');
      this.isSearchDom = this.$refs.searchDom.getElementsByClassName('el-form-item').length;
      for (let i = 0; i < domList.length; i++) {
        // 当当前dom数量超过设定的最大值，则隐藏其他dom，但不隐藏最后一个dom
        if (i >= this.searchDomMax && i !== domList.length - 1) {
          domList[i].style.display = this.isUnfold ? 'inline-block' : 'none';
        }
      }
    },
    searchFn(isReset = false) {
      this.$emit('searchFn', isReset);
    },
    resetFn() {
      this.$emit('resetFn', true);
    },
    addFn() {
      this.$emit('addFn');
    },
    handleCommand(command) {
      if (!command) {
        return;
      }
      this.$emit(command, this.$refs.table.selection);
    },
    clearSelection() {
      this.$refs.table.clearSelection();
    },
    sizeChangeFn(size) {
      this.searchParams.size = size;
      this.searchFn(false);
    },
    currentChangeFn(current) {
      this.searchParams.current = current;
      this.searchFn(false);
    },
    prevFn(pageNum) {
      this.searchParams.current = pageNum;
      this.searchFn(false);
    },
    nextFn(pageNum) {
      this.searchParams.current = pageNum;
      this.searchFn(false);
    },
    btnShowFn(btn, row) {
      try {
        if (typeof btn.show === 'function') {
          return btn.show(row);
        }
        return true;
      } catch (e) {
        return true;
      }
    },
    btnDisableFn(btn, row) {
      try {
        if (typeof btn.disabled === 'function') {
          return btn.disabled(row);
        }
        return false;
      } catch (e) {
        return false;
      }
    },
    resizeTable() {
      let vm = this;
      // vm.tableHeight = 1;
      setTimeout(() => {
        let cutHeight = vm.cutHeight;
        let baseTableHeight = vm.$refs['base-table-layer'].offsetHeight;
        let operationHeight = vm.$refs['operation-box'].offsetHeight;
        let paginationHeight = vm.$refs['pagination-box'].offsetHeight;
        vm.tableHeight = baseTableHeight - operationHeight - paginationHeight - cutHeight - 46;
      }, 50);
    },
    mergeTable({ row, column, rowIndex, columnIndex }) {
      let merge;
      this.$emit(
        'mergeTable',
        {
          row,
          column,
          rowIndex,
          columnIndex
        },
        (result) => {
          merge = result;
        }
      );
      this.$nextTick(() => {
        // this.$refs.table.doLayout();
      });
      if (isArray(merge) && merge.length > 0) {
        return merge;
      }
      if (merge instanceof Object && Object.values(merge).length > 0) {
        return merge;
      }
    },
    summaries(params) {
      let sum = [];
      this.$emit('summaries', params, (result) => {
        sum = result;
      });
      return sum;
    },
    handleSelectionChange(val) {
      this.$emit('selectChange', val);
    }
  }
};
</script>

<style scoped lang='less'>
@p: 0px;
@r: 0px;

.base-table-layer {
  height: 100%;
  display: flex;
  flex-direction: column;

  .operation-box {
    display: flex;
    flex-direction: column;
    padding-bottom: 10px;

    .operation-filter {
      flex: 1;
      // margin-bottom: 16px;
      background: #fff;
      padding: @p;
      border-radius: @r;
      padding-bottom: 6px;
      // padding-right: 30px;
      border-bottom: 1px dashed #dfdddd;

      :deep(.el-form) {
        .el-form-item {
          margin: 0;
          margin-right: 20px;
          margin-bottom: 10px;

          .el-form-item__label {
            background: #f5f7fa;
            padding: 0px;
            border: 1px solid #dcdfe6;
            border-right: 0;
            border-radius: 4px 0 0 4px;
            box-sizing: border-box;
            height: 40px;
            width: 100px;
            text-align: center;
          }

          .el-form-item__content {
            .el-input__inner {
              border-radius: 0 4px 4px 0;
              padding-right: 25px;
            }
          }
        }
      }

      .search-btn-group {
        display: flex;
        align-items: flex-start;
      }
    }
  }

  .table-box {
    flex: 1;
    box-sizing: border-box;

    :deep(.el-table) {
      height: 100%;
    }
  }

  .pagination-box {
    display: flex;
    justify-content: flex-end;

    :deep(.el-pagination) {
      padding: 0;
      padding-top: 10px;
      font-weight: normal;
      display: flex;
      align-items: center;

      .el-pagination__total {
        height: 100%;
        display: flex;
        align-items: center;
      }

      .el-pagination__sizes {
        height: 100%;
        line-height: inherit;
        display: flex;
        align-items: center;
      }
    }
  }
}

.operation-control {
  // margin-left: auto;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;

  &-t {
    margin: 0;
    font-weight: bold;
    color: #333;
    display: flex;
    align-items: center;

    &::before {
      content: '';
      display: block;
      width: 6px;
      height: 14px;
      background: @theme-color;
      margin-right: 8px;
      border-radius: 88px;
    }
  }
}

.drawer-box {
  padding: 20px !important;
  padding-top: 0 !important;

  :deep(.operation-filter) {
    padding: 0 !important;
  }

  :deep(.el-form-item) {
    margin-right: 0 !important;
    display: flex;

    .el-form-item__content {
      flex: 1;
    }

    .el-select {
      width: 100%;
    }

    .el-cascader {
      width: 100%;
    }
  }

  :deep(.el-form-item__content) {
    display: flex;
    justify-content: flex-end;
  }

  :deep(.el-input__inner) {
    width: 100%;
  }
}

:deep(.el-drawer__header) {
  margin-bottom: 20px !important;
}

.unfold {
  display: inline-block;
  height: 40px;
  line-height: 40px;
  padding-right: 12px;
  color: #4c84ff;
  cursor: pointer;

  i {
    padding-left: 6px;
    font-weight: bold;
  }
}

:deep(.el-table th.el-table__cell) {
  background: #fafafa;
  color: #333;
}

.l-main-box {
  background: #fff;
  border-radius: @r;
  padding: @p;
}

.searchStyle {
  display: flex;
  justify-content: space-between;

  &- {
    display: flex;
    flex: 1;
    flex-direction: initial;
    flex-wrap: wrap;
  }
}

.btnDom {
  display: flex;
  min-width: 240px;
  justify-content: flex-end;
}

/deep/ .el-date-editor.el-input,
.el-date-editor.el-input__inner {
  width: 198px;
}
</style>
