目录结构
理解目录结构后,才能知道“工作台界面、模板文件、配置文件、目标项目”分别在哪一层。
create-page-common/ # 项目根目录
├── web-project # web 项目源码根目录
│ ├── src/apis/create-page.js # 前端请求接口
│ ├── src/mixins/create.js # 页面生成混入与 API 生成逻辑
│ └── src/views/create/ # 页面创建主界面
│ ├── components/item-setting/ # 表单组件配置面板
│ ├── dialog/dialog-form-item-setting.vue # 组件配置弹窗
│ ├── create-list.vue # 列表页创建
│ ├── create-info.vue # 详情页创建
│ └── create-form.vue # 表单页创建
├── server # 服务端目录
│ ├── create_cfg_tmpl/ # 源配置与源模板目录
│ │ ├── vue2/config/config.js # Vue2 主配置文件
│ │ ├── vue2/config/config-form-valid-msg.js # Vue2 表单验证提示配置
│ │ ├── vue2/template/base/ # 基础模板
│ │ ├── vue2/template/dialog/ # 弹窗模板
│ │ ├── vue2/template/page/ # 页面模板
│ │ ├── vue3/config/config.js # Vue3 主配置文件
│ │ └── vue3/template/ # Vue3 模板目录
│ ├── web-server.js # 静态资源服务
│ └── main.js # 服务启动入口
└── 目标 Vue 项目 # 页面生成目标项目
注释说明:`web-project` 负责提供可视化操作界面;`server/create_cfg_tmpl` 才是模板和配置的核心来源。
模板语法
模板目录: `server/create_cfg_tmpl/**/template/`。修改模板后通常无需重启服务,刷新页面即可生效。
1. 标准输出
用于输出变量、对象属性和表达式结果。
# 直接输出变量
${{value}}
# 输出对象属性
${{data.key}}
${{data["key"]}}
# 输出表达式结果
${{a ? b : c}}
${{a || b}}
# 兼容输出写法
<%= value %>
<%= data.key %>
注释说明:`${{ }}` 和 `<%= %>` 在这里都表示标准输出。
2. 原文输出
用于输出不转义的内容。
# 输出不转义内容
${{@ value }}
<%- value %>
注释说明:适合输出已经拼好的 HTML 或属性片段。
3. 条件判断
按条件输出不同模板片段。
# 单分支条件
${{if value}} ... ${{/if}}
# 多分支条件
${{if v1}} ... ${{else if v2}} ... ${{/if}}
4. 循环
遍历数组或对象,常用于批量拼接表单项、表格列等结构。
# 遍历 target
${{each target}}
${{$index}} ${{$value}}
${{/each}}
5. 变量
先声明临时变量,再在同一模板中复用。
# art-template 变量声明
{{set temp = data.sub.content}}
# 兼容写法
<% var temp = data.sub.content; %>
6. 子模板
把重复结构拆分成子模板,便于复用。
# 引入当前目录下的子模板
{{include "./header.art"}}
# 传入数据
{{include "./header.art" data}}
# 根路径会相对 /template 目录解析
# 相对路径会相对当前模板所在目录解析
预设变量
预设变量会在不同类型模板中自动注入。修改模板前,应先确认当前模板能访问到哪些对象。
1. 路由变量
用于路由模板,负责拼接一级路由、二级路由和页面路径。
# 常见使用位置:
# server/create_cfg_tmpl/<模板>/template/router/*.art
{
path: "/${{lever1Path}}", // 一级路由 path
component: Layout, // 一级路由组件(通常是布局组件)
name: "${{lever1RouterName}}", // 一级路由名称
meta: {
title: "${{lever1PageName}}", // 一级菜单标题
icon: "el-icon-orange", // 菜单图标
code: "" // 预留权限码
},
redirect: "${{lever2Path}}", // 默认重定向到二级路由
children: [
{
path: "${{lever2Path}}", // 二级路由 path
component: () => import("@/views/${{filePath}}"), // 页面组件路径
name: "${{lever2RouterName}}", // 二级路由名称
meta: { title: "${{lever2PageName}}", code: "" } // 二级菜单元信息
}
]
}
2. API 变量
API、路由与页面生成都依赖这个对象。
# 常见使用位置:
# server/create_cfg_tmpl/<模板>/template/api/*.art
{
name, // 接口原始名称
nameHump, // 驼峰名称(用于函数名)
nameToPathfilter, // 接口名过滤后的 path 片段
nameToPath, // 接口名转 path 结果
desc, // 接口描述
type, // 请求方法(delete 会转成 del)
uri, // 接口 URL
fileName, // 文件名(非驼峰)
fileNameHump, // 文件名(驼峰)
fileDesc // 文件描述
}
注释说明:其中 `type` 会把 `delete` 统一转换为 `del`,以适配默认请求方法命名。
3. 页面变量
列表页、表单页、详情页最常使用的就是页面对象。
# 常见使用位置:
# server/create_cfg_tmpl/<模板>/template/page/*.art
{
rootPath, // 目标项目根路径
formData: [
{
column, // 字段名
isShow, // 是否显示
opts: {
range, // 范围查询相关配置
valid, // 表单验证规则
attr // 组件属性配置
},
needValidateOpts, // 是否需要校验
label, // 字段标题
labelDesc, // 字段描述
columnType, // 字段类型
formItemType, // 表单组件类型
range: {
f_, // 范围起始字段名
to_, // 范围结束字段名
isDatePickerRange, // 是否是日期范围
isStart // 是否为起始字段
}
}
],
tableData: [
{
column, // 列字段名
label, // 列标题
columnType, // 列字段类型
isShow, // 是否显示在列表中
showTips, // 是否显示 tooltip
alignType // 对齐方式
}
],
tableConfig: {
showBtnCol: false, // 是否显示操作列
showNumCol: true, // 是否显示序号列
showFormRightBtns: false // 是否显示右侧表单按钮
},
apiConfig // 当前页面关联的 API 配置
}
注释说明:`formData` 和 `tableData` 是页面模板里最核心的两个数组,分别控制检索 / 表单项和列表列。
内置函数
模板函数可全局访问,不区分模板类型。它们的目标是减少模板内部重复拼接逻辑。
1. 获取自定义组件列表
只返回页面中实际使用到的自定义组件,适合按需注入。
# 生成按需导入列表
<% var _CusPluginsList_ = $imports.getCusPluginsListImport(formData) %>
${{each _CusPluginsList_}}
import ${{$value.name}} from '${{$value.path}}'
${{/each}}
# 生成组件注册
export default {
components: {
${{each _CusPluginsList_}}${{$value.name}},${{/each}}
}
}
2. 获取表单验证规则
把字段验证配置转成页面 `rules` 对象。
# 收集字段验证规则
<% var _ValidationList_ = $imports.getValidationListImport(formData) %>
<el-form ref="claFrom" :model="claForm"
${{if _ValidationList_.length}} :rules="rules" ${{/if}}
label-width="auto" />
# 仅在存在规则时输出 rules
${{if _ValidationList_.length}}
rules: {
${{include 'base/base-form-rule.art' _ValidationList_}}
}
${{/if}}
3. 获取组件属性字符串
把 `opts.attr` 转成可直接拼接到组件标签中的属性片段。
# 把 opts.attr 转成组件属性
<el-input
v-model="claForm.${{column}}"
placeholder="${{label}}"
${{@ opts.attr | getFormItemAttr}}
/>
注释说明:以 `_` 开头且 `_` 结尾的私有属性不会被输出。
4. 获取组件数据源
适用于 `select`、`radioGroup`、`checkboxGroup` 等需要选项数据源的组件。
# 收集数据源并输出为 data
<% var _pluginsDataSourceList_ = $imports.getPluginsDataSourceImport(formData) %>
${{each _pluginsDataSourceList_}}
# ${{$value.label}}
${{$value.name}}:${{@ $value.data}}${{if _pluginsDataSourceList_.length - 1 != $index}},${{/if}}
${{/each}}
5. 获取字段默认值
根据字段类型自动生成 `''`、`[]`、`0` 等初始值。
# 根据字段类型生成默认值
${{each formData}}
${{@ $value.column | getObjectKeyExpr}}: ${{@ $value.columnType | getFormItemValue }}${{if formData.length - 1 != $index}},${{/if}} # ${{@ $value.label}}
${{/each}}
6. 转义对象键名
用于把非法标识符转换成合法的对象键。
# column = "tel-phone"
${{@ column | getObjectKeyExpr}}
# 输出:'tel-phone'
7. 转义对象属性访问方式
用于在 `v-model` 等场景中安全访问非法字段名。
# 适合 v-model / 对象属性访问
<el-input
type="textarea"
v-model="claForm${{@ column | getFieldAccessExpr }}">
</el-input>
# column = "tel-phone"
# 输出:claForm['tel-phone']
新增 UI 分组
如果当前预设的 Element UI / Element Plus 配置项不满足项目需求,可以新增自己的 UI 分组。
步骤 1
在 `web-project/src/views/create/components/item-setting/` 下新建目录,例如 `ant`。
web-project/src/views/create/components/item-setting/
├── _com # 公共组件
├── element-ui # Element UI 配置组
├── element-plus # Element Plus 配置组
└── ant # 新增的 UI 配置组
步骤 2
在分组目录中新增对应组件配置文件,例如 `set-input.vue`。
# 文件命名规则
set-input.vue
set-datePicker.vue
set-select.vue
步骤 3
修改 `_UI_TEMP_PATH_`,让工作台加载新分组。
# 单独加载 ant 组
const _$cusConfig$_ = {
_UI_TEMP_PATH_: "ant"
}
# 或组合加载多个组
const _$cusConfig$_ = {
_UI_TEMP_PATH_: ["element-ui", "element-plus"]
}
注释说明:数组写法时,右侧同名组件会覆盖左侧组件,适合局部覆盖差异。
扩展组件模板
如果你要新增一个自定义表单组件,通常需要同时处理配置声明、组件模板和可视化配置组件。
1. 在 `formItemOpts` 中声明组件
# 配置路径:
# server/create_cfg_tmpl/<模板>/config/config.js -> formItemOpts
formItemOpts: [
{
value: "cusDatePicker", // 组件类型标识(需和模板文件名一致)
label: "日期选择器(双)", // 在工作台展示的名称
path: "@/components/cusDatePicker/index.vue", // 组件导入路径
valid: {
trigger: "change", // 校验触发时机
type: "date" // 校验数据类型
}
}
]
2. 在模板目录中新增组件模板
文件名必须与 `value` 一致,例如 `cusDatePicker.art`。
server/create_cfg_tmpl/vue2/template/base/form/
└── cusDatePicker.art # 文件名必须与 value 一致
3. 如需可视化配置,再新增组件配置文件
组件配置文件继承 `inject: ['itemSetIns']`,通过原型链直接修改当前行数据。
# 文件路径:
# web-project/src/views/create/components/item-setting//set-input.vue
export default {
name: "SetInput", // 配置组件名称
inject: ["itemSetIns"], // 从父级注入当前字段上下文
data() {
return {
rowData: this.itemSetIns.rowData, // 当前字段原始数据
tmpRowData: this.itemSetIns.tmpRowData, // 当前字段临时编辑数据
formData: {
_prependType_: "", // 前缀类型
_prependVal_: "", // 前缀内容
_appendType_: "", // 后缀类型
_appendVal_: "" // 后缀内容
},
rewriteAttr: [] // 需重写的属性列表
}
},
methods: {
init() {
if (this.tmpRowData.opts.attr) {
// 把已配置属性回填到表单
Object.assign(this.formData, this.tmpRowData.opts.attr || {})
}
},
toSubmitFn() {
// 返回 true 表示允许提交当前配置
return true
}
}
}
4. 如果是新的 UI 框架,还要同步改模板语法
例如把 Element UI 的 `el-input` 改成 Ant Design Vue 的 `a-input`。
# 原模板
<el-input
placeholder="${{label}}"
${{@ opts.attr | getFormItemAttr}}
></el-input>
# 适配后的模板
<a-input
v-model:value="claForm.${{column}}"
placeholder="${{label}}"
${{@ opts.attr | getFormItemAttr}}
></a-input>
生成 mock 文件
默认可关闭。如果需要生成 mock 文件,可以使用基础 mock 模板进行扩展。
# 配置路径:
# server/create_cfg_tmpl/<模板>/config/config.js -> makeFile -> isMakeMock
{
url: '${{apiConfig.uri | getMockRouterUrl}}', // mock 路由地址
type: '${{apiConfig.type}}', // 请求方法
response: config => {
// 首次请求时初始化缓存样例数据
if (!demo.__cacheKey__['${{apiConfig.name}}']) {
const tobj = {
// 根据 tableData 自动生成字段 mock 规则
${{@ tableData | getMockRouterResData}}
}
demo.demoFnGetTheListKey(tobj)
demo.__cacheKey__['${{apiConfig.name}}'] = { ...tobj }
}
// 按分页参数返回列表数据
return demo.demoFnMakeListPageData('${{apiConfig.name}}', config.query)
}
}
注释说明:如果是 Vite 场景,也可以按项目里的 mock 方案进一步适配,重点在于复用字段推断和分页处理逻辑。
其它入口
1. 访问配置对象
模板中可以直接读取全局配置对象。
# 访问全局配置对象
$imports.comConfig
# 示例
输出作者:${{$imports.comConfig.author}}
2. 修改模板生效范围
只有 `server/create_cfg_tmpl` 下的源模板和源配置是长期有效的。
# 有效目录
server/create_cfg_tmpl/vue2/
server/create_cfg_tmpl/vue3/
# 临时目录
web-project/public/tmpl_cfg/
server/www/tmpl_cfg/
建议改动顺序: 先改配置,再改模板,最后才扩展工作台里的组件配置界面。这样更容易定位问题,也更不容易把影响面放大。