Przeglądaj źródła

【代码优化】代码生成: vue3_vben5_antd schema 主子表标准模式和内嵌模式模板完成

puhui999 1 rok temu
rodzic
commit
dfcbcf09d4

+ 22 - 115
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/schema/views/form.vue.vm

@@ -3,6 +3,12 @@ import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleCl
 
 import { useVbenModal } from '@vben/common-ui';
 import { message, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue';
+## 特殊:主子表专属逻辑
+#if ( $table.templateType == 10 || $table.templateType == 12 )
+  #foreach ($subSimpleClassName in $subSimpleClassNames)
+  import ${subSimpleClassName}Form from './${subSimpleClassName}Form.vue'
+  #end
+#end
 
 import { computed, ref } from 'vue';
 import { $t } from '#/locales';
@@ -10,20 +16,6 @@ import { useVbenForm } from '#/adapter/form';
 import { get${simpleClassName}, create${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
 
 import { useFormSchema } from '../data';
-#if ( $table.templateType == 10 || $table.templateType == 12 )
-#if ( $subTables && $subTables.size() > 0 )
-#foreach ($subTable in $subTables)
-  #set ($index = $foreach.count - 1)
-  #set ($subSimpleClassName = $subSimpleClassNames.get($index))
-  #if ($subTable.subJoinMany) ## 一对多
-import { useVbenVxeGrid } from '#/adapter/vxe-table';
-import { use${subSimpleClassName}GridColumns } from '../data';
-  #else
-import { use${subSimpleClassName}FormSchema } from '../data';
-  #end
-#end
-#end
-#end
 
 const emit = defineEmits(['success']);
 const formData = ref<${simpleClassName}Api.${simpleClassName}>();
@@ -48,43 +40,17 @@ const getTitle = computed(() => {
 
 ## 特殊:主子表专属逻辑
 #if ( $table.templateType == 10 || $table.templateType == 12 )
-#if ( $subTables && $subTables.size() > 0 )
-/** 子表的表单 */
-const subTabsName = ref('$subClassNameVars.get(0)')
-## 特殊:主子表专属逻辑
-#foreach ($subTable in $subTables)
-  #set ($index = $foreach.count - 1)
-  #set ($subSimpleClassName = $subSimpleClassNames.get($index))
-  #set ($subClassNameVar = $subClassNameVars.get($index))
-  #if ($subTable.subJoinMany) ## 一对多
-const [${subSimpleClassName}Grid, ${subClassNameVar}GridApi] = useVbenVxeGrid({
-  gridOptions: {
-    columns: use${subSimpleClassName}GridColumns(),
-    border: true,
-    showOverflow: true,
-    autoResize: true,
-    keepSource: true,
-    rowConfig: {
-      keyField: 'id',
-    },
-    pagerConfig: {
-      enabled: false,
-    },
-    toolbarConfig: {
-      enabled: false,
-    },
-  },
-});
-  #else
-const [${subSimpleClassName}Form, ${subClassNameVar}FormApi] = useVbenForm({
-  layout: 'horizontal',
-  schema: use${subSimpleClassName}FormSchema(),
-  showDefaultActions: false
-});
+  #if ( $subTables && $subTables.size() > 0 )
+
+  /** 子表的表单 */
+  const subTabsName = ref('$subClassNameVars.get(0)')
+    #foreach ($subClassNameVar in $subClassNameVars)
+      #set ($index = $foreach.count - 1)
+      #set ($subSimpleClassName = $subSimpleClassNames.get($index))
+      const ${subClassNameVar}FormRef = ref<InstanceType<typeof ${subSimpleClassName}Form>>()
+    #end
   #end
 #end
-#end
-#end
 
 const [Form, formApi] = useVbenForm({
   layout: 'horizontal',
@@ -92,7 +58,6 @@ const [Form, formApi] = useVbenForm({
   showDefaultActions: false
 });
 
-// TODO @puhui999: 处理完成主子表标准模式和内嵌模式下的表单提交
 const [Modal, modalApi] = useVbenModal({
   async onConfirm() {
     const { valid } = await formApi.validate();
@@ -107,9 +72,9 @@ const [Modal, modalApi] = useVbenModal({
           #set ($index = $foreach.count - 1)
           #set ($subClassNameVar = $subClassNameVars.get($index))
           #if ($subTable.subJoinMany) ## 一对多
-
+            ## TODO 列表值校验?
           #else
-            const { valid: ${subClassNameVar}Valid } = await ${subClassNameVar}FormApi.validate();
+            const ${subClassNameVar}Valid = await ${subClassNameVar}FormRef.value?.validate();
             if (!${subClassNameVar}Valid) {
               subTabsName.value = '${subClassNameVar}';
               return;
@@ -129,9 +94,9 @@ const [Modal, modalApi] = useVbenModal({
           #set ($index = $foreach.count - 1)
           #set ($subClassNameVar = $subClassNameVars.get($index))
           #if ($subTable.subJoinMany)
-            data.${subClassNameVar}s = ${subClassNameVar}GridApi.grid.getData();
+            data.${subClassNameVar}s = ${subClassNameVar}FormRef.value?.getData();
           #else
-            data.${subClassNameVar} = await ${subClassNameVar}FormApi.getValues();
+            data.${subClassNameVar} = await ${subClassNameVar}FormRef.value?.getValues();
           #end
         #end
       #end
@@ -187,67 +152,9 @@ const [Modal, modalApi] = useVbenModal({
           #set ($index = $foreach.count - 1)
           #set ($subClassNameVar = $subClassNameVars.get($index))
           #set ($subSimpleClassName = $subSimpleClassNames.get($index))
-          #set ($subColumns = $subColumnsList.get($index))##当前字段数组
-          #set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
-          <Tabs.TabPane key="$subClassNameVar" tab="${subTable.classComment}">
-            #if ($subTable.subJoinMany) ## 一对多
-              <${subSimpleClassName}Grid class="mx-4">
-                #foreach($column in $subColumns)
-                  #if ($column.createOperation || $column.updateOperation)
-                    #set ($javaField = $column.javaField)
-                    #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
-                    #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
-                      <template #${javaField}="{ row }">
-                        <Input v-model:value="row.${javaField}" />
-                      </template>
-                    #elseif($column.htmlType == "imageUpload")## 图片上传
-                      <template #${javaField}="{ row }">
-                        <UploadImg v-model:value="row.${javaField}" />
-                      </template>
-                    #elseif($column.htmlType == "fileUpload")## 文件上传
-                      <template #${javaField}="{ row }">
-                        <UploadFile v-model:value="row.${javaField}" />
-                      </template>
-                    #elseif($column.htmlType == "editor")## 文本编辑器
-                      <template #${javaField}="{ row }">
-                        <Textarea v-model:value="row.${javaField}" />
-                      </template>
-                    #elseif($column.htmlType == "select")## 下拉框
-                      <template #${javaField}="{ row, column }">
-                        <Select v-model:value="row.${javaField}" class="w-full">
-                          <Select.Option v-for="option in column.params.options" :key="option.value" :value="option.value">
-                            {{ option.label }}
-                          </Select.Option>
-                        </Select>
-                      </template>
-                    #elseif($column.htmlType == "checkbox")## 多选框
-                      <template #${javaField}="{ row, column }">
-                        <CheckboxGroup v-model:value="row.${javaField}" :options="column.params.options" />
-                      </template>
-                    #elseif($column.htmlType == "radio")## 单选框
-                      <template #${javaField}="{ row, column }">
-                        <RadioGroup v-model:value="row.${javaField}" :options="column.params.options" />
-                      </template>
-                    #elseif($column.htmlType == "datetime")## 时间框
-                      <template #${javaField}="{ row }">
-                        <DatePicker
-                          v-model:value="row.${javaField}"
-                          :showTime="true"
-                          format="YYYY-MM-DD HH:mm:ss"
-                          valueFormat='x'
-                        />
-                      </template>
-                    #elseif($column.htmlType == "textarea")## 文本框
-                      <template #${javaField}="{ row }">
-                        <Textarea v-model:value="row.${javaField}" />
-                      </template>
-                    #end
-                  #end
-                #end
-              </${subSimpleClassName}Grid>
-            #else
-              <${subSimpleClassName}Form class="mx-4" />
-            #end
+          #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
+          <Tabs.TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
+            <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData?.id" />
           </Tabs.TabPane>
         #end
       </Tabs>

+ 174 - 341
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/schema/views/modules/form_sub_normal.vue.vm

@@ -2,359 +2,192 @@
 #set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
 #set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
 #set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
-#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
+#set ($subClassNameVar = $subClassNameVars.get($subIndex))
 #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
-<template>
-#if ( $subTable.subJoinMany )## 情况一:一对多,table + form
-  <el-form
-    ref="formRef"
-    :model="formData"
-    :rules="formRules"
-    v-loading="formLoading"
-    label-width="0px"
-    :inline-message="true"
-  >
-    <el-table :data="formData" class="-mt-10px">
-      <el-table-column label="序号" type="index" width="100" />
-#foreach($column in $subColumns)
-    #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 ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
-        #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
-      <el-table-column label="${comment}" min-width="150">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <el-input v-model="row.${javaField}" placeholder="请输入${comment}" />
-          </el-form-item>
-        </template>
-      </el-table-column>
-        #elseif($column.htmlType == "imageUpload")## 图片上传
-      <el-table-column label="${comment}" min-width="200">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <UploadImg v-model="row.${javaField}" />
-          </el-form-item>
-        </template>
-      </el-table-column>
-        #elseif($column.htmlType == "fileUpload")## 文件上传
-      <el-table-column label="${comment}" min-width="200">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <UploadFile v-model="row.${javaField}" />
-          </el-form-item>
-        </template>
-      </el-table-column>
-        #elseif($column.htmlType == "editor")## 文本编辑器
-      <el-table-column label="${comment}" min-width="400">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <Editor v-model="row.${javaField}" height="150px" />
-          </el-form-item>
-        </template>
-      </el-table-column>
-        #elseif($column.htmlType == "select")## 下拉框
-      <el-table-column label="${comment}" min-width="150">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <el-select v-model="row.${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>
-        </template>
-      </el-table-column>
-        #elseif($column.htmlType == "checkbox")## 多选框
-      <el-table-column label="${comment}" min-width="150">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <el-checkbox-group v-model="row.${javaField}">
-              #if ("" != $dictType)## 有数据字典
-                <el-checkbox
-                  v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
-                  :key="dict.value"
-                  :label="dict.label"
-                  :value="dict.value"
-                />
-              #else##没数据字典
-                <el-checkbox label="请选择字典生成" />
-              #end
-            </el-checkbox-group>
-          </el-form-item>
-        </template>
-      </el-table-column>
-        #elseif($column.htmlType == "radio")## 单选框
-      <el-table-column label="${comment}" min-width="150">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <el-radio-group v-model="row.${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 value="1">请选择字典生成</el-radio>
-              #end
-            </el-radio-group>
-          </el-form-item>
-        </template>
-      </el-table-column>
-        #elseif($column.htmlType == "datetime")## 时间框
-      <el-table-column label="${comment}" min-width="150">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <el-date-picker
-              v-model="row.${javaField}"
-              type="date"
-              value-format="x"
-              placeholder="选择${comment}"
-            />
-          </el-form-item>
-        </template>
-      </el-table-column>
-        #elseif($column.htmlType == "textarea")## 文本框
-      <el-table-column label="${comment}" min-width="200">
-        <template #default="{ row, $index }">
-          <el-form-item :prop="`${$index}.${javaField}`" :rules="formRules.${javaField}" class="mb-0px!">
-            <el-input v-model="row.${javaField}" type="textarea" placeholder="请输入${comment}" />
-          </el-form-item>
-        </template>
-      </el-table-column>
-        #end
-    #end
-#end
-      <el-table-column align="center" fixed="right" label="操作" width="60">
-        <template #default="{ $index }">
-          <el-button @click="handleDelete($index)" link>—</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-  </el-form>
-  <el-row justify="center" class="mt-3">
-    <el-button @click="handleAdd" round>+ 添加${subTable.classComment}</el-button>
-  </el-row>
-#else## 情况二:一对一,form
-  <el-form
-    ref="formRef"
-    :model="formData"
-    :rules="formRules"
-    label-width="100px"
-    v-loading="formLoading"
-  >
-#foreach($column in $subColumns)
-  #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 ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
-      #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.label"
-          :value="dict.value"
-        />
-              #else##没数据字典
-        <el-checkbox label="请选择字典生成" />
-              #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 value="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>
+<script lang="ts" setup>
+  import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
+
+  import { computed, ref, h, onMounted,watch,nextTick } from 'vue';
+  import { $t } from '#/locales';
+
+#if ($subTable.subJoinMany) ## 一对多
+import { Plus } from "@vben/icons";
+import { Button, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue';
+import type { OnActionClickParams } from '#/adapter/vxe-table';
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
+import { use${subSimpleClassName}GridColumns } from '../data';
+import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
+#else
+import { useVbenForm } from '#/adapter/form';
+import { use${subSimpleClassName}FormSchema } from '../data';
+import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
 #end
-</template>
-<script setup lang="ts">
-import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
-import { ${simpleClassName}Api } from '@/api/${table.moduleName}/${table.businessName}'
 
 const props = defineProps<{
-  ${subJoinColumn.javaField}: undefined // ${subJoinColumn.columnComment}(主表的关联字段)
+   ${subJoinColumn.javaField}?: any // ${subJoinColumn.columnComment}(主表的关联字段)
 }>()
-const formLoading = ref(false) // 表单的加载中
-const formData = ref([])
-const formRules = reactive({
-#foreach ($column in $subColumns)
-    #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
 
-/** 监听主表的关联字段的变化,加载对应的子表数据 */
-watch(
-  () => props.${subJoinColumn.javaField},
-  async (val) => {
-    // 1. 重置表单
-#if ( $subTable.subJoinMany )
-    formData.value = []
-#else
-    formData.value = {
-    #foreach ($column in $subColumns)
-      #if ($column.createOperation || $column.updateOperation)
-        #if ($column.htmlType == "checkbox")
-      $column.javaField: [],
-        #else
-      $column.javaField: undefined,
-        #end
-      #end
-    #end
-    }
-#end
-    // 2. val 非空,则加载数据
-    if (!val) {
-      return;
+#if ($subTable.subJoinMany) ## 一对多
+/** 表格操作按钮的回调函数 */
+function onActionClick({
+ code,
+ row,
+}: OnActionClickParams<${simpleClassName}Api.${subSimpleClassName}>) {
+  switch (code) {
+    case 'delete': {
+      onDelete(row);
+      break;
     }
-    try {
-      formLoading.value = true
-#if ( $subTable.subJoinMany )
-      formData.value = await ${simpleClassName}Api.get${subSimpleClassName}ListBy${SubJoinColumnName}(val)
-#else
-      const data = await ${simpleClassName}Api.get${subSimpleClassName}By${SubJoinColumnName}(val)
-      if (!data) {
-        return
-      }
-      formData.value = data
-#end
-    } finally {
-      formLoading.value = false
-    }
-  },
-  { immediate: true }
-)
-#if ( $subTable.subJoinMany )
-
-/** 新增按钮操作 */
-const handleAdd = () => {
-  const row = {
-#foreach ($column in $subColumns)
-    #if ($column.createOperation || $column.updateOperation)
-      #if ($column.htmlType == "checkbox")
-    $column.javaField: [],
-      #else
-    $column.javaField: undefined,
-      #end
-  #end
-#end
   }
-  row.${subJoinColumn.javaField} = props.${subJoinColumn.javaField}
-  formData.value.push(row)
 }
 
-/** 删除按钮操作 */
-const handleDelete = (index) => {
-  formData.value.splice(index, 1)
-}
-#end
+const [${subSimpleClassName}Grid, ${subClassNameVar}GridApi] = useVbenVxeGrid({
+gridOptions: {
+  columns: use${subSimpleClassName}GridColumns(onActionClick),
+  border: true,
+  showOverflow: true,
+  autoResize: true,
+  keepSource: true,
+  rowConfig: {
+    keyField: 'id',
+  },
+  pagerConfig: {
+    enabled: false,
+  },
+  toolbarConfig: {
+    enabled: false,
+  },
+},
+});
 
-/** 表单校验 */
-const validate = () => {
-  return formRef.value.validate()
+/** 删除${subTable.classComment} */
+const onDelete =  async (row: ${simpleClassName}Api.${subSimpleClassName}) => {
+  await ${subClassNameVar}GridApi.grid.remove(row);
 }
 
-/** 表单值 */
-const getData = () => {
-  return formData.value
+/** 添加${subTable.classComment} */
+const handleAdd = async () => {
+  await ${subClassNameVar}GridApi.grid.insertAt({} as ${simpleClassName}Api.${subSimpleClassName}, -1);
 }
 
-defineExpose({ validate, getData })
-</script>
+/** 提供获取表格数据的方法供父组件调用 */
+defineExpose({
+  getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => {
+    return [
+      ...${subClassNameVar}GridApi.grid.getData(),
+      ...${subClassNameVar}GridApi.grid.getInsertRecords().map((row) => {
+        delete row.id;
+        return row;
+      }),
+    ];
+  },
+});
+
+/** 监听主表的关联字段的变化,加载对应的子表数据 */
+watch(
+    () => props.${subJoinColumn.javaField},
+    async (val) => {
+      if (!val) {
+        return;
+      }
+
+      await nextTick();
+      await ${subClassNameVar}GridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
+    },
+);
+#else
+const [${subSimpleClassName}Form, ${subClassNameVar}FormApi] = useVbenForm({
+layout: 'horizontal',
+schema: use${subSimpleClassName}FormSchema(),
+showDefaultActions: false
+});
+
+/** 暴露出表单校验方法和表单值获取方法 */
+defineExpose({
+  validate: async () => {
+    const { valid } = await ${subClassNameVar}FormApi.validate();
+    return valid;
+  },
+  getValues: ${subClassNameVar}FormApi.getValues,
+});
+
+/** 监听主表的关联字段的变化,加载对应的子表数据 */
+watch(
+    () => props.${subJoinColumn.javaField},
+    async (val) => {
+      if (!val) {
+        return;
+      }
+
+      await nextTick();
+      await ${subClassNameVar}FormApi.setValues(await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
+    },
+);
+#end
+</script>
+
+<template>
+#if ($subTable.subJoinMany) ## 一对多
+  <${subSimpleClassName}Grid class="mx-4">
+      #foreach($column in $subColumns)
+          #if ($column.createOperation || $column.updateOperation)
+              #set ($javaField = $column.javaField)
+              #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
+              #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
+                <template #${javaField}="{ row }">
+                  <Input v-model:value="row.${javaField}" />
+                </template>
+              #elseif($column.htmlType == "imageUpload")## 图片上传
+                <template #${javaField}="{ row }">
+                  <UploadImg v-model:value="row.${javaField}" />
+                </template>
+              #elseif($column.htmlType == "fileUpload")## 文件上传
+                <template #${javaField}="{ row }">
+                  <UploadFile v-model:value="row.${javaField}" />
+                </template>
+              #elseif($column.htmlType == "editor")## 文本编辑器
+                <template #${javaField}="{ row }">
+                  <Textarea v-model:value="row.${javaField}" />
+                </template>
+              #elseif($column.htmlType == "select")## 下拉框
+                <template #${javaField}="{ row, column }">
+                  <Select v-model:value="row.${javaField}" class="w-full">
+                    <Select.Option v-for="option in column.params.options" :key="option.value" :value="option.value">
+                      {{ option.label }}
+                    </Select.Option>
+                  </Select>
+                </template>
+              #elseif($column.htmlType == "checkbox")## 多选框
+                <template #${javaField}="{ row, column }">
+                  <CheckboxGroup v-model:value="row.${javaField}" :options="column.params.options" />
+                </template>
+              #elseif($column.htmlType == "radio")## 单选框
+                <template #${javaField}="{ row, column }">
+                  <RadioGroup v-model:value="row.${javaField}" :options="column.params.options" />
+                </template>
+              #elseif($column.htmlType == "datetime")## 时间框
+                <template #${javaField}="{ row }">
+                  <DatePicker
+                      v-model:value="row.${javaField}"
+                      :showTime="true"
+                      format="YYYY-MM-DD HH:mm:ss"
+                      valueFormat='x'
+                  />
+                </template>
+              #elseif($column.htmlType == "textarea")## 文本框
+                <template #${javaField}="{ row }">
+                  <Textarea v-model:value="row.${javaField}" />
+                </template>
+              #end
+          #end
+      #end
+  </${subSimpleClassName}Grid>
+  <div class="flex justify-center">
+    <Button :icon="h(Plus)" type="primary" ghost @click="handleAdd" v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:create']">
+      {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
+    </Button>
+  </div>
+#else
+  <${subSimpleClassName}Form class="mx-4" />
+#end
+</template>