Browse Source

code review:vue2 主子表的生成

YunaiV 1 year ago
parent
commit
df51a678eb

+ 1 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue/api/api.js.vm

@@ -63,7 +63,7 @@ export function export${simpleClassName}Excel(params) {
     responseType: 'blob'
   })
 }
-## 特殊:主子表专属逻辑
+## 特殊:主子表专属逻辑 TODO @puhui999:下面方法的【空格】不太对
 #foreach ($subTable in $subTables)
   #set ($index = $foreach.count - 1)
   #set ($subSimpleClassName = $subSimpleClassNames.get($index))

+ 266 - 266
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm

@@ -1,137 +1,137 @@
 <template>
   <Dialog :title="dialogTitle" v-model="dialogVisible">
     <el-form
-        ref="formRef"
-        :model="formData"
-        :rules="formRules"
-        label-width="100px"
-        v-loading="formLoading"
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="100px"
+      v-loading="formLoading"
     >
-        #foreach($column in $columns)
-            #if ($column.createOperation || $column.updateOperation)
-                #set ($dictType = $column.dictType)
-                #set ($javaField = $column.javaField)
-                #set ($javaType = $column.javaType)
-                #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-                #set ($comment = $column.columnComment)
-                #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
-                #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
-                    #set ($dictMethod = "getIntDictOptions")
-                #elseif ($javaType == "String")
-                    #set ($dictMethod = "getStrDictOptions")
-                #elseif ($javaType == "Boolean")
-                    #set ($dictMethod = "getBoolDictOptions")
+#foreach($column in $columns)
+    #if ($column.createOperation || $column.updateOperation)
+        #set ($dictType = $column.dictType)
+        #set ($javaField = $column.javaField)
+        #set ($javaType = $column.javaType)
+        #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+        #set ($comment = $column.columnComment)
+        #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
+        #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+            #set ($dictMethod = "getIntDictOptions")
+        #elseif ($javaType == "String")
+            #set ($dictMethod = "getStrDictOptions")
+        #elseif ($javaType == "Boolean")
+            #set ($dictMethod = "getBoolDictOptions")
+        #end
+        #if ( $table.templateType == 2 && $column.id == $treeParentColumn.id )
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-tree-select
+          v-model="formData.${javaField}"
+          :data="${classNameVar}Tree"
+          #if ($treeNameColumn.javaField == "name")
+          :props="defaultProps"
+          #else
+          :props="{...defaultProps, label: '$treeNameColumn.javaField'}"
+          #end
+          check-strictly
+          default-expand-all
+          placeholder="请选择${comment}"
+        />
+      </el-form-item>
+        #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
+      </el-form-item>
+        #elseif($column.htmlType == "imageUpload")## 图片上传
+      <el-form-item label="${comment}" prop="${javaField}">
+        <UploadImg v-model="formData.${javaField}" />
+      </el-form-item>
+        #elseif($column.htmlType == "fileUpload")## 文件上传
+      <el-form-item label="${comment}" prop="${javaField}">
+        <UploadFile v-model="formData.${javaField}" />
+      </el-form-item>
+        #elseif($column.htmlType == "editor")## 文本编辑器
+      <el-form-item label="${comment}" prop="${javaField}">
+        <Editor v-model="formData.${javaField}" height="150px" />
+      </el-form-item>
+        #elseif($column.htmlType == "select")## 下拉框
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
+                #if ("" != $dictType)## 有数据字典
+          <el-option
+            v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+                #else##没数据字典
+          <el-option label="请选择字典生成" value="" />
                 #end
-                #if ( $table.templateType == 2 && $column.id == $treeParentColumn.id )
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-tree-select
-                        v-model="formData.${javaField}"
-                        :data="${classNameVar}Tree"
-                        #if ($treeNameColumn.javaField == "name")
-                        :props="defaultProps"
-                        #else
-                        :props="{...defaultProps, label: '$treeNameColumn.javaField'}"
-                        #end
-                        check-strictly
-                        default-expand-all
-                        placeholder="请选择${comment}"
-                    />
-                  </el-form-item>
-                #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" />
-                  </el-form-item>
-                #elseif($column.htmlType == "imageUpload")## 图片上传
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <UploadImg v-model="formData.${javaField}" />
-                  </el-form-item>
-                #elseif($column.htmlType == "fileUpload")## 文件上传
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <UploadFile v-model="formData.${javaField}" />
-                  </el-form-item>
-                #elseif($column.htmlType == "editor")## 文本编辑器
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <Editor v-model="formData.${javaField}" height="150px" />
-                  </el-form-item>
-                #elseif($column.htmlType == "select")## 下拉框
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
-                        #if ("" != $dictType)## 有数据字典
-                          <el-option
-                              v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
-                              :key="dict.value"
-                              :label="dict.label"
-                              :value="dict.value"
-                          />
-                        #else##没数据字典
-                          <el-option label="请选择字典生成" value="" />
-                        #end
-                    </el-select>
-                  </el-form-item>
-                #elseif($column.htmlType == "checkbox")## 多选框
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-checkbox-group v-model="formData.${javaField}">
-                        #if ("" != $dictType)## 有数据字典
-                          <el-checkbox
-                              v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
-                              :key="dict.value"
-                              :label="dict.value"
-                          >
-                            {{ dict.label }}
-                          </el-checkbox>
-                        #else##没数据字典
-                          <el-checkbox>请选择字典生成</el-checkbox>
-                        #end
-                    </el-checkbox-group>
-                  </el-form-item>
-                #elseif($column.htmlType == "radio")## 单选框
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-radio-group v-model="formData.${javaField}">
-                        #if ("" != $dictType)## 有数据字典
-                          <el-radio
-                              v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
-                              :key="dict.value"
-                              :label="dict.value"
-                          >
-                            {{ dict.label }}
-                          </el-radio>
-                        #else##没数据字典
-                          <el-radio label="1">请选择字典生成</el-radio>
-                        #end
-                    </el-radio-group>
-                  </el-form-item>
-                #elseif($column.htmlType == "datetime")## 时间框
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-date-picker
-                        v-model="formData.${javaField}"
-                        type="date"
-                        value-format="x"
-                        placeholder="选择${comment}"
-                    />
-                  </el-form-item>
-                #elseif($column.htmlType == "textarea")## 文本框
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
-                  </el-form-item>
+        </el-select>
+      </el-form-item>
+        #elseif($column.htmlType == "checkbox")## 多选框
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-checkbox-group v-model="formData.${javaField}">
+                #if ("" != $dictType)## 有数据字典
+          <el-checkbox
+            v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
+            :key="dict.value"
+            :label="dict.value"
+          >
+            {{ dict.label }}
+          </el-checkbox>
+                #else##没数据字典
+          <el-checkbox>请选择字典生成</el-checkbox>
                 #end
