
代码生成器
概述
祺洛内置了 代码生成器,能够扫描项目中由 sea-orm-cli 生成的 Entity 文件,自动产出完整的后端与前端 CRUD 代码,极大减少重复劳动。
核心能力:
- 🦀 后端生成:Args 参数定义、Model 数据库操作、Service 路由处理、API 路由片段、mod.rs 声明
- 🖥️ 前端生成:API 请求封装、列表页 View、表单组件 Write、详情组件 Detail、多语言翻译片段
- ⚙️ 字段配置:可视配置字段在列表/搜索/表单/详情中的显示、排序、组件类型、验证规则
- 🔗 关联关系:自动识别 BelongsTo 关系,生成 Select 下拉和关联数据加载代码
- 🔒 数据权限:检测
dept_id+owner_id字段,一键启用数据隔离 - 📤 上传组件:自动识别图片字段,生成 Upload 组件和上传处理代码
快速开始
前提条件
- 使用
sea-orm-cli generate entity生成 Entity 文件(位于src/model/{module}/entity/目录下) - 确保后端服务已启动(代码生成器通过 API 调用后端扫描和生成接口)
操作步骤
- 登录管理后台,进入 工具 → 代码生成器
- 点击 扫描 按钮,系统自动扫描所有模块的 Entity 文件
- 在扫描结果中找到目标实体,点击 配置 按钮
- 在字段配置弹窗中调整各字段的显示、组件、验证等配置
- 点击 确认生成,查看生成的代码
- 下载或复制生成的代码,放置到项目对应目录
生成文件清单
后端文件(Rust)
| 序号 | 文件 | 路径模板 | 说明 |
|---|---|---|---|
| 1 | Args | src/model/{module}/args/{entity}.rs | 参数定义:Resp / Search / Add / Edit / Del |
| 2 | Model | src/model/{module}/model/{entity}.rs | 数据库操作:list / add / edit / del |
| 3 | Service | src/service/{module}/{entity}.rs | 路由处理函数 |
| 4 | API 路由片段 | src/api/{table}_route_fragment.txt | 路由注册函数片段(需手动合并) |
| 5 | API nest 片段 | mod_updates | .nest() 路由挂载片段(需手动合并) |
| 6 | mod 声明 | mod_updates | model/args/service 的 pub mod 声明(需手动合并) |
前端文件(Vue/TypeScript)
| 序号 | 文件 | 路径模板 | 说明 |
|---|---|---|---|
| 7 | API | src/api/{module}.ts | API 请求封装(list/add/edit/del) |
| 8 | View | src/views/{Module}/{entity}/{entity}.vue | 列表页(含搜索、表格、弹窗) |
| 9 | Write | src/views/{Module}/{entity}/components/Write.vue | 表单组件(新增/编辑) |
| 10 | Detail | src/views/{Module}/{entity}/components/Detail.vue | 详情展示组件 |
| 11 | 中文翻译 | src/locales/menuuser.zh-CN.snippet.json | 中文翻译片段(需合并到 locale 文件) |
| 12 | 英文翻译 | src/locales/menuuser.en.snippet.json | 英文翻译片段(需合并到 locale 文件) |
字段配置详解
在代码生成器的配置弹窗中,包含四个 Tab 页:
📋 列表配置
控制字段在列表页中的展示行为:
| 配置项 | 说明 | 默认值 |
|---|---|---|
| 显示 | 是否在表格列中展示 | 非主键字段默认显示 |
| 排序 | 是否支持点击表头排序 | 默认关闭 |
| 排序优先级 | 排序权重,值越高优先级越高 | 0(不参与默认排序) |
| 排序方向 | 升序 asc 或降序 desc | desc |
默认排序规则:
sort/order_num/sort_order字段:优先级最高,方向ascweight/priority字段:优先级次高,方向desc- 其他字段:不设默认排序,由用户手动配置
🔍 搜索配置
| 配置项 | 说明 | 默认值 |
|---|---|---|
| 搜索 | 是否作为搜索条件 | 默认关闭 |
| 组件 | 搜索表单使用的组件类型 | 自动推断 |
搜索字段仅对 String / Option<String> 类型的字段有效。搜索时使用 contains 模糊匹配,其他类型使用 eq 精确匹配。
📝 表单配置
| 配置项 | 说明 | 默认值 |
|---|---|---|
| 表单 | 是否在新增/编辑表单中显示 | 非主键字段默认显示 |
| 组件 | 表单使用的组件类型 | 自动推断 |
| 必填 | 是否必填 | 非 Optional 字段默认必填 |
| 最小长度 | 字符串最小长度验证 | — |
| 最大长度 | 字符串最大长度验证 | — |
| 正则 | 正则表达式验证 | — |
| 正则提示 | 正则验证失败提示语 | — |
📖 详情配置
| 配置项 | 说明 | 默认值 |
|---|---|---|
| 详情 | 是否在详情页展示 | 默认显示 |
组件类型推断
代码生成器根据字段名和 Rust 类型自动推断前端组件:
| 推断规则 | 组件类型 | 示例字段 |
|---|---|---|
字段名以 _at 结尾或 created_at / updated_at | DatePicker | created_at |
字段名包含 image / img / avatar / cover / pic / photo / thumbnail | Upload | cover, avatar |
字段名是 password | InputPassword | password |
字段名以 _id 结尾(外键) | Select | role_id, dept_id |
字段名是 status / type / kind / category / level 等 | Select | status, type |
字段名是 gender / sex | Radio | sex |
字段名是 sort / weight / priority 等 | InputNumber | sort_order |
Rust 类型 i32 / u32 / f32 / f64 | InputNumber | — |
Rust 类型 i64 / u64 | Input | — |
Rust 类型 bool | Switch | — |
Rust 类型 String 且字段名含 remark / content / description | InputTextarea | remark |
Rust 类型 String | Input | — |
Rust 类型 DateTime 等 | DatePicker | — |
支持的组件类型(可在配置中手动选择):
| 组件 | 说明 |
|---|---|
| Input | 文本输入框 |
| InputNumber | 数字输入框 |
| Select | 下拉选择 |
| Radio | 单选 |
| Checkbox | 多选 |
| Switch | 开关 |
| InputPassword | 密码输入 |
| DatePicker | 日期选择 |
| TimePicker | 时间选择 |
| DateTimePicker | 日期时间选择 |
| Upload | 文件上传 |
| Textarea | 文本域 |
关联关系处理
BelongsTo 关系
当 Entity 中定义了 BelongsTo 关系时(如外键 role_id 关联 sys_role 表),代码生成器会:
- 自动识别:解析 Entity 的
Relation枚举,提取BelongsTo关联信息 - 组件推断:将外键字段的组件自动设为
Select - 生成关联 API 调用:在列表页中自动生成关联表的列表请求
- 生成下拉选项加载:在
Write.vue表单中自动加载关联表的 Select 选项 - 关联显示字段推断:根据目标表名自动推断显示字段(如
sys_role→role_name,sys_dict_type→dict_name)
推断规则示例:
| 目标表名 | 推断显示字段 |
|---|---|
sys_role | role_name |
sys_dict_type | dict_name |
sys_dept | dept_name |
sys_user | username |
| 其他 | {目标名}_name |
在字段配置中可以手动覆盖 relation_target(关联目标表)和 relation_display_field(关联显示字段)。
数据权限
当实体同时包含 dept_id 和 owner_id 字段时,代码生成器会自动检测并提供 数据隔离 开关:
- 开启后,生成使用
TEMPLATE_MODEL_DATA_SCOPE和TEMPLATE_SERVICE_DATA_SCOPE模板 - Model 层的
list/add/edit/del操作会自动注入部门权限过滤 - Service 层会传入
UserInfo进行权限校验
上传组件
当字段名包含图片相关关键字(image / img / avatar / cover / pic / photo / thumbnail)时:
- Write.vue 中自动生成 Upload 组件配置
- 自动导入
ElMessage和useUserStore - 自动生成上传相关的
watch和submit处理代码 - View.vue 列表页中,图片字段自动使用
ElImage组件展示缩略图
多语言翻译
代码生成器为每个实体自动生成中英文翻译片段,包含所有字段的标签:
- 中文:自动推断中文标签(如
dict_name→字典名称,created_at→创建时间) - 英文:自动推断英文标签(如
dict_name→Dict Name,created_at→Created At)
生成的翻译片段需要手动合并到 src/locales/ 目录下的语言文件中。
常见字段的中文标签推断:
| 字段名模式 | 中文标签 |
|---|---|
id | ID |
name / *_name | 名称 |
title / *_title | 标题 |
status / *_status | 状态 |
sort / *_sort | 排序 |
remark / *_remark | 备注 |
created_at | 创建时间 |
updated_at | 更新时间 |
dept_id | 部门 |
owner_id | 所有者 |
cover / image / avatar | 封面/图片/头像 |
代码合并指南
生成代码后,需要手动将以下内容合并到项目中:
1. 后端 mod.rs 声明
将 mod_updates 中的声明添加到对应的 mod.rs 文件:
// src/model/{module}/args/mod.rs
pub mod {entity};
// src/model/{module}/model/mod.rs
pub mod {entity};
// src/service/{module}.rs
pub mod {entity};2. API 路由注册
将路由函数片段和 nest 片段合并到 src/api/{module}.rs:
// 路由函数
fn {module}_{entity}(router: Router) -> Router {
router
.route("/list", WebPathType::Get, Some("列表{model_name}"), get({service}::list))
.route("/edit", WebPathType::Put, Some("编辑{model_name}"), put({service}::edit))
.route("/add", WebPathType::Post, Some("添加{model_name}"), post({service}::add))
.route("/del", WebPathType::Delete, Some("删除{model_name}"), delete({service}::delete))
}
// nest 注册
.nest("/{entity}", {module}_{entity}(Router::new()))3. 前端多语言
将翻译片段合并到 src/locales/zh-CN.ts 和 src/en.ts 的 menuuser 对象中。
4. Service 文件注意
如果 Service 文件已存在(可能包含手写路由函数),代码生成器会 跳过不覆盖,避免丢失手写代码。
配置持久化
字段配置支持保存到后端。点击 确认生成 时,当前配置会自动保存,下次打开同一实体的配置弹窗时会自动加载历史配置。
保存接口:SaveFieldConfig,加载接口:LoadFieldConfig,以 module_name + table_name 为键。
后端架构
代码生成器的后端核心位于 src/common/codegen/ 目录:
| 文件 | 说明 |
|---|---|
mod.rs | 模块入口 |
parser.rs | Entity 解析器,解析 SeaORM Entity 文件,提取字段信息、关联关系 |
generator.rs | 代码生成引擎,构建模板上下文,渲染所有模板 |
templates.rs | 后端内联模板(Args、Model、Service、API 路由等) |
tera_templates/ | 前端 Tera 模板目录 |
核心数据结构:
// 实体信息
pub struct EntityInfo {
pub table_name: String, // 表名,如 test_api
pub module_name: String, // 模块名,如 test
pub model_name: String, // PascalCase 名,如 TestApi
pub primary_key: String, // 主键字段名
pub fields: Vec<FieldInfo>, // 所有字段
pub searchable_fields: Vec<FieldInfo>, // 可搜索字段
pub list_fields: Vec<FieldInfo>, // 列表展示字段
pub form_fields: Vec<FieldInfo>, // 表单字段
pub detail_fields: Vec<FieldInfo>, // 详情页字段
pub relations: Vec<RelationInfo>, // 关联关系
pub belongs_to_fields: Vec<FieldInfo>, // BelongsTo 字段
pub has_data_scope: bool, // 是否支持数据权限
}
// 字段信息
pub struct FieldInfo {
pub name: String, // snake_case 字段名
pub rust_type: String, // Rust 类型
pub is_primary_key: bool, // 是否主键
pub is_optional: bool, // 是否 Optional
pub frontend_component: String, // 推断的前端组件
pub show_in_list: bool, // 列表中显示
pub show_in_search: bool, // 搜索中显示
pub show_in_form: bool, // 表单中显示
pub sortable: bool, // 是否可排序
pub relation: Option<RelationInfo>, // 关联关系
}
// 字段配置(用户自定义)
pub struct FieldConfig {
pub field_name: String,
pub show_in_list: bool,
pub show_in_search: bool,
pub show_in_form: bool,
pub show_in_detail: bool,
pub component: Option<String>, // 覆盖组件类型
pub sortable: Option<bool>,
pub sort_priority: Option<i32>,
pub sort_order: Option<String>,
pub label: Option<String>, // 覆盖翻译标签
pub required: Option<bool>,
pub min_length: Option<i32>,
pub max_length: Option<i32>,
pub pattern: Option<String>,
pub pattern_message: Option<String>,
pub relation_target: Option<String>,
pub relation_display_field: Option<String>,
}生成代码示例
以 test_photo 实体为例,包含字段 id(i64), name(String), cover(Option<String>), created_at(DateTime), updated_at(DateTime):
后端 Args
use crate::model::prelude::*;
#[derive(Debug, Clone, Serialize, Deserialize, FromQueryResult, Validate)]
pub struct TestPhotoResp {
#[serde(with = "i64_to_string")]
pub id: i64,
pub name: String,
pub cover: Option<String>,
pub created_at: DateTime,
pub updated_at: DateTime,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct TestPhotoSearch {
pub name: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct TestPhotoAdd {
#[validate(length(min = 1, max = 255))]
pub name: String,
pub cover: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct TestPhotoEdit {
#[serde(with = "i64_to_string")]
pub id: i64,
#[validate(length(min = 1, max = 255))]
pub name: String,
pub cover: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Validate)]
pub struct TestPhotoDel {
#[serde(with = "i64_to_string")]
pub id: i64,
}前端 API
import request from '@/axios'
export enum TestPhotoApi {
list = '/test/test_photo/list',
add = '/test/test_photo/add',
edit = '/test/test_photo/edit',
del = '/test/test_photo/del'
}
export const GetTestPhotoList = (params: any) => {
return request.get({ url: TestPhotoApi.list, params })
}
export const AddTestPhoto = (data: any) => {
return request.post({ url: TestPhotoApi.add, data })
}
export const EditTestPhoto = (data: any) => {
return request.put({ url: TestPhotoApi.edit, data })
}
export const DelTestPhoto = (params: any) => {
return request.delete({ url: TestPhotoApi.del, params })
}常见问题
Q:扫描结果为空?
确保已使用 sea-orm-cli generate entity 生成 Entity 文件,且文件位于 src/model/{module}/entity/ 目录下。
Q:生成的 Service 文件被跳过?
如果 Service 文件已存在,代码生成器不会覆盖,避免丢失手写路由代码。如需重新生成,请先备份后删除旧文件。
Q:如何自定义组件类型?
在字段配置弹窗中,切换到 表单配置 或 搜索配置 Tab,在「组件」列的下拉框中选择所需的组件类型。
Q:如何添加表单验证?
在 表单配置 Tab 中,可以设置必填、最小/最大长度、正则表达式等验证规则。生成的 Write.vue 会自动包含对应的 Element Plus 表单验证规则。
Q:关联关系下拉选项为空?
确认关联目标表的 API 路由已正确注册,并且关联显示字段(relation_display_field)配置正确。
Q:如何启用数据权限?
当实体同时包含 dept_id 和 owner_id 字段时,配置弹窗顶部会出现「数据隔离」开关。开启后,生成的 Model 和 Service 代码会自动包含数据权限过滤逻辑。