table.vue 3.42 KB
<script setup lang="ts">
  import { computed, ref } from 'vue';
  import usePagination from '@/hooks/pagination';
  import { Table, Row, Col } from '@arco-design/web-vue';
  import { AnyObject, sizeType } from '@/types/global';

  type PropType = {
    loading?: boolean;
    rowKey?: string;
    hoverType?: string;
    hidePage?: boolean;
    simplePage?: boolean;
    pageSize?: number;
    size?: sizeType;
    onQuery: (params?: AnyObject) => Promise<any>;
  };

  defineEmits<{
    (e: 'rowSort', dataIndex: string, direction: string): void;
  }>();

  const props = withDefaults(defineProps<PropType>(), { loading: false, rowKey: 'id', size: 'small', pageSize: 20 });
  const { pagination, setPage, setPageSize, setTotal } = usePagination({
    simple: props.simplePage,
    size: props.size,
    pageSize: props.pageSize,
  });
  const list = ref<any[]>([]);
  const tableRef = ref();

  const pageQueryParams = computed(() => {
    return props.hidePage ? {} : { page: pagination.value.current, pageSize: pagination.value.pageSize };
  });

  const hoverType = computed(() => props.hoverType || 'default');

  const onFetch = () =>
    props.onQuery(pageQueryParams.value).then(({ data, meta }) => {
      list.value = data;
      setPage(props.hidePage ? 1 : meta.current);
      setTotal(props.hidePage ? data.length : meta.total);
      setPageSize(props.hidePage ? pagination.value.pageSize : meta.limit);
    });

  const onPageChange = (page: number) => {
    setPage(page || 1);
    onFetch();
  };

  const onSizeChange = (size: number) => {
    setPageSize(size);
    setPage(1);
    onFetch();
  };

  const onPush = (row: unknown) => {
    list.value.unshift(row);
    // eslint-disable-next-line no-plusplus
    ++pagination.value.total;
  };

  const onRemove = (index: number) => {
    list.value.splice(index, 1);
    // eslint-disable-next-line no-plusplus
    --pagination.value.total;
  };

  const resetSort = () => tableRef.value?.clearSorters();

  const getPagination = () => pagination.value;

  const getCount = () => pagination.value.total;

  const getList = () => list.value;

  const formatSortType = (type: string): string => type?.replace('end', '') ?? '';

  defineExpose({ onFetch, onPageChange, onSizeChange, resetSort, getCount, getPagination, getList, onPush, onRemove });
</script>

<template>
  <Row justify="space-between" align="center">
    <Col class="table-tool-item" :span="16" style="text-align: left">
      <slot name="tool" :size="size" />
    </Col>
    <Col class="table-tool-item" :span="8" style="text-align: right">
      <slot name="tool-right" :size="size" />
    </Col>
  </Row>
  <Table
    ref="tableRef"
    v-bind="$attrs"
    :row-key="rowKey as string"
    :loading="loading as boolean"
    :size="size as sizeType"
    :data="list"
    :pagination="hidePage ? false : pagination"
    :bordered="false"
    :table-layout-fixed="true"
    @page-change="onPageChange"
    @page-size-change="onSizeChange"
    @sorter-change="(dataIndex:string, direction:string) => $emit('rowSort', dataIndex, formatSortType(direction))"
  >
    <template #columns>
      <slot />
    </template>
  </Table>
</template>

<style lang="less" scoped>
  :deep(.arco-table-cell) {
    padding: 5px 8px !important;

    :hover {
      cursor: v-bind(hoverType);
    }

    & > .arco-table-td-content .arco-btn-size-small {
      padding: 5px !important;
    }
  }

  :deep(.table-tool-item) {
    > * {
      margin-bottom: 12px !important;
    }
  }
</style>