# 10.6 自定义模板开发 :::tip 概述 代码生成器使用 PHP 原生模板引擎渲染代码,模板文件存放在 `templates/` 目录下。修改模板即可自定义生成代码的格式。 ::: ## 模板目录结构 ```text templates/ ├── controller.php.tpl # 控制器模板 ├── logic.php.tpl # 业务逻辑模板(含 serializeMaps、导入导出) ├── model.php.tpl # 模型模板 ├── validate.php.tpl # 验证器模板 ├── ui/ # 普通列表模板(6个前端文件) │ ├── api.ts.tpl # API 接口模块模板 │ ├── index.vue.tpl # 列表页模板 │ ├── edit.vue.tpl # 编辑弹窗模板 │ ├── detail.vue.tpl # 详情弹窗模板 │ ├── columns.ts.tpl # 表格列配置模板 │ └── querySchemas.ts.tpl # 查询表单配置模板 └── ui2/ # 树形结构模板(4个前端文件) ├── api.ts.tpl ├── index.vue.tpl ├── edit.vue.tpl └── detail.vue.tpl ``` ## 模板变量 模板使用 PHP 原生语法,变量通过 `GeneratorService::buildTemplateVars()` 构建,渲染时通过 `extract($vars)` 注入。 ### 基础信息变量 | 变量 | 类型 | 说明 | 示例 | |------|------|------|------| | `$app_name` | string | 应用名(路由前缀) | `tool` | | `$module_name` | string | 模块名(小写下划线) | `example` | | `$module_comment` | string | 功能名称(表注释清洗后) | `案例` | | `$model_class_name` | string | 模型类名(大驼峰) | `Example` | | `$model_class_name_camel` | string | 模型类名(小驼峰) | `example` | | `$route_prefix` | string | 路由前缀 | `example` | | `$api_path` | string | API 路径 | `tool/example` | | `$permission_prefix` | string | 权限码前缀 | `sys:example` | | `$primary_key` | string | 主键字段名 | `id` | | `$table_name` | string | 表名(不含前缀) | `example` | ### 树形结构变量 | 变量 | 类型 | 说明 | 示例 | |------|------|------|------| | `$is_tree` | bool | 是否为树形结构 | `true` | | `$parent_id_field` | string | 父级字段名 | `parent_id` | | `$parent_id_field_camel` | string | 父级字段名(驼峰) | `parentId` | | `$display_field` | string | 显示字段名 | `name` | | `$display_field_camel` | string | 显示字段名(驼峰) | `name` | ### 字段列表变量 | 变量 | 类型 | 说明 | |------|------|------| | `$fields` | array | 全部字段列表 | | `$list_fields` | array | 列表页展示字段(排除隐藏字段) | | `$form_fields` | array | 表单字段(编辑弹窗用) | | `$filter_fields` | array | 筛选字段(搜索表单用) | | `$file_fields` | array | 文件/图片字段名列表 | | `$content_fields` | array | 富文本字段名列表 | | `$like_fields` | array | 模糊搜索字段名列表 | | `$eq_fields` | array | 精确匹配字段名列表 | | `$unique_fields` | array | 唯一性校验字段名列表 | | `$validate_rules` | array | 验证规则 | | `$validate_messages` | array | 验证提示信息 | | `$validate_fields` | array | 需验证的字段列表 | | `$serialize_maps` | array | 枚举字段 → 字典编码映射 | | `$foreign_keys` | array | 外键关联信息 | ### 功能标记变量 | 变量 | 类型 | 说明 | |------|------|------| | `$has_import` | bool | 是否生成导入方法 | | `$has_export` | bool | 是否生成导出方法 | | `$has_image_field` | bool | 是否包含图片字段 | | `$has_rich_text_field` | bool | 是否包含富文本字段 | | `$has_sort` | bool | 是否包含排序字段 | | `$is_tree_structure` | bool | 是否为树形结构(`$is_tree` 别名) | | `$template_type` | string | 模板类型:`ui` 或 `ui2` | ### 排序变量 | 变量 | 类型 | 说明 | 示例 | |------|------|------|------| | `$order_field` | string | 默认排序字段 | `id` 或 `sort` | | `$order_type` | string | 默认排序方向 | `desc` 或 `asc` | ### 字段结构 每个字段为一个数组,包含以下属性: ```php $field = [ 'name' => 'status', // 字段名(下划线) 'camel_name' => 'status', // 字段名(驼峰) 'label' => '状态', // 中文标签(取字段 COMMENT) 'type' => 'IntegerField', // 字段类型归一化后的类名 'db_type' => 'int', // 原始数据库类型 'default' => 0, // 默认值 'is_image' => false, // 是否为图片字段 'is_rich_text' => false, // 是否为富文本字段 'choices' => [ // 选项列表(有值时可生成 ElTag 渲染) ['value' => 0, 'label' => '正常', 'type' => 'success'], ['value' => 1, 'label' => '禁用', 'type' => 'danger'], ], ]; ``` ## 模板语法 模板使用 PHP 原生语法,通过 `` 输出变量,使用 `` 等控制结构: ### 后端模板示例(logic.php.tpl 片段) ```php declare(strict_types=1); namespace app\logic; use app\BaseLogic; use app\model\; class Logic extends BaseLogic { protected string $modelClass = ::class; protected string $validateClass = \app\validate\Validate::class; protected array $fileFields = [ "'$f'", $file_fields)) ?>]; protected string $fileSaveDir = ''; protected array $serializeMaps = [ $dict): ?> '' => '', ]; protected string $treeParentField = ''; protected string $treeLikeField = ''; } ``` ### 前端模板示例(columns.ts.tpl 片段) ```typescript import { h } from 'vue'; import { ElAvatar, ElTag } from 'element-plus'; export const columns = [ { type: 'selection' }, { label: 'ID', prop: 'id', fixed: 'left', width: 50 }, { label: '', prop: '', render(record) { return h(ElAvatar, { size: 48, src: record.row. }); }, render(record) { const map = { : { text: '', type: '' }, }; const s = map[record.row.]; return h(ElTag, { type: s?.type || 'info' }, { default: () => s?.text }); }, }, ]; ``` ## 自定义模板步骤 1. 修改 `templates/` 目录下的 `.tpl` 文件 2. 使用上述模板变量(`$model_class_name`、`$module_comment` 等) 3. 下次生成时自动使用新模板 :::warning 注意事项 - 修改模板后,已生成的代码不会自动更新 - 模板中不能使用短标签 ``,必须用 ``(渲染前有预检) - 模板文件不能含 UTF-8 BOM 头 - 树形结构模块使用 `ui2/` 模板,普通模块使用 `ui/` 模板 ::: ## 模板选择逻辑 ```text 表结构中包含 parent_id 或 pid 字段? │ ├─ 是 → 使用 ui2/ 树形模板(自动,无需手动选择) │ └─ 否 → 使用 ui/ 普通列表模板 ``` ## 生成的前端文件 `ui/` 模板生成 6 个文件(`ui2/` 生成 4 个,无 columns.ts 和 querySchemas.ts): | 文件 | 说明 | 引用关系 | |------|------|----------| | `api.ts` | API 接口模块 | 被 index.vue、edit.vue 导入 | | `index.vue` | 列表页 | 导入 columns.ts、querySchemas.ts | | `edit.vue` | 编辑弹窗 | 被 index.vue 动态加载 | | `detail.vue` | 详情弹窗 | 被 index.vue 动态加载 | | `columns.ts` | 表格列配置 | 被 index.vue 导入,含 ElTag/ElAvatar 渲染 | | `querySchemas.ts` | 查询表单配置 | 被 index.vue 导入,含 Select/Input/DatePicker 组件 | ## 相关文档 - [10.5 代码生成引擎](/zh/generator/code-engine.html) - [10.7 配置文件详解](/zh/generator/config.html) - [10.8 实战案例](/zh/generator/demo.html)