Commit 0a8257a565bb17ad53c32bddb3aca3740fdebddc

Authored by YunaiV
1 parent 055eb350

代码生成:主子表 normal 模式,1 对多的 form 生成

yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.infra.service.codegen.inner; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.infra.service.codegen.inner;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.map.MapUtil; 4 import cn.hutool.core.map.MapUtil;
  5 +import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
6 import cn.hutool.extra.template.TemplateConfig; 7 import cn.hutool.extra.template.TemplateConfig;
7 import cn.hutool.extra.template.TemplateEngine; 8 import cn.hutool.extra.template.TemplateEngine;
@@ -27,6 +28,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; @@ -27,6 +28,7 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
27 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; 28 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
28 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; 29 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
29 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum; 30 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
  31 +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
30 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties; 32 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
31 import com.google.common.annotations.VisibleForTesting; 33 import com.google.common.annotations.VisibleForTesting;
32 import com.google.common.collect.ImmutableTable; 34 import com.google.common.collect.ImmutableTable;
@@ -111,6 +113,16 @@ public class CodegenEngine { @@ -111,6 +113,16 @@ public class CodegenEngine {
111 vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue")) 113 vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue"))
112 .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/form.vue"), 114 .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/form.vue"),
113 vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Form.vue")) 115 vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Form.vue"))
  116 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_normal.vue"), // 特殊:主子表专属逻辑
  117 + vue3FilePath("views/${table.moduleName}/${classNameVar}/components/${subSimpleClassName}Form.vue"))
  118 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_inner.vue"), // 特殊:主子表专属逻辑
  119 + vue3FilePath("views/${table.moduleName}/${classNameVar}/components/${subSimpleClassName}Form.vue"))
  120 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/form_sub_erp.vue"), // 特殊:主子表专属逻辑
  121 + vue3FilePath("views/${table.moduleName}/${classNameVar}/components/${subSimpleClassName}Form.vue"))
  122 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_inner.vue"), // 特殊:主子表专属逻辑
  123 + vue3FilePath("views/${table.moduleName}/${classNameVar}/components/${subSimpleClassName}List.vue"))
  124 + .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("views/components/list_sub_erp.vue"), // 特殊:主子表专属逻辑
  125 + vue3FilePath("views/${table.moduleName}/${classNameVar}/components/${subSimpleClassName}List.vue"))
