Files
school-developer/docs/useTable与search-form兼容说明.md
2026-03-19 15:55:37 +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 回调即可。