- Table 模板添加 error 状态渲染支持 - Controller 模板统一使用 PATCH 方法(update 和 restore) - 修复 edit-dialog 模板花括号输出问题,添加 openBrace/closeBrace helper - 简化 Table 模板的 refetch 逻辑 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CRUD 代码生成器
基于 Plop.js 的全栈 CRUD 代码生成器,支持一键生成后端模块、前端模块、共享类型和 Prisma Model。
快速开始
pnpm generate
按提示输入模块信息即可自动生成完整的 CRUD 代码。
交互式提问
| 步骤 | 提示 | 说明 | 示例 |
|---|---|---|---|
| 1 | 模块名称 | 英文,小写开头 | product |
| 2 | 模块中文名 | 用于注释和 API 标签 | 产品 |
| 3 | 复数名称 | API 路径和表名 | products |
| 4 | 生成目标 | 多选:后端/前端/共享类型/Prisma | 全选 |
| 5 | 软删除 | 是否启用软删除 | Yes |
| 6 | 字段定义 | DSL 语法定义字段 | 见下方 |
| 7 | 搜索字段 | 选择可搜索的字段 | name, status |
| 8 | 分页配置 | 默认/最大分页、排序 | 20/100/createdAt/desc |
字段 DSL 语法
基本格式
字段名:类型[修饰符] 标签 "示例值" [验证规则...]
类型
| 类型 | 说明 | Prisma | TypeScript |
|---|---|---|---|
string |
字符串 | String |
string |
number |
数字 | Float |
number |
boolean |
布尔值 | Boolean |
boolean |
date |
日期 | DateTime |
Date |
datetime |
日期时间 | DateTime |
Date |
enum(a,b,c) |
枚举 | String |
'a' | 'b' | 'c' |
修饰符
| 修饰符 | 说明 |
|---|---|
? |
可选字段(nullable) |
! |
唯一约束 |
验证规则
| 规则 | 说明 | 适用类型 |
|---|---|---|
min:n |
最小值/最小长度 | string, number |
max:n |
最大值/最大长度 | string, number |
email |
邮箱格式 | string |
url |
URL 格式 | string |
控制标志
| 标志 | 说明 |
|---|---|
noCreate |
不在创建表单中使用 |
noUpdate |
不在更新表单中使用 |
noTable |
不在表格列中显示 |
示例
# 必填字符串,2-100 字符
name:string 名称 "示例名称" min:2 max:100
# 可选长文本
description:string? 描述 "描述内容" max:500
# 数字,最小值 0
price:number 价格 "99.99" min:0
# 枚举类型
status:enum(draft,published,archived) 状态 "draft"
# 唯一邮箱
email:string! 邮箱 "test@example.com" email
# 布尔值
isActive:boolean 是否激活 "true"
# 可选日期
publishedAt:datetime? 发布时间 "2026-01-16T10:00:00Z"
生成的文件
后端 (apps/api)
| 文件 | 说明 |
|---|---|
src/{module}/dto/{module}.dto.ts |
CreateDto、UpdateDto、ResponseDto、QueryDto |
src/{module}/{module}.service.ts |
CRUD 服务,继承 CrudService |
src/{module}/{module}.controller.ts |
RESTful 控制器,含 Swagger 文档 |
src/{module}/{module}.module.ts |
NestJS 模块 |
前端 (apps/web)
| 文件 | 说明 |
|---|---|
src/services/{module}.service.ts |
API 调用封装 |
src/hooks/use{Module}s.ts |
TanStack Query hooks |
src/components/{module}s/{Module}sTable.tsx |
数据表格组件 |
src/components/{module}s/{Module}CreateDialog.tsx |
创建对话框 |
src/components/{module}s/{Module}EditDialog.tsx |
编辑对话框 |
共享类型 (packages/shared)
| 文件 | 说明 |
|---|---|
src/types/{module}.ts |
接口类型定义 |
Prisma
| 文件 | 说明 |
|---|---|
prisma/schema.prisma |
追加模型定义 |
自动集成
生成器会自动修改以下文件完成集成:
| 文件 | 修改内容 |
|---|---|
apps/api/src/app.module.ts |
导入新模块 |
apps/api/src/prisma/prisma.service.ts |
添加软删除模型配置 |
apps/web/src/config/constants.ts |
添加 API 端点 |
packages/shared/src/types/index.ts |
导出新类型 |
生成后步骤
# 1. 同步数据库
pnpm db:generate && pnpm db:push
# 2. 重启开发服务器
pnpm dev
完整示例
以生成「产品」模块为例:
$ pnpm generate
? 模块名称(英文,如 product): product
? 模块中文名(如 产品): 产品
? 复数名称(如 products): products
? 选择要生成的模块: 后端 (NestJS), 前端 (Next.js), 共享类型, Prisma Model
? 是否启用软删除? Yes
? 定义字段:
name:string 名称 "示例产品" min:2 max:100
description:string? 描述 "产品描述" max:500
price:number 价格 "99.99" min:0
stock:number 库存 "100" min:0
status:enum(draft,published,archived) 状态 "draft"
? 选择支持搜索的字段: name, status
? 默认分页大小: 20
? 最大分页大小: 100
? 默认排序字段: createdAt
? 默认排序方向: desc
✔ 生成 apps/api/src/product/dto/product.dto.ts
✔ 生成 apps/api/src/product/product.service.ts
✔ 生成 apps/api/src/product/product.controller.ts
✔ 生成 apps/api/src/product/product.module.ts
✔ 生成 apps/web/src/services/product.service.ts
✔ 生成 apps/web/src/hooks/useProducts.ts
✔ 生成 apps/web/src/components/products/ProductsTable.tsx
✔ 生成 apps/web/src/components/products/ProductCreateDialog.tsx
✔ 生成 apps/web/src/components/products/ProductEditDialog.tsx
✔ 生成 packages/shared/src/types/product.ts
✔ 修改 apps/api/prisma/schema.prisma
✔ 修改 apps/api/src/app.module.ts
✔ 修改 apps/api/src/prisma/prisma.service.ts
✔ 修改 apps/web/src/config/constants.ts
✔ 修改 packages/shared/src/types/index.ts
✨ 生成完成!
目录结构
plop/
├── plopfile.ts # 主配置入口
├── package.json # ESM 模块配置
├── generators/
│ └── crud.ts # CRUD 生成器逻辑
├── helpers/
│ └── index.ts # Handlebars helpers
├── utils/
│ └── field-parser.ts # 字段 DSL 解析器
└── templates/
├── api/ # 后端模板
│ ├── dto.hbs
│ ├── service.hbs
│ ├── controller.hbs
│ └── module.hbs
├── web/ # 前端模板
│ ├── service.hbs
│ ├── hooks.hbs
│ ├── table.hbs
│ ├── create-dialog.hbs
│ └── edit-dialog.hbs
├── shared/ # 共享类型模板
│ └── types.hbs
└── prisma/ # Prisma 模板
└── model.hbs
扩展模板
如需自定义模板,可直接修改 plop/templates/ 目录下的 .hbs 文件。
可用的 Handlebars Helpers
| Helper | 说明 | 示例 |
|---|---|---|
pascalCase |
转 PascalCase | product → Product |
camelCase |
转 camelCase | product → product |
kebabCase |
转 kebab-case | productItem → product-item |
snakeCase |
转 snake_case | productItem → product_item |
constantCase |
转 CONSTANT_CASE | product → PRODUCT |
tsType |
获取 TS 类型 | string, number 等 |
prismaType |
获取 Prisma 类型 | String, Float 等 |
zodValidation |
生成 Zod 验证 | z.string().min(2) |
formControl |
生成表单控件 | <Input .../> |
常见问题
Q: 如何添加自定义字段类型?
修改 plop/utils/field-parser.ts 中的类型映射。
Q: 如何修改生成的代码风格?
直接编辑 plop/templates/ 下的模板文件。
Q: 生成后 TypeScript 报错?
确保运行 pnpm db:generate 更新 Prisma Client 类型。