mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
refactor: PageTable优化
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<transition name="el-zoom-in-top">
|
<transition name="el-zoom-in-top">
|
||||||
<!-- 查询表单 -->
|
<!-- 查询表单 -->
|
||||||
<SearchForm v-if="isShowSearch" :items="tableSearchItems" v-model="queryForm_" :search="queryData" :reset="reset" :search-col="searchCol">
|
<SearchForm v-if="isShowSearch" :items="tableSearchItems" v-model="queryForm_" :search="search" :reset="reset" :search-col="searchCol">
|
||||||
<!-- 遍历父组件传入的 solts 透传给子组件 -->
|
<!-- 遍历父组件传入的 solts 透传给子组件 -->
|
||||||
<template v-for="(_, key) in useSlots()" v-slot:[key]>
|
<template v-for="(_, key) in useSlots()" v-slot:[key]>
|
||||||
<slot :name="key"></slot>
|
<slot :name="key"></slot>
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<el-button v-if="showToolButton('search') && searchItems?.length" icon="Search" circle @click="queryData" />
|
<el-button v-if="showToolButton('search') && searchItems?.length" icon="Search" circle @click="search" />
|
||||||
|
|
||||||
<!-- <el-button v-if="showToolButton('refresh')" icon="Refresh" circle @click="execQuery()" /> -->
|
<!-- <el-button v-if="showToolButton('refresh')" icon="Refresh" circle @click="execQuery()" /> -->
|
||||||
|
|
||||||
@@ -82,16 +82,17 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
|
ref="tableRef"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:max-height="tableMaxHeight"
|
:max-height="tableMaxHeight"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
:data="state.data"
|
:data="tableData"
|
||||||
highlight-current-row
|
highlight-current-row
|
||||||
v-loading="state.loading"
|
v-loading="loading"
|
||||||
:size="props.size"
|
:size="props.size as any"
|
||||||
:border="border"
|
:border="border"
|
||||||
>
|
>
|
||||||
<el-table-column v-if="props.showSelection" type="selection" width="40" />
|
<el-table-column v-if="props.showSelection" :selectable="selectable" type="selection" width="40" />
|
||||||
|
|
||||||
<template v-for="(item, index) in tableColumns">
|
<template v-for="(item, index) in tableColumns">
|
||||||
<el-table-column
|
<el-table-column
|
||||||
@@ -150,11 +151,11 @@
|
|||||||
<el-row class="mt20" type="flex" justify="end">
|
<el-row class="mt20" type="flex" justify="end">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
:small="props.size == 'small'"
|
:small="props.size == 'small'"
|
||||||
@current-change="handlePageChange"
|
@current-change="handlePageNumChange"
|
||||||
@size-change="handleSizeChange"
|
@size-change="handlePageSizeChange"
|
||||||
style="text-align: right"
|
style="text-align: right"
|
||||||
layout="prev, pager, next, total, sizes, jumper"
|
layout="prev, pager, next, total, sizes, jumper"
|
||||||
:total="state.total"
|
:total="total"
|
||||||
v-model:current-page="queryForm_.pageNum"
|
v-model:current-page="queryForm_.pageNum"
|
||||||
v-model:page-size="queryForm_.pageSize"
|
v-model:page-size="queryForm_.pageSize"
|
||||||
:page-sizes="pageSizes"
|
:page-sizes="pageSizes"
|
||||||
@@ -176,16 +177,19 @@ import SearchForm from '@/components/SearchForm/index.vue';
|
|||||||
import { SearchItem } from '../SearchForm/index';
|
import { SearchItem } from '../SearchForm/index';
|
||||||
import SearchFormItem from '../SearchForm/components/SearchFormItem.vue';
|
import SearchFormItem from '../SearchForm/components/SearchFormItem.vue';
|
||||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||||
|
import { usePageTable } from '../../hooks/usePageTable';
|
||||||
|
import { ElTable } from 'element-plus';
|
||||||
|
|
||||||
const emit = defineEmits(['update:queryForm', 'update:selectionData', 'pageChange']);
|
const emit = defineEmits(['update:queryForm', 'update:selectionData', 'pageChange']);
|
||||||
|
|
||||||
export interface PageTableProps {
|
export interface PageTableProps {
|
||||||
size?: string;
|
size?: string;
|
||||||
showSelection?: boolean;
|
|
||||||
showSearch?: boolean; // 是否显示搜索表单
|
|
||||||
columns: TableColumn[]; // 列配置项 ==> 必传
|
|
||||||
data?: any[]; // 静态 table data 数据,若存在则不会使用 requestApi 返回的 data ==> 非必传
|
|
||||||
pageApi: Api; // 请求表格数据的 api
|
pageApi: Api; // 请求表格数据的 api
|
||||||
|
columns: TableColumn[]; // 列配置项 ==> 必传
|
||||||
|
showSelection?: boolean;
|
||||||
|
selectable?: (row: any) => boolean; // 是否可选
|
||||||
|
showSearch?: boolean; // 是否显示搜索表单
|
||||||
|
data?: any[]; // 静态 table data 数据,若存在则不会使用 requestApi 返回的 data ==> 非必传
|
||||||
lazy?: boolean; // 是否自动执行请求 api ==> 非必传(默认为false)
|
lazy?: boolean; // 是否自动执行请求 api ==> 非必传(默认为false)
|
||||||
beforeQueryFn?: (params: any) => any; // 执行查询时对查询参数进行处理,调整等
|
beforeQueryFn?: (params: any) => any; // 执行查询时对查询参数进行处理,调整等
|
||||||
dataHandlerFn?: (data: any) => any; // 数据处理回调函数,用于将请求回来的数据二次加工处理等
|
dataHandlerFn?: (data: any) => any; // 数据处理回调函数,用于将请求回来的数据二次加工处理等
|
||||||
@@ -212,6 +216,9 @@ const props = withDefaults(defineProps<PageTableProps>(), {
|
|||||||
searchCol: () => ({ xs: 1, sm: 3, md: 3, lg: 4, xl: 5 }),
|
searchCol: () => ({ xs: 1, sm: 3, md: 3, lg: 4, xl: 5 }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// table 实例
|
||||||
|
const tableRef = ref<InstanceType<typeof ElTable>>();
|
||||||
|
|
||||||
// 接收 columns 并设置为响应式
|
// 接收 columns 并设置为响应式
|
||||||
const tableColumns = reactive<TableColumn[]>(props.columns);
|
const tableColumns = reactive<TableColumn[]>(props.columns);
|
||||||
|
|
||||||
@@ -228,18 +235,6 @@ const showToolButton = (key: 'setting' | 'search') => {
|
|||||||
return Array.isArray(props.toolButton) ? props.toolButton.includes(key) : props.toolButton;
|
return Array.isArray(props.toolButton) ? props.toolButton.includes(key) : props.toolButton;
|
||||||
};
|
};
|
||||||
|
|
||||||
const state = reactive({
|
|
||||||
pageSizes: [] as any, // 可选每页显示的数据量
|
|
||||||
loading: false,
|
|
||||||
data: [],
|
|
||||||
total: 0,
|
|
||||||
// 输入框宽度
|
|
||||||
formatVal: '', // 格式化后的值
|
|
||||||
tableMaxHeight: '500px',
|
|
||||||
});
|
|
||||||
|
|
||||||
const { pageSizes, formatVal, tableMaxHeight } = toRefs(state);
|
|
||||||
|
|
||||||
const nowSearchItem: Ref<SearchItem> = ref(null) as any;
|
const nowSearchItem: Ref<SearchItem> = ref(null) as any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -254,19 +249,32 @@ const changeSimpleFormItem = (searchItem: SearchItem) => {
|
|||||||
|
|
||||||
const queryForm_: Ref<any> = useVModel(props, 'queryForm', emit);
|
const queryForm_: Ref<any> = useVModel(props, 'queryForm', emit);
|
||||||
|
|
||||||
watch(
|
const { tableData, total, loading, search, reset, getTableData, handlePageNumChange, handlePageSizeChange } = usePageTable(
|
||||||
() => state.data,
|
props.pageApi,
|
||||||
(newValue: any) => {
|
queryForm_,
|
||||||
if (newValue && newValue.length > 0) {
|
props.beforeQueryFn,
|
||||||
props.columns.forEach((item) => {
|
props.dataHandlerFn
|
||||||
if (item.autoWidth && item.show) {
|
|
||||||
item.autoCalculateMinWidth(state.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const state = reactive({
|
||||||
|
pageSizes: [] as any, // 可选每页显示的数据量
|
||||||
|
// 输入框宽度
|
||||||
|
formatVal: '', // 格式化后的值
|
||||||
|
tableMaxHeight: '500px',
|
||||||
|
});
|
||||||
|
|
||||||
|
const { pageSizes, formatVal, tableMaxHeight } = toRefs(state);
|
||||||
|
|
||||||
|
watch(tableData, (newValue: any) => {
|
||||||
|
if (newValue && newValue.length > 0) {
|
||||||
|
props.columns.forEach((item) => {
|
||||||
|
if (item.autoWidth && item.show) {
|
||||||
|
item.autoCalculateMinWidth(tableData.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
watch(isShowSearch, () => {
|
watch(isShowSearch, () => {
|
||||||
calcuTableHeight();
|
calcuTableHeight();
|
||||||
});
|
});
|
||||||
@@ -294,7 +302,7 @@ onMounted(async () => {
|
|||||||
state.pageSizes = [pageSize, pageSize * 2, pageSize * 3, pageSize * 4, pageSize * 5];
|
state.pageSizes = [pageSize, pageSize * 2, pageSize * 3, pageSize * 4, pageSize * 5];
|
||||||
|
|
||||||
if (!props.lazy) {
|
if (!props.lazy) {
|
||||||
await reqPageApi();
|
await getTableData();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -316,66 +324,9 @@ const handleSelectionChange = (val: any) => {
|
|||||||
emit('update:selectionData', val);
|
emit('update:selectionData', val);
|
||||||
};
|
};
|
||||||
|
|
||||||
const reqPageApi = async () => {
|
|
||||||
try {
|
|
||||||
state.loading = true;
|
|
||||||
|
|
||||||
let qf = queryForm_.value;
|
|
||||||
if (props.beforeQueryFn) {
|
|
||||||
qf = await props.beforeQueryFn(qf);
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await props.pageApi?.request(qf);
|
|
||||||
if (!res) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.total = res.total;
|
|
||||||
if (props.dataHandlerFn) {
|
|
||||||
state.data = await props.dataHandlerFn(res.list);
|
|
||||||
} else {
|
|
||||||
state.data = res.list;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
state.loading = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePageChange = (val: number) => {
|
|
||||||
queryForm_.value.pageNum = val;
|
|
||||||
execQuery();
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSizeChange = () => {
|
|
||||||
changePageNum(1);
|
|
||||||
execQuery();
|
|
||||||
};
|
|
||||||
|
|
||||||
const queryData = () => {
|
|
||||||
changePageNum(1);
|
|
||||||
execQuery();
|
|
||||||
};
|
|
||||||
|
|
||||||
const reset = () => {
|
|
||||||
// 将查询参数绑定的值置空,并重新粗发查询接口
|
|
||||||
for (let qi of props.searchItems) {
|
|
||||||
queryForm_.value[qi.prop] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
changePageNum(1);
|
|
||||||
execQuery();
|
|
||||||
};
|
|
||||||
|
|
||||||
const changePageNum = (pageNum: number) => {
|
|
||||||
queryForm_.value.pageNum = pageNum;
|
|
||||||
};
|
|
||||||
|
|
||||||
const execQuery = async () => {
|
|
||||||
await reqPageApi();
|
|
||||||
};
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
search: execQuery,
|
tableRef: tableRef,
|
||||||
|
search: getTableData,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
111
mayfly_go_web/src/hooks/usePageTable.ts
Normal file
111
mayfly_go_web/src/hooks/usePageTable.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
import Api from '@/common/Api';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { reactive, toRefs } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description table 页面操作方法封装
|
||||||
|
* @param {Api} api 获取表格数据 api (必传)
|
||||||
|
* @param {Object} param 获取数据请求参数 (非必传,默认为{pageNum: 1, pageSize: 10})
|
||||||
|
* @param {Function} dataCallBack 对api请求返回的数据进行处理的回调方法 (非必传)
|
||||||
|
* */
|
||||||
|
export const usePageTable = (
|
||||||
|
api?: Api,
|
||||||
|
params: any = {
|
||||||
|
// 当前页数
|
||||||
|
pageNum: 1,
|
||||||
|
// 每页显示条数
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
beforeQueryFn?: (params: any) => any,
|
||||||
|
dataCallBack?: (data: any) => any
|
||||||
|
) => {
|
||||||
|
const state = reactive({
|
||||||
|
// 表格数据
|
||||||
|
tableData: [],
|
||||||
|
// 总数量
|
||||||
|
total: 0,
|
||||||
|
// 查询参数,包含分页参数
|
||||||
|
searchParams: params,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 获取表格数据
|
||||||
|
* @return void
|
||||||
|
* */
|
||||||
|
const getTableData = async () => {
|
||||||
|
if (!api) return;
|
||||||
|
try {
|
||||||
|
state.loading = true;
|
||||||
|
let sp = { ...state.searchParams };
|
||||||
|
if (beforeQueryFn) {
|
||||||
|
sp = beforeQueryFn(sp);
|
||||||
|
state.searchParams = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = await api.request(sp);
|
||||||
|
dataCallBack && (res = dataCallBack(res));
|
||||||
|
|
||||||
|
state.tableData = res.list;
|
||||||
|
state.total = res.total;
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error(error?.message);
|
||||||
|
} finally {
|
||||||
|
state.loading = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 表格数据查询(pageNum = 1)
|
||||||
|
* @return void
|
||||||
|
* */
|
||||||
|
const search = () => {
|
||||||
|
state.searchParams.pageNum = 1;
|
||||||
|
getTableData();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 表格数据重置(pageNum = 1),除分页相关参数外其他查询参数置为空
|
||||||
|
* @return void
|
||||||
|
* */
|
||||||
|
const reset = () => {
|
||||||
|
state.searchParams.pageNum = 1;
|
||||||
|
for (let prop of Object.keys(state.searchParams)) {
|
||||||
|
if (prop == 'pageNum' || prop == 'pageSize') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
state.searchParams[prop] = null;
|
||||||
|
}
|
||||||
|
getTableData();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 每页条数改变
|
||||||
|
* @param {Number} val 当前条数
|
||||||
|
* @return void
|
||||||
|
* */
|
||||||
|
const handlePageSizeChange = (val: number) => {
|
||||||
|
state.searchParams.pageNum = 1;
|
||||||
|
state.searchParams.pageSize = val;
|
||||||
|
getTableData();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 当前页改变
|
||||||
|
* @param {Number} val 当前页
|
||||||
|
* @return void
|
||||||
|
* */
|
||||||
|
const handlePageNumChange = (val: number) => {
|
||||||
|
state.searchParams.pageNum = val;
|
||||||
|
getTableData();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...toRefs(state),
|
||||||
|
getTableData,
|
||||||
|
search,
|
||||||
|
reset,
|
||||||
|
handlePageSizeChange,
|
||||||
|
handlePageNumChange,
|
||||||
|
};
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user