-            #end
+        </el-checkbox-group>
+      </el-form-item>
+        #elseif($column.htmlType == "radio")## 单选框
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-radio-group v-model="formData.${javaField}">
+                #if ("" != $dictType)## 有数据字典
+          <el-radio
+            v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
+            :key="dict.value"
+            :label="dict.value"
+          >
+            {{ dict.label }}
+          </el-radio>
+                #else##没数据字典
+          <el-radio label="1">请选择字典生成</el-radio>
+                #end
+        </el-radio-group>
+      </el-form-item>
+        #elseif($column.htmlType == "datetime")## 时间框
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-date-picker
+          v-model="formData.${javaField}"
+          type="date"
+          value-format="x"
+          placeholder="选择${comment}"
+        />
+      </el-form-item>
+        #elseif($column.htmlType == "textarea")## 文本框
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" />
+      </el-form-item>
         #end
+    #end
+#end
     </el-form>
-      ## 特殊:主子表专属逻辑
-      #if ( $table.templateType == 10 || $table.templateType == 12 )
-        <!-- 子表的表单 -->
-        <el-tabs v-model="subTabsName">
-            #foreach ($subTable in $subTables)
-                #set ($index = $foreach.count - 1)
-                #set ($subClassNameVar = $subClassNameVars.get($index))
-                #set ($subSimpleClassName = $subSimpleClassNames.get($index))
-                #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
-              <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
-                <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData.id" />
-              </el-tab-pane>
-            #end
-        </el-tabs>
-      #end
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+    <!-- 子表的表单 -->
+    <el-tabs v-model="subTabsName">
+    #foreach ($subTable in $subTables)
+      #set ($index = $foreach.count - 1)
+      #set ($subClassNameVar = $subClassNameVars.get($index))
+      #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+      #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+      <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
+        <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData.id" />
+      </el-tab-pane>
+    #end
+    </el-tabs>
+#end
     <template #footer>
       <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
       <el-button @click="dialogVisible = false">取 消</el-button>
@@ -139,160 +139,160 @@
   </Dialog>
 </template>
 <script setup lang="ts">
-  import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
-  import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
-      ## 特殊:树表专属逻辑
-      #if ( $table.templateType == 2 )
-      import { defaultProps, handleTree } from '@/utils/tree'
-      #end
-      ## 特殊:主子表专属逻辑
-      #if ( $table.templateType == 10 || $table.templateType == 12 )
-          #foreach ($subSimpleClassName in $subSimpleClassNames)
-          import ${subSimpleClassName}Form from './components/${subSimpleClassName}Form.vue'
-          #end
-      #end
+import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
+import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
+## 特殊:树表专属逻辑
+#if ( $table.templateType == 2 )
+import { defaultProps, handleTree } from '@/utils/tree'
+#end
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+#foreach ($subSimpleClassName in $subSimpleClassNames)
+import ${subSimpleClassName}Form from './components/${subSimpleClassName}Form.vue'
+#end
+#end
 
-  const { t } = useI18n() // 国际化
-  const message = useMessage() // 消息弹窗
-
-  const dialogVisible = ref(false) // 弹窗的是否展示
-  const dialogTitle = ref('') // 弹窗的标题
-  const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
-  const formType = ref('') // 表单的类型:create - 新增;update - 修改
-  const formData = ref({
-      #foreach ($column in $columns)
-          #if ($column.createOperation || $column.updateOperation)
-              #if ($column.htmlType == "checkbox")
-                      $column.javaField: [],
-              #else
-                      $column.javaField: undefined,
-              #end
-          #end
-      #end
-  })
-  const formRules = reactive({
-      #foreach ($column in $columns)
-          #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
-              #set($comment=$column.columnComment)
-                  $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
-          #end
-      #end
-  })
-  const formRef = ref() // 表单 Ref
-      ## 特殊:树表专属逻辑
-      #if ( $table.templateType == 2 )
-      const ${classNameVar}Tree = ref() // 树形结构
-      #end
-      ## 特殊:主子表专属逻辑
-      #if ( $table.templateType == 10 || $table.templateType == 12 )
-          #if ( $subTables && $subTables.size() > 0 )
+const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
 
-          /** 子表的表单 */
-          const subTabsName = ref('$subClassNameVars.get(0)')
-              #foreach ($subClassNameVar in $subClassNameVars)
-              const ${subClassNameVar}FormRef = ref()
-              #end
-          #end
+const dialogVisible = ref(false) // 弹窗的是否展示
+const dialogTitle = ref('') // 弹窗的标题
+const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
+const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const formData = ref({
+#foreach ($column in $columns)
+    #if ($column.createOperation || $column.updateOperation)
+      #if ($column.htmlType == "checkbox")
+  $column.javaField: [],
+      #else
+  $column.javaField: undefined,
       #end
+    #end
+#end
+})
+const formRules = reactive({
+#foreach ($column in $columns)
+    #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
+        #set($comment=$column.columnComment)
+  $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
+    #end
+#end
+})
+const formRef = ref() // 表单 Ref
+## 特殊:树表专属逻辑
+#if ( $table.templateType == 2 )
+const ${classNameVar}Tree = ref() // 树形结构
+#end
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+#if ( $subTables && $subTables.size() > 0 )
 
-  /** 打开弹窗 */
-  const open = async (type: string, id?: number) => {
-    dialogVisible.value = true
-    dialogTitle.value = t('action.' + type)
-    formType.value = type
-    resetForm()
-    // 修改时,设置数据
-    if (id) {
-      formLoading.value = true
-      try {
-        formData.value = await ${simpleClassName}Api.get${simpleClassName}(id)
-      } finally {
-        formLoading.value = false
-      }
-    }
-      ## 特殊:树表专属逻辑
-      #if ( $table.templateType == 2 )
-        await get${simpleClassName}Tree()
-      #end
-  }
-  defineExpose({ open }) // 提供 open 方法,用于打开弹窗
+/** 子表的表单 */
+const subTabsName = ref('$subClassNameVars.get(0)')
+#foreach ($subClassNameVar in $subClassNameVars)
+const ${subClassNameVar}FormRef = ref()
+#end
+#end
+#end
 
