Files
2026-10-10 12:24:24 +08:00

241 lines
8.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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' => [ // 选项列表(有值时可生成 Tag 渲染)
['value' => 0, 'label' => '正常', 'type' => 'success'],
['value' => 1, 'label' => '禁用', 'type' => 'danger'],
],
];
```
## 模板语法
模板使用 PHP 原生语法,通过 `<?php echo ?>` 输出变量,使用 `<?php foreach ?>` 等控制结构:
### 后端模板示例(logic.php.tpl 片段)
```php
<?php echo '<?php' ?>
declare(strict_types=1);
namespace app\logic;
use app\BaseLogic;
use app\model\<?php echo $model_class_name ?>;
class <?php echo $model_class_name ?>Logic extends BaseLogic
{
protected string $modelClass = <?php echo $model_class_name ?>::class;
protected string $validateClass = \app\validate\<?php echo $model_class_name ?>Validate::class;
<?php if (!empty($file_fields)): ?>
protected array $fileFields = [<?php echo implode(', ', array_map(fn($f) => "'$f'", $file_fields)) ?>];
protected string $fileSaveDir = '<?php echo $module_name ?>';
<?php endif; ?>
<?php if (!empty($serialize_maps)): ?>
protected array $serializeMaps = [
<?php foreach ($serialize_maps as $field => $dict): ?>
'<?php echo $field ?>' => '<?php echo $dict ?>',
<?php endforeach; ?>
];
<?php endif; ?>
<?php if ($is_tree): ?>
protected string $treeParentField = '<?php echo $parent_id_field ?>';
protected string $treeLikeField = '<?php echo $display_field ?>';
<?php endif; ?>
}
```
### 前端模板示例(columns.ts.tpl 片段)
```typescript
import { h } from 'vue';
import { Tag, Avatar } from 'ant-design-vue';
export const columns = [
{
title: 'ID',
dataIndex: '<?php echo $primary_key ?>',
fixed: 'left',
width: 50,
},
<?php foreach ($list_fields as $field): ?>
{
title: '<?php echo $field['label'] ?>',
dataIndex: '<?php echo $field['camel_name'] ?>',
key: '<?php echo $field['camel_name'] ?>',
<?php if ($field['is_image']): ?>
customRender({ record }) {
return h(Avatar, {
size: 48,
src: record.<?php echo $field['camel_name'] ?>,
shape: 'square',
});
},
<?php elseif ($field['choices']): ?>
customRender({ record }) {
const statusMap = {
<?php foreach ($field['choices'] as $choice): ?>
<?php echo $choice['value'] ?>: { text: '<?php echo $choice['label'] ?>', color: '<?php echo ($choice['type'] === 'danger') ? 'error' : (($choice['type'] === 'info') ? 'default' : $choice['type']) ?>' },
<?php endforeach; ?>
};
const status = statusMap[record.<?php echo $field['camel_name'] ?>];
return h(Tag, { color: status?.color || 'default' }, { default: () => status?.text });
},
<?php endif; ?>
},
<?php endforeach; ?>
];
```
## 自定义模板步骤
1. 修改 `templates/` 目录下的 `.tpl` 文件
2. 使用上述模板变量(`$model_class_name`、`$module_comment` 等)
3. 下次生成时自动使用新模板
:::warning 注意事项
- 修改模板后,已生成的代码不会自动更新
- 模板中不能使用短标签 `<?= ?>`,必须用 `<?php echo ?>`(渲染前有预检)
- 模板文件不能含 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 导入,含 Tag/Avatar 渲染 |
| `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)