Files
school-developer/docs/useTable与search-form兼容说明.md
吴红兵 94c3473958 fix
2026-03-07 01:34:48 +08:00

12 KiB
Raw Blame History

useTable 与 search-form 组件兼容使用说明

概述

useTable Hook 完全兼容自定义 <search-form> 组件。只需要将搜索表单的数据对象作为 queryForm 传入即可。

兼容原理

  1. search-form 组件:只是一个表单包装器,接收 model prop 绑定到内部的 el-form
  2. useTable Hook:接收 queryForm 对象,会自动将其合并到 API 请求参数中
  3. 两者配合:将 search-formmodel 对象作为 useTablequeryForm 传入即可

改造示例

当前代码(手动管理)

<template>
	<!-- 搜索表单 -->
	<search-form v-show="showSearch" :model="search" ref="searchFormRef" @keyup-enter="handleFilter(search)">
		<!-- 表单项 -->
	</search-form>

	<!-- 表格 -->
	<el-table :data="tableData" v-loading="tableLoading">
		<!-- 表格列 -->
	</el-table>

	<!-- 分页 -->
	<pagination :current="page.currentPage" :size="page.pageSize" :total="page.total" @currentChange="currentChange" @sizeChange="handleSizeChange" />
</template>

<script setup lang="ts">
const search = reactive({
	deptCode: '',
	realName: '',
	teacherNo: '',
	// ... 其他字段
});

const tableData = ref([]);
const tableLoading = ref(false);
const page = reactive({
	currentPage: 1,
	pageSize: 10,
	total: 0,
});
const params = ref<any>({});

// 手动实现数据加载
const getList = (page: any) => {
	tableLoading.value = true;
	fetchList(
		Object.assign(
			{
				current: page.currentPage,
				size: page.pageSize,
			},
			params.value
		)
	).then((response: any) => {
		tableData.value = response.data.record.records;
		page.total = response.data.record.total;
		tableLoading.value = false;
	});
};

// 手动实现分页
const currentChange = (val: number) => {
	page.currentPage = val;
	getList(page);
};

const handleSizeChange = (val: number) => {
	page.pageSize = val;
	page.currentPage = 1;
	getList(page);
};

// 查询
const handleFilter = (param: any) => {
	params.value = { ...param };
	page.currentPage = 1;
	getList(page);
};

onMounted(() => {
	getList(page);
});
</script>

