AiCrudPage CRUD 页面组件
AiCrudPage 是 Forge Admin 的核心组件,提供完整的 CRUD 页面解决方案。集成搜索表单、数据表格(表格/卡片双模式)、新增/编辑/详情弹窗(模态框/抽屉/平铺/多页签)、批量删除、导入导出、自定义查询等功能。通过声明式配置即可快速搭建功能完备的后台管理页面。
快速上手
<template>
<AiCrudPage
ref="crudRef"
api="/api/user"
:columns="columns"
:search-schema="searchSchema"
:edit-schema="editSchema"
@load-list-success="onLoadSuccess"
/>
</template>
<script setup>
import { ref } from 'vue'
import { AiCrudPage } from '@/components/ai-form'
const crudRef = ref(null)
const columns = [
{ prop: 'username', label: '用户名', width: 120 },
{ prop: 'nickname', label: '昵称', width: 120 },
{ prop: 'status', label: '状态', width: 80, slot: 'status' },
{ prop: 'createTime', label: '创建时间', width: 180 }
]
const searchSchema = [
{ field: 'username', label: '用户名', type: 'input' },
{ field: 'status', label: '状态', type: 'select', props: { options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 }
] } }
]
const editSchema = [
{ field: 'username', label: '用户名', type: 'input', required: true, rules: [{ required: true, message: '请输入用户名' }] },
{ field: 'nickname', label: '昵称', type: 'input' },
{ field: 'status', label: '状态', type: 'radio', defaultValue: 1, props: { options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 }
] } }
]
</script>Props
以下为所有 Props 速览表。复杂对象类型(🔼 标记)可点击跳转到详细说明。
核心配置
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
api | String | '' | RESTful 基础路径,组件自动拼接 CRUD 接口。示例:'/api/user' |
apiConfig | Object | {} | ▶ 完整 API 配置 — 自定义每个接口地址,优先级高于 api |
rowKey | String | Function | 'id' | 行数据唯一标识字段 |
lazy | Boolean | false | true 时初始不加载数据,需手动调用 refresh() |
loadDetailOnEdit | Boolean | false | 编辑时是否通过详情接口加载最新数据 |
isEncrypt | Boolean | false | 是否对请求参数启用加密 |
publicQuery | Object | {} | 公共查询参数,拼接到 URL query string |
publicParams | Object | {} | 公共请求参数,合并到 POST body |
formDefaultValues | Object | {} | 新增/编辑弹窗打开时的默认表单值 |
submitDefaultParams | Object | {} | 提交时固定附加到提交数据的参数 |
搜索区域
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
searchSchema | Array | [] | ▶ 搜索表单字段配置 |
showSearch | Boolean | true | 是否显示搜索区域 |
searchGridCols | Number | 4 | 搜索表单每行最多几个字段 |
searchLabelWidth | String | Number | 'auto' | 搜索表单标签宽度,如 '80px'、100 |
searchEnableCollapse | Boolean | true | 字段超过阈值时自动折叠 |
searchMaxVisibleFields | Number | 3 | 折叠前最大可见字段数 |
searchYGap | Number | 10 | 搜索项行间距(px) |
表格配置
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
columns | Array | [] | ▶ 表格列配置 |
tableSize | String | 'medium' | 表格尺寸:'small' | 'medium' | 'large' |
tableProps | Object | {} | 透传给 Naive UI DataTable 的额外属性 |
tableRowGap | Number | 0 | 行间距附加高度(px),用于低代码列表预览 |
hideSelection | Boolean | false | 是否隐藏多选框列 |
striped | Boolean | false | 是否显示斑马纹 |
bordered | Boolean | false | 是否显示表格边框 |
maxHeight | Number | String | — | 表格最大高度,超出纵向滚动 |
scrollX | Number | — | 横向滚动最小宽度(px) |
resizable | Boolean | true | 列宽是否可拖拽调整 |
renderMode | String | 'table' | 渲染模式:'table' 表格 | 'card' 卡片 |
renderModeOptions | Array | — | 可切换的渲染模式选项(全量/仅指定) |
cardProps | Object | {} | ▶ 卡片模式配置 |
编辑表单
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
editSchema | Array | [] | ▶ 编辑表单字段配置 |
editGridCols | Number | 1 | 编辑表单栅格列数,大表单建议 2 |
editLabelWidth | String | Number | 'auto' | 编辑表单标签宽度 |
editLabelPlacement | String | 'left' | 标签位置:'left' | 'top' |
editLabelAlign | String | 'right' | 标签文字对齐:'left' | 'right' |
editSize | String | 'medium' | 表单项尺寸:'small' | 'medium' | 'large' |
editShowFeedback | Boolean | true | 是否显示校验反馈信息 |
editXGap | Number | 16 | 表单项列间距(px) |
editYGap | Number | 8 | 表单项行间距(px) |
editFormClass | String | Object | Array | '' | 编辑表单自定义 class |
editFormStyle | String | Object | Array | — | 编辑表单自定义 style |
弹窗 / 打开方式
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modalType | String | 'modal' | 弹窗类型:'modal' 模态框 | 'drawer' 抽屉 |
modalWidth | String | '800px' | 新增/编辑弹窗宽度 |
detailModalWidth | String | 'min(1080px, 92vw)' | 详情弹窗宽度 |
drawerPlacement | String | 'right' | 抽屉弹出位置:'left' | 'right' | 'top' | 'bottom' |
hideModalFooter | Boolean | false | 是否隐藏弹窗底部按钮 |
formOpenMode | String | '' | 表单打开方式。'' 兼容 modalType;'modal' 弹窗;'drawer' 抽屉;'flat' 平铺页面;'tabWorkspace' 多页签 |
hideDefaultDetailContent | Boolean | false | 详情模式是否隐藏默认只读表单,仅保留详情插槽 |
detailPanels | Array | [] | ▶ 详情扩展面板配置 |
tabWorkspace | Object | {} | ▶ 多页签工作区配置 |
childrenConfig | Array | [] | ▶ 主子表配置 |
工具栏
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
hideToolbar | Boolean | false | 是否隐藏整个工具栏 |
hideAdd | Boolean | false | 是否隐藏新增按钮 |
addButtonText | String | '新增' | 新增按钮文本 |
hideBatchDelete | Boolean | false | 是否隐藏批量删除按钮 |
showImport | Boolean | false | 是否显示导入按钮 |
showExport | Boolean | false | 是否显示导出按钮 |
exportButtonText | String | '导出' | 导出按钮文本 |
enableCustomQuery | Boolean | false | 是否启用自定义查询 |
customQueryConfigKey | String | '' | 自定义查询配置键 |
businessObjectCode | String | '' | 低代码业务对象编码 |
toolbarActions | Array | [] | ▶ 自定义工具栏按钮 |
runtimeActions | Array | [] | ▶ 运行态行操作按钮 |
纯填报表单 (formOnly)
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
formOnly | Boolean | false | 纯填报模式,不渲染列表和工具栏,仅展示填写表单 |
formOnlyTitle | String | '' | 填报页标题 |
formOnlySubmitText | String | '提交' | 提交按钮文案 |
formOnlySuccessTitle | String | '提交成功' | 提交成功后显示的标题 |
formOnlySuccessDescription | String | '单据已保存' | 提交成功后显示的描述 |
分页
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
showPagination | Boolean | true | 是否显示分页组件 |
pageNum | Number | 1 | 初始页码 |
pageSize | Number | 10 | 每页条数 |
pageSizes | Array | [10, 20, 50, 100] | 每页条数可选值 |
导入导出
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
importApi | String | '' | 导入接口地址,格式 '{method}@{path}' |
importHeaders | Object | {} | 导入请求自定义 Header |
importData | Object | {} | 导入时附加的额外参数,合并到 FormData |
importTemplateUrl | String | '' | 导入模板下载地址 |
exportApi | String | '' | 导出接口地址 |
exportFileName | String | '' | 导出文件名(不含扩展名) |
showExportTasks | Boolean | true | 是否显示异步导出任务入口 |
exportTaskConfigKey | String | '' | 导出任务对应的动态 CRUD 配置键 |
扩展模式
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
treeConfig | Object | {} | ▶ 树形表配置 — 启用树形表格 |
expandConfig | Object | {} | ▶ 行展开配置 — 表格行展开面板 |
enableTreeAddChild | Boolean | false | 是否显示「添加下级」按钮 |
listMethod | String | 'get' | 列表请求方法:'get' | 'post' |
listDataField | String | 'records' | 后端返回的列表数据字段名。如返回 { data: { rows: [...] } } 则设为 'rows' |
listTotalField | String | 'total' | 后端返回的总数字段名。如返回 { data: { totalCount: 100 } } 则设为 'totalCount' |
钩子函数
所有钩子均可选,支持同步返回或返回 Promise。返回
false会中断后续操作。详见 ▶ 钩子函数完整说明。
| 钩子 | 签名 | 说明 |
|---|---|---|
beforeLoadList | (params) => params | 列表请求前,可追加/修改请求参数 |
beforeRenderList | (list) => list | 列表数据渲染前,可做映射/转换 |
beforeSearch | (params) => params | false | 搜索请求前,返回 false 中断搜索 |
beforeRenderReset | () => void | 点击重置按钮后回调 |
beforeSubmit | (formData) => data | false | 表单提交前,返回 false 中断提交 |
afterBuildSubmitData | (submitData) => data | false | 数据合并后、发送前,返回 false 中断提交 |
afterSubmit | ({ data, response, isEdit }) => void | 提交成功后回调 |
beforeDelete | (rows) => boolean | 删除前确认,返回 false 中断删除 |
beforeRenderForm | (data) => data | 打开编辑/详情弹窗前预处理 |
beforeRenderDetail | (data) => data | 详情数据渲染前处理 |
1. 搜索表单 (searchSchema)
searchSchema 是一个 AiForm 字段 Schema 数组,每个元素定义一个搜索字段。AiForm 支持 34 种字段类型,详细参见 AiForm 字段类型速查表。
每个 schema 项支持的通用属性:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
field | String | 必填 | 字段名,绑定表单数据的 key,最终作为搜索参数传给后端 |
label | String | — | 表单标签文本 |
type | String | 'input' | 字段类型,决定渲染什么控件。支持 34 种,详见 字段类型速查表 |
placeholder | String | 自动生成 | 占位符文本。不设置时自动生成:「请输入{label}」或「请选择{label}」 |
props | Object | {} | 透传给底层 Naive UI 组件的属性。例如 select 类型的 options、multiple 等都放在这里 |
required | Boolean | false | 搜索表单通常不需要 required,但定义了会显示红色星号 |
rules | Array | [] | Naive UI 校验规则,格式 [{ required: true, message: '...' }] |
disabled | Boolean | Function | false | 是否禁用。支持函数 (formData) => boolean 动态判断 |
clearable | Boolean | true | 是否显示清除按钮 |
hidden | Boolean | false | 是否隐藏该字段 |
span | Number | 1 | 栅格占位宽度,配合 searchGridCols 控制每行显示几个字段 |
defaultValue | Any | — | 默认值,搜索表单加载时的初始值 |
onChange | Function | — | 值变化回调 ({ value, field, formData, context }) |
vIf | Function | — | 条件渲染,接收 (formData) 参数,返回布尔值 |
搜索区域专用 Props:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
showSearch | Boolean | true | 是否显示搜索区域 |
searchGridCols | Number | 4 | 搜索表单栅格列数(每行最多几个字段) |
searchLabelWidth | String | Number | 'auto' | 搜索表单标签宽度,如 '80px'、100 |
searchEnableCollapse | Boolean | true | 字段超过 searchMaxVisibleFields 时是否自动折叠 |
searchMaxVisibleFields | Number | 3 | 折叠前最大可见字段数,超出部分折叠 |
searchYGap | Number | 10 | 表单项行间距(px) |
搜索 Schema 示例:
const searchSchema = [
{ field: 'username', label: '用户名', type: 'input', props: { clearable: true } },
{ field: 'status', label: '状态', type: 'select', props: { options: statusOptions, clearable: true } },
{ field: 'createTime', label: '创建时间', type: 'daterange', props: { type: 'datetimerange', valueFormat: 'timestamp' } },
]2. 表格列 (columns)
columns 定义了表格显示哪些列,以及每一列的渲染方式。底层基于 Naive UI DataTable。
每列支持的属性:
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
prop | String | ✅ | 列数据字段名,对应行数据中的 key |
label | String | ✅ | 列标题 |
width | Number | String | — | 固定列宽,如 120 或 '120px' |
minWidth | Number | String | — | 最小列宽,列宽不足时不会小于此值 |
align | String | 'left' | 列对齐方式:'left' | 'center' | 'right' |
fixed | String | — | 固定列:'left' | 'right' |
ellipsis | Boolean | Object | — | 超出宽度省略。传对象可配置 { tooltip: true } 显示完整内容 |
sortable | Boolean | false | 是否可排序 |
type | String | — | 列类型。'selection' = 多选框列,'index' = 序号列 |
slot | String | — | 自定义插槽名,渲染时匹配 #table-{slot} 插槽。设置后不使用默认的 prop 文本渲染 |
render | Function | — | 自定义渲染函数 (row, index) => VNode。返回 h() 创建的 VNode |
actions | Array | — | 操作列按钮配置(详见下方) |
show | Boolean | Function | true | 列是否可见,支持函数 (row, index) => boolean |
className | String | Function | — | 列自定义 class |
children | Array | — | 多级表头的子列配置 |
actions 操作列配置:
用于在列上渲染操作按钮组(编辑、删除等),无需手写 slot。
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
label | String | ✅ | 按钮文本 |
key | String | — | 按钮唯一标识 |
type | String | 'default' | 按钮类型:'primary' | 'info' | 'success' | 'warning' | 'error' | 'default' |
icon | String | — | 图标名称 |
onClick | Function | ✅ | 点击回调 (row) => void |
visible | Function | — | 按钮可见性 (row) => boolean |
表格外观 Props:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
rowKey | String | Function | 'id' | 行数据唯一标识字段名,或函数 (row) => key |
hideSelection | Boolean | false | 是否隐藏多选框列 |
striped | Boolean | false | 是否显示斑马纹 |
bordered | Boolean | false | 是否显示表格边框 |
tableSize | String | 'medium' | 表格尺寸:'small' | 'medium' | 'large' |
tableRowGap | Number | 0 | 行间距附加高度(px),用于低代码列表预览 |
maxHeight | Number | String | — | 表格最大高度,超出后纵向滚动 |
scrollX | Number | — | 横向滚动最小宽度(px) |
resizable | Boolean | true | 列宽是否可拖拽调整 |
tableProps | Object | {} | 透传给 Naive UI DataTable 的额外属性(覆盖默认配置) |
列配置示例:
const columns = [
{ type: 'selection', width: 50, fixed: 'left' },
{ prop: 'id', label: 'ID', width: 80, align: 'center' },
{ prop: 'username', label: '用户名', minWidth: 120 },
{ prop: 'status', label: '状态', width: 90, render: row => h(DictTag, { dict: statusDict, value: row.status }) },
{ prop: 'remark', label: '备注', minWidth: 140, ellipsis: { tooltip: true } },
{ prop: 'createTime', label: '创建时间', width: 180, sortable: true },
{
prop: 'actions', label: '操作', width: 180, fixed: 'right', align: 'center',
actions: [
{ label: '编辑', key: 'edit', type: 'primary', onClick: row => crudRef.value?.handleEdit(row) },
{ label: '删除', key: 'delete', type: 'error', onClick: row => crudRef.value?.handleDelete(row), visible: row => row.status !== 'locked' },
],
},
]3. 编辑表单 (editSchema)
editSchema 和 searchSchema 使用相同的 AiForm Schema 格式(详见 字段类型速查表),但新增/编辑场景通常需要 required、rules、vIf 等功能。
编辑表单专用 Props:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
editSchema | Array<Object> | [] | 编辑表单字段配置 |
childrenConfig | Array<Object> | [] | 主子表模板的子表配置(详见 子表配置) |
editGridCols | Number | 1 | 编辑表单栅格列数。大表单建议设为 2 |
editLabelWidth | String | Number | 'auto' | 编辑表单标签宽度 |
editLabelPlacement | String | 'left' | 标签位置:'left'(左对齐)| 'top'(顶部) |
editLabelAlign | String | 'right' | 标签文字对齐:'left' | 'right' |
editSize | String | 'medium' | 表单项尺寸:'small' | 'medium' | 'large' |
editShowFeedback | Boolean | true | 是否显示校验反馈信息 |
editXGap | Number | 16 | 表单项列间距(px) |
editYGap | Number | 8 | 表单项行间距(px) |
editFormClass | String | Object | Array | '' | 编辑表单自定义 class |
editFormStyle | String | Object | Array | — | 编辑表单自定义 style |
formAssets | Array<Object> | [] | 表单资产列表,运行态按钮可打开其他独立表单 |
编辑 Schema 示例:
const editSchema = [
{ field: 'username', label: '用户名', type: 'input', span: 1,
rules: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
props: { placeholder: '请输入用户名' } },
{ field: 'nickname', label: '昵称', type: 'input', span: 1,
props: { placeholder: '请输入昵称' } },
{ field: 'gender', label: '性别', type: 'radio', span: 1,
defaultValue: 1, props: { options: [{ label: '男', value: 1 }, { label: '女', value: 0 }] } },
{ field: 'email', label: '邮箱', type: 'input', span: 1,
rules: [{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }] },
{ type: 'divider', label: '其他信息', span: 2, props: { titlePlacement: 'left' } },
{ field: 'remark', label: '备注', type: 'textarea', span: 2,
props: { rows: 3, maxlength: 200, showCount: true } },
]4. 弹窗/表单打开方式
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
modalType | String | 'modal' | 弹窗类型:'modal'(模态框)| 'drawer'(抽屉) |
modalWidth | String | '800px' | 新增/编辑弹窗宽度 |
detailModalWidth | String | 'min(1080px, 92vw)' | 详情弹窗宽度 |
drawerPlacement | String | 'right' | 抽屉位置:'left' | 'right' | 'top' | 'bottom' |
hideModalFooter | Boolean | false | 是否隐藏弹窗底部按钮 |
formOpenMode | String | '' | 表单打开方式。'' 兼容 modalType;'modal' 弹窗;'drawer' 抽屉;'flat' 平铺页面;'tabWorkspace' 多页签工作区 |
hideDefaultDetailContent | Boolean | false | 详情模式是否隐藏默认只读表单,仅保留详情插槽 |
detailPanels | Array<Object> | [] | 详情页扩展面板配置(详见 详情扩展面板) |
tabWorkspace | Object | {} | 多页签工作区配置(详见 多页签工作区) |
5. API 配置 (apiConfig)
AiCrudPage 支持两种 API 配置方式:简单模式(只传 api 基础路径)和完整模式(传 apiConfig 对象)。
API 相关 Props:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
api | String | '' | RESTful 基础路径,如 '/api/user'。组件自动拼接:GET /api/user/page、POST /api/user、PUT /api/user、DELETE /api/user/:id、GET /api/user/:id |
apiConfig | Object | {} | 自定义 API 配置,优先级高于 api。不传时由 api 自动推导 |
isEncrypt | Boolean | false | 是否对请求参数启用加密 |
listMethod | String | 'get' | 列表请求方法:'get' | 'post' |
listDataField | String | 'records' | 后端返回的列表数据字段名。如返回 { code: 200, data: { rows: [...] } } 则设为 'rows' |
listTotalField | String | 'total' | 后端返回的总数字段名。如返回 { data: { totalCount: 100 } } 则设为 'totalCount' |
apiConfig 对象详细结构:
格式为 '{method}@{path}',如 'get@/api/user/page'。支持 URL 占位符 :{fieldName}。
| 键名 | 格式 | 说明 |
|---|---|---|
list | '{method}@{path}' | 列表查询接口。支持 GET/POST |
add | '{method}@{path}' | 新增接口 |
create | '{method}@{path}' | 新增接口(别名,与 add 二选一) |
update | '{method}@{path}' | 更新接口,通常带 :id 占位符 |
delete | '{method}@{path}' | 删除接口,支持批量 |
detail | '{method}@{path}' | 详情接口,编辑时调用(需 loadDetailOnEdit) |
URL 占位符规则:
URL 中 :keyName 会被自动替换为当前行数据中对应字段的值。占位符名称必须与 rowKey 属性值一致。
// rowKey 默认 'id'
apiConfig: {
update: 'put@/api/user/:id', // 点击编辑时 → PUT /api/user/123
detail: 'get@/api/user/:id' // 点击详情时 → GET /api/user/123
}
// 自定义 rowKey='userId'
apiConfig: {
update: 'put@/api/user/:userId', // → PUT /api/user/456
}导入导出 API Props:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
importApi | String | '' | 导入接口地址,格式 '{method}@{path}' |
importHeaders | Object | {} | 导入请求自定义 Header |
importData | Object | {} | 导入时附加的额外参数,合并到 FormData |
importTemplateUrl | String | '' | 导入模板下载地址 |
exportApi | String | '' | 导出接口地址 |
exportFileName | String | '' | 导出文件名(不含扩展名) |
showExportTasks | Boolean | true | 是否显示异步导出任务入口 |
exportTaskConfigKey | String | '' | 导出任务对应的动态 CRUD 配置键,不传时自动解析 |
6. 工具栏
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
hideToolbar | Boolean | false | 是否隐藏整个工具栏 |
hideAdd | Boolean | false | 是否隐藏新增按钮 |
addButtonText | String | '新增' | 新增按钮文本 |
hideBatchDelete | Boolean | false | 是否隐藏批量删除按钮 |
showImport | Boolean | false | 是否显示导入按钮 |
showExport | Boolean | false | 是否显示导出按钮 |
exportButtonText | String | '导出' | 导出按钮文本 |
enableCustomQuery | Boolean | false | 是否启用自定义查询 |
customQueryConfigKey | String | '' | 自定义查询配置键 |
businessObjectCode | String | '' | 低代码业务对象编码,用于详情页加载流程状态 |
toolbarActions — 自定义工具栏按钮:
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
label | String | ✅ | 按钮文本 |
key | String | — | 唯一标识,用于 custom-action 事件区分 |
type | String | 'default' | 'primary' | 'info' | 'success' | 'warning' | 'error' | 'default' |
icon | String | — | 图标名称 |
permissionCode | String | — | 权限码,无权限时自动隐藏 |
visible | Boolean | Function | true | 可见性控制。函数签名为 (selectedRows) => boolean |
displayCondition | String | — | 显示条件表达式 |
position | String | 'toolbar' | 'toolbar' 工具栏按钮;'row' 行操作按钮 |
onClick | Function | — | 点击回调。工具栏按钮传入选中的行数据;行操作按钮传入当前行 |
runtimeActions — 运行态行操作:
结构同 toolbarActions,但 position 固定为 'row'。由低代码业务对象按记录状态动态追加。
formOnly — 纯填报表单模式:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
formOnly | Boolean | false | 开启后不渲染列表和工具栏,仅展示填写表单 |
formOnlyTitle | String | '' | 表单填报页标题 |
formOnlySubmitText | String | '提交' | 提交按钮文案 |
formOnlySuccessTitle | String | '提交成功' | 提交成功后显示的标题 |
formOnlySuccessDescription | String | '单据已保存' | 提交成功后显示的描述 |
7. 主子表 (childrenConfig)
子表配置用于在主表编辑弹窗中嵌入多个子表(如订单 + 订单明细)。
childrenConfig 每项结构:
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
key | String | ✅ | 子表唯一标识,对应提交数据中的字段名 |
title | String | ✅ | 子表显示标题 |
fields | Array | ✅ | 子表字段配置,格式同 editSchema |
showInDetail | Boolean | true | 是否在详情页展示 |
relationType | String | — | 'ONE_TO_MANY' 一对多 |
sourceField | String | — | 子表中关联主表的字段名 |
targetField | String | — | 主表中被关联的字段名 |
api | Object | — | 子表独立 API 配置,格式同 apiConfig(可选,不传则跟随主表提交) |
const childrenConfig = [
{
key: 'items',
title: '订单明细',
fields: [
{ field: 'productName', label: '商品名称', type: 'input', required: true },
{ field: 'quantity', label: '数量', type: 'number', required: true, props: { min: 1 } },
{ field: 'price', label: '单价', type: 'number', required: true, props: { precision: 2 } },
],
api: {
list: 'get@/api/order/:id/items',
add: 'post@/api/order/:id/items',
update: 'put@/api/order/:id/items/:itemId',
delete: 'delete@/api/order/:id/items/:itemId',
},
},
]8. 分页
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
showPagination | Boolean | true | 是否显示分页组件 |
pageNum | Number | 1 | 初始页码 |
pageSize | Number | 10 | 每页条数 |
pageSizes | Array<Number> | [10, 20, 50, 100] | 每页条数可选值 |
9. 卡片模式 (cardProps)
设 renderMode="card" 后,表格以卡片网格形式展示。通过 cardProps 控制卡片布局和内容。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
cols / gridCols | String | '1 s:2 m:3 l:4 xl:4 2xl:4' | 响应式栅格列数,支持断点语法 |
gap | Number | 10 | 卡片间距(px) |
titleKey / titleField | String | 第一列 | 卡片标题字段(column.key) |
fieldLimit | Number | 4 | 卡片正文显示的最大字段数 |
selectOnClick | Boolean | false | 点击卡片是否触发勾选 |
maxHeight | Number | — | 卡片区域最大高度,超出滚动 |
style | Object | — | 自定义样式对象 |
const cardProps = {
cols: '1 s:2 m:3 l:4',
gap: 16,
titleKey: 'name',
fieldLimit: 6,
selectOnClick: true,
}卡片内容通过插槽 #table-card="{ row }" 完全自定义渲染。设置此插槽后 titleKey 和 fieldLimit 不再生效。
10. 多页签工作区 (tabWorkspace)
当 formOpenMode="tabWorkspace" 时,新增/编辑表单在页签中打开,支持同时编辑多条记录。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
maxTabs | Number | 8 | 最大同时打开的页签数 |
reuseRecordTab | Boolean | true | 相同记录 ID 是否复用已有页签(而非新开) |
closeAfterSave | Boolean | false | 保存后是否自动关闭页签 |
showDirtyMark | Boolean | true | 未保存变更是否显示脏标记 |
const tabWorkspace = {
maxTabs: 8,
reuseRecordTab: true,
closeAfterSave: false,
showDirtyMark: true,
}11. 详情扩展面板 (detailPanels)
在详情弹窗中,除了默认的只读表单和子表,还可以添加扩展面板展示关联数据。
detailPanels 每项结构:
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
type | String | ✅ | 面板类型:'table'(表格)| 'descriptions'(描述列表)| 'quantity-balance'(数量余额)| 'quantity-ledger'(数量台账)| 'custom'(自定义) |
key | String | ✅ | 面板唯一标识 |
title | String | ✅ | 面板标题 |
dataSource | Object | — | 数据加载配置 |
dataSource.type | String | 'api' | 'api' 接口加载 | 'row' 行数据 | 'static' 静态数据 | 'none' 不加载 |
dataSource.api | String | — | API 配置,格式 '{method}@{path}' |
dataSource.paramsMap | Object | — | 请求参数映射,支持 ${row.fieldName} 占位符 |
table | Object | — | type='table' 时有效。配置 { columns, pagination, maxHeight, size, bordered } |
descriptions | Object | — | type='descriptions' 时有效。配置 { columns, fields } |
quantity | Object | — | 数量台账面板专用。配置 { queryType, paramsMap, pageSize } |
const detailPanels = [
{
type: 'table', key: 'relatedOrders', title: '关联订单',
dataSource: {
type: 'api', api: 'get@/api/order/listByCustomer',
paramsMap: { customerId: '${row.id}' },
},
table: {
columns: [
{ prop: 'orderNo', label: '订单号', minWidth: 140 },
{ prop: 'amount', label: '金额', width: 100 },
],
pagination: { pageSize: 5 },
maxHeight: 300,
size: 'small',
},
},
{
type: 'descriptions', key: 'summary', title: '摘要',
descriptions: {
columns: 3,
fields: [
{ field: 'createUser', label: '创建人' },
{ field: 'createTime', label: '创建时间' },
],
},
},
]12. 行展开 (expandConfig)
表格每行可展开显示额外面板,支持表格、描述列表、表单、选项卡、数量台账等多种类型。
顶层配置:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | Boolean | false | 是否启用行展开 |
trigger | String | 'icon' | 展开触发方式:'icon'(图标)| 'cell'(单元格)| 'row'(整行) |
lazy | Boolean | true | 是否懒加载面板数据 |
cache | Boolean | true | 是否缓存已加载的面板 |
defaultExpanded | Boolean | false | 是否默认展开所有行 |
layout.mode | String | 'single' | 'single' 单面板 | 'tabs' 多 Tab 面板 |
layout.density | String | 'compact' | 密度:'compact' | 'default' | 'loose' |
layout.padding | Number | 12 | 面板内边距 |
panels 每项结构与 detailPanels 相同。
const expandConfig = {
enabled: true,
trigger: 'icon',
lazy: true,
layout: { mode: 'tabs', density: 'compact' },
panels: [
{
type: 'table', key: 'members', title: '项目成员',
dataSource: {
type: 'api', api: 'get@/api/project/:id/members',
paramsMap: { projectId: '${row.id}' },
},
table: {
columns: [
{ prop: 'userName', label: '姓名', width: 120 },
{ prop: 'roleName', label: '角色', width: 100 },
],
maxHeight: 280,
size: 'small',
pagination: false,
},
},
],
}13. 树形表 (treeConfig)
当数据为树形结构时,通过 treeConfig 启用树形表格。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enabled | Boolean | false | 是否启用树形表 |
keyField | String | 'id' | 节点主键字段 |
childrenField | String | 'children' | 子节点字段名(后端返回的嵌套数组字段) |
loadMode | String | 'full' | 'full' 全量加载(后端一次返回完整树)| 'lazy' 懒加载(点击展开时调接口) |
启用树形表后,可配合 enableTreeAddChild 在行操作中显示「添加下级」按钮。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enableTreeAddChild | Boolean | false | 是否显示「添加下级」按钮(左树右表场景通常不需要) |
const treeConfig = {
enabled: true,
keyField: 'id',
childrenField: 'children',
loadMode: 'full',
}14. 钩子函数
所有钩子均为可选,支持同步返回或返回 Promise。返回 false 会中断后续操作。
| 钩子 | 签名 | 返回值 | 说明 |
|---|---|---|---|
beforeLoadList | (params) | params - 修改后的请求参数 | 列表请求前,可追加/修改请求参数 |
beforeRenderList | (list) | list - 处理后的列表数据 | 列表数据渲染前,做映射/转换 |
beforeSearch | (params) | params | false — 返回 false 中断搜索 | 点击搜索按钮后,请求发出前 |
beforeRenderReset | () | void | 点击重置按钮后回调 |
beforeSubmit | (formData) | data | false — 返回 false 中断提交 | 表单提交前,可追加字段或做业务校验 |
afterBuildSubmitData | (submitData) | data | false — 返回 false 中断提交 | 主从表数据合并后、发送请求前,做最终校验 |
afterSubmit | ({ data, response, isEdit }) | void | 提交成功后回调,常用于刷新列表或跳转 |
beforeDelete | (rows) | boolean — 返回 false 中断删除 | 删除前确认 |
beforeRenderForm | (data) | data - 处理后的表单数据 | 打开编辑/详情弹窗前预处理数据 |
beforeRenderDetail | (data) | data - 处理后的详情数据 | 详情数据渲染前处理 |
15. 其他配置
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
lazy | Boolean | false | 初始不加载列表数据,需手动调用 refresh() |
loadDetailOnEdit | Boolean | false | 编辑时是否通过详情接口加载最新数据(开启后多一次请求,但数据更准确) |
publicQuery | Object | {} | 公共查询参数,拼接到 URL query string。不会随搜索变化 |
publicParams | Object | {} | 公共请求参数,合并到请求 body(POST) |
formDefaultValues | Object | {} | 新增/编辑弹窗打开时的默认表单值 |
submitDefaultParams | Object | {} | 提交时固定合并到提交数据的参数 |
字段类型速查表
searchSchema 和 editSchema 的每个字段通过 type 属性决定渲染哪种控件。以下是全部 34 种类型的详细说明。
基础输入类
| type | 渲染组件 | 关键属性 (props / 顶层) |
|---|---|---|
input | <n-input> | placeholder, maxlength, showCount, type: 'password' |
textarea | <n-input type="textarea"> | rows(默认 3), maxlength, showCount, autosize |
number / inputnumber / input-number | <n-input-number> | min, max, step(默认 1), precision, showButton(默认 true) |
switch | <n-switch> | checkedValue(默认 true), uncheckedValue(默认 false), checkedText, uncheckedText |
slider | <n-slider> | min(默认 0), max(默认 100), step(默认 1), marks, tooltip |
rate | <n-rate> | count(默认 5), allowHalf |
color / colorPicker | <n-color-picker> | showAlpha, modes(默认 ['hex']) |
text | 只读文本 | formatter: (value, field, formData) => string, copy: true 显示复制按钮 |
选择类
| type | 渲染组件 | 关键属性 |
|---|---|---|
select | <n-select> | options: [{ label, value }], multiple, filterable(默认 true), remote, onSearch, dictType |
dictSelect | <DictSelect> | dictType, multiple, filterable, cascade: { sourceField, sourceDictType, mode, emptyStrategy } |
radio | <n-radio-group> | options: [{ label, value }], dictType |
radioButton | <n-radio-group> + <n-radio-button> | 同 radio。props: { button: true } 等效 |
checkbox | <n-checkbox-group> | options: [{ label, value }], dictType |
cascader | <n-cascader> | options(树形), dictType, multiple, filterable, cascade, showPath |
treeSelect | <n-tree-select> | 同 cascader |
transfer | <n-transfer> | options, filterable |
orgTreeSelect / orgSelect / departmentSelect / 等 | <n-tree-select> | 自动从 /system/org/tree 加载数据,支持 multiple, filterable, cascade |
userSelect / userPicker / user / 等 | <UserSelectPicker> | 用户选择器,支持 multiple |
regionTreeSelect | <RegionTreeSelect> | 行政区划树,支持 filterable |
customSelect | <AiCustomSelect> | api: 'get@/api/xxx', labelField, valueField, remote, transform |
objectReference | <n-select>(远程) | referenceObjectCode, referenceValueField, referenceDisplayField |
recordSelector | <AiRecordSelectorModal> | selectorTitle, 各 *ObjectCode / *Code 属性, displayFields, keywordFields, fieldMappings |
日期时间类
| type | 渲染组件 | 关键属性 |
|---|---|---|
date | <n-date-picker type="date"> | format(默认 'yyyy-MM-dd'), valueFormat(默认同 format) |
datetime | <n-date-picker type="datetime"> | 默认格式 'yyyy-MM-dd HH:mm:ss' |
month | <n-date-picker type="month"> | 默认格式 'yyyy-MM' |
year | <n-date-picker type="year"> | 默认格式 'yyyy' |
time | <n-time-picker> | 默认格式 'HH:mm:ss' |
daterange | <n-date-picker type="daterange"> | startPlaceholder: '开始日期', endPlaceholder: '结束日期', 值格式同上 |
datetimerange | <n-date-picker type="datetimerange"> | 默认占位 '开始时间' / '结束时间',格式 'yyyy-MM-dd HH:mm:ss' |
timerange | 双 <n-time-picker> | 类似 daterange,格式 'HH:mm:ss' |
上传类
| type | 渲染组件 | 关键属性 |
|---|---|---|
upload | <n-upload> | action, headers, data, max, accept, multiple, listType, uploadText |
fileUpload | <FileUpload> | action, businessType, businessId, storageType, limit, fileSize, fileType, multiple, valueType |
imageUpload | <ImageUpload> | 同 fileUpload。额外 limit 控制最大图片数,tip 显示提示文本 |
特殊类型
| type | 渲染组件 | 关键属性 |
|---|---|---|
slot | <slot> | slotName(默认为 field.field 的值),插槽暴露 { value, field, formData, updateValue } |
divider | <AiFormSectionTitle> | 分组分隔线,label 显示标题文本。span: 2 可占满整行 |
card | <n-card> | 卡片容器,可嵌套子字段。子字段通过 children 数组定义 |
tabs + tabPane | <n-tabs> + <n-tab-pane> | 选项卡布局,每个 tabPane 内含独立子字段 |
collapse + collapseItem | <n-collapse> + <n-collapse-item> | 折叠面板布局 |
row + col | 栅格行/列 | 高级布局控制,row 内含多个 col,col 内含子字段 |
所有字段通用的配置属性
无论哪种 type,都支持以下属性:
{
field: 'fieldName', // 字段名(必填)
label: '显示标签', // 标签文本
type: 'input', // 字段类型(必填)
span: 1, // 栅格宽度,配合 editGridCols 控制每行几个字段
required: false, // 是否必填(显示红色星号)
rules: [], // Naive UI 校验规则
defaultValue: '', // 默认值
placeholder: '', // 占位符(不设则自动生成)
disabled: false, // 禁用(支持函数 (formData) => boolean)
clearable: true, // 是否可清空
hidden: false, // 是否隐藏
vIf: (formData) => true, // 条件渲染
props: {}, // 透传给底层组件的属性
onChange: ({ value, field, formData, context }) => {}, // 值变化回调
labelTip: '', // 标签旁问号提示
description: '', // 控件下方描述文字
showFeedback: true, // 是否显示校验反馈
}事件
| 事件名 | 参数 | 触发时机 |
|---|---|---|
load-list-success | { list, total, params } | 列表数据加载成功 |
load-list-error | { error, params } | 列表数据加载失败 |
add | { defaultValues } | 点击新增,弹窗打开后 |
edit | { row } | 点击编辑,弹窗打开后 |
detail | { row } | 点击详情,弹窗打开后 |
delete | { row, rows } | 删除成功 |
submit-success | { data, response, isEdit } | 新增或编辑提交成功 |
submit-error | { error, isEdit } | 新增或编辑提交失败 |
selection-change | { keys, rows } | 表格多选状态变化 |
modal-open | { status: 'add' | 'edit' | 'detail', row } | 弹窗打开 |
modal-close | — | 弹窗关闭 |
render-mode-change | { mode: 'table' | 'card' } | 切换列表/卡片模式 |
custom-action | { action, row, rows } | 自定义工具栏按钮点击。action 为 toolbarActions 中的 key |
插槽
工具栏插槽
| 插槽名 | 说明 |
|---|---|
toolbar | 覆盖整个工具栏区域 |
toolbar-start | 工具栏左侧(与默认按钮共存) |
toolbar-end | 工具栏右侧(与默认按钮共存) |
toolbar-right-start | 右侧操作区开始位置 |
toolbar-right-end | 右侧操作区结束位置 |
表格列插槽
列插槽名格式:table-{slot},其中 {slot} 是 columns 中该列定义的 slot 属性值。插槽 props:{ row, index }。
<template #table-status="{ row }">
<n-tag :type="row.status === 1 ? 'success' : 'default'">{{ row.status === 1 ? '启用' : '禁用' }}</n-tag>
</template>卡片渲染插槽
table-card:卡片模式下完全自定义卡片内容。props:{ row }。
搜索表单插槽
格式:search-{field},其中 {field} 为 searchSchema 中该字段的 field 值。
编辑/详情表单插槽
格式:form-{field},其中 {field} 为 editSchema 中该字段的 field 值。额外支持 form-group-header="{ group }"。
暴露方法
通过 ref 获取组件实例后调用:
const crudRef = ref(null)
crudRef.value.refresh() // 刷新列表(保持搜索条件和分页)
crudRef.value.search() // 触发搜索(重置到第一页)
crudRef.value.loadList({ name: 'test' }) // 加载列表,可传入额外参数
crudRef.value.getSelectedRows() // 获取选中行数据 → Array
crudRef.value.getSelectedKeys() // 获取选中行主键 → Array
crudRef.value.setSelectedKeys([1, 2, 3]) // 通过主键数组设置选中
crudRef.value.clearSelection() // 清除所有选中
crudRef.value.getTableData() // 获取当前表格全部数据 → Array
crudRef.value.setTableData([...]) // 直接设置表格数据(不触发请求)进阶用法
主子表 CRUD
<AiCrudPage
api="/api/order"
:columns="orderColumns"
:edit-schema="orderEditSchema"
:children-config="orderItemConfig"
:edit-grid-cols="2"
modal-width="960px"
/>const orderItemConfig = [{
key: 'items', title: '订单明细',
fields: [
{ field: 'productName', label: '商品名称', type: 'input', required: true },
{ field: 'quantity', label: '数量', type: 'number', required: true, props: { min: 1 } },
{ field: 'price', label: '单价', type: 'number', required: true, props: { precision: 2 } },
],
api: {
list: 'get@/api/order/:id/items',
add: 'post@/api/order/:id/items',
update: 'put@/api/order/:id/items/:itemId',
delete: 'delete@/api/order/:id/items/:itemId',
},
}]左树右表
<AiCrudPage
api="/api/dept"
:columns="deptColumns"
:tree-config="{ enabled: true, keyField: 'id', childrenField: 'children', loadMode: 'full' }"
:enable-tree-add-child="false"
hide-add
/>纯填报表单
<AiCrudPage
:edit-schema="formSchema"
:edit-grid-cols="2"
form-only
form-only-title="员工入职登记"
form-only-submit-text="提交入职申请"
:api-config="{ add: 'post@/api/employee/onboarding' }"
@submit-success="onSubmitSuccess"
/>卡片模式
<AiCrudPage
api="/api/product"
:columns="productColumns"
:edit-schema="productEditSchema"
render-mode="card"
:show-render-mode-switch="true"
:card-props="{ cols: '1 s:2 m:3 l:4', gap: 16, fieldLimit: 6 }"
>
<template #table-card="{ row }">
<div class="product-card">
<img :src="row.image" />
<h4>{{ row.name }}</h4>
<p>¥{{ row.price }}</p>
</div>
</template>
</AiCrudPage>抽屉编辑 + 行展开子表
<AiCrudPage
api="/api/project"
:columns="projectColumns"
:edit-schema="projectEditSchema"
modal-type="drawer"
drawer-placement="right"
modal-width="720px"
:expand-config="{
enabled: true,
trigger: 'icon',
lazy: true,
layout: { mode: 'tabs', density: 'compact' },
panels: [{
type: 'table', key: 'members', title: '项目成员',
dataSource: {
type: 'api', api: 'get@/api/project/:id/members',
paramsMap: { projectId: '${row.id}' },
},
table: {
columns: memberColumns,
maxHeight: 280, size: 'small', pagination: false,
},
}],
}"
/>自定义工具栏 + 确认删除
<AiCrudPage
ref="crudRef"
api="/api/order"
:columns="orderColumns"
:toolbar-actions="[
{ label: '批量审批', key: 'batch-audit', type: 'info', icon: 'check-circle', onClick: handleBatchAudit },
{ label: '导出选中', key: 'export-selected', type: 'warning' },
]"
:before-delete="async (rows) => {
return await dialog.warning({
title: '确认删除',
content: `确定删除选中的 ${rows.length} 条记录?不可恢复。`,
positiveText: '确认删除',
}) !== false
}"
:before-submit="(formData) => ({ ...formData, updatedBy: userStore.userId })"
@custom-action="({ action, rows }) => { if (action === 'batch-audit') auditRows(rows) }"
/>多页签录入
<AiCrudPage
api="/api/contract"
:columns="contractColumns"
:edit-schema="contractEditSchema"
:children-config="contractItemsConfig"
form-open-mode="tabWorkspace"
:tab-workspace="{ maxTabs: 8, reuseRecordTab: true, closeAfterSave: false }"
modal-width="1024px"
/>注意事项
columns为必填项,至少需包含prop和labelapi和apiConfig二选一即可,apiConfig优先级更高- URL 占位符名称需与
rowKey属性值一致 - 钩子函数返回
false会中断操作且不弹提示,需自行处理用户反馈 lazy=true时初始不加载列表,需手动调用refresh()或search()- 大表单建议设
editGridCols=2,配合modalWidth调整弹窗宽度 - 卡片模式需通过
#table-card插槽或cardProps.titleKey自定义渲染 searchSchema和editSchema共享同一套字段类型体系,但搜索表单通常不需要required校验
