488 lines
12 KiB
Markdown
488 lines
12 KiB
Markdown
# 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` 回调即可。
|