改造后代码(使用 useTable

<template>
	<!-- 搜索表单 - 保持不变 -->
	<search-form v-show="showSearch" :model="search" ref="searchFormRef" @keyup-enter="handleFilter(search)">
		<!-- 表单项 -->
	</search-form>

	<!-- 表格 - 使用 state.dataList  state.loading -->
	<el-table :data="state.dataList" v-loading="state.loading" :cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle">
		<!-- 表格列 -->
	</el-table>

	<!-- 分页 - 使用 state.pagination -->
	<pagination
		:current="state.pagination.current"
		:size="state.pagination.size"
		:total="state.pagination.total"
		@currentChange="currentChangeHandle"
		@sizeChange="sizeChangeHandle"
	/>
</template>

<script setup lang="ts">
import { BasicTableProps, useTable } from '/@/hooks/table';
import { fetchList } from '/@/api/professional/teacherbase';

// 搜索表单数据 - 保持不变
const search = reactive({
	deptCode: '',
	realName: '',
	teacherNo: '',
	// ... 其他字段
});

// 额外参数(如 flag 等)
const params = ref<any>({});

// 配置 useTable
const state: BasicTableProps = reactive<BasicTableProps>({
	// 将 search 对象作为 queryForm
	queryForm: search,

	// 自定义 pageList 方法,合并额外参数
	pageList: async (queryParams: any) => {
		// 合并 search 和 params 中的额外参数
		return await fetchList({
			...queryParams,
			...params.value,
		});
	},

	// 数据属性映射(根据后端返回结构调整)
	props: {
		item: 'record.records', // 数据列表路径
		totalCount: 'record.total', // 总数字段路径
	},

	// 数据加载完成后的回调
	onLoaded: async (state) => {
		// 数据转换逻辑
		state.dataList = convertDictData(state.dataList);

		// 其他处理逻辑(如 auditAll
		// ...
	},
});

// 使用 useTable Hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle, state } = useTable(state);

// 查询方法 - 简化
const handleFilter = (param: any) => {
	// 更新额外参数
	params.value = { ...param };
	// 调用 getDataList 刷新数据(会自动跳转到第一页)
	getDataList();
};

// 重置查询
const resetQuery = () => {
	searchFormRef.value?.formRef?.resetFields();
	// 重置 search 对象
	Object.keys(search).forEach((key) => {
		search[key] = '';
	});
	params.value = {};
	getDataList();
};

// 其他需要刷新表格的地方
const handelQuickSeach = (val: any) => {
	params.value.flag = val;
	getDataList(); // 使用 getDataList 替代 getList(page)
};

const updateInoutFlag = (row: any, val: any) => {
	const updateParams = { teacherNo: row.teacherNo, inoutFlag: val };
	messageBox.confirm('确认操作?').then(() => {
		updateInout(updateParams).then((res: any) => {
			message.success('修改成功');
			getDataList(false); // 刷新但保持当前页
		});
	});
};

// 数据转换函数(保持不变)
const convertDictData = (records: any[]) => {
	// ... 转换逻辑
	return records;
};
</script>

关键改造点

1. 导入 useTable

import { BasicTableProps, useTable } from '/@/hooks/table';

2. 配置 state

const state: BasicTableProps = reactive<BasicTableProps>({
	queryForm: search, // 将 search 对象作为 queryForm
	pageList: fetchList, // 或自定义方法
	props: {
		item: 'record.records',
		totalCount: 'record.total',
	},
});

3. 处理额外参数

如果查询时需要额外的参数(如 params.value.flag),有两种方式:

方式一:自定义 pageList 方法(推荐)

const params = ref<any>({});

const state: BasicTableProps = reactive<BasicTableProps>({
	queryForm: search,
	pageList: async (queryParams: any) => {
		// 合并额外参数
		return await fetchList({
			...queryParams,
			...params.value, // 合并额外参数
		});
	},
});

方式二:在 onLoaded 中处理

const state: BasicTableProps = reactive<BasicTableProps>({
	queryForm: search,
	pageList: fetchList,
	onLoaded: async (state) => {
		// 可以在这里处理数据转换等逻辑
	},
});

4. 替换数据引用

原代码 改造后
tableData state.dataList
tableLoading state.loading
page.currentPage state.pagination.current
page.pageSize state.pagination.size
page.total state.pagination.total

5. 替换方法调用

原代码 改造后
getList(page) getDataList()getDataList(false)
currentChange(val) currentChangeHandle(val)
handleSizeChange(val) sizeChangeHandle(val)

6. 处理数据转换

如果需要在数据加载后进行转换,使用 onLoaded 回调:

const state: BasicTableProps = reactive<BasicTableProps>({
	queryForm: search,
	pageList: fetchList,
	onLoaded: async (state) => {
		// 字典数据转换
		state.dataList = convertDictData(state.dataList);

		// 处理 auditAll 等逻辑
		// 注意:需要在 API 响应中获取,或通过其他方式处理
	},
});

完整改造示例(针对当前页面)

// 1. 导入 useTable
import { BasicTableProps, useTable } from '/@/hooks/table';

// 2. 搜索表单数据(保持不变)
const search = reactive({
	deptCode: '',
	secDeptCode: '',
	tied: '',
	realName: '',
	teacherNo: '',
	retireDate: '',
	pfTitleId: '',
	stationDutyLevelId: '',
	politicsStatus: '',
	teacherCate: '',
	inoutFlag: '',
});

// 3. 额外参数(用于 flag 等)
const params = ref<any>({});

// 4. 配置 useTable
const state: BasicTableProps = reactive<BasicTableProps>({
	queryForm: search, // 将 search 作为 queryForm

	// 自定义 pageList合并额外参数
	pageList: async (queryParams: any) => {
		// 合并 search 和 params
		const mergedParams = {
			...queryParams,
			...params.value,
			tied: search.tied, // 如果需要特殊处理
		};
		return await fetchList(mergedParams);
	},

	// 数据属性映射
	props: {
		item: 'record.records',
		totalCount: 'record.total',
	},

	// 数据加载完成回调
	onLoaded: async (state) => {
		// 字典数据转换
		state.dataList = convertDictData(state.dataList);

		// 注意auditAll 需要从 API 响应中获取
		// 如果 API 返回在 response.data.auditAll需要特殊处理
	},
});

// 5. 使用 useTable
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle, state } = useTable(state);

