useCrud 组合式函数
通用 CRUD 操作 Hook,封装了列表查询、分页、加载状态管理等常用功能。
基础用法
vue
<script setup>
import { useCrud } from '@/composables/useCrud'
import { userApi } from '@/services/modules/user'
const {
loading,
tableData,
total,
queryParams,
fetchList,
handleQuery,
resetQuery
} = useCrud({
api: userApi
})
</script>参数
UseCrudOptions
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| api | CrudApi<T> | - | CRUD API 对象(必填) |
| defaultQuery | Partial<QueryParams> | {} | 默认查询参数 |
| immediate | boolean | true | 是否立即执行查询 |
CrudApi 接口
typescript
interface CrudApi<T> {
getList: (params: QueryParams) => Promise<PageResult<T>>
save?: (data: Partial<T>) => Promise<any>
delete?: (ids: string[]) => Promise<any>
getById?: (id: string) => Promise<T>
}返回值
状态
| 属性 | 类型 | 说明 |
|---|---|---|
| loading | Ref<boolean> | 加载状态 |
| tableData | Ref<T[]> | 表格数据 |
| total | Ref<number> | 总条数 |
| queryParams | Reactive<QueryParams> | 查询参数 |
| selectedIds | Ref<string[]> | 选中的行ID |
| hasSelection | ComputedRef<boolean> | 是否有选中项 |
方法
| 方法名 | 说明 | 参数 |
|---|---|---|
| fetchList | 获取列表数据 | - |
| handleQuery | 查询(重置到第一页) | - |
| resetQuery | 重置查询 | - |
| handlePageChange | 处理分页变化 | page: number |
| handleSizeChange | 处理每页条数变化 | size: number |
| handleSelectionChange | 处理选择变化 | selection: T[] |
| handleDelete | 删除单条数据 | row: T, message?: string |
| handleBatchDelete | 批量删除 | message?: string |
| handleSave | 保存数据 | data: Partial<T>, isEdit?: boolean |
| fetchDetail | 获取单条详情 | id: string |
完整示例
vue
<template>
<div class="page-container">
<!-- 查询表单 -->
<el-form :model="queryParams" inline>
<el-form-item label="用户名">
<el-input v-model="queryParams.username" placeholder="请输入用户名" clearable />
</el-form-item>
<el-form-item label="状态">
<DictSelect v-model="queryParams.status" dictType="sys_user_status" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<div class="toolbar">
<el-button type="primary" @click="handleAdd">新增</el-button>
<el-button type="danger" :disabled="!hasSelection" @click="handleBatchDelete">批量删除</el-button>
</div>
<!-- 数据表格 -->
<el-table
v-loading="loading"
:data="tableData"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="username" label="用户名" />
<el-table-column prop="nickname" label="昵称" />
<el-table-column prop="status" label="状态">
<template #default="{ row }">
<DictTag :value="row.status" dictType="sys_user_status" />
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
<el-button type="danger" link @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="queryParams.pageNum"
v-model:page-size="queryParams.pageSize"
:total="total"
@current-change="handlePageChange"
@size-change="handleSizeChange"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useCrud } from '@/composables/useCrud'
import { userApi } from '@/services/modules/user'
import { DictSelect, DictTag } from '@/components/Dict'
// 使用 useCrud
const {
loading,
tableData,
total,
queryParams,
hasSelection,
fetchList,
handleQuery,
resetQuery,
handlePageChange,
handleSizeChange,
handleSelectionChange,
handleDelete,
handleBatchDelete
} = useCrud({
api: userApi,
defaultQuery: {
username: '',
status: undefined
}
})
// 新增
const handleAdd = () => {
// 打开新增弹窗
}
// 编辑
const handleEdit = (row) => {
// 打开编辑弹窗
}
</script>注意事项
- API 必填:
api.getList是必填的,其他方法可选 - 自动过滤:查询时会自动过滤掉空值参数
- 分页处理:删除后如果当前页无数据,会自动返回上一页
- 错误处理:内部已封装错误处理,无需额外 try-catch