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

## 概述

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

## 兼容原理

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

## 改造示例

### 当前代码（手动管理）

```vue
<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）

```vue
<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

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

### 2. 配置 state

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

### 3. 处理额外参数

如果查询时需要额外的参数（如 `params.value.flag`），有两种方式：

#### 方式一：自定义 pageList 方法（推荐）

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

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

#### 方式二：在 onLoaded 中处理

```typescript
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` 回调：

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

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

## 完整改造示例（针对当前页面）

```typescript
// 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`：

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

### 2. 额外参数处理

如果查询时需要额外的参数（不在 `search` 对象中），使用自定义 `pageList` 方法合并：

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

### 3. 数据转换

如果需要在数据加载后进行转换，使用 `onLoaded` 回调：

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

### 4. 特殊响应字段

如果 API 响应中有特殊字段（如 `auditAll`），需要在 `onLoaded` 中处理，或者自定义 `pageList` 方法：

```typescript
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` 时自动加载数据。如果不需要自动加载，设置：

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

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

## 优势总结

使用 `useTable` 后：

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

## 总结

**`useTable` 完全兼容自定义 `<search-form>` 组件**，只需要：

1. 将 `search` 对象作为 `queryForm` 传入
2. 使用 `state.dataList`、`state.loading`、`state.pagination` 替代手动管理的状态
3. 使用 `getDataList()` 替代 `getList(page)`
4. 使用 `currentChangeHandle`、`sizeChangeHandle` 替代手动分页方法

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