114 .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("api/api.ts"), 126 .put(CodegenFrontTypeEnum.VUE3.getType(), vue3TemplatePath("api/api.ts"),
115 vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts")) 127 vue3FilePath("api/${table.moduleName}/${classNameVar}/index.ts"))
116 // Vue3 Schema 模版 128 // Vue3 Schema 模版
@@ -202,17 +214,9 @@ public class CodegenEngine { @@ -202,17 +214,9 @@ public class CodegenEngine {
202 templates.forEach((vmPath, filePath) -> { 214 templates.forEach((vmPath, filePath) -> {
203 // 2.1 特殊:主子表专属逻辑 215 // 2.1 特殊:主子表专属逻辑
204 if (isSubTemplate(vmPath)) { 216 if (isSubTemplate(vmPath)) {
205 - if (CollUtil.isEmpty(subTables)) {  
206 - return;  
207 - }  
208 - for (int i = 0; i < subTables.size(); i++) {  
209 - bindingMap.put("subIndex", i);  
210 - generateCode(result, vmPath, filePath, bindingMap);  
211 - }  
212 - bindingMap.remove("subIndex"); 217 + generateSubCode(table, subTables, result, vmPath, filePath, bindingMap);
213 return; 218 return;
214 } 219 }
215 -  
216 // 2.2 默认生成 220 // 2.2 默认生成
217 generateCode(result, vmPath, filePath, bindingMap); 221 generateCode(result, vmPath, filePath, bindingMap);
218 }); 222 });
@@ -228,6 +232,35 @@ public class CodegenEngine { @@ -228,6 +232,35 @@ public class CodegenEngine {
228 result.put(filePath, content); 232 result.put(filePath, content);
229 } 233 }
230 234
  235 + private void generateSubCode(CodegenTableDO table, List<CodegenTableDO> subTables,
  236 + Map<String, String> result, String vmPath,
  237 + String filePath, Map<String, Object> bindingMap) {
  238 + // 没有子表,所以不生成
  239 + if (CollUtil.isEmpty(subTables)) {
  240 + return;
  241 + }
  242 + // 主子表的模式匹配。目的:过滤掉个性化的模版
  243 + if (vmPath.contains("_normal")
  244 + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_NORMAL.getType())) {
  245 + return;
  246 + }
  247 + if (vmPath.contains("_erp")
  248 + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_ERP.getType())) {
  249 + return;
  250 + }
  251 + if (vmPath.contains("_inner")
  252 + && ObjectUtil.notEqual(table.getTemplateType(), CodegenTemplateTypeEnum.MASTER_INNER.getType())) {
  253 + return;
  254 + }
  255 +
  256 + // 逐个生成
  257 + for (int i = 0; i < subTables.size(); i++) {
  258 + bindingMap.put("subIndex", i);
  259 + generateCode(result, vmPath, filePath, bindingMap);
  260 + }
  261 + bindingMap.remove("subIndex");
  262 + }
  263 +
231 /** 264 /**
232 * 格式化生成后的代码 265 * 格式化生成后的代码
233 * 266 *
@@ -323,6 +356,7 @@ public class CodegenEngine { @@ -323,6 +356,7 @@ public class CodegenEngine {
323 return templates; 356 return templates;
324 } 357 }
325 358
  359 + @SuppressWarnings("unchecked")
326 private String formatFilePath(String filePath, Map<String, Object> bindingMap) { 360 private String formatFilePath(String filePath, Map<String, Object> bindingMap) {
327 filePath = StrUtil.replace(filePath, "${basePackage}", 361 filePath = StrUtil.replace(filePath, "${basePackage}",
328 getStr(bindingMap, "basePackage").replaceAll("\\.", "/")); 362 getStr(bindingMap, "basePackage").replaceAll("\\.", "/"));
@@ -346,6 +380,8 @@ public class CodegenEngine { @@ -346,6 +380,8 @@ public class CodegenEngine {
346 filePath = StrUtil.replace(filePath, "${subTable.moduleName}", subTable.getModuleName()); 380 filePath = StrUtil.replace(filePath, "${subTable.moduleName}", subTable.getModuleName());
347 filePath = StrUtil.replace(filePath, "${subTable.businessName}", subTable.getBusinessName()); 381 filePath = StrUtil.replace(filePath, "${subTable.businessName}", subTable.getBusinessName());
348 filePath = StrUtil.replace(filePath, "${subTable.className}", subTable.getClassName()); 382 filePath = StrUtil.replace(filePath, "${subTable.className}", subTable.getClassName());
  383 + filePath = StrUtil.replace(filePath, "${subSimpleClassName}",
  384 + ((List<String>) bindingMap.get("subSimpleClassNames")).get(subIndex));
349 } 385 }
350 return filePath; 386 return filePath;
351 } 387 }
@@ -417,4 +453,5 @@ public class CodegenEngine { @@ -417,4 +453,5 @@ public class CodegenEngine {
417 private static boolean isSubTemplate(String path) { 453 private static boolean isSubTemplate(String path) {
418 return path.contains("_sub"); 454 return path.contains("_sub");
419 } 455 }
  456 +
420 } 457 }
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm
@@ -43,4 +43,57 @@ export const delete${simpleClassName} = async (id: number) =&gt; { @@ -43,4 +43,57 @@ export const delete${simpleClassName} = async (id: number) =&gt; {
43 // 导出${table.classComment} Excel 43 // 导出${table.classComment} Excel
44 export const export${simpleClassName} = async (params) => { 44 export const export${simpleClassName} = async (params) => {
45 return await request.download({ url: `${baseURL}/export-excel`, params }) 45 return await request.download({ url: `${baseURL}/export-excel`, params })
46 -}  
47 \ No newline at end of file 46 \ No newline at end of file
  47 +}
  48 +## 特殊:主子表专属逻辑
  49 +#foreach ($subTable in $subTables)
  50 +#set ($index = $foreach.count - 1)
  51 +#set ($subSimpleClassName = $subSimpleClassNames.get($index))
  52 +#set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
  53 +#set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  54 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  55 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  56 +#set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  57 +#set ($subClassNameVar = $subClassNameVars.get($index))
  58 +
  59 +// ==================== 子表($subTable.classComment) ====================
  60 +## 情况一:MASTER_ERP 时,需要分查询页子表
  61 +#if ( $table.templateType == 11 )
  62 +
  63 +// 获得${subTable.classComment}分页
  64 +export const get${subSimpleClassName}Page = async (params) => {
  65 + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/page`, params })
  66 +}
  67 +## 情况二:非 MASTER_ERP 时,需要列表查询子表
  68 +#else
  69 + #if ( $subTable.subJoinMany )
  70 +
  71 +// 获得${subTable.classComment}列表
  72 +export const get${subSimpleClassName}ListBy${SubJoinColumnName} = async (${subJoinColumn.javaField}) => {
  73 + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} })
  74 +}
  75 + #else
  76 +
  77 +// 获得${subTable.classComment}
  78 +export const get${subSimpleClassName}By${SubJoinColumnName} = async (${subJoinColumn.javaField}) => {
  79 + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}`, ${subJoinColumn.javaField} })
  80 +}
  81 + #end
  82 +#end
  83 +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作
  84 +#if ( $table.templateType == 11 )
  85 +// 新增${subTable.classComment}
  86 +export const create${subSimpleClassName} = async (data) => {
  87 + return await request.post({ url: `${baseURL}/${subSimpleClassName_strikeCase}/create`, data })
  88 +}
  89 +
  90 +// 修改${subTable.classComment}
  91 +export const update${subSimpleClassName} = async (data) => {
  92 + return await request.put({ url: `${baseURL}/${subSimpleClassName_strikeCase}/update`, data })
  93 +}
  94 +
  95 +// 删除${subTable.classComment}
  96 +export const delete${subSimpleClassName} = async (id: number) => {
  97 + return await request.delete({ url: `${baseURL}/${subSimpleClassName_strikeCase}/delete?id=` + id })
  98 +}
  99 +#end
  100 +#end
48 \ No newline at end of file 101 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub.vue.vm renamed to yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_inner.vue.vm 0 → 100644
  1 +## 主表的 normal 和 inner 使用相同的 form 表单
  2 +#parse("codegen/vue3/views/components/form_sub_inner.vue.vm")
0 \ No newline at end of file 3 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  6 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  7 +<template>
  8 + <el-form
  9 + ref="formRef"
  10 + :model="formData"
  11 + :rules="formRules"
  12 + v-loading="formLoading"
  13 + label-width="0px"
  14 + :inline-message="true"
  15 + >
  16 + <el-table :data="formData" class="-mt-10px">
  17 + <el-table-column label="序号" type="index" width="100" />
  18 +#foreach($column in $subColumns)
  19 + #if ($column.createOperation || $column.updateOperation)
  20 + #set ($dictType = $column.dictType)
  21 + #set ($javaField = $column.javaField)
  22 + #set ($javaType = $column.javaType)
  23 + #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  24 + #set ($comment = $column.columnComment)
  25 + #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
  26 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  27 + #set ($dictMethod = "getIntDictOptions")
  28 + #elseif ($javaType == "String")
  29 + #set ($dictMethod = "getStrDictOptions")
  30 + #elseif ($javaType == "Boolean")
  31 + #set ($dictMethod = "getBoolDictOptions")
  32 + #end
  33 + #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 TODO 芋艿:这里要忽略下 join 字段;
  34 + <el-table-column label="${comment}" width="150">
  35 + <template #default="{ row, $index }">
  36 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  37 + <el-input v-model="row.${javaField}" placeholder="请输入${comment}" />
  38 + </el-form-item>
  39 + </template>
  40 + </el-table-column>
  41 + #elseif($column.htmlType == "imageUpload")## 图片上传
  42 + <el-table-column label="${comment}" width="200">
  43 + <template #default="{ row, $index }">
  44 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  45 + <UploadImg v-model="row.${javaField}" />
  46 + </el-form-item>
  47 + </template>
  48 + </el-table-column>
  49 + #elseif($column.htmlType == "fileUpload")## 文件上传
  50 + <el-table-column label="${comment}" width="200">
  51 + <template #default="{ row, $index }">
  52 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  53 + <UploadFile v-model="row.${javaField}" />
  54 + </el-form-item>
  55 + </template>
  56 + </el-table-column>
  57 + #elseif($column.htmlType == "editor")## 文本编辑器
  58 + <el-table-column label="${comment}" width="400">
  59 + <template #default="{ row, $index }">
  60 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  61 + <Editor v-model="row.${javaField}" height="150px" />
  62 + </el-form-item>
  63 + </template>
  64 + </el-table-column>
  65 + #elseif($column.htmlType == "select")## 下拉框
  66 + <el-table-column label="${comment}" width="150">
  67 + <template #default="{ row, $index }">
  68 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  69 + <el-select v-model="row.${javaField}" placeholder="请选择${comment}">
  70 + #if ("" != $dictType)## 有数据字典
  71 + <el-option
  72 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  73 + :key="dict.value"
  74 + :label="dict.label"
  75 + :value="dict.value"
  76 + />
  77 + #else##没数据字典
  78 + <el-option label="请选择字典生成" value="" />
  79 + #end
  80 + </el-select>
  81 + </el-form-item>
  82 + </template>
  83 + </el-table-column>
  84 + #elseif($column.htmlType == "checkbox")## 多选框
  85 + <el-table-column label="${comment}" width="150">
  86 + <template #default="{ row, $index }">
  87 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  88 + <el-checkbox-group v-model="row.${javaField}">
  89 + #if ("" != $dictType)## 有数据字典
  90 + <el-checkbox
  91 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  92 + :key="dict.value"
  93 + :label="dict.value"
  94 + >
  95 + {{ dict.label }}
  96 + </el-checkbox>
  97 + #else##没数据字典
  98 + <el-checkbox>请选择字典生成</el-checkbox>
  99 + #end
  100 + </el-checkbox-group>
  101 + </el-form-item>
  102 + </template>
  103 + </el-table-column>
  104 + #elseif($column.htmlType == "radio")## 单选框
  105 + <el-table-column label="${comment}" width="150">
  106 + <template #default="{ row, $index }">
  107 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  108 + <el-radio-group v-model="row.${javaField}">
  109 + #if ("" != $dictType)## 有数据字典
  110 + <el-radio
  111 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  112 + :key="dict.value"
  113 + :label="dict.value"
  114 + >
  115 + {{ dict.label }}
  116 + </el-radio>
  117 + #else##没数据字典
  118 + <el-radio label="1">请选择字典生成</el-radio>
  119 + #end
  120 + </el-radio-group>
  121 + </el-form-item>
  122 + </template>
  123 + </el-table-column>
  124 + #elseif($column.htmlType == "datetime")## 时间框
  125 + <el-table-column label="${comment}" width="150">
  126 + <template #default="{ row, $index }">
  127 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  128 + <el-date-picker
  129 + v-model="row.${javaField}"
  130 + type="date"
  131 + value-format="x"
  132 + placeholder="选择${comment}"
  133 + />
  134 + </el-form-item>
  135 + </template>
  136 + </el-table-column>
  137 + #elseif($column.htmlType == "textarea")## 文本框
  138 + <el-table-column label="${comment}" width="200">
  139 + <template #default="{ row, $index }">
  140 + <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
  141 + <el-input v-model="row.${javaField}" type="textarea" placeholder="请输入${comment}" />
  142 + </el-form-item>
  143 + </template>
  144 + </el-table-column>
  145 + #end
  146 + #end
  147 +#end
  148 + </el-table>
  149 + </el-form>
  150 + <el-row justify="center" class="mt-3">
  151 + <el-button @click="handleAdd" round>+ 添加${subTable.classComment}</el-button>
  152 + </el-row>
  153 +</template>
  154 +<script setup lang="ts">
  155 +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
  156 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
  157 +
  158 +const props = defineProps<{
  159 + ${subJoinColumn.javaField}: undefined // ${subJoinColumn.columnComment}(主表的关联字段)
  160 +}>()
  161 +const formLoading = ref(false) // 表单的加载中
  162 +const formData = ref([])
  163 +const formRules = reactive({
  164 +#foreach ($column in $subColumns)
  165 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  166 + #set($comment=$column.columnComment)
  167 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
  168 + #end
  169 +#end
  170 +})
  171 +const formRef = ref() // 表单 Ref
  172 +
  173 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  174 +watch(
  175 + () => props.${subJoinColumn.javaField},
  176 + async (val) => {
  177 + // 情况一:val 为空,说明是新增,则置空
  178 + if (!val) {
  179 + formData.value = []
  180 + return;
  181 + }
  182 + // 情况二:val 非空,说明是修改,则加载数据
  183 + try {
  184 + formLoading.value = true
  185 + formData.value = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(val)
  186 + } finally {
  187 + formLoading.value = false
  188 + }
  189 + },
  190 + { immediate: true }
  191 +)
  192 +
  193 +/** 新增按钮操作 */
  194 +const handleAdd = () => {
  195 + const row = {
  196 +#foreach ($column in $subColumns)
  197 + #if ($column.createOperation || $column.updateOperation)
  198 + #if ($column.htmlType == "checkbox")
  199 + $column.javaField: [],
  200 + #else
  201 + $column.javaField: undefined,
  202 + #end
  203 + #end
  204 +#end
  205 + }
  206 + row.${subJoinColumn.javaField} = props.${subJoinColumn.javaField}
  207 + formData.value.push(row)
  208 +}
  209 +
  210 +/** 删除按钮操作 */
  211 +const handleDelete = (index) => {
  212 + formData.value.splice(index, 1)
  213 +}
  214 +
  215 +/** 表单校验 */
  216 +const validate = () => {
  217 + return formRef.value.validate()
  218 +}
  219 +
  220 +/** 表单值 */
  221 +const getData = () => {
  222 + return formData.value
  223 +}
  224 +
  225 +defineExpose({ validate, getData })
  226 +</script>
0 \ No newline at end of file 227 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub.vue.vm renamed to yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_erp.vue.vm
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub_inner.vue.vm 0 → 100644
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm
@@ -27,12 +27,10 @@ @@ -27,12 +27,10 @@
27 <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" /> 27 <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
28 </el-form-item> 28 </el-form-item>
29 #elseif($column.htmlType == "imageUpload")## 图片上传 29 #elseif($column.htmlType == "imageUpload")## 图片上传
30 - #set ($hasImageUploadColumn = true)  
31 <el-form-item label="${comment}"> 30 <el-form-item label="${comment}">
32 <UploadImg v-model="formData.${javaField}" /> 31 <UploadImg v-model="formData.${javaField}" />
33 </el-form-item> 32 </el-form-item>
34 #elseif($column.htmlType == "fileUpload")## 文件上传 33 #elseif($column.htmlType == "fileUpload")## 文件上传
35 - #set ($hasFileUploadColumn = true)  
36 <el-form-item label="${comment}"> 34 <el-form-item label="${comment}">
37 <UploadFile v-model="formData.${javaField}" /> 35 <UploadFile v-model="formData.${javaField}" />
38 </el-form-item> 36 </el-form-item>
@@ -124,11 +122,11 @@ const formType = ref(&#39;&#39;) // 表单的类型:create - 新增;update - 修改 @@ -124,11 +122,11 @@ const formType = ref(&#39;&#39;) // 表单的类型:create - 新增;update - 修改
124 const formData = ref({ 122 const formData = ref({
125 #foreach ($column in $columns) 123 #foreach ($column in $columns)
126 #if ($column.createOperation || $column.updateOperation) 124 #if ($column.createOperation || $column.updateOperation)
127 - #if ($column.htmlType == "checkbox") 125 + #if ($column.htmlType == "checkbox")
128 $column.javaField: [], 126 $column.javaField: [],
129 - #else 127 + #else
130 $column.javaField: undefined, 128 $column.javaField: undefined,
131 - #end 129 + #end
132 #end 130 #end
133 #end 131 #end
134 }) 132 })
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineTest.java
@@ -208,7 +208,63 @@ public class CodegenEngineTest extends BaseMockitoUnitTest { @@ -208,7 +208,63 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
208 .setCreateOperation(true).setUpdateOperation(true).setListOperation(true) 208 .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
209 .setListOperationCondition(CodegenColumnListConditionEnum.LIKE.getCondition()).setListOperationResult(true) 209 .setListOperationCondition(CodegenColumnListConditionEnum.LIKE.getCondition()).setListOperationResult(true)
210 .setHtmlType(CodegenColumnHtmlTypeEnum.INPUT.getType()); 210 .setHtmlType(CodegenColumnHtmlTypeEnum.INPUT.getType());
211 - List<CodegenColumnDO> contactColumns = Arrays.asList(contactIdColumn, contactStudentIdColumn, contactNameColumn); 211 + CodegenColumnDO contactsAvatarColumn = new CodegenColumnDO().setColumnName("avatar").setDataType(JdbcType.VARCHAR.name())
  212 + .setColumnComment("头像").setNullable(false).setPrimaryKey(false)
  213 + .setOrdinalPosition(4).setJavaType("String").setJavaField("avatar").setExample("https://www.iocoder.cn/1.png")
  214 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(false)
  215 + .setListOperationResult(true)
  216 + .setHtmlType(CodegenColumnHtmlTypeEnum.UPLOAD_IMAGE.getType());
  217 + CodegenColumnDO contactVideoColumn = new CodegenColumnDO().setColumnName("video").setDataType(JdbcType.VARCHAR.name())
  218 + .setColumnComment("视频").setNullable(false).setPrimaryKey(false)
  219 + .setOrdinalPosition(5).setJavaType("String").setJavaField("video").setExample("https://www.iocoder.cn/1.mp4")
  220 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(false)
  221 + .setListOperationResult(true)
  222 + .setHtmlType(CodegenColumnHtmlTypeEnum.UPLOAD_FILE.getType());
  223 + CodegenColumnDO contactDescriptionColumn = new CodegenColumnDO().setColumnName("description").setDataType(JdbcType.VARCHAR.name())
  224 + .setColumnComment("个人简介").setNullable(false).setPrimaryKey(false)
  225 + .setOrdinalPosition(6).setJavaType("String").setJavaField("description").setExample("我是介绍")
  226 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(false)
  227 + .setListOperationResult(true)
  228 + .setHtmlType(CodegenColumnHtmlTypeEnum.EDITOR.getType());
  229 + CodegenColumnDO contactSex1Column = new CodegenColumnDO().setColumnName("sex1").setDataType(JdbcType.VARCHAR.name())
  230 + .setColumnComment("性别 1").setNullable(false).setPrimaryKey(false)
  231 + .setOrdinalPosition(7).setJavaType("String").setJavaField("sex1").setExample("男")
  232 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  233 + .setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition()).setListOperationResult(true)
  234 + .setHtmlType(CodegenColumnHtmlTypeEnum.SELECT.getType()).setDictType("system_sex1");
  235 + CodegenColumnDO contactSex2Column = new CodegenColumnDO().setColumnName("sex2").setDataType(JdbcType.INTEGER.name())
  236 + .setColumnComment("性别 2").setNullable(false).setPrimaryKey(false)
  237 + .setOrdinalPosition(8).setJavaType("Integer").setJavaField("sex2").setExample("1")
  238 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  239 + .setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition()).setListOperationResult(true)
  240 + .setHtmlType(CodegenColumnHtmlTypeEnum.CHECKBOX.getType()).setDictType("system_sex2");
  241 + CodegenColumnDO contactSex3Column = new CodegenColumnDO().setColumnName("sex3").setDataType(JdbcType.BOOLEAN.name())
  242 + .setColumnComment("性别 3").setNullable(false).setPrimaryKey(false)
  243 + .setOrdinalPosition(9).setJavaType("Boolean").setJavaField("sex3").setExample("true")
  244 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  245 + .setListOperationResult(true)
  246 + .setHtmlType(CodegenColumnHtmlTypeEnum.RADIO.getType()).setDictType("system_sex3");
  247 + CodegenColumnDO contactBirthdayColumn = new CodegenColumnDO().setColumnName("birthday").setDataType(JdbcType.DATE.name())
  248 + .setColumnComment("出生日期").setNullable(false).setPrimaryKey(false)
  249 + .setOrdinalPosition(10).setJavaType("LocalDateTime").setJavaField("birthday")
  250 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  251 + .setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition()).setListOperationResult(true)
  252 + .setHtmlType(CodegenColumnHtmlTypeEnum.DATETIME.getType());
  253 + CodegenColumnDO contactMemoColumn = new CodegenColumnDO().setColumnName("memo").setDataType(JdbcType.VARCHAR.name())
  254 + .setColumnComment("备注").setNullable(false).setPrimaryKey(false)
  255 + .setOrdinalPosition(11).setJavaType("String").setJavaField("memo").setExample("我是备注")
  256 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(false)
  257 + .setListOperationResult(true)
  258 + .setHtmlType(CodegenColumnHtmlTypeEnum.TEXTAREA.getType());
  259 + CodegenColumnDO contactCreateTimeColumn = new CodegenColumnDO().setColumnName("create_time").setDataType(JdbcType.DATE.name())
  260 + .setColumnComment("创建时间").setNullable(false).setPrimaryKey(false)
  261 + .setOrdinalPosition(12).setJavaType("LocalDateTime").setJavaField("createTime")
  262 + .setCreateOperation(false).setUpdateOperation(false).setListOperation(true)
  263 + .setListOperationCondition(CodegenColumnListConditionEnum.BETWEEN.getCondition()).setListOperationResult(true)
  264 + .setHtmlType(CodegenColumnHtmlTypeEnum.DATETIME.getType());
  265 + List<CodegenColumnDO> contactColumns = Arrays.asList(contactIdColumn, contactStudentIdColumn,
  266 + contactNameColumn, contactsAvatarColumn, contactVideoColumn, contactDescriptionColumn,
  267 + contactSex1Column, contactSex2Column, contactSex3Column, contactBirthdayColumn, contactMemoColumn, contactCreateTimeColumn);