-  /** 提交表单 */
-  const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
-  const submitForm = async () => {
-    // 校验表单
-    await formRef.value.validate()
-      ## 特殊:主子表专属逻辑
-      #if ( $table.templateType == 10 || $table.templateType == 12 )
-          #if ( $subTables && $subTables.size() > 0 )
-            // 校验子表单
-              #foreach ($subTable in $subTables)
-                  #set ($index = $foreach.count - 1)
-                  #set ($subClassNameVar = $subClassNameVars.get($index))
-                try {
-                  await ${subClassNameVar}FormRef.value.validate()
-                } catch (e) {
-                  subTabsName.value = '${subClassNameVar}'
-                  return
-                }
-              #end
-          #end
-      #end
-    // 提交请求
+/** 打开弹窗 */
+const open = async (type: string, id?: number) => {
+  dialogVisible.value = true
+  dialogTitle.value = t('action.' + type)
+  formType.value = type
+  resetForm()
+  // 修改时,设置数据
+  if (id) {
     formLoading.value = true
     try {
-      const data = formData.value as unknown as ${simpleClassName}Api.${simpleClassName}VO
-        ## 特殊:主子表专属逻辑
-        #if ( $table.templateType == 10 || $table.templateType == 12 )
-            #if ( $subTables && $subTables.size() > 0 )
-              // 拼接子表的数据
-                #foreach ($subTable in $subTables)
-                    #set ($index = $foreach.count - 1)
-                    #set ($subClassNameVar = $subClassNameVars.get($index))
-                  data.${subClassNameVar}#if ( $subTable.subJoinMany)s#end = ${subClassNameVar}FormRef.value.getData()
-                #end
-            #end
-        #end
-      if (formType.value === 'create') {
-        await ${simpleClassName}Api.create${simpleClassName}(data)
-        message.success(t('common.createSuccess'))
-      } else {
-        await ${simpleClassName}Api.update${simpleClassName}(data)
-        message.success(t('common.updateSuccess'))
-      }
-      dialogVisible.value = false
-      // 发送操作成功的事件
-      emit('success')
+      formData.value = await ${simpleClassName}Api.get${simpleClassName}(id)
     } finally {
       formLoading.value = false
     }
   }
+## 特殊:树表专属逻辑
+#if ( $table.templateType == 2 )
+  await get${simpleClassName}Tree()
+#end
+}
+defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
-  /** 重置表单 */
-  const resetForm = () => {
-    formData.value = {
-        #foreach ($column in $columns)
-            #if ($column.createOperation || $column.updateOperation)
-                #if ($column.htmlType == "checkbox")
-                        $column.javaField: [],
-                #else
-                        $column.javaField: undefined,
-                #end
-            #end
-        #end
+/** 提交表单 */
+const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
+const submitForm = async () => {
+  // 校验表单
+  await formRef.value.validate()
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+#if ( $subTables && $subTables.size() > 0 )
+  // 校验子表单
+  #foreach ($subTable in $subTables)
+  #set ($index = $foreach.count - 1)
+  #set ($subClassNameVar = $subClassNameVars.get($index))
+  try {
+    await ${subClassNameVar}FormRef.value.validate()
+  } catch (e) {
+    subTabsName.value = '${subClassNameVar}'
+    return
+  }
+  #end
+#end
+#end
+  // 提交请求
+  formLoading.value = true
+  try {
+    const data = formData.value as unknown as ${simpleClassName}Api.${simpleClassName}VO
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+#if ( $subTables && $subTables.size() > 0 )
+    // 拼接子表的数据
+  #foreach ($subTable in $subTables)
+  #set ($index = $foreach.count - 1)
+  #set ($subClassNameVar = $subClassNameVars.get($index))
+    data.${subClassNameVar}#if ( $subTable.subJoinMany)s#end = ${subClassNameVar}FormRef.value.getData()
+  #end
+#end
+#end
+    if (formType.value === 'create') {
+      await ${simpleClassName}Api.create${simpleClassName}(data)
+      message.success(t('common.createSuccess'))
+    } else {
+      await ${simpleClassName}Api.update${simpleClassName}(data)
+      message.success(t('common.updateSuccess'))
     }
-    formRef.value?.resetFields()
+    dialogVisible.value = false
+    // 发送操作成功的事件
+    emit('success')
+  } finally {
+    formLoading.value = false
   }
-      ## 特殊:树表专属逻辑
-      #if ( $table.templateType == 2 )
+}
 
-      /** 获得${table.classComment}树 */
-      const get${simpleClassName}Tree = async () => {
-              ${classNameVar}Tree.value = []
-        const data = await ${simpleClassName}Api.get${simpleClassName}List()
-        const root: Tree = { id: 0, name: '顶级${table.classComment}', children: [] }
-        root.children = handleTree(data, 'id', '${treeParentColumn.javaField}')
-              ${classNameVar}Tree.value.push(root)
-      }
+/** 重置表单 */
+const resetForm = () => {
+  formData.value = {
+#foreach ($column in $columns)
+  #if ($column.createOperation || $column.updateOperation)
+      #if ($column.htmlType == "checkbox")
+    $column.javaField: [],
+      #else
+    $column.javaField: undefined,
       #end
+  #end
+#end
+  }
+  formRef.value?.resetFields()
+}
+## 特殊:树表专属逻辑
+#if ( $table.templateType == 2 )
+
+/** 获得${table.classComment}树 */
+const get${simpleClassName}Tree = async () => {
+  ${classNameVar}Tree.value = []
+  const data = await ${simpleClassName}Api.get${simpleClassName}List()
+  const root: Tree = { id: 0, name: '顶级${table.classComment}', children: [] }
+  root.children = handleTree(data, 'id', '${treeParentColumn.javaField}')
+  ${classNameVar}Tree.value.push(root)
+}
+#end
 </script>

+ 314 - 317
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm

@@ -2,375 +2,372 @@
   <ContentWrap>
     <!-- 搜索工作栏 -->
     <el-form
-        class="-mb-15px"
-        :model="queryParams"
-        ref="queryFormRef"
-        :inline="true"
-        label-width="68px"
+      class="-mb-15px"
+      :model="queryParams"
+      ref="queryFormRef"
+      :inline="true"
+      label-width="68px"
     >
-        #foreach($column in $columns)
-            #if ($column.listOperation)
-                #set ($dictType = $column.dictType)
-                #set ($javaField = $column.javaField)
-                #set ($javaType = $column.javaType)
-                #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-                #set ($comment = $column.columnComment)
-                #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
-                #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
-                    #set ($dictMethod = "getIntDictOptions")
-                #elseif ($javaType == "String")
-                    #set ($dictMethod = "getStrDictOptions")
-                #elseif ($javaType == "Boolean")
-                    #set ($dictMethod = "getBoolDictOptions")
-                #end
-                #if ($column.htmlType == "input")
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-input
-                        v-model="queryParams.${javaField}"
-                        placeholder="请输入${comment}"
-                        clearable
-                        @keyup.enter="handleQuery"
-                        class="!w-240px"
-                    />
-                  </el-form-item>
-                #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
-                  <el-form-item label="${comment}" prop="${javaField}">
-                    <el-select
-                        v-model="queryParams.${javaField}"
-                        placeholder="请选择${comment}"
-                        clearable
-                        class="!w-240px"
-                    >
-                        #if ("" != $dictType)## 设置了 dictType 数据字典的情况
-                          <el-option
-                              v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
-                              :key="dict.value"
-                              :label="dict.label"
-                              :value="dict.value"
-                          />
-                        #else## 未设置 dictType 数据字典的情况
-                          <el-option label="请选择字典生成" value="" />
-                        #end
-                    </el-select>
-                  </el-form-item>
-                #elseif($column.htmlType == "datetime")
-                    #if ($column.listOperationCondition != "BETWEEN")## 非范围
-                      <el-form-item label="${comment}" prop="${javaField}">
-                        <el-date-picker
-                            v-model="queryParams.${javaField}"
-                            value-format="YYYY-MM-DD"
-                            type="date"
-                            placeholder="选择${comment}"
-                            clearable
-                            class="!w-240px"
-                        />
-                      </el-form-item>
-                    #else## 范围
-                      <el-form-item label="${comment}" prop="${javaField}">
-                        <el-date-picker
-                            v-model="queryParams.${javaField}"
-                            value-format="YYYY-MM-DD HH:mm:ss"
-                            type="daterange"
-                            start-placeholder="开始日期"
-                            end-placeholder="结束日期"
-                            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-                            class="!w-240px"
-                        />
-                      </el-form-item>
-                    #end
-                #end
+    #foreach($column in $columns)
+        #if ($column.listOperation)
+            #set ($dictType = $column.dictType)
+            #set ($javaField = $column.javaField)
+            #set ($javaType = $column.javaType)
+            #set ($AttrName = $column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+            #set ($comment = $column.columnComment)
+            #set ($dictMethod = "getDictOptions")## 计算使用哪个 dict 字典方法
+            #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
+                #set ($dictMethod = "getIntDictOptions")
+            #elseif ($javaType == "String")
+                #set ($dictMethod = "getStrDictOptions")
+            #elseif ($javaType == "Boolean")
+                #set ($dictMethod = "getBoolDictOptions")
             #end
-        #end
+            #if ($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-input
+          v-model="queryParams.${javaField}"
+          placeholder="请输入${comment}"
+          clearable
+          @keyup.enter="handleQuery"
+          class="!w-240px"
+        />
+      </el-form-item>
+            #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-select
+          v-model="queryParams.${javaField}"
+          placeholder="请选择${comment}"
+          clearable
+          class="!w-240px"
+        >
+                #if ("" != $dictType)## 设置了 dictType 数据字典的情况
+          <el-option
+            v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+                #else## 未设置 dictType 数据字典的情况
+          <el-option label="请选择字典生成" value="" />
+                #end
+        </el-select>
+      </el-form-item>
+    #elseif($column.htmlType == "datetime")
+      #if ($column.listOperationCondition != "BETWEEN")## 非范围
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-date-picker
+          v-model="queryParams.${javaField}"
+          value-format="YYYY-MM-DD"
+          type="date"
+          placeholder="选择${comment}"
+          clearable
+          class="!w-240px"
+        />
+      </el-form-item>
+      #else## 范围
+      <el-form-item label="${comment}" prop="${javaField}">
+        <el-date-picker
+          v-model="queryParams.${javaField}"
+          value-format="YYYY-MM-DD HH:mm:ss"
+          type="daterange"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+          class="!w-240px"
+        />
+      </el-form-item>
+      #end
+    #end
+    #end
+    #end
       <el-form-item>
         <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
         <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
         <el-button
-            type="primary"
-            plain
-            @click="openForm('create')"
-            v-hasPermi="['${permissionPrefix}:create']"
+          type="primary"
+          plain
+          @click="openForm('create')"
+          v-hasPermi="['${permissionPrefix}:create']"
         >
           <Icon icon="ep:plus" class="mr-5px" /> 新增
         </el-button>
         <el-button
-            type="success"
-            plain
-            @click="handleExport"
-            :loading="exportLoading"
-            v-hasPermi="['${permissionPrefix}:export']"
+          type="success"
+          plain
+          @click="handleExport"
+          :loading="exportLoading"
+          v-hasPermi="['${permissionPrefix}:export']"
         >
           <Icon icon="ep:download" class="mr-5px" /> 导出
         </el-button>
-          ## 特殊:树表专属逻辑
-          #if ( $table.templateType == 2 )
-            <el-button type="danger" plain @click="toggleExpandAll">
-              <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
-            </el-button>
-          #end
+## 特殊:树表专属逻辑
+#if ( $table.templateType == 2 )
+        <el-button type="danger" plain @click="toggleExpandAll">
+          <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠
+        </el-button>
+#end
       </el-form-item>
     </el-form>
   </ContentWrap>
 
   <!-- 列表 -->
   <ContentWrap>
-      ## 特殊:主子表专属逻辑
-      #if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
-      <el-table
-          v-loading="loading"
-          :data="list"
-          :stripe="true"
-          :show-overflow-tooltip="true"
-          highlight-current-row
-          @current-change="handleCurrentChange"
-      >
-          ## 特殊:树表专属逻辑
-      #elseif ( $table.templateType == 2 )
-      <el-table
-          v-loading="loading"
-          :data="list"
-          :stripe="true"
-          :show-overflow-tooltip="true"
-          row-key="id"
-          :default-expand-all="isExpandAll"
-          v-if="refreshTable"
-      >
-      #else
-      <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      #end
-      ## 特殊:主子表专属逻辑
-      #if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
-        <!-- 子表的列表 -->
-        <el-table-column type="expand">
-          <template #default="scope">
-            <el-tabs model-value="$subClassNameVars.get(0)">
-                #foreach ($subTable in $subTables)
-                    #set ($index = $foreach.count - 1)
-                    #set ($subClassNameVar = $subClassNameVars.get($index))
-                    #set ($subSimpleClassName = $subSimpleClassNames.get($index))
-                    #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
-                  <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
-                    <${subSimpleClassName}List :${subJoinColumn_strikeCase}="scope.row.id" />
-                  </el-tab-pane>
-                #end
-            </el-tabs>
-          </template>
-        </el-table-column>
-      #end
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
+    <el-table
+      v-loading="loading"
+      :data="list"
+      :stripe="true"
+      :show-overflow-tooltip="true"
+      highlight-current-row
+      @current-change="handleCurrentChange"
+    >
+## 特殊:树表专属逻辑
+#elseif ( $table.templateType == 2 )
+    <el-table
+      v-loading="loading"
+      :data="list"
+      :stripe="true"
+      :show-overflow-tooltip="true"
+      row-key="id"
+      :default-expand-all="isExpandAll"
+      v-if="refreshTable"
+    >
+#else
+    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
+#end
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
+      <!-- 子表的列表 -->
+      <el-table-column type="expand">
+        <template #default="scope">
+          <el-tabs model-value="$subClassNameVars.get(0)">
+            #foreach ($subTable in $subTables)
+              #set ($index = $foreach.count - 1)
+              #set ($subClassNameVar = $subClassNameVars.get($index))
+              #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+              #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+            <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
+              <${subSimpleClassName}List :${subJoinColumn_strikeCase}="scope.row.id" />
+            </el-tab-pane>
+            #end
+          </el-tabs>
+        </template>
+      </el-table-column>
+#end
       #foreach($column in $columns)
-          #if ($column.listOperationResult)
-              #set ($dictType=$column.dictType)
-              #set ($javaField = $column.javaField)
-              #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-              #set ($comment=$column.columnComment)
-              #if ($column.javaType == "LocalDateTime")## 时间类型
-                <el-table-column
-                    label="${comment}"
-                    align="center"
-                    prop="${javaField}"
-                    :formatter="dateFormatter"
-                    width="180px"
-                />
-              #elseif($column.dictType && "" != $column.dictType)## 数据字典
-                <el-table-column label="${comment}" align="center" prop="${javaField}">
-                  <template #default="scope">
-                    <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.${column.javaField}" />
-                  </template>
-                </el-table-column>
-              #else
-                <el-table-column label="${comment}" align="center" prop="${javaField}" />
-              #end
-          #end
+      #if ($column.listOperationResult)
+        #set ($dictType=$column.dictType)
+        #set ($javaField = $column.javaField)
+        #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+        #set ($comment=$column.columnComment)
+        #if ($column.javaType == "LocalDateTime")## 时间类型
+      <el-table-column
+        label="${comment}"
+        align="center"
+        prop="${javaField}"
+        :formatter="dateFormatter"
+        width="180px"
+      />
+        #elseif($column.dictType && "" != $column.dictType)## 数据字典
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.${column.javaField}" />
+        </template>
+      </el-table-column>
+        #else
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+        #end
       #end
-    <el-table-column label="操作" align="center">
-      <template #default="scope">
-        <el-button
+    #end
+      <el-table-column label="操作" align="center">
+        <template #default="scope">
+          <el-button
             link
             type="primary"
             @click="openForm('update', scope.row.id)"
             v-hasPermi="['${permissionPrefix}:update']"
-        >
-          编辑
-        </el-button>
-        <el-button
+          >
+            编辑
+          </el-button>
+          <el-button
             link
             type="danger"
             @click="handleDelete(scope.row.id)"
             v-hasPermi="['${permissionPrefix}:delete']"
-        >
-          删除
-        </el-button>
-      </template>
-    </el-table-column>
-  </el-table>
-## 特殊:树表专属逻辑(树不需要分页)
-#if ( $table.templateType != 2 )
+          >
+            删除
+          </el-button>
+        </template>
+      </el-table-column>
+    </el-table>
     <!-- 分页 -->
     <Pagination
-        :total="total"
-        v-model:page="queryParams.pageNo"
-        v-model:limit="queryParams.pageSize"
-        @pagination="getList"
+      :total="total"
+      v-model:page="queryParams.pageNo"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
     />
-#end
   </ContentWrap>
 
   <!-- 表单弹窗:添加/修改 -->
   <${simpleClassName}Form ref="formRef" @success="getList" />
-    ## 特殊:主子表专属逻辑
-    #if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
-      <!-- 子表的列表 -->
-      <ContentWrap>
-        <el-tabs model-value="$subClassNameVars.get(0)">
-            #foreach ($subTable in $subTables)
-                #set ($index = $foreach.count - 1)
-                #set ($subClassNameVar = $subClassNameVars.get($index))
-                #set ($subSimpleClassName = $subSimpleClassNames.get($index))
-                #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
-              <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
-                <${subSimpleClassName}List :${subJoinColumn_strikeCase}="currentRow.id" />
-              </el-tab-pane>
-            #end
-        </el-tabs>
-      </ContentWrap>
-    #end
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 11 && $subTables && $subTables.size() > 0 )
+  <!-- 子表的列表 -->
+  <ContentWrap>
+    <el-tabs model-value="$subClassNameVars.get(0)">
+      #foreach ($subTable in $subTables)
+        #set ($index = $foreach.count - 1)
+        #set ($subClassNameVar = $subClassNameVars.get($index))
+        #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+        #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+      <el-tab-pane label="${subTable.classComment}" name="$subClassNameVar">
+        <${subSimpleClassName}List :${subJoinColumn_strikeCase}="currentRow.id" />
+      </el-tab-pane>
+      #end
+    </el-tabs>
+  </ContentWrap>
+#end
 </template>
 
 <script setup lang="ts">
-  import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
-  import { dateFormatter } from '@/utils/formatTime'
-      ## 特殊:树表专属逻辑
-      #if ( $table.templateType == 2 )
-      import { handleTree } from '@/utils/tree'
-      #end
-  import download from '@/utils/download'
-  import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
-  import ${simpleClassName}Form from './${simpleClassName}Form.vue'
-      ## 特殊:主子表专属逻辑
-      #if ( $table.templateType != 10 )
-          #foreach ($subSimpleClassName in $subSimpleClassNames)
-          import ${subSimpleClassName}List from './components/${subSimpleClassName}List.vue'
-          #end
-      #end
+import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
+import { dateFormatter } from '@/utils/formatTime'
+## 特殊:树表专属逻辑
+#if ( $table.templateType == 2 )
+import { handleTree } from '@/utils/tree'
+#end
+import download from '@/utils/download'
+import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${table.businessName}'
+import ${simpleClassName}Form from './${simpleClassName}Form.vue'
+## 特殊:主子表专属逻辑
+#if ( $table.templateType != 10 )
+#foreach ($subSimpleClassName in $subSimpleClassNames)
+import ${subSimpleClassName}List from './components/${subSimpleClassName}List.vue'
+#end
+#end
 
-  defineOptions({ name: '${table.className}' })
+defineOptions({ name: '${table.className}' })
 
-  const message = useMessage() // 消息弹窗
-  const { t } = useI18n() // 国际化
+const message = useMessage() // 消息弹窗
+const { t } = useI18n() // 国际化
 
-  const loading = ref(true) // 列表的加载中
-  const list = ref([]) // 列表的数据
-      ## 特殊:树表专属逻辑(树不需要分页接口)
-      #if ( $table.templateType != 2 )
-      const total = ref(0) // 列表的总页数
-      #end
-  const queryParams = reactive({
-      ## 特殊:树表专属逻辑(树不需要分页接口)
-      #if ( $table.templateType != 2 )
-        pageNo: 1,
-        pageSize: 10,
-      #end
-      #foreach ($column in $columns)
-          #if ($column.listOperation)
-              #if ($column.listOperationCondition != 'BETWEEN')
-                      $column.javaField: null,
-              #end
-              #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
-                      $column.javaField: [],
-              #end
-          #end
+const loading = ref(true) // 列表的加载中
+const list = ref([]) // 列表的数据
+## 特殊:树表专属逻辑(树不需要分页接口)
+#if ( $table.templateType != 2 )
+const total = ref(0) // 列表的总页数
+#end
+const queryParams = reactive({
+## 特殊:树表专属逻辑(树不需要分页接口)
+#if ( $table.templateType != 2 )
+  pageNo: 1,
+  pageSize: 10,
+#end
+  #foreach ($column in $columns)
+    #if ($column.listOperation)
+      #if ($column.listOperationCondition != 'BETWEEN')
+  $column.javaField: null,
+  #end
+      #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
+  $column.javaField: [],
       #end
-  })
-  const queryFormRef = ref() // 搜索的表单
-  const exportLoading = ref(false) // 导出的加载中
+    #end
+  #end
+})
+const queryFormRef = ref() // 搜索的表单
+const exportLoading = ref(false) // 导出的加载中
 
-  /** 查询列表 */
-  const getList = async () => {
-    loading.value = true
-    try {
-        ## 特殊:树表专属逻辑(树不需要分页接口)
-        #if ( $table.templateType == 2 )
-          const data = await ${simpleClassName}Api.get${simpleClassName}List(queryParams)
-          list.value = handleTree(data, 'id', '${treeParentColumn.javaField}')
-        #else
-          const data = await ${simpleClassName}Api.get${simpleClassName}Page(queryParams)
-          list.value = data.list
-          total.value = data.total
-        #end
-    } finally {
-      loading.value = false
-    }
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+## 特殊:树表专属逻辑(树不需要分页接口)
+  #if ( $table.templateType == 2 )
+    const data = await ${simpleClassName}Api.get${simpleClassName}List(queryParams)
+    list.value = handleTree(data, 'id', '${treeParentColumn.javaField}')
+  #else
+    const data = await ${simpleClassName}Api.get${simpleClassName}Page(queryParams)
+    list.value = data.list
+    total.value = data.total
+  #end
+  } finally {
+    loading.value = false
   }
+}
 
-  /** 搜索按钮操作 */
-  const handleQuery = () => {
-    queryParams.pageNo = 1
-    getList()
-  }
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
 
-  /** 重置按钮操作 */
-  const resetQuery = () => {
-    queryFormRef.value.resetFields()
-    handleQuery()
-  }
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value.resetFields()
+  handleQuery()
+}
 
