tool.ts
/**Generate unique ID */ let _idCounter = 0; export function generateUniqueID() {<!-- --> var ts = new Date().getTime().toString(); var parts = ts.split("").reverse(); var id = ""; for (var i = 0; i < 5; + + i) {<!-- --> var index = Math.floor(Math.random() * parts.length); id + = parts[index]; } id + = ( + + _idCounter); return id; }
<template> <div class="table-box" :id="props.id"> <Table class="table-content" bordered :rowKey="(record) => record[props.rowKey]" :row-selection="rowSelection" :pagination="false" :scroll="{ y: props.scrollY || state.scrollY }" :columns="props.columns" :loading="state.loading" :data-source="state.tableData" :size="props.size" v-bind="$attrs"> <template v-slot:headerCell="{ column }"> <p class="table-title" :class="tableTitleClass(props.columns)">{<!-- -->{ column.title }}</p> </template> <template v-if="props.isCustomEmpty" v-slot:emptyText> <slot name="emptyText"></slot> </template> <template v-slot:bodyCell="{ column, record, index }"> <template v-for="slotName of props.slots"> <slot v-if="slotName === column?.dataIndex & amp; & amp; column?.dataIndex !== 'index'" :name="slotName" :column="column" :record="record" :index="index"></slot> </template> <span v-if="column & amp; & amp; column?.dataIndex === 'index'"> {<!-- -->{ getRowIndex(index) }} </span> <span v-if="column & amp; & amp; column?.dataIndex !== 'index' & amp; & amp; !props?.slots?.includes(column.dataIndex as string)">{<!-- -->{ parseDefaultValue(record, column.dataIndex as string) }}</span> </template> </Table> <a-pagination v-if="props.isPagination" v-model:current="state.pagination.current" v-model:page-size="state.pagination.pageSize" :total="state.pagination.total" :showQuickJumper="state.pagination.showQuickJumper" :showSizeChanger="state.pagination.showSizeChanger" @change="state.pagination.onChange" :show-total="state.pagination.showTotal" :position="state.pagination.position" :size="props.size" /> </div> </template> <script lang="ts" setup> import {<!-- --> Table, TablePaginationConfig } from "ant-design-vue"; import {<!-- --> SizeType } from "ant-design-vue/lib/config-provider"; import {<!-- --> reactive, computed, watch, nextTick, onUnmounted } from "vue" import request from "@/lib/request"; import {<!-- --> AxiosRequestConfig } from "axios" import _ from 'lodash' import {<!-- --> generateUniqueID } from "@/lib/tool"; const props = withDefaults(defineProps<{<!-- --> columns: any[]; pagination?: false | TablePaginationConfig; dataSource?: any[]; slots?: string[]; scrollY?: number | 'auto'; rowKey?: string; url?: string; baseURL?: string; reqMethods?: string; reqHeaders?: object; query?: object; parseTableData?: Function; isPagination?: boolean; defaultLoad?: boolean; pageParams?: any; pageNo?: string | number; pageSize?: string | number; isSelected?: boolean; size?: SizeType; updateLoading?: Function; isCustomEmpty?: boolean; isClearSelectKeys?: boolean; currentKeys?: string[]; currentKeysTable?: any[] id?: string }>(), {<!-- --> defaultLoad: true, pagination: false, isPagination: true, isSelected: true, size: 'small', isCustomEmpty: false, reqMethods: "POST", parseTableData: ({<!-- --> data, code }: any) => {<!-- --> if (code == 200) {<!-- --> return {<!-- --> data: data.data, total: data.totalCount }; } return {<!-- -->}; }, rowKey: 'id', id:'BaseTable' + generateUniqueID(), isClearSelectKeys: true }); const {<!-- --> baseURL = window.APP_CONFIG.baseUrl, reqHeaders = {<!-- -->}, pageParams = {<!-- --> pageNo: 1, pageSize: 10, }, } = props interface TypeState {<!-- --> loading: boolean; tableData?: any[]; pagination: TablePaginationConfig; selectedVlanIds: number[] | string[]; scrollY: number | 'auto'; tableHeight: string; selectedRows: any[]; } const state: TypeState = reactive({<!-- --> loading: false, tableData: props.dataSource, pagination: {<!-- --> current: pageParams.pageNo, pageSize: pageParams.pageSize, total: 0, showSizeChanger: true, showQuickJumper: true, position: ["bottomCenter"], showTotal: (total) => `Total ${<!-- -->total} items`, // Show how many pieces of data there are in total onChange: pageChange }, selectedVlanIds: [] as string[] | number[], selectedRows: [] as any[], scrollY: 0, tableHeight: `calc(100% - 56px)` }) function pageChange(page: number, pageSize: number) {<!-- --> currentChange(page) pageSize != state.pagination.pageSize & amp; & amp; sizeChange(pageSize) } const $emit = defineEmits(['currentChange', 'sizeChange', 'onData', 'selectChange', 'tableChange']); // Trigger event of parent component async function getData() {<!-- --> if (!props.url) return; let params: AxiosRequestConfig = {<!-- --> baseURL: baseURL, url: props.url, method: props.reqMethods, headers: reqHeaders, }; const page = {<!-- --> pageNo: state.pagination.current, pageSize: state.pagination.pageSize, } if (props.reqMethods === "GET") {<!-- --> params = {<!-- --> ...params, params: props.isPagination ? {<!-- --> ...props.query, ...page } : props.query, }; } else {<!-- --> params = {<!-- --> ...params, data: props.isPagination ? {<!-- --> ...props.query, ...page } : props.query, }; } try {<!-- --> if (props?.updateLoading) {<!-- --> props.updateLoading(true) } else {<!-- --> state.loading = true; } let dataS = await request(params); if (dataS) {<!-- --> let {<!-- --> data, total } = props.parseTableData(dataS); if (props?.isClearSelectKeys) {<!-- --> onSelectChange([], []) } if (props?.currentKeys?.length) {<!-- --> onSelectChange(props?.currentKeys, props?.currentKeysTable) } state.tableData = data; state.pagination.total = total; $emit("onData", data); } } catch (error) {<!-- --> console.log(error); } finally {<!-- --> if (props?.updateLoading) {<!-- --> props.updateLoading(false) } else {<!-- --> state.loading = false; } } } function refresh() {<!-- --> if (props.isPagination) {<!-- --> currentChange(1); } else {<!-- --> getData(); } } function currentChange(val: number) {<!-- --> state.pagination.current = val; getData(); } function sizeChange(val: number) {<!-- --> state.pagination.pageSize = val; $emit("sizeChange", val); currentChange(1); } const onSelectChange = (changeAbleRowKeys: any[], selectedRows: any) => {<!-- --> state.selectedVlanIds = changeAbleRowKeys; state.selectedRows = selectedRows; $emit('selectChange', changeAbleRowKeys, selectedRows) }; const onSelect = (record: any, selected: any, _selectedRows: any) => {<!-- --> let arr = state.selectedVlanIds as any[]; if (selected) {<!-- --> // onSelectChange(selectedRows?.map((e: any) => e[props.rowKey]), selectedRows) arr.push(record[props.rowKey] as string) state.selectedRows.push(record) onSelectChange(state.selectedVlanIds, state.selectedRows) } else {<!-- --> const arrI = arr.findIndex((e) => e === record[props.rowKey]) const rowI = state.selectedRows.findIndex((e) => e[props.rowKey] === record[props.rowKey]) state.selectedRows.splice(rowI, 1) arr.splice(arrI, 1) onSelectChange(arr, state.selectedRows) } } const onSelectAll = (selected: any, _selectedRows: any, _changeRows: any) => {<!-- --> if (selected) {<!-- --> if (state.tableData) {<!-- --> onSelectChange(state.tableData?.map((e: any) => e[props.rowKey]), state.tableData) } } else {<!-- --> onSelectChange([], []) } } const rowSelection = computed(() => {<!-- --> let result: {<!-- -->} | undefined = undefined if (props.isSelected) {<!-- --> result = {<!-- --> selectedRowKeys: state.selectedVlanIds, // onChange: onSelectChange, onSelectAll: onSelectAll, hideDefaultSelections: true, onSelect: onSelect, } } return result; }); props.defaultLoad & amp; & amp; refresh() const parseDefaultValue = (record: Record<string, any>, dataIndex: string) => {<!-- --> const dataIndexs = dataIndex.split("."); let result = record; dataIndexs.forEach((element) => {<!-- --> if (result) {<!-- --> result = result[element]; } }); if (result == null) {<!-- --> return "--"; } return result; }; function getRowIndex(index: number) {<!-- --> const pageParams = {<!-- --> pageNo: state?.pagination?.current || 0, pageSize: state?.pagination?.pageSize, } if (pageParams & amp; & amp; pageParams.pageSize) {<!-- --> return ( pageParams.pageSize * (pageParams?.pageNo - 1) + index + 1 ); } return index + 1; } function tableTitleClass(column: any) {<!-- --> return `${<!-- -->column?.isRequired ? 'is-required' : ''}` } function getTableData() {<!-- --> return state.tableData } function getSelectKeys() {<!-- --> return state.selectedVlanIds } const doLayout = _.debounce(function () {<!-- --> nextTick(() => {<!-- --> const tableMain = (document.querySelector(`#${<!-- -->props.id} .table-content`) as HTMLDivElement)?.offsetHeight const headerH = (document.querySelector(`#${<!-- -->props.id} .ant-table-header`) as HTMLDivElement)?.offsetHeight state.scrollY = tableMain - headerH }) }, 200) doLayout() window.addEventListener("resize", doLayout); onUnmounted(() => {<!-- --> window.removeEventListener('resize', doLayout) }) watch( () => props.isPagination, (val) => {<!-- --> nextTick(() => {<!-- --> const paginationH = (document.querySelector(`#${<!-- -->props.id} .ant-pagination`) as HTMLDivElement)?.offsetHeight state.tableHeight = val ? `calc(100% - ${<!-- -->paginationH}px)` : `100%` }) }, {<!-- --> immediate: true } ); watch( () => props.dataSource, (val) => {<!-- --> state.tableData = val }, {<!-- --> immediate: true, deep: true } ); watch( () => state.tableData, (val) => {<!-- --> $emit('tableChange', val) doLayout() }, {<!-- --> immediate: true } ); defineExpose({<!-- --> refresh, getTableData, doLayout, onSelectChange, getSelectKeys }) </script> <style scoped lang="scss"> $bg-color: #fff; .table-box {<!-- --> height: 100%; background-color: $bg-color; .table-content {<!-- --> height: v-bind("state.tableHeight"); overflow: auto; } :deep(.ant-pagination) {<!-- --> padding: 12px; display: flex; justify-content: center; background-color: $bg-color; } } .is-required {<!-- --> & amp;:before {<!-- --> content: '*'; color: red } } .table-title {<!-- --> white-space: break-spaces; } </style>