Commit 07e71e2ab0ca9703454ef8d959e432c8b9bd6de1

Authored by YunaiV
1 parent 0a8257a5

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

yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/api/api.ts.vm
@@ -75,7 +75,7 @@ export const get${subSimpleClassName}ListBy${SubJoinColumnName} = async (${subJo @@ -75,7 +75,7 @@ export const get${subSimpleClassName}ListBy${SubJoinColumnName} = async (${subJo
75 75
76 // 获得${subTable.classComment} 76 // 获得${subTable.classComment}
77 export const get${subSimpleClassName}By${SubJoinColumnName} = async (${subJoinColumn.javaField}) => { 77 export const get${subSimpleClassName}By${SubJoinColumnName} = async (${subJoinColumn.javaField}) => {
78 - return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}`, ${subJoinColumn.javaField} }) 78 + return await request.get({ url: `${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=` + ${subJoinColumn.javaField} })
79 } 79 }
80 #end 80 #end
81 #end 81 #end
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm
@@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
5 #set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 5 #set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
6 #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 6 #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
7 <template> 7 <template>
  8 +#if ( $subTable.subJoinMany )## 情况一:一对多,table + form
8 <el-form 9 <el-form
9 ref="formRef" 10 ref="formRef"
10 :model="formData" 11 :model="formData"
@@ -150,6 +151,109 @@ @@ -150,6 +151,109 @@
150 <el-row justify="center" class="mt-3"> 151 <el-row justify="center" class="mt-3">
151 <el-button @click="handleAdd" round>+ 添加${subTable.classComment}</el-button> 152 <el-button @click="handleAdd" round>+ 添加${subTable.classComment}</el-button>
152 </el-row> 153 </el-row>
  154 +#else## 情况二:一对一,form
  155 + <el-form
  156 + ref="formRef"
  157 + :model="formData"
  158 + :rules="formRules"
  159 + label-width="100px"
  160 + v-loading="formLoading"
  161 + >
  162 +#foreach($column in $subColumns)
  163 + #if ($column.createOperation || $column.updateOperation)
  164 + #set ($dictType = $column.dictType)
  165 + #set ($javaField = $column.javaField)
  166 + #set ($javaType = $column.javaType)
  167 + #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  168 + #set ($comment = $column.columnComment)
  169 + #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
  170 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  171 + #set ($dictMethod = "getIntDictOptions")
  172 + #elseif ($javaType == "String")
  173 + #set ($dictMethod = "getStrDictOptions")
  174 + #elseif ($javaType == "Boolean")
  175 + #set ($dictMethod = "getBoolDictOptions")
  176 + #end
  177 + #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 TODO 芋艿:这里要忽略下 join 字段;
  178 + <el-form-item label="${comment}" prop="${javaField}">
  179 + <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
  180 + </el-form-item>
  181 + #elseif($column.htmlType == "imageUpload")## 图片上传
  182 + <el-form-item label="${comment}">
  183 + <UploadImg v-model="formData.${javaField}" />
  184 + </el-form-item>
  185 + #elseif($column.htmlType == "fileUpload")## 文件上传
  186 + <el-form-item label="${comment}">
  187 + <UploadFile v-model="formData.${javaField}" />
  188 + </el-form-item>
  189 + #elseif($column.htmlType == "editor")## 文本编辑器
  190 + <el-form-item label="${comment}">
  191 + <Editor v-model="formData.${javaField}" height="150px" />
  192 + </el-form-item>
  193 + #elseif($column.htmlType == "select")## 下拉框
  194 + <el-form-item label="${comment}" prop="${javaField}">
  195 + <el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
  196 + #if ("" != $dictType)## 有数据字典
  197 + <el-option
  198 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  199 + :key="dict.value"
  200 + :label="dict.label"
  201 + :value="dict.value"
  202 + />
  203 + #else##没数据字典
  204 + <el-option label="请选择字典生成" value="" />
  205 + #end
  206 + </el-select>
  207 + </el-form-item>
  208 + #elseif($column.htmlType == "checkbox")## 多选框
  209 + <el-form-item label="${comment}" prop="${javaField}">
  210 + <el-checkbox-group v-model="formData.${javaField}">
  211 + #if ("" != $dictType)## 有数据字典
  212 + <el-checkbox
  213 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  214 + :key="dict.value"
  215 + :label="dict.value"
  216 + >
  217 + {{ dict.label }}
  218 + </el-checkbox>
  219 + #else##没数据字典
  220 + <el-checkbox>请选择字典生成</el-checkbox>
  221 + #end
  222 + </el-checkbox-group>
  223 + </el-form-item>
  224 + #elseif($column.htmlType == "radio")## 单选框
  225 + <el-form-item label="${comment}" prop="${javaField}">
  226 + <el-radio-group v-model="formData.${javaField}">
  227 + #if ("" != $dictType)## 有数据字典
  228 + <el-radio
  229 + v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
  230 + :key="dict.value"
  231 + :label="dict.value"
  232 + >
  233 + {{ dict.label }}
  234 + </el-radio>
  235 + #else##没数据字典
  236 + <el-radio label="1">请选择字典生成</el-radio>
  237 + #end
  238 + </el-radio-group>
  239 + </el-form-item>
  240 + #elseif($column.htmlType == "datetime")## 时间框
  241 + <el-form-item label="${comment}" prop="${javaField}">
  242 + <el-date-picker
  243 + v-model="formData.${javaField}"
  244 + type="date"
  245 + value-format="x"
  246 + placeholder="选择${comment}"
  247 + />
  248 + </el-form-item>
  249 + #elseif($column.htmlType == "textarea")## 文本框
  250 + <el-form-item label="${comment}" prop="${javaField}">
  251 + <el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
  252 + </el-form-item>
  253 + #end
  254 + #end
  255 +#end
  256 +#end
153 </template> 257 </template>
154 <script setup lang="ts"> 258 <script setup lang="ts">
155 import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' 259 import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
@@ -176,19 +280,38 @@ watch( @@ -176,19 +280,38 @@ watch(
176 async (val) => { 280 async (val) => {
177 // 情况一:val 为空,说明是新增,则置空 281 // 情况一:val 为空,说明是新增,则置空
178 if (!val) { 282 if (!val) {
  283 +#if ( $subTable.subJoinMany )
179 formData.value = [] 284 formData.value = []
  285 +#else
  286 + formData.value = {
  287 + #foreach ($column in $subColumns)
  288 + #if ($column.createOperation || $column.updateOperation)
  289 + #if ($column.htmlType == "checkbox")
  290 + $column.javaField: [],
  291 + #else
  292 + $column.javaField: undefined,
  293 + #end
  294 + #end
  295 + #end
  296 + }
  297 +#end
180 return; 298 return;
181 } 299 }
182 // 情况二:val 非空,说明是修改,则加载数据 300 // 情况二:val 非空,说明是修改,则加载数据
183 try { 301 try {
184 formLoading.value = true 302 formLoading.value = true
  303 +#if ( $subTable.subJoinMany )
185 formData.value = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(val) 304 formData.value = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(val)
  305 +#else
  306 + formData.value = await ${simpleClassName}Api.get${subSimpleClassName}By${SubJoinColumnName}(val)
  307 +#end
186 } finally { 308 } finally {
187 formLoading.value = false 309 formLoading.value = false
188 } 310 }
189 }, 311 },
190 { immediate: true } 312 { immediate: true }
191 ) 313 )
  314 +#if ( $subTable.subJoinMany )
192 315
193 /** 新增按钮操作 */ 316 /** 新增按钮操作 */
194 const handleAdd = () => { 317 const handleAdd = () => {
@@ -211,6 +334,7 @@ const handleAdd = () =&gt; { @@ -211,6 +334,7 @@ const handleAdd = () =&gt; {
211 const handleDelete = (index) => { 334 const handleDelete = (index) => {
212 formData.value.splice(index, 1) 335 formData.value.splice(index, 1)
213 } 336 }
  337 +#end
214 338
215 /** 表单校验 */ 339 /** 表单校验 */
216 const validate = () => { 340 const validate = () => {
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm
@@ -102,6 +102,21 @@ @@ -102,6 +102,21 @@
102 #end 102 #end
103 #end 103 #end
104 </el-form> 104 </el-form>
  105 +## 特殊:主子表专属逻辑
  106 +#if ( $subTables && $subTables.size() > 0 )
  107 + <!-- 子表的表单 -->
  108 + <el-tabs v-model="subTabsName">
  109 + #foreach ($subTable in $subTables)
  110 + #set ($index = $foreach.count - 1)
  111 + #set ($subClassNameVar = $subClassNameVars.get($index))
  112 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  113 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  114 + <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
  115 + <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData.id" />
  116 + </el-tab-pane>
  117 + #end
  118 + </el-tabs>
  119 +#end
105 <template #footer> 120 <template #footer>
106 <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> 121 <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
107 <el-button @click="dialogVisible = false">取 消</el-button> 122 <el-button @click="dialogVisible = false">取 消</el-button>
@@ -111,6 +126,10 @@ @@ -111,6 +126,10 @@
111 <script setup lang="ts"> 126 <script setup lang="ts">
112 import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' 127 import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
113 import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}' 128 import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
  129 +## 特殊:主子表专属逻辑
  130 +#foreach ($subSimpleClassName in $subSimpleClassNames)
  131 +import ${subSimpleClassName}Form from './components/${subSimpleClassName}Form.vue'
  132 +#end
114 133
115 const { t } = useI18n() // 国际化 134 const { t } = useI18n() // 国际化
116 const message = useMessage() // 消息弹窗 135 const message = useMessage() // 消息弹窗
@@ -139,6 +158,15 @@ const formRules = reactive({ @@ -139,6 +158,15 @@ const formRules = reactive({
139 #end 158 #end
140 }) 159 })
141 const formRef = ref() // 表单 Ref 160 const formRef = ref() // 表单 Ref
  161 +## 特殊:主子表专属逻辑
  162 +#if ( $subTables && $subTables.size() > 0 )
  163 +
  164 +/** 子表的表单 */
  165 +const subTabsName = ref('$subClassNameVars.get(0)')
  166 +#foreach ($subClassNameVar in $subClassNameVars)
  167 +const ${subClassNameVar}FormRef = ref()
  168 +#end
  169 +#end
142 170
143 /** 打开弹窗 */ 171 /** 打开弹窗 */
144 const open = async (type: string, id?: number) => { 172 const open = async (type: string, id?: number) => {
@@ -163,10 +191,33 @@ const emit = defineEmits([&#39;success&#39;]) // 定义 success 事件,用于操作成 @@ -163,10 +191,33 @@ const emit = defineEmits([&#39;success&#39;]) // 定义 success 事件,用于操作成
163 const submitForm = async () => { 191 const submitForm = async () => {
164 // 校验表单 192 // 校验表单
165 await formRef.value.validate() 193 await formRef.value.validate()
  194 +## 特殊:主子表专属逻辑
  195 +#if ( $subTables && $subTables.size() > 0 )
  196 + // 校验子表单
  197 + #foreach ($subTable in $subTables)
  198 + #set ($index = $foreach.count - 1)
  199 + #set ($subClassNameVar = $subClassNameVars.get($index))
  200 + try {
  201 + await ${subClassNameVar}FormRef.value.validate()
  202 + } catch (e) {
  203 + subTabsName.value = '${subClassNameVar}'
  204 + return
  205 + }
  206 + #end
  207 +#end
166 // 提交请求 208 // 提交请求
167 formLoading.value = true 209 formLoading.value = true
168 try { 210 try {
169 const data = formData.value as unknown as ${simpleClassName}Api.${simpleClassName}VO 211 const data = formData.value as unknown as ${simpleClassName}Api.${simpleClassName}VO
  212 +## 特殊:主子表专属逻辑
  213 +#if ( $subTables && $subTables.size() > 0 )
  214 + // 拼接子表的数据
  215 + #foreach ($subTable in $subTables)
  216 + #set ($index = $foreach.count - 1)
  217 + #set ($subClassNameVar = $subClassNameVars.get($index))
  218 + data.${subClassNameVar}#if ( $subTable.subJoinMany)s#end = ${subClassNameVar}FormRef.value.getData()
  219 + #end
  220 +#end
170 if (formType.value === 'create') { 221 if (formType.value === 'create') {
171 await ${simpleClassName}Api.create${simpleClassName}(data) 222 await ${simpleClassName}Api.create${simpleClassName}(data)
172 message.success(t('common.createSuccess')) 223 message.success(t('common.createSuccess'))
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineTest.java
@@ -284,7 +284,69 @@ public class CodegenEngineTest extends BaseMockitoUnitTest { @@ -284,7 +284,69 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
284 .setCreateOperation(false).setUpdateOperation(true).setListOperation(false) 284 .setCreateOperation(false).setUpdateOperation(true).setListOperation(false)
285 .setListOperationResult(true) 285 .setListOperationResult(true)
286 .setId(200L); 286 .setId(200L);
287 - List<CodegenColumnDO> addressColumns = Arrays.asList(addressIdColumn, addressStudentIdColumn); 287 + CodegenColumnDO addressNameColumn = new CodegenColumnDO().setColumnName("name").setDataType(JdbcType.VARCHAR.name())
  288 + .setColumnComment("名字").setNullable(false).setPrimaryKey(false)
  289 + .setOrdinalPosition(3).setJavaType("String").setJavaField("name").setExample("芋头")
  290 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  291 + .setListOperationCondition(CodegenColumnListConditionEnum.LIKE.getCondition()).setListOperationResult(true)
  292 + .setHtmlType(CodegenColumnHtmlTypeEnum.INPUT.getType());
  293 + CodegenColumnDO addressAvatarColumn = new CodegenColumnDO().setColumnName("avatar").setDataType(JdbcType.VARCHAR.name())
  294 + .setColumnComment("头像").setNullable(false).setPrimaryKey(false)
  295 + .setOrdinalPosition(4).setJavaType("String").setJavaField("avatar").setExample("https://www.iocoder.cn/1.png")
  296 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(false)
  297 + .setListOperationResult(true)
  298 + .setHtmlType(CodegenColumnHtmlTypeEnum.UPLOAD_IMAGE.getType());
  299 + CodegenColumnDO addressVideoColumn = new CodegenColumnDO().setColumnName("video").setDataType(JdbcType.VARCHAR.name())
  300 + .setColumnComment("视频").setNullable(false).setPrimaryKey(false)
  301 + .setOrdinalPosition(5).setJavaType("String").setJavaField("video").setExample("https://www.iocoder.cn/1.mp4")
  302 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(false)
  303 + .setListOperationResult(true)
  304 + .setHtmlType(CodegenColumnHtmlTypeEnum.UPLOAD_FILE.getType());
  305 + CodegenColumnDO addressDescriptionColumn = new CodegenColumnDO().setColumnName("description").setDataType(JdbcType.VARCHAR.name())
  306 + .setColumnComment("个人简介").setNullable(false).setPrimaryKey(false)
  307 + .setOrdinalPosition(6).setJavaType("String").setJavaField("description").setExample("我是介绍")
  308 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(false)
  309 + .setListOperationResult(true)
  310 + .setHtmlType(CodegenColumnHtmlTypeEnum.EDITOR.getType());
  311 + CodegenColumnDO addressSex1Column = new CodegenColumnDO().setColumnName("sex1").setDataType(JdbcType.VARCHAR.name())
  312 + .setColumnComment("性别 1").setNullable(false).setPrimaryKey(false)
  313 + .setOrdinalPosition(7).setJavaType("String").setJavaField("sex1").setExample("男")
  314 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  315 + .setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition()).setListOperationResult(true)
  316 + .setHtmlType(CodegenColumnHtmlTypeEnum.SELECT.getType()).setDictType("system_sex1");
  317 + CodegenColumnDO addressSex2Column = new CodegenColumnDO().setColumnName("sex2").setDataType(JdbcType.INTEGER.name())
  318 + .setColumnComment("性别 2").setNullable(false).setPrimaryKey(false)
  319 + .setOrdinalPosition(8).setJavaType("Integer").setJavaField("sex2").setExample("1")
  320 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  321 + .setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition()).setListOperationResult(true)
  322 + .setHtmlType(CodegenColumnHtmlTypeEnum.CHECKBOX.getType()).setDictType("system_sex2");
  323 + CodegenColumnDO addressSex3Column = new CodegenColumnDO().setColumnName("sex3").setDataType(JdbcType.BOOLEAN.name())
  324 + .setColumnComment("性别 3").setNullable(false).setPrimaryKey(false)
  325 + .setOrdinalPosition(9).setJavaType("Boolean").setJavaField("sex3").setExample("true")
  326 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  327 + .setListOperationResult(true)
  328 + .setHtmlType(CodegenColumnHtmlTypeEnum.RADIO.getType()).setDictType("system_sex3");
  329 + CodegenColumnDO addressBirthdayColumn = new CodegenColumnDO().setColumnName("birthday").setDataType(JdbcType.DATE.name())
  330 + .setColumnComment("出生日期").setNullable(false).setPrimaryKey(false)
  331 + .setOrdinalPosition(10).setJavaType("LocalDateTime").setJavaField("birthday")
  332 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(true)
  333 + .setListOperationCondition(CodegenColumnListConditionEnum.EQ.getCondition()).setListOperationResult(true)
  334 + .setHtmlType(CodegenColumnHtmlTypeEnum.DATETIME.getType());
  335 + CodegenColumnDO addressMemoColumn = new CodegenColumnDO().setColumnName("memo").setDataType(JdbcType.VARCHAR.name())
  336 + .setColumnComment("备注").setNullable(false).setPrimaryKey(false)
  337 + .setOrdinalPosition(11).setJavaType("String").setJavaField("memo").setExample("我是备注")
  338 + .setCreateOperation(true).setUpdateOperation(true).setListOperation(false)
  339 + .setListOperationResult(true)
  340 + .setHtmlType(CodegenColumnHtmlTypeEnum.TEXTAREA.getType());
  341 + CodegenColumnDO addressCreateTimeColumn = new CodegenColumnDO().setColumnName("create_time").setDataType(JdbcType.DATE.name())
  342 + .setColumnComment("创建时间").setNullable(false).setPrimaryKey(false)
  343 + .setOrdinalPosition(12).setJavaType("LocalDateTime").setJavaField("createTime")
  344 + .setCreateOperation(false).setUpdateOperation(false).setListOperation(true)
  345 + .setListOperationCondition(CodegenColumnListConditionEnum.BETWEEN.getCondition()).setListOperationResult(true)
  346 + .setHtmlType(CodegenColumnHtmlTypeEnum.DATETIME.getType());
  347 + List<CodegenColumnDO> addressColumns = Arrays.asList(addressIdColumn, addressStudentIdColumn,
  348 + addressNameColumn, addressAvatarColumn, addressVideoColumn, addressDescriptionColumn,
  349 + addressSex1Column, addressSex2Column, addressSex3Column, addressBirthdayColumn, addressMemoColumn, addressCreateTimeColumn);
288 350
289 // 调用 351 // 调用
290 Map<String, String> result = codegenEngine.execute(table, columns, 352 Map<String, String> result = codegenEngine.execute(table, columns,