-  /** 添加/修改操作 */
-  const formRef = ref()
-  const openForm = (type: string, id?: number) => {
-    formRef.value.open(type, id)
-  }
+/** 添加/修改操作 */
+const formRef = ref()
+const openForm = (type: string, id?: number) => {
+  formRef.value.open(type, id)
+}
 
-  /** 删除按钮操作 */
-  const handleDelete = async (id: number) => {
-    try {
-      // 删除的二次确认
-      await message.delConfirm()
-      // 发起删除
-      await ${simpleClassName}Api.delete${simpleClassName}(id)
-      message.success(t('common.delSuccess'))
-      // 刷新列表
-      await getList()
-    } catch {}
-  }
+/** 删除按钮操作 */
+const handleDelete = async (id: number) => {
+  try {
+    // 删除的二次确认
+    await message.delConfirm()
+    // 发起删除
+    await ${simpleClassName}Api.delete${simpleClassName}(id)
+    message.success(t('common.delSuccess'))
+    // 刷新列表
+    await getList()
+  } catch {}
+}
 
-  /** 导出按钮操作 */
-  const handleExport = async () => {
-    try {
-      // 导出的二次确认
-      await message.exportConfirm()
-      // 发起导出
-      exportLoading.value = true
-      const data = await ${simpleClassName}Api.export${simpleClassName}(queryParams)
-      download.excel(data, '${table.classComment}.xls')
-    } catch {
-    } finally {
-      exportLoading.value = false
-    }
+/** 导出按钮操作 */
+const handleExport = async () => {
+  try {
+    // 导出的二次确认
+    await message.exportConfirm()
+    // 发起导出
+    exportLoading.value = true
+    const data = await ${simpleClassName}Api.export${simpleClassName}(queryParams)
+    download.excel(data, '${table.classComment}.xls')
+  } catch {
+  } finally {
+    exportLoading.value = false
   }
-      ## 特殊:主子表专属逻辑
-      #if ( $table.templateType == 11 )
+}
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 11 )
 
