vue3+antdv 表格封装

tool.ts


/**生成唯一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 && column?.dataIndex !== 'index'" :name="slotName"
                        :column="column" :record="record" :index="index">slot>
                template>
                <span v-if="column && column?.dataIndex === 'index'">
                    {{ getRowIndex(index) }}
                span>
                <span
                    v-if="column && column?.dataIndex !== 'index' && !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}`, // 展示总共有几条数据
        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 && sizeChange(pageSize)
}

const $emit = defineEmits(['currentChange', 'sizeChange', 'onData', 'selectChange', 'tableChange']); // 父组件的触发事件
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 && 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 && 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 {
    &:before {
        content: '*';
        color: red
    }
}

.table-title {
    white-space: break-spaces;
}
style>

你可能感兴趣的:(javascript,前端,vue.js)