<template>
  <div class="scTable" ref="scTableMain" :style="{ height: theight }" v-loading="loading">
    <div :class="!hideDo ? 'scTable-table' : 'scTable-table-noPag'">
      <el-table
        v-bind="$attrs"
        :data="tableData"
        :row-key="rowKey"
        :key="toggleIndex"
        ref="scTable"
        height="100%"
        @sort-change="sortChange"
        @filter-change="filterChange"
      >
        <slot></slot>
        <template v-for="(item, index) in userColumn" :key="index">
          <el-table-column
            v-if="!item.hide"
            :column-key="item.prop"
            :label="item.label"
            :prop="item.prop"
            :width="item.width"
            :sortable="item.sortable"
            :fixed="item.fixed"
            :filters="item.filters"
            :filter-method="remoteFilter || !item.filters ? null : filterHandler"
          >
            <template #default="scope">
              <slot :name="item.prop" v-bind="scope">
                {{ scope.row[item.prop] }}
              </slot>
            </template>
          </el-table-column>
        </template>
        <el-table-column min-width="1"></el-table-column>
        <template #empty>
          <el-empty :description="emptyText" :image-size="80"></el-empty>
        </template>
      </el-table>
    </div>
    <div class="scTable-page" v-if="!hidePagination && !hideDo">
      <div class="scTable-pagination">
        <el-pagination
          v-if="!hidePagination"
          background
          :small="true"
          :layout="paginationLayout"
          :total="total"
          :page-size="pageSize"
          :pager-count="pagerCount"
          v-model:currentPage="currentPage"
          @current-change="paginationChange"
        ></el-pagination>
      </div>
      <div class="scTable-do" v-if="!hiderefresh">
        <el-button
          @click="refresh"
          icon="el-icon-refresh"
          circle
          style="margin-left: 15px"
        ></el-button>
      </div>
    </div>
  </div>
</template>

<script>
import { reactive, watch, onMounted, ref, toRefs, getCurrentInstance, computed } from 'vue'
import config from '@/config/table'