-      /** 选中行操作 */
-      const currentRow = ref({}) // 选中行
-      const handleCurrentChange = (row) => {
-        currentRow.value = row
-      }
-      #end
-      ## 特殊:树表专属逻辑
-      #if ( $table.templateType == 2 )
+/** 选中行操作 */
+const currentRow = ref({}) // 选中行
+const handleCurrentChange = (row) => {
+  currentRow.value = row
+}
+#end
+## 特殊:树表专属逻辑
+#if ( $table.templateType == 2 )
 
-      /** 展开/折叠操作 */
-      const isExpandAll = ref(true) // 是否展开,默认全部展开
-      const refreshTable = ref(true) // 重新渲染表格状态
-      const toggleExpandAll = async () => {
-        refreshTable.value = false
-        isExpandAll.value = !isExpandAll.value
-        await nextTick()
-        refreshTable.value = true
-      }
-      #end
+/** 展开/折叠操作 */
+const isExpandAll = ref(true) // 是否展开,默认全部展开
+const refreshTable = ref(true) // 重新渲染表格状态
+const toggleExpandAll = async () => {
+  refreshTable.value = false
+  isExpandAll.value = !isExpandAll.value
+  await nextTick()
+  refreshTable.value = true
+}
+#end
 
-  /** 初始化 **/
-  onMounted(() => {
-    getList()
-  })
+/** 初始化 **/
+onMounted(() => {
+  getList()
+})
 </script>