// 6. 查询方法(简化)
const handleFilter = (param: any) => {
	params.value = { ...param };
	getDataList(); // 自动跳转到第一页
};

// 7. 重置查询
const resetQuery = () => {
	searchFormRef.value?.formRef?.resetFields();
	Object.keys(search).forEach((key) => {
		search[key] = '';
	});
	params.value = {};
	getDataList();
};

// 8. 快速查询
const handelQuickSeach = (val: any) => {
	params.value.flag = val;
	getDataList();
};

// 9. 其他需要刷新的地方
const updateInoutFlag = (row: any, val: any) => {
	const updateParams = { teacherNo: row.teacherNo, inoutFlag: val };
	messageBox.confirm('确认操作?').then(() => {
		updateInout(updateParams).then((res: any) => {
			message.success('修改成功');
			getDataList(false); // 保持当前页
		});
	});
};

注意事项

1. API 响应结构

如果 API 返回结构是 response.data.record.records,需要配置 props

props: {
  item: 'record.records',
  totalCount: 'record.total'
}

2. 额外参数处理

如果查询时需要额外的参数(不在 search 对象中),使用自定义 pageList 方法合并:

pageList: async (queryParams: any) => {
	return await fetchList({
		...queryParams,
		...params.value, // 额外参数
		// 或其他特殊参数
	});
};

3. 数据转换

如果需要在数据加载后进行转换,使用 onLoaded 回调:

onLoaded: async (state) => {
	state.dataList = convertDictData(state.dataList);
};

4. 特殊响应字段

如果 API 响应中有特殊字段(如 auditAll),需要在 onLoaded 中处理,或者自定义 pageList 方法:

pageList: async (queryParams: any) => {
	const response = await fetchList({
		...queryParams,
		...params.value,
	});

	// 处理特殊字段
	if (response.data.auditAll == '0') {
		auditAll.value = false;
	} else {
		auditAll.value = true;
	}

	return response;
};

5. 初始化数据加载

useTable 默认会在 onMounted 时自动加载数据。如果不需要自动加载,设置:

const state: BasicTableProps = reactive<BasicTableProps>({
	queryForm: search,
	pageList: fetchList,
	createdIsNeed: false, // 禁用自动加载
});

// 手动调用
onMounted(() => {
	init();
	loadSearchDictData();
	getDataList(); // 手动加载
});

优势总结

使用 useTable 后:

  1. 代码量减少:不需要手动管理 tableDatatableLoadingpage
  2. 自动状态管理loading、分页、数据自动管理
  3. 统一方法getDataList() 统一刷新数据
  4. 兼容性好:完全兼容自定义 search-form 组件
  5. 灵活扩展:支持自定义 pageListonLoaded 等回调

总结

useTable 完全兼容自定义 <search-form> 组件,只需要:

  1. search 对象作为 queryForm 传入
  2. 使用 state.dataListstate.loadingstate.pagination 替代手动管理的状态
  3. 使用 getDataList() 替代 getList(page)
  4. 使用 currentChangeHandlesizeChangeHandle 替代手动分页方法

如果有额外参数或特殊处理,使用自定义 pageList 方法或 onLoaded 回调即可。