export default {
  name: 'scTable',
  props: {
    tableName: { type: String, default: '' },
    apiObj: { type: Object, default: () => {} },
    params: { type: Object, default: () => ({}) },
    data: { type: Object, default: () => {} },
    height: { type: [String, Number], default: '100%' },
    rowKey: { type: String, default: '' },
    column: { type: Object, default: () => {} },
    hideDo: { type: Boolean, default: false }, // 是否显示分页
    pagerCount: { type: Number, default: 7 }, // 是否显示分页
    hiderefresh: { type: Boolean, default: false }, // 是否显示刷新
    remoteSort: { type: Boolean, default: false },
    remoteFilter: { type: Boolean, default: false },
    hidePagination: { type: Boolean, default: false },
    paginationLayout: { type: String, default: 'total, prev, pager, next, jumper' }
  },

  setup(props) {
    const { proxy } = getCurrentInstance()
    const scTable = ref(null)
    const scTableMain = ref(null)
    const state = reactive({
      emptyText: '暂无数据',
      toggleIndex: 0,
      tableData: [],
      pageSize: config.pageSize,
      total: 0,
      currentPage: 1,
      prop: null,
      order: null,
      loading: false,
      tableHeight: '100%',
      tableParams: props.params,
      userColumn: []
    })
    // 计算高度
    const theight = computed(() => {
      return Number(props.height) ? `${Number(props.height)}px` : props.height
    })
    // 监听响应式对象
    watch(
      () => [props.data, props.apiObj],
      ([newdataValue, newapiObjValue], [olddataValue, oldapiObjValue]) => {
        // 判断是不是newdataValue发生的变化
        if (olddataValue !== newdataValue) {
          if (props.data != undefined) {
            state.tableData = props.data
            state.total = state.tableData.length
          }
        }
        // 判断是不是oldapiObjValue发生的变化
        if (oldapiObjValue !== newapiObjValue) {
          state.tableParams = props.params
          refresh()
        }
      }
    )
    onMounted(() => {
      state.userColumn = props.column

      // 判断是否静态数据
      if (props.apiObj) {
        getData()
      } else if (props.data) {
        state.tableData = props.data
        state.total = state.tableData.length
      }
    })

    // 获取数据
    const getData = async () => {
      state.loading = true

      const reqData = {
        [config.request.page]: state.currentPage,
        [config.request.pageSize]: state.pageSize
      }
      if (props.hidePagination) {
        delete reqData[config.request.page]
        delete reqData[config.request.pageSize]
      }
      Object.assign(reqData, state.tableParams)
      try {
        var res = await props.apiObj.get(reqData)
      } catch (error) {
        console.log(error)
        state.loading = false
        state.emptyText = error.statusText
        return false
      }
      if (res.code != 200) {
        state.loading = false
        state.emptyText = res.msg
      } else {
        state.emptyText = '暂无数据'
        if (res.data) {
          state.tableData = res.data.list
          state.total = res.data.total
        } else {
          state.tableData = []
          state.total = 0
        }
        state.loading = false
      }
      scTable.value.$el.querySelector('.el-table__body-wrapper').scrollTop = 0
    }
    // 分页点击
    const paginationChange = () => {
      getData()
    }
    // 刷新数据
    const refresh = () => {
      scTable.value.clearSelection()
      getData()
    }
    // 更新数据 合并上一次params
    const upData = (params, page = 1) => {
      state.currentPage = page
      scTable.value.clearSelection()
      Object.assign(state.tableParams, params || {})
      getData()
    }
    // 清空数据data
    const clearData = () => {
      state.tableData = []
    }
    // 重载数据 替换params
    const reload = (params, page = 1) => {
      state.currentPage = page
      state.tableParams = params || {}
      scTable.value.clearSelection()
      scTable.value.clearSort()
      scTable.value.clearFilter()
      getData()
    }
    // 排序事件
    const sortChange = (obj) => {
      if (!props.remoteSort) {
        return false
      }
      if (obj.column && obj.prop) {
        state.prop = obj.prop
        state.order = obj.order
      } else {
        state.prop = null
        state.order = null
      }
      getData()
    }
    // 本地过滤
    const filterHandler = (value, row, column) => {
      const property = column.property
      return row[property] === value
    }
    // 过滤事件
    const filterChange = (filters) => {
      if (!props.remoteFilter) {
        return false
      }
      Object.keys(filters).forEach((key) => {
        filters[key] = filters[key].join(',')
      })
      upData(filters)
    }
    // 原生方法转发
    const clearSelection = () => {
      scTable.value.clearSelection()
    }
    const toggleRowSelection = (row, selected) => {
      scTable.value.toggleRowSelection(row, selected)
    }
    const toggleAllSelection = () => {
      scTable.value.toggleAllSelection()
    }
    const toggleRowExpansion = (row, expanded) => {
      scTable.value.toggleRowExpansion(row, expanded)
    }
    const setCurrentRow = (row) => {
      scTable.value.setCurrentRow(row)
    }
    const clearSort = () => {
      scTable.value.clearSort()
    }
    const clearFilter = (columnKey) => {
      scTable.value.clearFilter(columnKey)
    }
    const doLayout = () => {
      scTable.value.doLayout()
    }
    const sort = (prop, order) => {
      scTable.value.sort(prop, order)
    }
    return {
      ...toRefs(state),
      scTable,
      scTableMain,
      getData,
      paginationChange,
      refresh,
      upData,
      reload,
      sortChange,
      filterHandler,
      filterChange,
      clearSelection,
      toggleRowSelection,
      toggleAllSelection,
      toggleRowExpansion,
      setCurrentRow,
      clearSort,
      clearFilter,
      doLayout,
      sort,
      clearData,
      theight
    }
  }
}
</script>

<style scoped>
.scTable {
}
.scTable-table {
  height: calc(100% - 50px);
}
.scTable-table-noPag {
  height: 100%;
}
.scTable-page {
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 15px;
}
.scTable-do {
  white-space: nowrap;
}
</style>

Logo

前往低代码交流专区

更多推荐