+ 13 - 89
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineTest.java → yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java

@@ -10,33 +10,32 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
-import cn.iocoder.yudao.module.infra.enums.codegen.*;
 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
-import org.apache.ibatis.type.JdbcType;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.mockito.InjectMocks;
 import org.mockito.Spy;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * {@link CodegenEngine} 的单元测试
+ * {@link CodegenEngine} 的单元测试抽象基类
  *
  * @author 芋道源码
  */
-public class CodegenEngineTest extends BaseMockitoUnitTest {
+public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest {
 
     @InjectMocks
-    private CodegenEngine codegenEngine;
+    protected CodegenEngine codegenEngine;
 
     @Spy
-    private CodegenProperties codegenProperties = new CodegenProperties()
+    protected CodegenProperties codegenProperties = new CodegenProperties()
             .setBasePackage("cn.iocoder.yudao");
 
     @BeforeEach
@@ -44,87 +43,12 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
         codegenEngine.initGlobalBindingMap();
     }
 
-    @Test
-    public void testExecute_vue3_one() {
-        // 准备参数
-        CodegenTableDO table = getTable("student")
-                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
-                .setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
-        List<CodegenColumnDO> columns = getColumnList("student");
-
-        // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns, null, null);
-        // 断言
-        assertResult(result, "codegen/vue3_one");
-//        writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one");
-    }
-
-    @Test
-    public void testExecute_vue3_tree() {
-        // 准备参数
-        CodegenTableDO table = getTable("category")
-                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
-                .setTemplateType(CodegenTemplateTypeEnum.TREE.getType());
-        List<CodegenColumnDO> columns = getColumnList("category");
-
-        // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns, null, null);
-        // 断言
-        assertResult(result, "codegen/vue3_tree");
-//        writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree");
-//        writeFile(result, "/Users/yunai/test/demo66.zip");
-    }
-
-    @Test
-    public void testExecute_vue3_master_normal() {
-        testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "codegen/vue3_master_normal");
-    }
-
-    @Test
-    public void testExecute_vue3_master_erp() {
-        testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_ERP, "codegen/vue3_master_erp");
-    }
-
-    @Test
-    public void testExecute_vue3_master_inner() {
-        testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_INNER, "codegen/vue3_master_inner");
-    }
-
-    private void testExecute_vue3_master(CodegenTemplateTypeEnum templateType,
-                                         String path) {
-        // 准备参数
-        CodegenTableDO table = getTable("student")
-                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
-                .setTemplateType(templateType.getType());
-        List<CodegenColumnDO> columns = getColumnList("student");
-        // 准备参数(子表)
-        CodegenTableDO contactTable = getTable("contact")
-                .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
-                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
-                .setSubJoinColumnId(100L).setSubJoinMany(true);
-        List<CodegenColumnDO> contactColumns = getColumnList("contact");
-        // 准备参数(班主任)
-        CodegenTableDO teacherTable = getTable("teacher")
-                .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
-                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
-                .setSubJoinColumnId(200L).setSubJoinMany(false);
-        List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
-
-        // 调用
-        Map<String, String> result = codegenEngine.execute(table, columns,
-                Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
-        // 断言
-        assertResult(result, path);
-//        writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/" + path);
-//        writeFile(result, "/Users/yunai/test/demo11.zip");
-    }
-
-    private static CodegenTableDO getTable(String name) {
+    protected static CodegenTableDO getTable(String name) {
         String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
         return JsonUtils.parseObject(content, "table", CodegenTableDO.class);
     }
 
-    private static List<CodegenColumnDO> getColumnList(String name) {
+    protected static List<CodegenColumnDO> getColumnList(String name) {
         String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
         List<CodegenColumnDO> list = JsonUtils.parseArray(content, "columns", CodegenColumnDO.class);
         list.forEach(column -> {
@@ -148,7 +72,7 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
     }
 
     @SuppressWarnings("rawtypes")
-    private static void assertResult(Map<String, String> result, String path) {
+    protected static void assertResult(Map<String, String> result, String path) {
         String assertContent = ResourceUtil.readUtf8Str(path + "/assert.json");
         List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class);
         assertEquals(asserts.size(), result.size());
@@ -169,7 +93,7 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
      * @param result 生成的代码
      * @param path 写入文件的路径
      */
-    private void writeFile(Map<String, String> result, String path) {
+    protected void writeFile(Map<String, String> result, String path) {
         // 生成压缩包
         String[] paths = result.keySet().toArray(new String[0]);
         ByteArrayInputStream[] ins = result.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
@@ -185,7 +109,7 @@ public class CodegenEngineTest extends BaseMockitoUnitTest {
      * @param result 生成的代码
      * @param basePath 写入文件的路径(绝对路径)
      */
-    private void writeResult(Map<String, String> result, String basePath) {
+    protected void writeResult(Map<String, String> result, String basePath) {
         // 写入文件内容
         List<Map<String, String>> asserts = new ArrayList<>();
         result.forEach((filePath, fileContent) -> {

+ 5 - 112
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue2Test.java

@@ -1,47 +1,21 @@
 package cn.iocoder.yudao.module.infra.service.codegen.inner;
 
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.io.resource.ResourceUtil;
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.core.util.ZipUtil;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
-import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Spy;
 
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.*;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
 
 /**
- * {@link CodegenEngine} 的单元测试
+ * {@link CodegenEngine} 的 Vue2 + Element UI 单元测试
  *
  * @author 芋道源码
  */
-public class CodegenEngineVue2Test extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private CodegenEngine codegenEngine;
-
-    @Spy
-    private CodegenProperties codegenProperties = new CodegenProperties()
-            .setBasePackage("cn.iocoder.yudao");
-
-    @BeforeEach
-    public void setUp() {
-        codegenEngine.initGlobalBindingMap();
-    }
+public class CodegenEngineVue2Test extends CodegenEngineAbstractTest {
 
     @Test
     public void testExecute_vue2_one() {
@@ -118,85 +92,4 @@ public class CodegenEngineVue2Test extends BaseMockitoUnitTest {
 //        writeFile(result, "/Users/yunai/test/demo11.zip");
     }
 
-    private static CodegenTableDO getTable(String name) {
-        String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
-        return JsonUtils.parseObject(content, "table", CodegenTableDO.class);
-    }
-
-    private static List<CodegenColumnDO> getColumnList(String name) {
-        String content = ResourceUtil.readUtf8Str("codegen/table/" + name + ".json");
-        List<CodegenColumnDO> list = JsonUtils.parseArray(content, "columns", CodegenColumnDO.class);
-        list.forEach(column -> {
-            if (column.getNullable() == null) {
-                column.setNullable(false);
-            }
-            if (column.getCreateOperation() == null) {
-                column.setCreateOperation(false);
-            }
-            if (column.getUpdateOperation() == null) {
-                column.setUpdateOperation(false);
-            }
-            if (column.getListOperation() == null) {
-                column.setListOperation(false);
-            }
-            if (column.getListOperationResult() == null) {
-                column.setListOperationResult(false);
-            }
-        });
-        return list;
-    }
-
-    @SuppressWarnings("rawtypes")
-    private static void assertResult(Map<String, String> result, String path) {
-        String assertContent = ResourceUtil.readUtf8Str(path + "/assert.json");
-        List<HashMap> asserts = JsonUtils.parseArray(assertContent, HashMap.class);
-        assertEquals(asserts.size(), result.size());
-        // 校验每个文件
-        asserts.forEach(assertMap -> {
-            String contentPath = (String) assertMap.get("contentPath");
-            String filePath = (String) assertMap.get("filePath");
-            String content = ResourceUtil.readUtf8Str(path + "/" + contentPath);
-            assertEquals(content, result.get(filePath), filePath + ":不匹配");
-        });
-    }
-
-    // ==================== 调试专用 ====================
-
-    /**
-     * 【调试使用】将生成的代码,写入到文件
-     *
-     * @param result 生成的代码
-     * @param path 写入文件的路径
-     */
-    private void writeFile(Map<String, String> result, String path) {
-        // 生成压缩包
-        String[] paths = result.keySet().toArray(new String[0]);
-        ByteArrayInputStream[] ins = result.values().stream().map(IoUtil::toUtf8Stream).toArray(ByteArrayInputStream[]::new);
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        ZipUtil.zip(outputStream, paths, ins);
-        // 写入文件
-        FileUtil.writeBytes(outputStream.toByteArray(), path);
-    }
-
-    /**
-     * 【调试使用】将生成的结果,写入到文件
-     *
-     * @param result 生成的代码
-     * @param basePath 写入文件的路径(绝对路径)
-     */
-    private void writeResult(Map<String, String> result, String basePath) {
-        // 写入文件内容
-        List<Map<String, String>> asserts = new ArrayList<>();
-        result.forEach((filePath, fileContent) -> {
-            String lastFilePath = StrUtil.subAfter(filePath, '/', true);
-            String contentPath = StrUtil.subAfter(lastFilePath, '.', true)
-                    + '/' + StrUtil.subBefore(lastFilePath, '.', true);
-            asserts.add(MapUtil.<String, String>builder().put("filePath", filePath)
-                    .put("contentPath", contentPath).build());
-            FileUtil.writeUtf8String(fileContent, basePath + "/" + contentPath);
-        });
-        // 写入 assert.json 文件
-        FileUtil.writeUtf8String(JsonUtils.toJsonPrettyString(asserts), basePath +"/assert.json");
-    }
-
 }

+ 95 - 0
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVue3Test.java

@@ -0,0 +1,95 @@
+package cn.iocoder.yudao.module.infra.service.codegen.inner;
+
+import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
+import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
+import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
+import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link CodegenEngine} 的 Vue2 + Element Plus 单元测试
+ *
+ * @author 芋道源码
+ */
+public class CodegenEngineVue3Test extends CodegenEngineAbstractTest {
+
+    @Test
+    public void testExecute_vue3_one() {
+        // 准备参数
+        CodegenTableDO table = getTable("student")
+                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
+                .setTemplateType(CodegenTemplateTypeEnum.ONE.getType());
+        List<CodegenColumnDO> columns = getColumnList("student");
+
+        // 调用
+        Map<String, String> result = codegenEngine.execute(table, columns, null, null);
+        // 断言
+        assertResult(result, "codegen/vue3_one");
+//        writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_one");
+    }
+
+    @Test
+    public void testExecute_vue3_tree() {
+        // 准备参数
+        CodegenTableDO table = getTable("category")
+                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
+                .setTemplateType(CodegenTemplateTypeEnum.TREE.getType());
+        List<CodegenColumnDO> columns = getColumnList("category");
+
+        // 调用
+        Map<String, String> result = codegenEngine.execute(table, columns, null, null);
+        // 断言
+        assertResult(result, "codegen/vue3_tree");
+//        writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/codegen/vue3_tree");
+//        writeFile(result, "/Users/yunai/test/demo66.zip");
+    }
+
+    @Test
+    public void testExecute_vue3_master_normal() {
+        testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_NORMAL, "codegen/vue3_master_normal");
+    }
+
+    @Test
+    public void testExecute_vue3_master_erp() {
+        testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_ERP, "codegen/vue3_master_erp");
+    }
+
+    @Test
+    public void testExecute_vue3_master_inner() {
+        testExecute_vue3_master(CodegenTemplateTypeEnum.MASTER_INNER, "codegen/vue3_master_inner");
+    }
+
+    private void testExecute_vue3_master(CodegenTemplateTypeEnum templateType,
+                                         String path) {
+        // 准备参数
+        CodegenTableDO table = getTable("student")
+                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
+                .setTemplateType(templateType.getType());
+        List<CodegenColumnDO> columns = getColumnList("student");
+        // 准备参数(子表)
+        CodegenTableDO contactTable = getTable("contact")
+                .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
+                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
+                .setSubJoinColumnId(100L).setSubJoinMany(true);
+        List<CodegenColumnDO> contactColumns = getColumnList("contact");
+        // 准备参数(班主任)
+        CodegenTableDO teacherTable = getTable("teacher")
+                .setTemplateType(CodegenTemplateTypeEnum.SUB.getType())
+                .setFrontType(CodegenFrontTypeEnum.VUE3.getType())
+                .setSubJoinColumnId(200L).setSubJoinMany(false);
+        List<CodegenColumnDO> teacherColumns = getColumnList("teacher");
+
+        // 调用
+        Map<String, String> result = codegenEngine.execute(table, columns,
+                Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns));
+        // 断言
+        assertResult(result, path);
+//        writeResult(result, "/root/ruoyi-vue-pro/yudao-module-infra/yudao-module-infra-biz/src/test/resources/" + path);
+//        writeFile(result, "/Users/yunai/test/demo11.zip");
+    }
+
+}