# 一个 CRUD 页面从 2 天到 10 分钟:用 Forge Admin 的 AiCrudPage 实操
> 不讲架构,不讲原理,这篇就是手把手:怎么用 Forge Admin 10 分钟搭一个能跑的 CRUD 页面。
做过后台的都知道,一个"列表 + 搜索 + 新增 + 编辑 + 删除"的标准 CRUD 页面,要写多少东西:
- Controller(分页查询、详情、新增、修改、删除 5 个接口)
- Service + ServiceImpl(业务逻辑)
- Mapper + Mapper XML(SQL)
- Entity + DTO + VO(三层数据对象)
- Vue 页面(搜索表单、表格、弹窗表单、增删改查按钮、分页)
熟练的开发,两天能写完一个。不熟练的,三天起步。
但如果你的后台框架有一套协议驱动的 CRUD 组件,**10 分钟就能配出一个能跑的页面**。
这篇就用 Forge Admin 的 `AiCrudPage` 组件,从零搭一个"业务类型管理"页面,全程配置,几乎不写业务代码。
---
## 一、最终效果:我们要搭什么
目标:一个"消息业务类型管理"页面,包含:
- 顶部搜索:业务类型编码、名称、状态
- 表格列表:编码、名称、跳转方式、图标、排序、状态
- 新增/编辑弹窗:表单填写
- 删除确认
效果就是后台系统里最常见的那个页面。区别是:**别人写两天,我们配 10 分钟。**
---
## 二、第一步:准备后端接口
`AiCrudPage` 不生成接口,它只消费接口。所以后端要先准备好标准的 5 个 RESTful 接口:
| 操作 | 方法 | 路径 |
|------|------|------|
| 分页查询 | GET | `/api/message/bizType/page` |
| 详情查询 | GET | `/api/message/bizType/:id` |
| 新增 | POST | `/api/message/bizType` |
| 修改 | PUT | `/api/message/bizType` |
| 删除 | DELETE | `/api/message/bizType/:id` |
如果你用了 Forge 的代码生成器,这 5 个接口是一键生成的。这里假设你已经有了。
> 关键约定:分页参数前端传 `pageNum` + `pageSize`,后端必须用相同命名接收。URL 占位符用 `:id`(冒号),不是 `{id}`(花括号)。
---
## 三、第二步:写 apiConfig(告诉组件接口在哪)
`AiCrudPage` 的核心配置之一是 `apiConfig`,它告诉组件每个操作对应哪个接口:
```js
const apiConfig = {
list: 'get@/api/message/bizType/page',
detail: 'get@/api/message/bizType/:id',
add: 'post@/api/message/bizType',
update: 'put@/api/message/bizType',
delete: 'delete@/api/message/bizType/:id',
}
```
格式是 `方法@路径`,就这一行一个接口,清晰明了。
- `list`:分页查询
- `detail`:详情(编辑时回显用)
- `add`:新增
- `update`:修改
- `delete`:删除
注意占位符是 `:id`,不是 `{id}`。这是组件的约定,写错了识别不了。
---
## 四、第三步:配置搜索表单(searchSchema)
搜索表单也是一个 JSON 数组,每个对象是一个搜索字段:
```js
const searchSchema = [
{
field: 'bizType',
label: '业务类型编码',
type: 'input',
props: {
placeholder: '请输入业务类型编码',
},
},
{
field: 'bizName',
label: '业务类型名称',
type: 'input',
props: {
placeholder: '请输入业务类型名称',
},
},
{
field: 'enabled',
label: '状态',
type: 'select',
props: {
placeholder: '请选择状态',
clearable: true,
options: [
{ label: '启用', value: 1 },
{ label: '禁用', value: 0 },
],
},
},
]
```
`type` 支持的常用类型:
- `input`:文本输入
- `select`:下拉选择
- `datePicker`:日期选择
- `dict`:字典下拉(配合 `useDict` 用)
每个字段的 `props` 会透传给底层 Naive UI 组件,所以 Naive UI 支持的属性这里都能用。
> 如果是状态、类型这种枚举,建议用字典组件 `DictSelect`,不要在页面里写死 `options`。这是项目规范。
---
## 五、第四步:配置表格列(columns)
表格列也是一个数组:
```js
const tableColumns = [
{ prop: 'bizType', label: '业务类型编码', width: 150 },
{ prop: 'bizName', label: '业务类型名称', width: 150 },
{ prop: 'jumpUrl', label: '跳转URL模板', ellipsis: { tooltip: true } },
{
prop: 'jumpTarget',
label: '跳转方式',
width: 100,
render: (row) => {
return h(NTag, { size: 'small' }, {
default: () => row.jumpTarget === '_blank' ? '新窗口' : '当前页',
})
},
},
{ prop: 'icon', label: '图标', width: 100 },
{ prop: 'sort', label: '排序', width: 80 },
]
```
几个常用属性:
- `prop`:字段名(对应后端返回的字段)
- `label`:列标题
- `width`:列宽
- `ellipsis`:超长省略,`tooltip: true` 鼠标悬停显示完整内容
- `render`:自定义渲染(用 `h` 函数渲染标签、按钮等)
需要渲染状态标签、操作按钮、图片的地方,用 `render` 写。不需要自定义的,填 `prop` + `label` 就行。
---
## 六、第五步:配置新增/编辑表单(editSchema)
弹窗里的表单也是 schema 配置:
```js
const editSchema = [
{
field: 'bizType',
label: '业务类型编码',
type: 'input',
rules: { required: true, message: '请输入业务类型编码' },
},
{
field: 'bizName',
label: '业务类型名称',
type: 'input',
rules: { required: true, message: '请输入业务类型名称' },
},
{
field: 'jumpUrl',
label: '跳转URL模板',
type: 'input',
},
{
field: 'jumpTarget',
label: '跳转方式',
type: 'select',
props: {
options: [
{ label: '当前页', value: '_self' },
{ label: '新窗口', value: '_blank' },
],
},
},
{
field: 'sort',
label: '排序',
type: 'inputNumber',
defaultValue: 0,
},
{
field: 'enabled',
label: '状态',
type: 'switch',
defaultValue: 1,
},
]
```
`rules` 是表单校验规则,`defaultValue` 是新增时的默认值。
新增和编辑共用一份 schema。编辑时,组件会自动调 `detail` 接口回显数据(需要配 `:load-detail-on-edit="true"`)。
---
## 七、第六步:组装页面
把上面三份配置交给 `AiCrudPage`,页面就完成了:
```vue
```
就这么多。一个完整的 CRUD 页面,包含搜索、表格、分页、新增弹窗、编辑回显、删除确认,全部到位。
整个 Vue 文件大约 150 行,其中大部分是配置数据,几乎不写逻辑代码。
---
## 八、如果不想写代码:用低代码搭建器
上面是"写配置"的方式。如果你连配置都不想写,Forge 还提供了**可视化低代码搭建器**:
1. 进入"AI 应用开发"页面
2. 点"AI 智能开发",用自然语言描述需求:"我要一个业务类型管理,有编码、名称、跳转方式、排序、状态"
3. AI 生成数据模型和页面配置
4. 在可视化编辑器里拖拽微调
5. 发布,菜单自动注册
这条路适合:
- 不想写任何代码的业务人员
- 快速原型验证
- 标准化程度高的 CRUD 业务
而 `AiCrudPage` 适合:
- 开发者想掌控细节
- 业务有自定义逻辑
- 需要下载代码二次开发
两条路,按需选。
---
## 九、和传统写法对比
| 对比项 | 传统手写 | AiCrudPage 配置 |
|--------|----------|-----------------|
| 开发时间 | 1-2 天 | 10 分钟 |
| 代码量 | 5-6 个文件,数百行 | 1 个 Vue 文件,约 150 行 |
| 改字段 | 改 Entity/DTO/VO/Mapper/Vue | 改 schema 配置 |
| 加搜索条件 | 改 Mapper XML + Vue | 加一个 schema 对象 |
| 改表格列 | 改 Vue | 改 columns 数组 |
| 一致性 | 看开发水平 | 组件统一保证 |
| 复杂业务 | 灵活 | 可下载代码包二次开发 |
这不是说传统写法没用。复杂业务逻辑、复杂联表查询、特殊交互,该手写还是手写。但 80% 的标准 CRUD 页面,用配置能省大量时间。
---
## 十、几个踩坑提醒
**1. 占位符用 `:id` 不是 `{id}`**
```js
// ✅ 对
detail: 'get@/api/message/bizType/:id'
// ❌ 错
detail: 'get@/api/message/bizType/{id}'
```
组件只识别 `includes(':id')`,写花括号会匹配不到。
**2. 分页参数叫 `pageNum` 不叫 `page`**
后端 Controller 必须用 `@RequestParam(defaultValue = "1") Integer pageNum`,不能用 `page`。前后端命名必须一致。
**3. 字典别写死 options**
状态、类型这种枚举值,不要在 schema 里写死 `options`。维护到 `sys_dict_type` + `sys_dict_data`,前端用 `useDict` 或 `DictSelect`。这样加一个枚举值不用改代码。
**4. schema 定义成 computed**
如果 schema 里用了字典(`useDict`),必须把 schema 定义成 `computed`,确保字典异步加载后响应式更新:
```js
const editSchema = computed(() => [
{
field: 'status',
label: '状态',
type: 'dict',
dictType: 'sys_normal_disable',
},
])
```
**5. 图片字段用 AuthImage**
如果表格里有图片列,用 `AuthImage` 组件渲染(自动带 Token),不要直接用 `NAvatar` 的 `src`。`imageUpload` 存的是 fileId 不是 URL。
---
## 十一、总结:什么时候用 AiCrudPage
**适合用:**
- 标准 CRUD 管理页面(用户、角色、字典、配置、业务类型……)
- 字段以表单输入、下拉、开关为主
- 搜索条件简单
- 团队想统一页面风格和交互
**不适合用:**
- 复杂多表联查的报表页面
- 有复杂交互逻辑的页面(拖拽排序、实时计算、复杂联动)
- 非标格式的页面(看板、日历、流程图)
**我的建议是:** 先用 `AiCrudPage` 把 80% 的标准页面快速搞定,省下的时间投入到那 20% 真正需要手写的复杂业务上。这才是低代码该有的价值——不是替代开发,是把重复劳动自动化。
---
## 上手体验
光看不练假把式,直接上演示站(账号 `admin` / `123456`):
- 后台演示:http://www.dlforgelab.com:8084/forge/login
- 项目文档:http://www.dlforgelab.com:8084/forge-docs/
- Gitee:https://gitee.com/ForgeLab/forge-admin
- GitHub:https://github.com/yaomindong1996/forge-admin
> 你平时搭一个 CRUD 页面要多久?有没有试过用配置驱动的方式?评论区聊聊,觉得有用求个👍收藏。