前言
CR公司其他大佬负责的项目-后台管理系统,主要就是很多列表页的展示,项目基于vite+vue+antdVue+ts, 开发新页面,cv大法就不用说了,每次直接cv老页面,然后改改改改改改改改改改改改改改改改改改改改改改改改改改, 代码都是一摸一样,就很烦。。。。
目的
这里就通过自定义hook优化List业务代码,使cv更简单,减少代码量,提高代码复用性、阅读性,提高工作效率。
hook options
field | desciption |
---|---|
columns | 列表配置 |
firstDontLoad | 是否初次加载数据 |
extraParams | 额外参数 |
mapRequest | 参数处理函数 |
mapResponse | 请求处理函数 |
ajax | 请求 |
throwErrorMessageWhenResNotFitDefined | 是否抛出异常 |
paginationConfig | 分页配置 |
export type TableResponse<T extends Record<string, any>> = {
total: number;
list: T[];
};
export type TableRequest<T extends Record<string, any>> = {
isAsc?: string; //"desc" | "asc";
oderByColumn?: string;
currentPage: number;
pageSize: number;
} & T;
type Option<
ExtraParams extends Record<string, any>,
RecordRaw extends Record<string, any>
> = {
columns?: ColumnsType<RecordRaw>;
firstDontLoad?: boolean;
extraParams?: ExtraParams;
mapRequest?: (params: any) => any;
mapResponse?: (dataSource: RecordRaw[], other: any) => RecordRaw[];
ajax: (
params: TableRequest<ExtraParams>
) => Promise<TableResponse<RecordRaw>>;
throwErrorMessageWhenResNotFitDefined?: boolean;
paginationConfig?: Partial<TablePaginationConfig>;
};
useTable Hook
export function useTable<ExtraParams, RecordRaw>(
option: Option<ExtraParams, RecordRaw>
) {
const pagination = reactive<TablePaginationConfig>({
total: 0,
current: 1,
pageSize: 10,
pageSizeOptions: ["10", "20", "50", "100"],
showQuickJumper: true,
showSizeChanger: true,
showTotal: function (total) {
return "共" + total + "条";
},
...(option.paginationConfig ?? {}),
});
const sorter = ref<SorterResult<any> | null>(null);
const loading = ref(!option.firstDontLoad);
const dataSource = ref<RecordRaw[]>([]);
const scroll = ref({
x:
option.columns?.reduce(
(prev, cur) => prev + (typeof cur.width === "number" ? cur.width : 120),
0
) ?? 1300,
});
const fetchData = async () => {
loading.value = true;
try {
const params = (
option?.extraParams ? toRaw(unref(option.extraParams)) : {}
) as ExtraParams;
const t = {
...params,
isAsc: sorter.value?.order?.slice(0, -3) ?? undefined,
oderByColumn: sorter.value?.field as string,
currentPage: pagination.current!,
pageSize: pagination.pageSize!,
};
const p =
typeof option?.mapRequest === "function" ? option.mapRequest(t) : t;
const { total, list, ...other } = await option.ajax(p);
if (Array.isArray(list)) {
if (typeof option.mapResponse === "function") {
dataSource.value = option.mapResponse(list, other) as any;
} else {
dataSource.value = list as any;
}
pagination.total = total;
} else if (option.throwErrorMessageWhenResNotFitDefined) {
message.error("接口格式错误,请联系管理员!");
}
} catch (e) {
console.error(e);
} finally {
loading.value = false;
}
};
onMounted(() => {
if (option.firstDontLoad) {
return;
}
fetchData().then();
});
const onChange: TableProps["onChange"] = (p, _, s) => {
Object.keys(p).forEach((key) => {
(pagination as any)[key] = (p as any)[key];
});
sorter.value = s as SorterResult<RecordRaw>;
fetchData().then();
};
const onRefresh = (reset: boolean = false) => {
if (reset) {
pagination.current = 1;
sorter.value = null;
}
fetchData().then();
};
return {
columns: option?.columns ?? [],
onChange,
pagination,
loading,
dataSource,
onRefresh,
scroll,
};
}
使用方法
<template>
<Table :scroll="{ x: 1300 }"
:loading="loading"
:columns="columns"
@change="onChange"
:data-source="dataSource"
:pagination="pagination"
>
</Table>
</template>
<script setup lang="ts">
const { loading, pagination, onChange, onRefresh, dataSource } = useTable({
extraParams,
firstDontLoad: true,
ajax: api,
mapResponse: (data) =>
data.map((c, i) => ({
...c,
index: i + 1,
})) ?? [],
});
</script>