Commit 07e71e2ab0ca9703454ef8d959e432c8b9bd6de1
1 parent
0a8257a5
代码生成:主子表 normal 模式,1 对 1 的 form 生成
Showing
4 changed files
with
239 additions
and
2 deletions
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 | 75 | |
| 76 | 76 | // 获得${subTable.classComment} |
| 77 | 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 | 80 | #end |
| 81 | 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 | 5 | #set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 |
| 6 | 6 | #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 |
| 7 | 7 | <template> |
| 8 | +#if ( $subTable.subJoinMany )## 情况一:一对多,table + form | |
| 8 | 9 | <el-form |
| 9 | 10 | ref="formRef" |
| 10 | 11 | :model="formData" |
| ... | ... | @@ -150,6 +151,109 @@ |
| 150 | 151 | <el-row justify="center" class="mt-3"> |
| 151 | 152 | <el-button @click="handleAdd" round>+ 添加${subTable.classComment}</el-button> |
| 152 | 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 | 257 | </template> |
| 154 | 258 | <script setup lang="ts"> |
| 155 | 259 | import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' |
| ... | ... | @@ -176,19 +280,38 @@ watch( |
| 176 | 280 | async (val) => { |
| 177 | 281 | // 情况一:val 为空,说明是新增,则置空 |
| 178 | 282 | if (!val) { |
| 283 | +#if ( $subTable.subJoinMany ) | |
| 179 | 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 | 298 | return; |
| 181 | 299 | } |
| 182 | 300 | // 情况二:val 非空,说明是修改,则加载数据 |
| 183 | 301 | try { |
| 184 | 302 | formLoading.value = true |
| 303 | +#if ( $subTable.subJoinMany ) | |
| 185 | 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 | 308 | } finally { |
| 187 | 309 | formLoading.value = false |
| 188 | 310 | } |
| 189 | 311 | }, |
| 190 | 312 | { immediate: true } |
| 191 | 313 | ) |
| 314 | +#if ( $subTable.subJoinMany ) | |
| 192 | 315 | |
| 193 | 316 | /** 新增按钮操作 */ |
| 194 | 317 | const handleAdd = () => { |
| ... | ... | @@ -211,6 +334,7 @@ const handleAdd = () => { |
| 211 | 334 | const handleDelete = (index) => { |
| 212 | 335 | formData.value.splice(index, 1) |
| 213 | 336 | } |
| 337 | +#end | |
| 214 | 338 | |
| 215 | 339 | /** 表单校验 */ |
| 216 | 340 | const validate = () => { | ... | ... |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm
| ... | ... | @@ -102,6 +102,21 @@ |
| 102 | 102 | #end |
| 103 | 103 | #end |
| 104 | 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 | 120 | <template #footer> |
| 106 | 121 | <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> |
| 107 | 122 | <el-button @click="dialogVisible = false">取 消</el-button> |
| ... | ... | @@ -111,6 +126,10 @@ |
| 111 | 126 | <script setup lang="ts"> |
| 112 | 127 | import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' |
| 113 | 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 | 134 | const { t } = useI18n() // 国际化 |
| 116 | 135 | const message = useMessage() // 消息弹窗 |
| ... | ... | @@ -139,6 +158,15 @@ const formRules = reactive({ |
| 139 | 158 | #end |
| 140 | 159 | }) |
| 141 | 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 | 172 | const open = async (type: string, id?: number) => { |
| ... | ... | @@ -163,10 +191,33 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成 |
| 163 | 191 | const submitForm = async () => { |
| 164 | 192 | // 校验表单 |
| 165 | 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 | 209 | formLoading.value = true |
| 168 | 210 | try { |
| 169 | 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 | 221 | if (formType.value === 'create') { |
| 171 | 222 | await ${simpleClassName}Api.create${simpleClassName}(data) |
| 172 | 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 | 284 | .setCreateOperation(false).setUpdateOperation(true).setListOperation(false) |
| 285 | 285 | .setListOperationResult(true) |
| 286 | 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 | 352 | Map<String, String> result = codegenEngine.execute(table, columns, | ... | ... |