212 // 子表(地址) 268 // 子表(地址)
213 CodegenTableDO addressTable = new CodegenTableDO().setScene(CodegenSceneEnum.ADMIN.getScene()) 269 CodegenTableDO addressTable = new CodegenTableDO().setScene(CodegenSceneEnum.ADMIN.getScene())
214 .setTableName("infra_demo_student_address").setTableComment("学生地址表") 270 .setTableName("infra_demo_student_address").setTableComment("学生地址表")
@@ -222,26 +278,20 @@ public class CodegenEngineTest extends BaseMockitoUnitTest { @@ -222,26 +278,20 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
222 .setOrdinalPosition(1).setJavaType("Long").setJavaField("id").setExample("1024") 278 .setOrdinalPosition(1).setJavaType("Long").setJavaField("id").setExample("1024")
223 .setCreateOperation(false).setUpdateOperation(true).setListOperation(false) 279 .setCreateOperation(false).setUpdateOperation(true).setListOperation(false)
224 .setListOperationResult(true); 280 .setListOperationResult(true);
225 - CodegenColumnDO addressStudentColumn = new CodegenColumnDO().setColumnName("student_id").setDataType(JdbcType.BIGINT.name()) 281 + CodegenColumnDO addressStudentIdColumn = new CodegenColumnDO().setColumnName("student_id").setDataType(JdbcType.BIGINT.name())
226 .setColumnComment("学生编号").setNullable(false).setPrimaryKey(false) 282 .setColumnComment("学生编号").setNullable(false).setPrimaryKey(false)
227 .setOrdinalPosition(2).setJavaType("Long").setJavaField("studentId").setExample("2048") 283 .setOrdinalPosition(2).setJavaType("Long").setJavaField("studentId").setExample("2048")
228 .setCreateOperation(false).setUpdateOperation(true).setListOperation(false) 284 .setCreateOperation(false).setUpdateOperation(true).setListOperation(false)
229 .setListOperationResult(true) 285 .setListOperationResult(true)
230 .setId(200L); 286 .setId(200L);
231 - CodegenColumnDO addressDetailColumn = new CodegenColumnDO().setColumnName("detail").setDataType(JdbcType.VARCHAR.name())  
232 - .setColumnComment("明细").setNullable(false).setPrimaryKey(false)  
233 - .setOrdinalPosition(3).setJavaType("String").setJavaField("detail").setExample("码头路 88 号")  
234 - .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)  
235 - .setListOperationCondition(CodegenColumnListConditionEnum.LIKE.getCondition()).setListOperationResult(true)  
236 - .setHtmlType(CodegenColumnHtmlTypeEnum.INPUT.getType());  
237 - List<CodegenColumnDO> addressColumns = Arrays.asList(addressIdColumn, addressStudentColumn, addressDetailColumn); 287 + List<CodegenColumnDO> addressColumns = Arrays.asList(addressIdColumn, addressStudentIdColumn);
238 288
239 // 调用 289 // 调用
240 Map<String, String> result = codegenEngine.execute(table, columns, 290 Map<String, String> result = codegenEngine.execute(table, columns,
241 Arrays.asList(contactTable, addressTable), Arrays.asList(contactColumns, addressColumns)); 291 Arrays.asList(contactTable, addressTable), Arrays.asList(contactColumns, addressColumns));
242 292
243 // 断言 293 // 断言
244 - assertEquals(25, result.size()); 294 + assertEquals(27, result.size());
245 295
246 for (Map.Entry<String, String> entry : result.entrySet()) { 296 for (Map.Entry<String, String> entry : result.entrySet()) {
247 System.out.println(entry.getKey()); 297 System.out.println(entry.getKey());