Files
school-developer/docs/useTable与search-form兼容说明.md
guochunsi 74c06bb8a0 a
2025-12-31 17:40:01 +08:00

517 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` 回调即可。