This commit is contained in:
guochunsi
2025-12-31 17:40:01 +08:00
parent 6d94e91b70
commit 74c06bb8a0
713 changed files with 115034 additions and 46 deletions

View File

@@ -0,0 +1,516 @@
# 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` 回调即可。