Commit dd6be0e59574e8f44ed7dfe5d3f86a6e017ca283

Authored by YunaiV
1 parent 69121bec

feat(mybatis): 支持 likeRightIfPresent 条件拼接

Showing 24 changed files with 3884 additions and 4 deletions
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/LambdaQueryWrapperX.java
@@ -25,6 +25,13 @@ public class LambdaQueryWrapperX<T> extends LambdaQueryWrapper<T> { @@ -25,6 +25,13 @@ public class LambdaQueryWrapperX<T> extends LambdaQueryWrapper<T> {
25 return this; 25 return this;
26 } 26 }
27 27
  28 + public LambdaQueryWrapperX<T> likeRightIfPresent(SFunction<T, ?> column, String val) {
  29 + if (StringUtils.hasText(val)) {
  30 + return (LambdaQueryWrapperX<T>) super.likeRight(column, val);
  31 + }
  32 + return this;
  33 + }
  34 +
28 public LambdaQueryWrapperX<T> inIfPresent(SFunction<T, ?> column, Collection<?> values) { 35 public LambdaQueryWrapperX<T> inIfPresent(SFunction<T, ?> column, Collection<?> values) {
29 if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) { 36 if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
30 return (LambdaQueryWrapperX<T>) super.in(column, values); 37 return (LambdaQueryWrapperX<T>) super.in(column, values);
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java
@@ -27,6 +27,13 @@ public class MPJLambdaWrapperX&lt;T&gt; extends MPJLambdaWrapper&lt;T&gt; { @@ -27,6 +27,13 @@ public class MPJLambdaWrapperX&lt;T&gt; extends MPJLambdaWrapper&lt;T&gt; {
27 return this; 27 return this;
28 } 28 }
29 29
  30 + public <S> MPJLambdaWrapperX<T> likeRightIfPresent(SFunction<S, ?> column, String val) {
  31 + if (StringUtils.hasText(val)) {
  32 + return (MPJLambdaWrapperX<T>) super.likeRight(column, val);
  33 + }
  34 + return this;
  35 + }
  36 +
30 public <S> MPJLambdaWrapperX<T> inIfPresent(SFunction<S, ?> column, Collection<?> values) { 37 public <S> MPJLambdaWrapperX<T> inIfPresent(SFunction<S, ?> column, Collection<?> values) {
31 if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) { 38 if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
32 return (MPJLambdaWrapperX<T>) super.in(column, values); 39 return (MPJLambdaWrapperX<T>) super.in(column, values);
@@ -102,7 +109,6 @@ public class MPJLambdaWrapperX&lt;T&gt; extends MPJLambdaWrapper&lt;T&gt; { @@ -102,7 +109,6 @@ public class MPJLambdaWrapperX&lt;T&gt; extends MPJLambdaWrapper&lt;T&gt; {
102 return this; 109 return this;
103 } 110 }
104 111
105 -  
106 // ========== 重写父类方法,方便链式调用 ========== 112 // ========== 重写父类方法,方便链式调用 ==========
107 113
108 @Override 114 @Override
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/QueryWrapperX.java
@@ -25,6 +25,13 @@ public class QueryWrapperX&lt;T&gt; extends QueryWrapper&lt;T&gt; { @@ -25,6 +25,13 @@ public class QueryWrapperX&lt;T&gt; extends QueryWrapper&lt;T&gt; {
25 return this; 25 return this;
26 } 26 }
27 27
  28 + public QueryWrapperX<T> likeRightIfPresent(String column, String val) {
  29 + if (StringUtils.hasText(val)) {
  30 + return (QueryWrapperX<T>) super.likeRight(column, val);
  31 + }
  32 + return this;
  33 + }
  34 +
28 public QueryWrapperX<T> inIfPresent(String column, Collection<?> values) { 35 public QueryWrapperX<T> inIfPresent(String column, Collection<?> values) {
29 if (!CollectionUtils.isEmpty(values)) { 36 if (!CollectionUtils.isEmpty(values)) {
30 return (QueryWrapperX<T>) super.in(column, values); 37 return (QueryWrapperX<T>) super.in(column, values);
@@ -95,13 +102,13 @@ public class QueryWrapperX&lt;T&gt; extends QueryWrapper&lt;T&gt; { @@ -95,13 +102,13 @@ public class QueryWrapperX&lt;T&gt; extends QueryWrapper&lt;T&gt; {
95 } 102 }
96 103
97 public QueryWrapperX<T> betweenIfPresent(String column, Object[] values) { 104 public QueryWrapperX<T> betweenIfPresent(String column, Object[] values) {
98 - if (values!= null && values.length != 0 && values[0] != null && values[1] != null) { 105 + if (values != null && values.length != 0 && values[0] != null && values[1] != null) {
99 return (QueryWrapperX<T>) super.between(column, values[0], values[1]); 106 return (QueryWrapperX<T>) super.between(column, values[0], values[1]);
100 } 107 }
101 - if (values!= null && values.length != 0 && values[0] != null) { 108 + if (values != null && values.length != 0 && values[0] != null) {
102 return (QueryWrapperX<T>) ge(column, values[0]); 109 return (QueryWrapperX<T>) ge(column, values[0]);
103 } 110 }
104 - if (values!= null && values.length != 0 && values[1] != null) { 111 + if (values != null && values.length != 0 && values[1] != null) {
105 return (QueryWrapperX<T>) le(column, values[1]); 112 return (QueryWrapperX<T>) le(column, values[1]);
106 } 113 }
107 return this; 114 return this;
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/enums/codegen/CodegenFrontTypeEnum.java
@@ -21,6 +21,9 @@ public enum CodegenFrontTypeEnum { @@ -21,6 +21,9 @@ public enum CodegenFrontTypeEnum {
21 VUE3_VBEN5_ANTD_SCHEMA(40), // Vue3 VBEN5 + ANTD + schema 模版 21 VUE3_VBEN5_ANTD_SCHEMA(40), // Vue3 VBEN5 + ANTD + schema 模版
22 VUE3_VBEN5_ANTD_GENERAL(41), // Vue3 VBEN5 + ANTD 标准模版 22 VUE3_VBEN5_ANTD_GENERAL(41), // Vue3 VBEN5 + ANTD 标准模版
23 23
  24 + VUE3_VBEN5_ANTDV_NEXT_SCHEMA(42), // Vue3 VBEN5 + Antdv Next + schema 模版
  25 + VUE3_VBEN5_ANTDV_NEXT_GENERAL(43), // Vue3 VBEN5 + Antdv Next 标准模版
  26 +
24 VUE3_VBEN5_EP_SCHEMA(50), // Vue3 VBEN5 + EP + schema 模版 27 VUE3_VBEN5_EP_SCHEMA(50), // Vue3 VBEN5 + EP + schema 模版
25 VUE3_VBEN5_EP_GENERAL(51), // Vue3 VBEN5 + EP 标准模版 28 VUE3_VBEN5_EP_GENERAL(51), // Vue3 VBEN5 + EP 标准模版
26 29
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
@@ -241,6 +241,46 @@ public class CodegenEngine { @@ -241,6 +241,46 @@ public class CodegenEngine {
241 vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue")) 241 vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
242 .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑 242 .put(CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL.getType(), vue3Vben5EpGeneralTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑
243 vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue")) 243 vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
  244 + // VUE3_VBEN5_ANTDV_NEXT_SCHEMA
  245 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/data.ts"),
  246 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/data.ts"))
  247 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/index.vue"),
  248 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
  249 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/form.vue"),
  250 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue"))
  251 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/import.vue"),
  252 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/import-form.vue"))
  253 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("api/api.ts"),
  254 + vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
  255 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑
  256 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
  257 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/form_sub_inner.vue"), // 特殊:主子表专属逻辑
  258 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
  259 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/form_sub_erp.vue"), // 特殊:主子表专属逻辑
  260 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
  261 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/list_sub_inner.vue"), // 特殊:主子表专属逻辑
  262 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
  263 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), vue3Vben5AntdvNextSchemaTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑
  264 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
  265 + // VUE3_VBEN5_ANTDV_NEXT_GENERAL
  266 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/index.vue"),
  267 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
  268 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/form.vue"),
  269 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/form.vue"))
  270 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/import.vue"),
  271 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/import-form.vue"))
  272 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("api/api.ts"),
  273 + vue3VbenFilePath("api/${table.moduleName}/${table.businessName}/index.ts"))
  274 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/form_sub_normal.vue"), // 特殊:主子表专属逻辑
  275 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
  276 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/form_sub_inner.vue"), // 特殊:主子表专属逻辑
  277 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
  278 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/form_sub_erp.vue"), // 特殊:主子表专属逻辑
  279 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-form.vue"))
  280 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/list_sub_inner.vue"), // 特殊:主子表专属逻辑
  281 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
  282 + .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), vue3Vben5AntdvNextGeneralTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑
  283 + vue3VbenFilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
244 .build(); 284 .build();
245 285
246 @Resource 286 @Resource
@@ -682,6 +722,14 @@ public class CodegenEngine { @@ -682,6 +722,14 @@ public class CodegenEngine {
682 return "codegen/vue3_vben5_ele/general/" + path + ".vm"; 722 return "codegen/vue3_vben5_ele/general/" + path + ".vm";
683 } 723 }
684 724
  725 + private static String vue3Vben5AntdvNextSchemaTemplatePath(String path) {
  726 + return "codegen/vue3_vben5_antdv_next/schema/" + path + ".vm";
  727 + }
  728 +
  729 + private static String vue3Vben5AntdvNextGeneralTemplatePath(String path) {
  730 + return "codegen/vue3_vben5_antdv_next/general/" + path + ".vm";
  731 + }
  732 +
685 private static boolean isSubTemplate(String path) { 733 private static boolean isSubTemplate(String path) {
686 return path.contains("_sub"); 734 return path.contains("_sub");
687 } 735 }
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/api/api.ts.vm 0 → 100644
  1 +import type { PageParam, PageResult } from '@vben/request';
  2 +import type { Dayjs } from 'dayjs';
  3 +
  4 +import { requestClient } from '#/api/request';
  5 +#set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
  6 +
  7 +export namespace ${simpleClassName}Api {
  8 + ## 特殊:主子表专属逻辑
  9 + #foreach ($subTable in $subTables)
  10 + #set ($index = $foreach.count - 1)
  11 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  12 + #set ($subColumns = $subColumnsList.get($index))##当前字段数组
  13 + /** ${subTable.classComment}信息 */
  14 + export interface ${subSimpleClassName} {
  15 + #foreach ($column in $subColumns)
  16 + #if ($column.createOperation || $column.updateOperation)
  17 + #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
  18 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
  19 + #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
  20 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
  21 + #else
  22 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
  23 + #end
  24 + #end
  25 + #end
  26 + }
  27 +
  28 + #end
  29 + /** ${table.classComment}信息 */
  30 + export interface ${simpleClassName} {
  31 + #foreach ($column in $columns)
  32 + #if ($column.createOperation || $column.updateOperation)
  33 + #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
  34 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
  35 + #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
  36 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
  37 + #else
  38 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
  39 + #end
  40 + #end
  41 + #end
  42 + #if ( $table.templateType == 2 )
  43 + children?: ${simpleClassName}[];
  44 + #end
  45 + ## 特殊:主子表专属逻辑
  46 + #if ( $table.templateType == 10 || $table.templateType == 12 )
  47 + #foreach ($subTable in $subTables)
  48 + #set ($index = $foreach.count - 1)
  49 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  50 + #if ( $subTable.subJoinMany )
  51 + ${subSimpleClassName.toLowerCase()}s?: ${subSimpleClassName}[]
  52 + #else
  53 + ${subSimpleClassName.toLowerCase()}?: ${subSimpleClassName}
  54 + #end
  55 + #end
  56 + #end
  57 + }
  58 +}
  59 +
  60 +#if ( $table.templateType != 2 )
  61 +/** 查询${table.classComment}分页 */
  62 +export function get${simpleClassName}Page(params: PageParam) {
  63 + return requestClient.get<PageResult<${simpleClassName}Api.${simpleClassName}>>('${baseURL}/page', { params });
  64 +}
  65 +#else
  66 +/** 查询${table.classComment}列表 */
  67 +export function get${simpleClassName}List(params: any) {
  68 + return requestClient.get<${simpleClassName}Api.${simpleClassName}[]>('${baseURL}/list', { params });
  69 +}
  70 +#end
  71 +
  72 +/** 查询${table.classComment}详情 */
  73 +export function get${simpleClassName}(id: number) {
  74 + return requestClient.get<${simpleClassName}Api.${simpleClassName}>(`${baseURL}/get?id=${id}`);
  75 +}
  76 +
  77 +/** 新增${table.classComment} */
  78 +export function create${simpleClassName}(data: ${simpleClassName}Api.${simpleClassName}) {
  79 + return requestClient.post('${baseURL}/create', data);
  80 +}
  81 +
  82 +/** 修改${table.classComment} */
  83 +export function update${simpleClassName}(data: ${simpleClassName}Api.${simpleClassName}) {
  84 + return requestClient.put('${baseURL}/update', data);
  85 +}
  86 +
  87 +/** 删除${table.classComment} */
  88 +export function delete${simpleClassName}(id: number) {
  89 + return requestClient.delete(`${baseURL}/delete?id=${id}`);
  90 +}
  91 +
  92 +#if ( $table.templateType != 2 && $deleteBatchEnable)
  93 +/** 批量删除${table.classComment} */
  94 +export function delete${simpleClassName}List(ids: number[]) {
  95 + return requestClient.delete(`${baseURL}/delete-list?ids=${ids.join(',')}`)
  96 +}
  97 +#end
  98 +
  99 +/** 导出${table.classComment} */
  100 +export function export${simpleClassName}(params: any) {
  101 + return requestClient.download('${baseURL}/export-excel', { params });
  102 +}
  103 +#if ($importEnable)
  104 +
  105 +/** 下载${table.classComment}导入模板 */
  106 +export function import${simpleClassName}Template() {
  107 + return requestClient.download('${baseURL}/get-import-template');
  108 +}
  109 +
  110 +/** 导入${table.classComment} */
  111 +export function import${simpleClassName}(data: FormData) {
  112 + return requestClient.post('${baseURL}/import', data);
  113 +}
  114 +#end
  115 +
  116 +## 特殊:主子表专属逻辑
  117 +#foreach ($subTable in $subTables)
  118 + #set ($index = $foreach.count - 1)
  119 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  120 + #set ($subPrimaryColumn = $subPrimaryColumns.get($index))##当前 primary 字段
  121 + #set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  122 + #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  123 + #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  124 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  125 + #set ($subClassNameVar = $subClassNameVars.get($index))
  126 +
  127 +// ==================== 子表($subTable.classComment) ====================
  128 +
  129 +## 情况一:MASTER_ERP 时,需要分查询页子表
  130 +#if ( $table.templateType == 11 )
  131 +/** 获得${subTable.classComment}分页 */
  132 +export function get${subSimpleClassName}Page(params: PageParam) {
  133 + return requestClient.get<PageResult<${simpleClassName}Api.${subSimpleClassName}>>(`${baseURL}/${subSimpleClassName_strikeCase}/page`, { params });
  134 +}
  135 + ## 情况二:非 MASTER_ERP 时,需要列表查询子表
  136 +#else
  137 +#if ( $subTable.subJoinMany )
  138 +/** 获得${subTable.classComment}列表 */
  139 +export function get${subSimpleClassName}ListBy${SubJoinColumnName}(${subJoinColumn.javaField}: number) {
  140 + return requestClient.get<${simpleClassName}Api.${subSimpleClassName}[]>(`${baseURL}/${subSimpleClassName_strikeCase}/list-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=${${subJoinColumn.javaField}}`);
  141 +}
  142 +#else
  143 +/** 获得${subTable.classComment} */
  144 +export function get${subSimpleClassName}By${SubJoinColumnName}(${subJoinColumn.javaField}: number) {
  145 + return requestClient.get<${simpleClassName}Api.${subSimpleClassName}>(`${baseURL}/${subSimpleClassName_strikeCase}/get-by-${subJoinColumn_strikeCase}?${subJoinColumn.javaField}=${${subJoinColumn.javaField}}`);
  146 +}
  147 +#end
  148 +#end
  149 +## 特殊:MASTER_ERP 时,支持单个的新增、修改、删除操作
  150 +#if ( $table.templateType == 11 )
  151 +/** 新增${subTable.classComment} */
  152 +export function create${subSimpleClassName}(data: ${simpleClassName}Api.${subSimpleClassName}) {
  153 + return requestClient.post(`${baseURL}/${subSimpleClassName_strikeCase}/create`, data);
  154 +}
  155 +
  156 +/** 修改${subTable.classComment} */
  157 +export function update${subSimpleClassName}(data: ${simpleClassName}Api.${subSimpleClassName}) {
  158 + return requestClient.put(`${baseURL}/${subSimpleClassName_strikeCase}/update`, data);
  159 +}
  160 +
  161 +/** 删除${subTable.classComment} */
  162 +export function delete${subSimpleClassName}(id: number) {
  163 + return requestClient.delete(`${baseURL}/${subSimpleClassName_strikeCase}/delete?id=${id}`);
  164 +}
  165 +
  166 +#if ($deleteBatchEnable)
  167 +/** 批量删除${subTable.classComment} */
  168 +export function delete${subSimpleClassName}List(ids: number[]) {
  169 + return requestClient.delete(`${baseURL}/${subSimpleClassName_strikeCase}/delete-list?ids=${ids.join(',')}`)
  170 +}
  171 +#end
  172 +
  173 +/** 获得${subTable.classComment} */
  174 +export function get${subSimpleClassName}(id: number) {
  175 + return requestClient.get<${simpleClassName}Api.${subSimpleClassName}>(`${baseURL}/${subSimpleClassName_strikeCase}/get?id=${id}`);
  176 +}
  177 +#end
  178 +#end
  179 +
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/form.vue.vm 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { Rule } from 'antdv-next/es/form';
  3 +import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
  4 +
  5 +import { computed, ref } from 'vue';
  6 +
  7 +import { useVbenModal } from '@vben/common-ui';
  8 +import { DICT_TYPE } from '@vben/constants';
  9 +import { getDictOptions } from '@vben/hooks';
  10 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  11 +import { ImageUpload, FileUpload } from "#/components/upload";
  12 +import { message, Tabs, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'antdv-next';
  13 +#if($table.templateType == 2)## 树表需要导入这些
  14 +import { get${simpleClassName}List } from '#/api/${table.moduleName}/${table.businessName}';
  15 +import { handleTree } from '@vben/utils'
  16 +#end
  17 +## 特殊:主子表专属逻辑
  18 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  19 + #foreach ($subSimpleClassName in $subSimpleClassNames)
  20 + #set ($index = $foreach.count - 1)
  21 + #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  22 + import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
  23 + #end
  24 +#end
  25 +
  26 +import { $t } from '#/locales';
  27 +import { get${simpleClassName}, create${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
  28 +
  29 +const emit = defineEmits(['success']);
  30 +
  31 +const formRef = ref();
  32 +const formData = ref<Partial<${simpleClassName}Api.${simpleClassName}>>({
  33 +#foreach ($column in $columns)
  34 + #if ($column.createOperation || $column.updateOperation)
  35 + #if ($column.htmlType == "checkbox")
  36 + $column.javaField: [],
  37 + #else
  38 + $column.javaField: undefined,
  39 + #end
  40 + #end
  41 +#end
  42 +});
  43 +const rules: Record<string, Rule[]> = {
  44 + #foreach ($column in $columns)
  45 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  46 + #set($comment=$column.columnComment)
  47 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
  48 + #end
  49 + #end
  50 +};
  51 +## 特殊:树表专属逻辑
  52 +#if ( $table.templateType == 2 )
  53 +const ${classNameVar}Tree = ref<any[]>([]) // 树形结构
  54 +#end
  55 +const getTitle = computed(() => {
  56 + return formData.value?.id
  57 + ? $t('ui.actionTitle.edit', ['${table.classComment}'])
  58 + : $t('ui.actionTitle.create', ['${table.classComment}']);
  59 +});
  60 +
  61 +## 特殊:主子表专属逻辑
  62 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  63 + #if ( $subTables && $subTables.size() > 0 )
  64 + /** 子表的表单 */
  65 + const subTabsName = ref('$subClassNameVars.get(0)')
  66 + #foreach ($subClassNameVar in $subClassNameVars)
  67 + #set ($index = $foreach.count - 1)
  68 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  69 + const ${subClassNameVar}FormRef = ref<InstanceType<typeof ${subSimpleClassName}Form>>()
  70 + #end
  71 + #end
  72 +#end
  73 +
  74 +/** 重置表单 */
  75 +function resetForm() {
  76 + formData.value = {
  77 + #foreach ($column in $columns)
  78 + #if ($column.createOperation || $column.updateOperation)
  79 + #if ($column.htmlType == "checkbox")
  80 + $column.javaField: [],
  81 + #else
  82 + $column.javaField: undefined,
  83 + #end
  84 + #end
  85 + #end
  86 + };
  87 + formRef.value?.resetFields();
  88 +}
  89 +
  90 +## 特殊:树表专属逻辑
  91 +#if ( $table.templateType == 2 )
  92 +/** 获得${table.classComment}树 */
  93 +async function get${simpleClassName}Tree() {
  94 + ${classNameVar}Tree.value = []
  95 + const data = await get${simpleClassName}List({});
  96 + data.unshift({
  97 + id: 0,
  98 + name: '顶级${table.classComment}',
  99 + });
  100 + ${classNameVar}Tree.value = handleTree(data);
  101 +}
  102 +#end
  103 +
  104 +const [Modal, modalApi] = useVbenModal({
  105 + async onConfirm() {
  106 + await formRef.value?.validate();
  107 + ## 特殊:主子表专属逻辑
  108 + #if ( $table.templateType == 10 || $table.templateType == 12 )
  109 + #if ( $subTables && $subTables.size() > 0 )
  110 + // 校验子表单
  111 + #foreach ($subTable in $subTables)
  112 + #set ($index = $foreach.count - 1)
  113 + #set ($subClassNameVar = $subClassNameVars.get($index))
  114 + #if ($subTable.subJoinMany) ## 一对多
  115 + ## TODO 列表值校验?
  116 + #else
  117 + try {
  118 + await ${subClassNameVar}FormRef.value?.validate()
  119 + } catch (e) {
  120 + subTabsName.value = '${subClassNameVar}'
  121 + return
  122 + }
  123 + #end
  124 + #end
  125 + #end
  126 + #end
  127 + modalApi.lock();
  128 + // 提交表单
  129 + const data = formData.value as ${simpleClassName}Api.${simpleClassName};
  130 + ## 特殊:主子表专属逻辑
  131 + #if ( $table.templateType == 10 || $table.templateType == 12 )
  132 + #if ( $subTables && $subTables.size() > 0 )
  133 + // 拼接子表的数据
  134 + #foreach ($subTable in $subTables)
  135 + #set ($index = $foreach.count - 1)
  136 + #set ($subClassNameVar = $subClassNameVars.get($index))
  137 + #if ($subTable.subJoinMany)
  138 + data.${subClassNameVar}s = ${subClassNameVar}FormRef.value?.getData();
  139 + #else
  140 + data.${subClassNameVar} = ${subClassNameVar}FormRef.value?.getValues();
  141 + #end
  142 + #end
  143 + #end
  144 + #end
  145 + try {
  146 + await (formData.value?.id ? update${simpleClassName}(data) : create${simpleClassName}(data));
  147 + // 关闭并提示
  148 + await modalApi.close();
  149 + emit('success');
  150 + message.success({
  151 + content: $t('ui.actionMessage.operationSuccess'),
  152 + });
  153 + } finally {
  154 + modalApi.unlock();
  155 + }
  156 + },
  157 + async onOpenChange(isOpen: boolean) {
  158 + if (!isOpen) {
  159 + resetForm()
  160 + return;
  161 + }
  162 + // 加载数据
  163 + let data = modalApi.getData<${simpleClassName}Api.${simpleClassName}>();
  164 + if (!data) {
  165 + return;
  166 + }
  167 + if (data.id) {
  168 + modalApi.lock();
  169 + try {
  170 + data = await get${simpleClassName}(data.id);
  171 + } finally {
  172 + modalApi.unlock();
  173 + }
  174 + }
  175 + formData.value = data;
  176 +#if ( $table.templateType == 2 )
  177 + // 加载树数据
  178 + await get${simpleClassName}Tree()
  179 +#end
  180 + },
  181 +});
  182 +</script>
  183 +
  184 +<template>
  185 + <Modal :title="getTitle">
  186 + <Form
  187 + ref="formRef"
  188 + :model="formData"
  189 + :rules="rules"
  190 + :label-col="{ span: 5 }"
  191 + :wrapper-col="{ span: 18 }"
  192 + >
  193 + #foreach($column in $columns)
  194 + #if ($column.createOperation || $column.updateOperation)
  195 + #set ($dictType = $column.dictType)
  196 + #set ($javaField = $column.javaField)
  197 + #set ($javaType = $column.javaType)
  198 + #set ($comment = $column.columnComment)
  199 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  200 + #set ($dictMethod = "number")
  201 + #elseif ($javaType == "String")
  202 + #set ($dictMethod = "string")
  203 + #elseif ($javaType == "Boolean")
  204 + #set ($dictMethod = "boolean")
  205 + #end
  206 + #if ( $table.templateType == 2 && $column.id == $treeParentColumn.id )
  207 + <Form.Item label="${comment}" name="${javaField}">
  208 + <TreeSelect
  209 + v-model:value="formData.${javaField}"
  210 + :treeData="${classNameVar}Tree"
  211 + #if ($treeNameColumn.javaField == "name")
  212 + :fieldNames="{
  213 + label: 'name',
  214 + value: 'id',
  215 + children: 'children',
  216 + }"
  217 + #else
  218 + :fieldNames="{
  219 + label: '$treeNameColumn.javaField',
  220 + value: 'id',
  221 + children: 'children',
  222 + }"
  223 + #end
  224 + checkable
  225 + treeDefaultExpandAll
  226 + placeholder="请选择${comment}"
  227 + />
  228 + </Form.Item>
  229 + #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  230 + <Form.Item label="${comment}" name="${javaField}">
  231 + <Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  232 + </Form.Item>
  233 + #elseif($column.htmlType == "imageUpload")## 图片上传
  234 + <Form.Item label="${comment}" name="${javaField}">
  235 + <ImageUpload v-model:value="formData.${javaField}" />
  236 + </Form.Item>
  237 + #elseif($column.htmlType == "fileUpload")## 文件上传
  238 + <Form.Item label="${comment}" name="${javaField}">
  239 + <FileUpload v-model:value="formData.${javaField}" />
  240 + </Form.Item>
  241 + #elseif($column.htmlType == "editor")## 文本编辑器
  242 + <Form.Item label="${comment}" name="${javaField}">
  243 + <RichTextarea v-model="formData.${javaField}" height="500px" />
  244 + </Form.Item>
  245 + #elseif($column.htmlType == "select")## 下拉框
  246 + <Form.Item label="${comment}" name="${javaField}">
  247 + <Select v-model:value="formData.${javaField}" placeholder="请选择${comment}">
  248 + #if ("" != $dictType)## 有数据字典
  249 + <SelectOption
  250 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  251 + :key="dict.value"
  252 + :value="dict.value"
  253 + >
  254 + {{ dict.label }}
  255 + </SelectOption>
  256 + #else##没数据字典
  257 + <SelectOption label="请选择字典生成" value="" />
  258 + #end
  259 + </Select>
  260 + </Form.Item>
  261 + #elseif($column.htmlType == "checkbox")## 多选框
  262 + <Form.Item label="${comment}" name="${javaField}">
  263 + <CheckboxGroup v-model:value="formData.${javaField}">
  264 + #if ("" != $dictType)## 有数据字典
  265 + <Checkbox
  266 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  267 + :key="dict.value"
  268 + :value="dict.value"
  269 + >
  270 + {{ dict.label }}
  271 + </Checkbox>
  272 + #else##没数据字典
  273 + <Checkbox label="请选择字典生成" />
  274 + #end
  275 + </CheckboxGroup>
  276 + </Form.Item>
  277 + #elseif($column.htmlType == "radio")## 单选框
  278 + <Form.Item label="${comment}" name="${javaField}">
  279 + <RadioGroup v-model:value="formData.${javaField}">
  280 + #if ("" != $dictType)## 有数据字典
  281 + <Radio
  282 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  283 + :key="dict.value"
  284 + :value="dict.value"
  285 + >
  286 + {{ dict.label }}
  287 + </Radio>
  288 + #else##没数据字典
  289 + <Radio value="1">请选择字典生成</Radio>
  290 + #end
  291 + </RadioGroup>
  292 + </Form.Item>
  293 + #elseif($column.htmlType == "datetime")## 时间框
  294 + <Form.Item label="${comment}" name="${javaField}">
  295 + <DatePicker
  296 + v-model:value="formData.${javaField}"
  297 + valueFormat="x"
  298 + placeholder="选择${comment}"
  299 + />
  300 + </Form.Item>
  301 + #elseif($column.htmlType == "textarea")## 文本框
  302 + <Form.Item label="${comment}" name="${javaField}">
  303 + <TextArea v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  304 + </Form.Item>
  305 + #end
  306 + #end
  307 + #end
  308 + </Form>
  309 + ## 特殊:主子表专属逻辑
  310 + #if ( $table.templateType == 10 || $table.templateType == 12 )
  311 + <!-- 子表的表单 -->
  312 + <Tabs v-model:active-key="subTabsName">
  313 + #foreach ($subTable in $subTables)
  314 + #set ($index = $foreach.count - 1)
  315 + #set ($subClassNameVar = $subClassNameVars.get($index))
  316 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  317 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  318 + <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
  319 + <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData?.id" />
  320 + </TabPane>
  321 + #end
  322 + </Tabs>
  323 + #end
  324 + </Modal>
  325 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/import.vue.vm 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { FileType } from 'antdv-next/es/upload/interface';
  3 +
  4 +import { ref } from 'vue';
  5 +
  6 +import { useVbenModal } from '@vben/common-ui';
  7 +import { downloadFileFromBlobPart } from '@vben/utils';
  8 +
  9 +import { Button, message, Upload } from 'antdv-next';
  10 +
  11 +import { import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}';
  12 +
  13 +defineOptions({ name: '${simpleClassName}Import' });
  14 +
  15 +const emit = defineEmits(['success']);
  16 +const fileRef = ref<File | null>(null);
  17 +
  18 +const [Modal, modalApi] = useVbenModal({
  19 + async onConfirm() {
  20 + if (!fileRef.value) {
  21 + message.error('请上传文件');
  22 + return;
  23 + }
  24 + modalApi.lock();
  25 + try {
  26 + const formData = new FormData();
  27 + formData.append('file', fileRef.value);
  28 + const response: any = await import${simpleClassName}(formData);
  29 + const data = response?.data ?? response ?? {};
  30 + let text = '导入成功数量:' + (data.successCount || 0) + ';导入失败数量:' + (data.failureCount || 0) + ';';
  31 + if (data.failureRows) {
  32 + Object.keys(data.failureRows).forEach((rowNo) => {
  33 + text += '< 第' + rowNo + '行: ' + data.failureRows[rowNo] + ' >';
  34 + });
  35 + }
  36 + message.info(text);
  37 + await modalApi.close();
  38 + emit('success');
  39 + } finally {
  40 + modalApi.unlock();
  41 + }
  42 + },
  43 +});
  44 +
  45 +/** 上传前:拦截 antd Upload 的自动上传,文件存到 ref */
  46 +function beforeUpload(file: FileType) {
  47 + fileRef.value = file as unknown as File;
  48 + return false;
  49 +}
  50 +
  51 +/** 下载导入模板 */
  52 +async function handleDownload() {
  53 + const data = await import${simpleClassName}Template();
  54 + downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data });
  55 +}
  56 +</script>
  57 +
  58 +<template>
  59 + <Modal title="导入${table.classComment}" class="w-1/3">
  60 + <div class="mx-4">
  61 + <Upload :max-count="1" accept=".xls,.xlsx" :before-upload="beforeUpload">
  62 + <Button type="primary"> 选择 Excel 文件 </Button>
  63 + </Upload>
  64 + </div>
  65 + <template #prepend-footer>
  66 + <div class="flex flex-auto items-center">
  67 + <Button @click="handleDownload"> 下载导入模板 </Button>
  68 + </div>
  69 + </template>
  70 + </Modal>
  71 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/index.vue.vm 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
  3 +
  4 +import { ref, h, reactive, onMounted, nextTick } from 'vue';
  5 +
  6 +import { Page, useVbenModal } from '@vben/common-ui';
  7 +import { DICT_TYPE } from '@vben/constants';
  8 +import { getDictOptions } from '@vben/hooks';
  9 +import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table';
  10 +import { cloneDeep, downloadFileFromBlobPart, formatDateTime, isEmpty } from '@vben/utils';
  11 +import { Button, Card, message, Tabs, Pagination, Form, RangePicker, DatePicker, Select, Input } from 'antdv-next';
  12 +import ${simpleClassName}Form from './modules/form.vue';
  13 +import { Download, Plus, RefreshCw, Search, Trash2 } from '@vben/icons';
  14 +import { DictTag } from '#/components/dict-tag';
  15 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  16 +import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
  17 +
  18 +## 特殊:主子表专属逻辑
  19 +#if ( $table.templateType == 11 || $table.templateType == 12 )
  20 + #foreach ($subSimpleClassName in $subSimpleClassNames)
  21 + #set ($index = $foreach.count - 1)
  22 + #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  23 + import ${subSimpleClassName}List from './modules/${subSimpleClassName_strikeCase}-list.vue'
  24 + #end
  25 +#end
  26 +
  27 +import { $t } from '#/locales';
  28 +#if (${table.templateType} == 2)## 树表接口
  29 +import { handleTree } from '@vben/utils'
  30 +import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
  31 +#else## 标准表接口
  32 +import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}List,#end export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
  33 +#end
  34 +#if ($importEnable)
  35 +import ${simpleClassName}Import from './modules/import-form.vue';
  36 +#end
  37 +
  38 +#if ($table.templateType == 12 || $table.templateType == 11) ## 内嵌和erp情况
  39 +/** 子表的列表 */
  40 +const subTabsName = ref('$subClassNameVars.get(0)')
  41 +#if ($table.templateType == 11)
  42 +const select${simpleClassName} = ref<${simpleClassName}Api.${simpleClassName}>();
  43 +async function onCellClick({ row }: { row: ${simpleClassName}Api.${simpleClassName} }) {
  44 + select${simpleClassName}.value = row
  45 +}
  46 +#end
  47 +#end
  48 +
  49 +const loading = ref(true) // 列表的加载中
  50 +#if ( $table.templateType == 2 )
  51 +const list = ref<any[]>([]) // 树列表的数据
  52 +#else
  53 +const list = ref<${simpleClassName}Api.${simpleClassName}[]>([]) // 列表的数据
  54 +#end
  55 +
  56 +## 特殊:树表专属逻辑(树不需要分页接口)
  57 +#if ( $table.templateType != 2 )
  58 +const total = ref(0) // 列表的总页数
  59 +#end
  60 +const queryParams = reactive({
  61 +## 特殊:树表专属逻辑(树不需要分页接口)
  62 +#if ( $table.templateType != 2 )
  63 + pageNo: 1,
  64 + pageSize: 10,
  65 +#end
  66 +#foreach ($column in $columns)
  67 + #if ($column.listOperation)
  68 + #if ($column.listOperationCondition != 'BETWEEN')
  69 + $column.javaField: undefined,
  70 + #end
  71 + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
  72 + $column.javaField: undefined,
  73 + #end
  74 + #end
  75 +#end
  76 +})
  77 +const queryFormRef = ref() // 搜索的表单
  78 +const exportLoading = ref(false) // 导出的加载中
  79 +
  80 +/** 查询列表 */
  81 +async function getList() {
  82 + loading.value = true
  83 + try {
  84 + const params = cloneDeep(queryParams) as any;
  85 + #foreach ($column in $columns)
  86 + #if ($column.listOperation)
  87 + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
  88 + if (params.${column.javaField} && Array.isArray(params.${column.javaField})) {
  89 + params.${column.javaField} = (params.${column.javaField} as string[]).join(',');
  90 + }
  91 + #end
  92 + #end
  93 + #end
  94 + ## 特殊:树表专属逻辑(树不需要分页接口)
  95 + #if ( $table.templateType == 2 )
  96 + list.value = await get${simpleClassName}List(params);
  97 + #else
  98 + const data = await get${simpleClassName}Page(params)
  99 + list.value = data.list
  100 + total.value = data.total
  101 + #end
  102 + } finally {
  103 + loading.value = false
  104 + }
  105 +}
  106 +
  107 +/** 搜索按钮操作 */
  108 +function handleQuery() {
  109 +#if ( $table.templateType != 2 )
  110 + queryParams.pageNo = 1
  111 +#end
  112 + getList()
  113 +}
  114 +
  115 +/** 重置按钮操作 */
  116 +function resetQuery() {
  117 + queryFormRef.value.resetFields()
  118 + handleQuery()
  119 +}
  120 +
  121 +const [FormModal, formModalApi] = useVbenModal({
  122 + connectedComponent: ${simpleClassName}Form,
  123 + destroyOnClose: true,
  124 +});
  125 +#if ($importEnable)
  126 +const [ImportFormModal, importFormModalApi] = useVbenModal({
  127 + connectedComponent: ${simpleClassName}Import,
  128 + destroyOnClose: true,
  129 +});
  130 +
  131 +/** 导入${table.classComment} */
  132 +function handleImport() {
  133 + importFormModalApi.open();
  134 +}
  135 +#end
  136 +
  137 +/** 创建${table.classComment} */
  138 +function handleCreate() {
  139 + formModalApi.setData(null).open();
  140 +}
  141 +
  142 +/** 编辑${table.classComment} */
  143 +function handleEdit(row: ${simpleClassName}Api.${simpleClassName}) {
  144 + formModalApi.setData(row).open();
  145 +}
  146 +
  147 +#if (${table.templateType} == 2)## 树表特有:新增下级
  148 +/** 新增下级${table.classComment} */
  149 +function handleAppend(row: ${simpleClassName}Api.${simpleClassName}) {
  150 + formModalApi.setData({ ${treeParentColumn.javaField}: row.id }).open();
  151 +}
  152 +#end
  153 +
  154 +/** 删除${table.classComment} */
  155 +async function handleDelete(row: ${simpleClassName}Api.${simpleClassName}) {
  156 + const hideLoading = message.loading({
  157 + content: $t('ui.actionMessage.deleting', [row.id]),
  158 + duration: 0,
  159 + });
  160 + try {
  161 + await delete${simpleClassName}(row.id!);
  162 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  163 + await getList();
  164 + } finally {
  165 + hideLoading();
  166 + }
  167 +}
  168 +
  169 +#if ($table.templateType != 2 && $deleteBatchEnable)
  170 +/** 批量删除${table.classComment} */
  171 +async function handleDeleteBatch() {
  172 + const hideLoading = message.loading({
  173 + content: $t('ui.actionMessage.deleting'),
  174 + duration: 0,
  175 + });
  176 + try {
  177 + await delete${simpleClassName}List(checkedIds.value);
  178 + checkedIds.value = [];
  179 + message.success($t('ui.actionMessage.deleteSuccess'));
  180 + await getList();
  181 + } finally {
  182 + hideLoading();
  183 + }
  184 +}
  185 +
  186 +const checkedIds = ref<number[]>([])
  187 +function handleRowCheckboxChange({
  188 + records,
  189 +}: {
  190 + records: ${simpleClassName}Api.${simpleClassName}[];
  191 +}) {
  192 + checkedIds.value = records.map((item) => item.id!);
  193 +}
  194 +#end
  195 +
  196 +/** 导出表格 */
  197 +async function handleExport() {
  198 +try {
  199 + exportLoading.value = true;
  200 + const data = await export${simpleClassName}(queryParams);
  201 + downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data });
  202 +}finally {
  203 + exportLoading.value = false;
  204 +}
  205 +}
  206 +
  207 +
  208 +#if (${table.templateType} == 2)
  209 +/** 切换树形展开/收缩状态 */
  210 +const isExpanded = ref(true);
  211 +function handleExpand() {
  212 + isExpanded.value = !isExpanded.value;
  213 + tableRef.value?.setAllTreeExpand(isExpanded.value);
  214 +}
  215 +#end
  216 +
  217 +/** 初始化 */
  218 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  219 +onMounted(() => {
  220 + getList();
  221 +});
  222 +</script>
  223 +
  224 +<template>
  225 + <Page auto-content-height>
  226 + <FormModal @success="getList" />
  227 +#if ($importEnable)
  228 + <ImportFormModal @success="getList" />
  229 +#end
  230 +
  231 + <Card v-if="!hiddenSearchBar" class="mb-4">
  232 + <!-- 搜索工作栏 -->
  233 + <Form
  234 + :model="queryParams"
  235 + ref="queryFormRef"
  236 + layout="inline"
  237 + >
  238 + #foreach($column in $columns)
  239 + #if ($column.listOperation)
  240 + #set ($dictType = $column.dictType)
  241 + #set ($javaField = $column.javaField)
  242 + #set ($javaType = $column.javaType)
  243 + #set ($comment = $column.columnComment)
  244 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  245 + #set ($dictMethod = "number")
  246 + #elseif ($javaType == "String")
  247 + #set ($dictMethod = "string")
  248 + #elseif ($javaType == "Boolean")
  249 + #set ($dictMethod = "boolean")
  250 + #end
  251 + #if ($column.htmlType == "input")
  252 + <Form.Item label="${comment}" name="${javaField}">
  253 + <Input
  254 + v-model:value="queryParams.${javaField}"
  255 + placeholder="请输入${comment}"
  256 + allowClear
  257 + @pressEnter="handleQuery"
  258 + class="w-full"
  259 + />
  260 + </Form.Item>
  261 + #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")
  262 + <Form.Item label="${comment}" name="${javaField}">
  263 + <Select
  264 + v-model:value="queryParams.${javaField}"
  265 + placeholder="请选择${comment}"
  266 + allowClear
  267 + class="w-full"
  268 + >
  269 + #if ("" != $dictType)## 设置了 dictType 数据字典的情况
  270 + <SelectOption
  271 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  272 + :key="dict.value"
  273 + :value="dict.value"
  274 + >
  275 + {{ dict.label }}
  276 + </SelectOption>
  277 + #else## 未设置 dictType 数据字典的情况
  278 + <SelectOption label="请选择字典生成" value="" />
  279 + #end
  280 + </Select>
  281 + </Form.Item>
  282 + #elseif($column.htmlType == "datetime")
  283 + #if ($column.listOperationCondition != "BETWEEN")## 非范围
  284 + <Form.Item label="${comment}" name="${javaField}">
  285 + <DatePicker
  286 + v-model:value="queryParams.${javaField}"
  287 + valueFormat="YYYY-MM-DD"
  288 + placeholder="选择${comment}"
  289 + allowClear
  290 + class="w-full"
  291 + />
  292 + </Form.Item>
  293 + #else## 范围
  294 + <Form.Item label="${comment}" name="${javaField}">
  295 + <RangePicker
  296 + v-model:value="queryParams.${javaField}"
  297 + v-bind="getRangePickerDefaultProps()"
  298 + class="w-full"
  299 + />
  300 + </Form.Item>
  301 + #end
  302 + #end
  303 + #end
  304 + #end
  305 + <Form.Item>
  306 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  307 + <Button class="ml-2" @click="handleQuery" type="primary">
  308 + 搜索
  309 + </Button>
  310 + </Form.Item>
  311 + </Form>
  312 + </Card>
  313 +
  314 + <!-- 列表 -->
  315 + <Card title="${table.classComment}">
  316 + <template #extra>
  317 + <VbenVxeTableToolbar
  318 + ref="tableToolbarRef"
  319 + v-model:hidden-search="hiddenSearchBar"
  320 + >
  321 + #if (${table.templateType} == 2)
  322 + <Button @click="handleExpand" class="mr-2">
  323 + {{ isExpanded ? '收缩' : '展开' }}
  324 + </Button>
  325 + #end
  326 + <Button
  327 + class="ml-2"
  328 + :icon="h(Plus)"
  329 + type="primary"
  330 + @click="handleCreate"
  331 + v-access:code="['${permissionPrefix}:create']"
  332 + >
  333 + {{ $t('ui.actionTitle.create', ['${table.classComment}']) }}
  334 + </Button>
  335 +#if ($importEnable)
  336 + <Button
  337 + class="ml-2"
  338 + type="primary"
  339 + @click="handleImport"
  340 + v-access:code="['${permissionPrefix}:import']"
  341 + >
  342 + 导入
  343 + </Button>
  344 +#end
  345 + <Button
  346 + :icon="h(Download)"
  347 + type="primary"
  348 + class="ml-2"
  349 + :loading="exportLoading"
  350 + @click="handleExport"
  351 + v-access:code="['${permissionPrefix}:export']"
  352 + >
  353 + {{ $t('ui.actionTitle.export') }}
  354 + </Button>
  355 + #if ($table.templateType != 2 && $deleteBatchEnable)
  356 + <Button
  357 + :icon="h(Trash2)"
  358 + type="primary"
  359 + danger
  360 + class="ml-2"
  361 + :disabled="isEmpty(checkedIds)"
  362 + @click="handleDeleteBatch"
  363 + v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:delete']"
  364 + >
  365 + 批量删除
  366 + </Button>
  367 + #end
  368 + </VbenVxeTableToolbar>
  369 + </template>
  370 + <VxeTable
  371 + ref="tableRef"
  372 + :data="list"
  373 + #if ( $table.templateType == 2 )
  374 + :tree-config="{
  375 + parentField: '${treeParentColumn.javaField}',
  376 + rowField: 'id',
  377 + transform: true,
  378 + expandAll: true,
  379 + reserve: true,
  380 + }"
  381 + #end
  382 +#if ($table.templateType == 11) ## erp情况
  383 + @cell-click="onCellClick"
  384 + :row-config="{
  385 + keyField: 'id',
  386 + isHover: true,
  387 + isCurrent: true,
  388 + }"
  389 +#end
  390 + show-overflow
  391 + :loading="loading"
  392 +#if ($table.templateType != 2 && $deleteBatchEnable)
  393 + @checkboxAll="handleRowCheckboxChange"
  394 + @checkboxChange="handleRowCheckboxChange"
  395 +#end
  396 + >
  397 +#if ($table.templateType != 2 && $deleteBatchEnable)
  398 + <VxeColumn type="checkbox" width="40" />
  399 +#end
  400 + ## 特殊:主子表专属逻辑
  401 + #if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
  402 + <!-- 子表的列表 -->
  403 + <VxeColumn type="expand" width="60">
  404 + <template #content="{ row }">
  405 + <!-- 子表的表单 -->
  406 + <Tabs v-model:active-key="subTabsName" class="mx-8">
  407 + #foreach ($subTable in $subTables)
  408 + #set ($index = $foreach.count - 1)
  409 + #set ($subClassNameVar = $subClassNameVars.get($index))
  410 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  411 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  412 + <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
  413 + <${subSimpleClassName}List :${subJoinColumn_strikeCase}="row?.id" />
  414 + </TabPane>
  415 + #end
  416 + </Tabs>
  417 + </template>
  418 + </VxeColumn>
  419 + #end
  420 + #foreach($column in $columns)
  421 + #if ($column.listOperationResult)
  422 + #set ($dictType=$column.dictType)
  423 + #set ($javaField = $column.javaField)
  424 + #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
  425 + #set ($comment=$column.columnComment)
  426 + #if ($column.javaType == "LocalDateTime")## 时间类型
  427 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  428 + <template #default="{row}">
  429 + {{formatDateTime(row.${javaField})}}
  430 + </template>
  431 + </VxeColumn>
  432 + #elseif($column.dictType && "" != $column.dictType)## 数据字典
  433 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  434 + <template #default="{row}">
  435 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
  436 + </template>
  437 + </VxeColumn>
  438 + #elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField)
  439 + <VxeColumn field="${javaField}" title="${comment}" align="center" tree-node/>
  440 + #else
  441 + <VxeColumn field="${javaField}" title="${comment}" align="center" />
  442 + #end
  443 + #end
  444 + #end
  445 + <VxeColumn field="operation" title="操作" align="center">
  446 + <template #default="{row}">
  447 +#if ( $table.templateType == 2 )
  448 + <Button
  449 + size="small"
  450 + type="link"
  451 + @click="handleAppend(row)"
  452 + v-access:code="['${permissionPrefix}:create']"
  453 + >
  454 + 新增下级
  455 + </Button>
  456 +#end
  457 + <Button
  458 + size="small"
  459 + type="link"
  460 + @click="handleEdit(row)"
  461 + v-access:code="['${permissionPrefix}:update']"
  462 + >
  463 + {{ $t('ui.actionTitle.edit') }}
  464 + </Button>
  465 + <Button
  466 + size="small"
  467 + type="link"
  468 + danger
  469 + class="ml-2"
  470 + #if ( $table.templateType == 2 )
  471 + :disabled="!isEmpty(row?.children)"
  472 + #end
  473 + @click="handleDelete(row)"
  474 + v-access:code="['${permissionPrefix}:delete']"
  475 + >
  476 + {{ $t('ui.actionTitle.delete') }}
  477 + </Button>
  478 + </template>
  479 + </VxeColumn>
  480 + </VxeTable>
  481 +#if ( $table.templateType != 2 )
  482 + <!-- 分页 -->
  483 + <div class="mt-2 flex justify-end">
  484 + <Pagination
  485 + :total="total"
  486 + v-model:current="queryParams.pageNo"
  487 + v-model:page-size="queryParams.pageSize"
  488 + show-size-changer
  489 + @change="getList"
  490 + />
  491 + </div>
  492 +#end
  493 + </Card>
  494 +#if ($table.templateType == 11) ## erp情况
  495 + <Card>
  496 + <!-- 子表的表单 -->
  497 + <Tabs v-model:active-key="subTabsName">
  498 + #foreach ($subTable in $subTables)
  499 + #set ($index = $foreach.count - 1)
  500 + #set ($subClassNameVar = $subClassNameVars.get($index))
  501 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  502 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  503 + <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
  504 + <${subSimpleClassName}List :${subJoinColumn_strikeCase}="select${simpleClassName}?.id" />
  505 + </TabPane>
  506 + #end
  507 + </Tabs>
  508 + </Card>
  509 +#end
  510 + </Page>
  511 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_erp.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +<script lang="ts" setup>
  6 +import type { Rule } from 'antdv-next/es/form';
  7 +import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
  8 +
  9 +import { computed, ref } from 'vue';
  10 +
  11 +import { useVbenModal } from '@vben/common-ui';
  12 +import { DICT_TYPE } from '@vben/constants';
  13 +import { getDictOptions } from '@vben/hooks';
  14 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  15 +import { ImageUpload, FileUpload } from "#/components/upload";
  16 +import { message, Tabs, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'antdv-next';
  17 +
  18 +import { $t } from '#/locales';
  19 +
  20 +import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
  21 +
  22 +const emit = defineEmits(['success']);
  23 +const getTitle = computed(() => {
  24 + return formData.value?.id
  25 + ? $t('ui.actionTitle.edit', ['${subTable.classComment}'])
  26 + : $t('ui.actionTitle.create', ['${subTable.classComment}']);
  27 +});
  28 +
  29 +const formRef = ref();
  30 +const formData = ref<Partial<${simpleClassName}Api.${subSimpleClassName}>>({
  31 + #foreach ($column in $subColumns)
  32 + #if ($column.createOperation || $column.updateOperation)
  33 + #if ($column.htmlType == "checkbox")
  34 + $column.javaField: [],
  35 + #else
  36 + $column.javaField: undefined,
  37 + #end
  38 + #end
  39 + #end
  40 +});
  41 +const rules: Record<string, Rule[]> = {
  42 + #foreach ($column in $subColumns)
  43 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  44 + #set($comment=$column.columnComment)
  45 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
  46 + #end
  47 + #end
  48 +};
  49 +
  50 +const [Modal, modalApi] = useVbenModal({
  51 + async onConfirm() {
  52 + await formRef.value?.validate();
  53 +
  54 + modalApi.lock();
  55 + // 提交表单
  56 + const data = formData.value as ${simpleClassName}Api.${subSimpleClassName};
  57 + try {
  58 + await (formData.value?.id ? update${subSimpleClassName}(data) : create${subSimpleClassName}(data));
  59 + // 关闭并提示
  60 + await modalApi.close();
  61 + emit('success');
  62 + message.success({
  63 + content: $t('ui.actionMessage.operationSuccess'),
  64 + });
  65 + } finally {
  66 + modalApi.unlock();
  67 + }
  68 + },
  69 + async onOpenChange(isOpen: boolean) {
  70 + if (!isOpen) {
  71 + resetForm()
  72 + return;
  73 + }
  74 +
  75 + // 加载数据
  76 + let data = modalApi.getData<${simpleClassName}Api.${subSimpleClassName}>();
  77 + if (!data) {
  78 + return;
  79 + }
  80 + if (data.id) {
  81 + modalApi.lock();
  82 + try {
  83 + data = await get${subSimpleClassName}(data.id);
  84 + } finally {
  85 + modalApi.unlock();
  86 + }
  87 + }
  88 + // 设置到 values
  89 + formData.value = data;
  90 + },
  91 +});
  92 +
  93 +/** 重置表单 */
  94 +function resetForm(){
  95 + formData.value = {
  96 + #foreach ($column in $subColumns)
  97 + #if ($column.createOperation || $column.updateOperation)
  98 + #if ($column.htmlType == "checkbox")
  99 + $column.javaField: [],
  100 + #else
  101 + $column.javaField: undefined,
  102 + #end
  103 + #end
  104 + #end
  105 + };
  106 + formRef.value?.resetFields();
  107 +}
  108 +</script>
  109 +
  110 +<template>
  111 + <Modal :title="getTitle">
  112 + <Form
  113 + ref="formRef"
  114 + :model="formData"
  115 + :rules="rules"
  116 + :label-col="{ span: 5 }"
  117 + :wrapper-col="{ span: 18 }"
  118 + >
  119 + #foreach($column in $subColumns)
  120 + #if ($column.createOperation || $column.updateOperation)
  121 + #set ($dictType = $column.dictType)
  122 + #set ($javaField = $column.javaField)
  123 + #set ($javaType = $column.javaType)
  124 + #set ($comment = $column.columnComment)
  125 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  126 + #set ($dictMethod = "number")
  127 + #elseif ($javaType == "String")
  128 + #set ($dictMethod = "string")
  129 + #elseif ($javaType == "Boolean")
  130 + #set ($dictMethod = "boolean")
  131 + #end
  132 + #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  133 + <Form.Item label="${comment}" name="${javaField}">
  134 + <Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  135 + </Form.Item>
  136 + #elseif($column.htmlType == "imageUpload")## 图片上传
  137 + <Form.Item label="${comment}" name="${javaField}">
  138 + <ImageUpload v-model:value="formData.${javaField}" />
  139 + </Form.Item>
  140 + #elseif($column.htmlType == "fileUpload")## 文件上传
  141 + <Form.Item label="${comment}" name="${javaField}">
  142 + <FileUpload v-model:value="formData.${javaField}" />
  143 + </Form.Item>
  144 + #elseif($column.htmlType == "editor")## 文本编辑器
  145 + <Form.Item label="${comment}" name="${javaField}">
  146 + <RichTextarea v-model="formData.${javaField}" height="500px" />
  147 + </Form.Item>
  148 + #elseif($column.htmlType == "select")## 下拉框
  149 + <Form.Item label="${comment}" name="${javaField}">
  150 + <Select v-model:value="formData.${javaField}" placeholder="请选择${comment}">
  151 + #if ("" != $dictType)## 有数据字典
  152 + <SelectOption
  153 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  154 + :key="dict.value"
  155 + :value="dict.value"
  156 + >
  157 + {{ dict.label }}
  158 + </SelectOption>
  159 + #else##没数据字典
  160 + <SelectOption label="请选择字典生成" value="" />
  161 + #end
  162 + </Select>
  163 + </Form.Item>
  164 + #elseif($column.htmlType == "checkbox")## 多选框
  165 + <Form.Item label="${comment}" name="${javaField}">
  166 + <CheckboxGroup v-model:value="formData.${javaField}">
  167 + #if ("" != $dictType)## 有数据字典
  168 + <Checkbox
  169 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  170 + :key="dict.value"
  171 + :value="dict.value"
  172 + >
  173 + {{ dict.label }}
  174 + </Checkbox>
  175 + #else##没数据字典
  176 + <Checkbox label="请选择字典生成" />
  177 + #end
  178 + </CheckboxGroup>
  179 + </Form.Item>
  180 + #elseif($column.htmlType == "radio")## 单选框
  181 + <Form.Item label="${comment}" name="${javaField}">
  182 + <RadioGroup v-model:value="formData.${javaField}">
  183 + #if ("" != $dictType)## 有数据字典
  184 + <Radio
  185 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  186 + :key="dict.value"
  187 + :value="dict.value"
  188 + >
  189 + {{ dict.label }}
  190 + </Radio>
  191 + #else##没数据字典
  192 + <Radio value="1">请选择字典生成</Radio>
  193 + #end
  194 + </RadioGroup>
  195 + </Form.Item>
  196 + #elseif($column.htmlType == "datetime")## 时间框
  197 + <Form.Item label="${comment}" name="${javaField}">
  198 + <DatePicker
  199 + v-model:value="formData.${javaField}"
  200 + valueFormat="x"
  201 + placeholder="选择${comment}"
  202 + />
  203 + </Form.Item>
  204 + #elseif($column.htmlType == "textarea")## 文本框
  205 + <Form.Item label="${comment}" name="${javaField}">
  206 + <TextArea v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  207 + </Form.Item>
  208 + #end
  209 + #end
  210 + #end
  211 + </Form>
  212 + </Modal>
  213 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_inner.vue.vm 0 → 100644
  1 +## 主表的 normal 和 inner 使用相同的 form 表单
  2 +#parse("codegen/vue3_vben5_antd/general/views/modules/form_sub_normal.vue.vm")
0 \ No newline at end of file 3 \ No newline at end of file
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_normal.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +#set ($subClassNameVar = $subClassNameVars.get($subIndex))
  6 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  7 +<script lang="ts" setup>
  8 +import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
  9 +
  10 +import { computed, ref, h, onMounted, watch, nextTick } from 'vue';
  11 +
  12 +import { DICT_TYPE } from '@vben/constants';
  13 +import { getDictOptions } from '@vben/hooks';
  14 +
  15 +import { message, Tabs, Form, Input, TextArea, Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'antdv-next';
  16 +import { $t } from '#/locales';
  17 +
  18 +#if ($subTable.subJoinMany) ## 一对多
  19 +import type { VxeTableInstance } from '#/adapter/vxe-table';
  20 +import { Plus } from "@vben/icons";
  21 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  22 +import { ImageUpload, FileUpload } from "#/components/upload";
  23 +import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
  24 +#else
  25 +import type { Rule } from 'antdv-next/es/form';
  26 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  27 +import { ImageUpload, FileUpload } from "#/components/upload";
  28 +import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
  29 +#end
  30 +
  31 +const props = defineProps<{
  32 + ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
  33 +}>()
  34 +
  35 +#if ($subTable.subJoinMany) ## 一对多
  36 +const list = ref<${simpleClassName}Api.${subSimpleClassName}[]>([]) // 列表的数据
  37 +const tableRef = ref<VxeTableInstance>();
  38 +
  39 +/** 添加${subTable.classComment} */
  40 +async function handleAdd() {
  41 + await tableRef.value?.insertAt({} as ${simpleClassName}Api.${subSimpleClassName}, -1);
  42 +}
  43 +
  44 +/** 删除${subTable.classComment} */
  45 +async function handleDelete(row: ${simpleClassName}Api.${subSimpleClassName}) {
  46 + await tableRef.value?.remove(row);
  47 +}
  48 +
  49 +/** 提供获取表格数据的方法供父组件调用 */
  50 +defineExpose({
  51 + getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => {
  52 + const data = list.value as ${simpleClassName}Api.${subSimpleClassName}[];
  53 + const removeRecords = tableRef.value?.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
  54 + const insertRecords = tableRef.value?.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
  55 + return [
  56 + ...data.filter(
  57 + (row) => !removeRecords.some((removed) => removed.id === row.id),
  58 + ),
  59 + ...insertRecords.map((row: any) => ({ ...row, id: undefined })),
  60 + ];
  61 + },
  62 +});
  63 +
  64 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  65 +watch(
  66 + () => props.${subJoinColumn.javaField},
  67 + async (val) => {
  68 + if (!val) {
  69 + return;
  70 + }
  71 + list.value = await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
  72 + },
  73 + { immediate: true },
  74 +);
  75 +#else
  76 +const formRef = ref();
  77 +const formData = ref<Partial<${simpleClassName}Api.${subSimpleClassName}>>({
  78 + #foreach ($column in $subColumns)
  79 + #if ($column.createOperation || $column.updateOperation)
  80 + #if ($column.htmlType == "checkbox")
  81 + $column.javaField: [],
  82 + #else
  83 + $column.javaField: undefined,
  84 + #end
  85 + #end
  86 + #end
  87 +});
  88 +const rules: Record<string, Rule[]> = {
  89 + #foreach ($column in $subColumns)
  90 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  91 + #set($comment=$column.columnComment)
  92 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
  93 + #end
  94 + #end
  95 +};
  96 +/** 暴露出表单校验方法和表单值获取方法 */
  97 +defineExpose({
  98 + validate: async () => await formRef.value?.validate(),
  99 + getValues: ()=> formData.value,
  100 +});
  101 +
  102 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  103 +watch(
  104 + () => props.${subJoinColumn.javaField},
  105 + async (val) => {
  106 + if (!val) {
  107 + return;
  108 + }
  109 + await nextTick();
  110 + formData.value = await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
  111 + },
  112 + { immediate: true },
  113 +);
  114 +#end
  115 +</script>
  116 +
  117 +<template>
  118 +#if ($subTable.subJoinMany) ## 一对多
  119 + <VxeTable ref="tableRef" :data="list" show-overflow class="mx-4">
  120 + #foreach($column in $subColumns)
  121 + #if ($column.createOperation || $column.updateOperation)
  122 + #set ($comment = $column.columnComment)
  123 + #set ($javaField = $column.javaField)
  124 + #set ($javaType = $column.javaType)
  125 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  126 + #set ($dictMethod = "number")
  127 + #elseif ($javaType == "String")
  128 + #set ($dictMethod = "string")
  129 + #elseif ($javaType == "Boolean")
  130 + #set ($dictMethod = "boolean")
  131 + #end
  132 + #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  133 + #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  134 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  135 + <template #default="{ row }">
  136 + <Input v-model:value="row.${javaField}" />
  137 + </template>
  138 + </VxeColumn>
  139 + #elseif($column.htmlType == "imageUpload")## 图片上传
  140 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  141 + <template #default="{ row }">
  142 + <ImageUpload v-model:value="row.${javaField}" />
  143 + </template>
  144 + </VxeColumn>
  145 + #elseif($column.htmlType == "fileUpload")## 文件上传
  146 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  147 + <template #default="{ row }">
  148 + <FileUpload v-model:value="row.${javaField}" />
  149 + </template>
  150 + </VxeColumn>
  151 + #elseif($column.htmlType == "select")## 下拉框
  152 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  153 + <template #default="{ row }">
  154 + <Select v-model:value="row.${javaField}" placeholder="请选择${comment}">
  155 + #if ("" != $dictType)## 有数据字典
  156 + <SelectOption
  157 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  158 + :key="dict.value"
  159 + :value="dict.value"
  160 + >
  161 + {{ dict.label }}
  162 + </SelectOption>
  163 + #else##没数据字典
  164 + <SelectOption label="请选择字典生成" value="" />
  165 + #end
  166 + </Select>
  167 + </template>
  168 + </VxeColumn>
  169 + #elseif($column.htmlType == "checkbox")## 多选框
  170 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  171 + <template #default="{ row }">
  172 + <CheckboxGroup v-model:value="row.${javaField}">
  173 + #if ("" != $dictType)## 有数据字典
  174 + <Checkbox
  175 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  176 + :key="dict.value"
  177 + :value="dict.value"
  178 + >
  179 + {{ dict.label }}
  180 + </Checkbox>
  181 + #else##没数据字典
  182 + <Checkbox label="请选择字典生成" />
  183 + #end
  184 + </CheckboxGroup>
  185 + </template>
  186 + </VxeColumn>
  187 + #elseif($column.htmlType == "radio")## 单选框
  188 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  189 + <template #default="{ row }">
  190 + <RadioGroup v-model:value="row.${javaField}">
  191 + #if ("" != $dictType)## 有数据字典
  192 + <Radio
  193 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  194 + :key="dict.value"
  195 + :value="dict.value"
  196 + >
  197 + {{ dict.label }}
  198 + </Radio>
  199 + #else##没数据字典
  200 + <Radio value="1">请选择字典生成</Radio>
  201 + #end
  202 + </RadioGroup>
  203 + </template>
  204 + </VxeColumn>
  205 + #elseif($column.htmlType == "datetime")## 时间框
  206 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  207 + <template #default="{ row }">
  208 + <DatePicker
  209 + v-model:value="row.${javaField}"
  210 + :showTime="true"
  211 + format="YYYY-MM-DD HH:mm:ss"
  212 + valueFormat='x'
  213 + />
  214 + </template>
  215 + </VxeColumn>
  216 + #elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 文本框
  217 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  218 + <template #default="{ row }">
  219 + <TextArea v-model:value="row.${javaField}" />
  220 + </template>
  221 + </VxeColumn>
  222 + #end
  223 + #end
  224 + #end
  225 + <VxeColumn field="operation" title="操作" align="center">
  226 + <template #default="{ row }">
  227 + <Button
  228 + size="small"
  229 + type="link"
  230 + danger
  231 + @click="handleDelete(row)"
  232 + v-access:code="['${permissionPrefix}:delete']"
  233 + >
  234 + {{ $t('ui.actionTitle.delete') }}
  235 + </Button>
  236 + </template>
  237 + </VxeColumn>
  238 + </VxeTable>
  239 + <div class="flex justify-center mt-4">
  240 + <Button :icon="h(Plus)" type="primary" ghost @click="handleAdd" v-access:code="['${permissionPrefix}:create']">
  241 + {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
  242 + </Button>
  243 + </div>
  244 +#else
  245 + <Form
  246 + ref="formRef"
  247 + class="mx-4"
  248 + :model="formData"
  249 + :rules="rules"
  250 + :label-col="{ span: 5 }"
  251 + :wrapper-col="{ span: 18 }"
  252 + >
  253 + #foreach($column in $subColumns)
  254 + #if ($column.createOperation || $column.updateOperation)
  255 + #set ($dictType = $column.dictType)
  256 + #set ($javaField = $column.javaField)
  257 + #set ($javaType = $column.javaType)
  258 + #set ($comment = $column.columnComment)
  259 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  260 + #set ($dictMethod = "number")
  261 + #elseif ($javaType == "String")
  262 + #set ($dictMethod = "string")
  263 + #elseif ($javaType == "Boolean")
  264 + #set ($dictMethod = "boolean")
  265 + #end
  266 + #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  267 + <Form.Item label="${comment}" name="${javaField}">
  268 + <Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  269 + </Form.Item>
  270 + #elseif($column.htmlType == "imageUpload")## 图片上传
  271 + <Form.Item label="${comment}" name="${javaField}">
  272 + <ImageUpload v-model:value="formData.${javaField}" />
  273 + </Form.Item>
  274 + #elseif($column.htmlType == "fileUpload")## 文件上传
  275 + <Form.Item label="${comment}" name="${javaField}">
  276 + <FileUpload v-model:value="formData.${javaField}" />
  277 + </Form.Item>
  278 + #elseif($column.htmlType == "editor")## 文本编辑器
  279 + <Form.Item label="${comment}" name="${javaField}">
  280 + <RichTextarea v-model="formData.${javaField}" height="500px" />
  281 + </Form.Item>
  282 + #elseif($column.htmlType == "select")## 下拉框
  283 + <Form.Item label="${comment}" name="${javaField}">
  284 + <Select v-model:value="formData.${javaField}" placeholder="请选择${comment}">
  285 + #if ("" != $dictType)## 有数据字典
  286 + <SelectOption
  287 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  288 + :key="dict.value"
  289 + :value="dict.value"
  290 + >
  291 + {{ dict.label }}
  292 + </SelectOption>
  293 + #else##没数据字典
  294 + <SelectOption label="请选择字典生成" value="" />
  295 + #end
  296 + </Select>
  297 + </Form.Item>
  298 + #elseif($column.htmlType == "checkbox")## 多选框
  299 + <Form.Item label="${comment}" name="${javaField}">
  300 + <CheckboxGroup v-model:value="formData.${javaField}">
  301 + #if ("" != $dictType)## 有数据字典
  302 + <Checkbox
  303 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  304 + :key="dict.value"
  305 + :value="dict.value"
  306 + >
  307 + {{ dict.label }}
  308 + </Checkbox>
  309 + #else##没数据字典
  310 + <Checkbox label="请选择字典生成" />
  311 + #end
  312 + </CheckboxGroup>
  313 + </Form.Item>
  314 + #elseif($column.htmlType == "radio")## 单选框
  315 + <Form.Item label="${comment}" name="${javaField}">
  316 + <RadioGroup v-model:value="formData.${javaField}">
  317 + #if ("" != $dictType)## 有数据字典
  318 + <Radio
  319 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  320 + :key="dict.value"
  321 + :value="dict.value"
  322 + >
  323 + {{ dict.label }}
  324 + </Radio>
  325 + #else##没数据字典
  326 + <Radio value="1">请选择字典生成</Radio>
  327 + #end
  328 + </RadioGroup>
  329 + </Form.Item>
  330 + #elseif($column.htmlType == "datetime")## 时间框
  331 + <Form.Item label="${comment}" name="${javaField}">
  332 + <DatePicker
  333 + v-model:value="formData.${javaField}"
  334 + valueFormat="x"
  335 + placeholder="选择${comment}"
  336 + />
  337 + </Form.Item>
  338 + #elseif($column.htmlType == "textarea")## 文本框
  339 + <Form.Item label="${comment}" name="${javaField}">
  340 + <TextArea v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  341 + </Form.Item>
  342 + #end
  343 + #end
  344 + #end
  345 + </Form>
  346 +#end
  347 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_erp.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  6 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex))
  7 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  8 +<script lang="ts" setup>
  9 +import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}';
  10 +import type { VxeTableInstance } from '#/adapter/vxe-table';
  11 +
  12 +import { reactive, ref, h, nextTick, watch, onMounted } from 'vue';
  13 +
  14 +import { DICT_TYPE } from '@vben/constants';
  15 +import { getDictOptions } from '@vben/hooks';
  16 +
  17 +import { DictTag } from '#/components/dict-tag';
  18 +import { getRangePickerDefaultProps } from '#/utils/rangePickerProps';
  19 +import { VxeColumn, VxeTable } from '#/adapter/vxe-table';
  20 +import { formatDateTime } from '@vben/utils';
  21 +
  22 +#if ($table.templateType == 11) ## erp
  23 +import { useVbenModal } from '@vben/common-ui';
  24 +import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table';
  25 +import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
  26 +import { Tinymce as RichTextarea } from '#/components/tinymce';
  27 +import { ImageUpload, FileUpload } from "#/components/upload";
  28 +import { message, Button, Card, Tabs, Pagination, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, RangePicker, DatePicker, TreeSelect } from 'antdv-next';
  29 +import { Plus, Trash2 } from '@vben/icons';
  30 +import { $t } from '#/locales';
  31 +#end
  32 +
  33 +#if ($table.templateType == 11) ## erp
  34 +import { delete${subSimpleClassName},#if ($deleteBatchEnable) delete${subSimpleClassName}List,#end get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${table.businessName}';
  35 +import { isEmpty, cloneDeep } from '@vben/utils';
  36 +#else
  37 +#if ($subTable.subJoinMany) ## 一对多
  38 +import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
  39 +#else
  40 +import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
  41 +#end
  42 +#end
  43 +
  44 +const props = defineProps<{
  45 + ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
  46 +}>()
  47 +
  48 +#if ($table.templateType == 11) ## erp
  49 +const [FormModal, formModalApi] = useVbenModal({
  50 + connectedComponent: ${subSimpleClassName}Form,
  51 + destroyOnClose: true,
  52 +});
  53 +
  54 +/** 创建${subTable.classComment} */
  55 +function handleCreate() {
  56 + if (!props.${subJoinColumn.javaField}){
  57 + message.warning("请先选择一个${table.classComment}!")
  58 + return
  59 + }
  60 + formModalApi.setData({${subJoinColumn.javaField}: props.${subJoinColumn.javaField}}).open();
  61 +}
  62 +
  63 +/** 编辑${subTable.classComment} */
  64 +function handleEdit(row: ${simpleClassName}Api.${subSimpleClassName}) {
  65 + formModalApi.setData(row).open();
  66 +}
  67 +
  68 +/** 删除${subTable.classComment} */
  69 +async function handleDelete(row: ${simpleClassName}Api.${subSimpleClassName}) {
  70 + const hideLoading = message.loading({
  71 + content: $t('ui.actionMessage.deleting', [row.id]),
  72 + duration: 0,
  73 + });
  74 + try {
  75 + await delete${subSimpleClassName}(row.id!);
  76 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  77 + await getList();
  78 + } finally {
  79 + hideLoading();
  80 + }
  81 +}
  82 +
  83 +#if ($deleteBatchEnable)
  84 +/** 批量删除${subTable.classComment} */
  85 +async function handleDeleteBatch() {
  86 + const hideLoading = message.loading({
  87 + content: $t('ui.actionMessage.deleting'),
  88 + duration: 0,
  89 + });
  90 + try {
  91 + await delete${subSimpleClassName}List(checkedIds.value);
  92 + checkedIds.value = [];
  93 + message.success($t('ui.actionMessage.deleteSuccess'));
  94 + await getList();
  95 + } finally {
  96 + hideLoading();
  97 + }
  98 +}
  99 +
  100 +const checkedIds = ref<number[]>([])
  101 +function handleRowCheckboxChange({
  102 + records,
  103 +}: {
  104 + records: ${simpleClassName}Api.${subSimpleClassName}[];
  105 +}) {
  106 + checkedIds.value = records.map((item) => item.id!);
  107 +}
  108 +#end
  109 +#end
  110 +
  111 +const loading = ref(true) // 列表的加载中
  112 +const list = ref<${simpleClassName}Api.${subSimpleClassName}[]>([]) // 列表的数据
  113 +#if ($table.templateType == 11) ## erp
  114 +const total = ref(0) // 列表的总页数
  115 +#end
  116 +#if ($table.templateType == 11) ## erp
  117 +const queryFormRef = ref() // 搜索的表单
  118 +const queryParams = reactive({
  119 + pageNo: 1,
  120 + pageSize: 10,
  121 + #foreach ($column in $subColumns)
  122 + #if ($column.listOperation)
  123 + #if ($column.listOperationCondition != 'BETWEEN')
  124 + $column.javaField: undefined,
  125 + #end
  126 + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
  127 + $column.javaField: undefined,
  128 + #end
  129 + #end
  130 + #end
  131 +})
  132 +
  133 +/** 搜索按钮操作 */
  134 +function handleQuery() {
  135 + queryParams.pageNo = 1
  136 + getList()
  137 +}
  138 +
  139 +/** 重置按钮操作 */
  140 +function resetQuery() {
  141 + queryFormRef.value.resetFields()
  142 + handleQuery()
  143 +}
  144 +#end
  145 + /** 查询列表 */
  146 +async function getList() {
  147 + loading.value = true
  148 + try {
  149 + if (!props.${subJoinColumn.javaField}){
  150 + return []
  151 + }
  152 + ## 特殊:树表专属逻辑(树不需要分页接口)
  153 + #if ($table.templateType == 11) ## erp
  154 + const params = cloneDeep(queryParams) as any;
  155 + #foreach ($column in $columns)
  156 + #if ($column.listOperation)
  157 + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
  158 + if (params.${column.javaField} && Array.isArray(params.${column.javaField})) {
  159 + params.${column.javaField} = (params.${column.javaField} as string[]).join(',');
  160 + }
  161 + #end
  162 + #end
  163 + #end
  164 + params.${subJoinColumn.javaField} = props.${subJoinColumn.javaField};
  165 + const data = await get${subSimpleClassName}Page(params)
  166 + list.value = data.list
  167 + total.value = data.total
  168 + #else
  169 + #if ($subTable.subJoinMany) ## 一对多
  170 + list.value = await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
  171 + #else
  172 + list.value = [await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)];
  173 + #end
  174 + #end
  175 + } finally {
  176 + loading.value = false
  177 + }
  178 +}
  179 +
  180 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  181 +watch(
  182 + () => props.${subJoinColumn.javaField},
  183 + async (val) => {
  184 + if (!val) {
  185 + return;
  186 + }
  187 + await nextTick();
  188 + await getList()
  189 + },
  190 + { immediate: true },
  191 +);
  192 +
  193 +#if ($table.templateType == 11) ## erp
  194 +/** 初始化 */
  195 +const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar();
  196 +onMounted(() => {
  197 + getList();
  198 +});
  199 +#end
  200 +</script>
  201 +
  202 +<template>
  203 + #if ($table.templateType == 11) ## erp
  204 + <FormModal @success="getList" />
  205 + <div class="h-[600px]">
  206 + <Card v-if="!hiddenSearchBar" class="mb-4">
  207 + <!-- 搜索工作栏 -->
  208 + <Form
  209 + :model="queryParams"
  210 + ref="queryFormRef"
  211 + layout="inline"
  212 + >
  213 + #foreach($column in $subColumns)
  214 + #if ($column.listOperation)
  215 + #set ($dictType = $column.dictType)
  216 + #set ($javaField = $column.javaField)
  217 + #set ($javaType = $column.javaType)
  218 + #set ($comment = $column.columnComment)
  219 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  220 + #set ($dictMethod = "number")
  221 + #elseif ($javaType == "String")
  222 + #set ($dictMethod = "string")
  223 + #elseif ($javaType == "Boolean")
  224 + #set ($dictMethod = "boolean")
  225 + #end
  226 + #if ($column.htmlType == "input")
  227 + <Form.Item label="${comment}" name="${javaField}">
  228 + <Input
  229 + v-model:value="queryParams.${javaField}"
  230 + placeholder="请输入${comment}"
  231 + allowClear
  232 + @pressEnter="handleQuery"
  233 + class="w-full"
  234 + />
  235 + </Form.Item>
  236 + #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")
  237 + <Form.Item label="${comment}" name="${javaField}">
  238 + <Select
  239 + v-model:value="queryParams.${javaField}"
  240 + placeholder="请选择${comment}"
  241 + allowClear
  242 + class="w-full"
  243 + >
  244 + #if ("" != $dictType)## 设置了 dictType 数据字典的情况
  245 + <SelectOption
  246 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  247 + :key="dict.value"
  248 + :value="dict.value"
  249 + >
  250 + {{ dict.label }}
  251 + </SelectOption>
  252 + #else## 未设置 dictType 数据字典的情况
  253 + <SelectOption label="请选择字典生成" value="" />
  254 + #end
  255 + </Select>
  256 + </Form.Item>
  257 + #elseif($column.htmlType == "datetime")
  258 + #if ($column.listOperationCondition != "BETWEEN")## 非范围
  259 + <Form.Item label="${comment}" name="${javaField}">
  260 + <DatePicker
  261 + v-model:value="queryParams.${javaField}"
  262 + valueFormat="YYYY-MM-DD"
  263 + placeholder="选择${comment}"
  264 + allowClear
  265 + class="w-full"
  266 + />
  267 + </Form.Item>
  268 + #else## 范围
  269 + <Form.Item label="${comment}" name="${javaField}">
  270 + <RangePicker
  271 + v-model:value="queryParams.${javaField}"
  272 + v-bind="getRangePickerDefaultProps()"
  273 + class="w-full"
  274 + />
  275 + </Form.Item>
  276 + #end
  277 + #end
  278 + #end
  279 + #end
  280 + <Form.Item>
  281 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  282 + <Button class="ml-2" @click="handleQuery" type="primary">
  283 + 搜索
  284 + </Button>
  285 + </Form.Item>
  286 + </Form>
  287 + </Card>
  288 +
  289 + <!-- 列表 -->
  290 + <Card title="${table.classComment}">
  291 + <template #extra>
  292 + <VbenVxeTableToolbar
  293 + ref="tableToolbarRef"
  294 + v-model:hidden-search="hiddenSearchBar"
  295 + >
  296 + <Button
  297 + class="ml-2"
  298 + :icon="h(Plus)"
  299 + type="primary"
  300 + @click="handleCreate"
  301 + v-access:code="['${permissionPrefix}:create']"
  302 + >
  303 + {{ $t('ui.actionTitle.create', ['${table.classComment}']) }}
  304 + </Button>
  305 + #if ($deleteBatchEnable)
  306 + <Button
  307 + :icon="h(Trash2)"
  308 + type="primary"
  309 + danger
  310 + class="ml-2"
  311 + :disabled="isEmpty(checkedIds)"
  312 + @click="handleDeleteBatch"
  313 + v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:delete']"
  314 + >
  315 + 批量删除
  316 + </Button>
  317 + #end
  318 + </VbenVxeTableToolbar>
  319 + </template>
  320 + <VxeTable
  321 + ref="tableRef"
  322 + :data="list"
  323 + show-overflow
  324 + :loading="loading"
  325 + #if ($deleteBatchEnable)
  326 + @checkboxAll="handleRowCheckboxChange"
  327 + @checkboxChange="handleRowCheckboxChange"
  328 + #end
  329 + >
  330 + #if ($deleteBatchEnable)
  331 + <VxeColumn type="checkbox" width="40" />
  332 + #end
  333 + #foreach($column in $subColumns)
  334 + #if ($column.listOperationResult)
  335 + #set ($dictType=$column.dictType)
  336 + #set ($javaField = $column.javaField)
  337 + #set ($comment=$column.columnComment)
  338 + #if ($column.javaType == "LocalDateTime")## 时间类型
  339 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  340 + <template #default="{row}">
  341 + {{formatDateTime(row.${javaField})}}
  342 + </template>
  343 + </VxeColumn>
  344 + #elseif($column.dictType && "" != $column.dictType)## 数据字典
  345 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  346 + <template #default="{row}">
  347 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
  348 + </template>
  349 + </VxeColumn>
  350 + #elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField)
  351 + <VxeColumn field="${javaField}" title="${comment}" align="center" tree-node/>
  352 + #else
  353 + <VxeColumn field="${javaField}" title="${comment}" align="center" />
  354 + #end
  355 + #end
  356 + #end
  357 + <VxeColumn field="operation" title="操作" align="center">
  358 + <template #default="{row}">
  359 + <Button
  360 + size="small"
  361 + type="link"
  362 + @click="handleEdit(row)"
  363 + v-access:code="['${permissionPrefix}:update']"
  364 + >
  365 + {{ $t('ui.actionTitle.edit') }}
  366 + </Button>
  367 + <Button
  368 + size="small"
  369 + type="link"
  370 + danger
  371 + class="ml-2"
  372 + @click="handleDelete(row)"
  373 + v-access:code="['${permissionPrefix}:delete']"
  374 + >
  375 + {{ $t('ui.actionTitle.delete') }}
  376 + </Button>
  377 + </template>
  378 + </VxeColumn>
  379 + </VxeTable>
  380 + <!-- 分页 -->
  381 + <div class="mt-2 flex justify-end">
  382 + <Pagination
  383 + :total="total"
  384 + v-model:current="queryParams.pageNo"
  385 + v-model:page-size="queryParams.pageSize"
  386 + show-size-changer
  387 + @change="getList"
  388 + />
  389 + </div>
  390 + </Card>
  391 + </div>
  392 + #else
  393 + <Card title="${subTable.classComment}列表">
  394 + <VxeTable
  395 + :data="list"
  396 + show-overflow
  397 + :loading="loading"
  398 + >
  399 + #foreach($column in $subColumns)
  400 + #if ($column.listOperationResult)
  401 + #set ($dictType=$column.dictType)
  402 + #set ($javaField = $column.javaField)
  403 + #set ($comment=$column.columnComment)
  404 + #if ($column.javaType == "LocalDateTime")## 时间类型
  405 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  406 + <template #default="{row}">
  407 + {{formatDateTime(row.${javaField})}}
  408 + </template>
  409 + </VxeColumn>
  410 + #elseif($column.dictType && "" != $column.dictType)## 数据字典
  411 + <VxeColumn field="${javaField}" title="${comment}" align="center">
  412 + <template #default="{row}">
  413 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
  414 + </template>
  415 + </VxeColumn>
  416 + #else
  417 + <VxeColumn field="${javaField}" title="${comment}" align="center" />
  418 + #end
  419 + #end
  420 + #end
  421 + </VxeTable>
  422 + </Card>
  423 + #end
  424 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_inner.vue.vm 0 → 100644
  1 +## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点:
  2 +## 1)inner 使用 list 不分页,erp 使用 page 分页
  3 +## 2)erp 支持单个子表的新增、修改、删除,inner 不支持
  4 +#parse("codegen/vue3_vben5_antd/general/views/modules/list_sub_erp.vue.vm")
0 \ No newline at end of file 5 \ No newline at end of file
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/api/api.ts.vm 0 → 100644
  1 +#parse("codegen/vue3_vben5_ele/schema/api/api.ts.vm")
0 \ No newline at end of file 2 \ No newline at end of file
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/data.ts.vm 0 → 100644
  1 +#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
  2 +import type { VbenFormSchema } from '#/adapter/form';
  3 +import type { VxeTableGridOptions } from '#/adapter/vxe-table';
  4 +import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
  5 +
  6 +import { DICT_TYPE } from '@vben/constants';
  7 +import { getDictOptions } from '@vben/hooks';
  8 +#if(${table.templateType} == 2)## 树表需要导入这些
  9 +import { get${simpleClassName}List } from '#/api/${table.moduleName}/${table.businessName}';
  10 +import { handleTree } from '@vben/utils';
  11 +#end
  12 +
  13 +import { getRangePickerDefaultProps } from '#/utils';
  14 +
  15 +/** 新增/修改的表单 */
  16 +export function useFormSchema(): VbenFormSchema[] {
  17 + return [
  18 + {
  19 + fieldName: 'id',
  20 + component: 'Input',
  21 + dependencies: {
  22 + triggerFields: [''],
  23 + show: () => false,
  24 + },
  25 + },
  26 +#if(${table.templateType} == 2)## 树表特有字段:上级
  27 + {
  28 + fieldName: '${treeParentColumn.javaField}',
  29 + label: '上级${table.classComment}',
  30 + component: 'ApiTreeSelect',
  31 + componentProps: {
  32 + allowClear: true,
  33 + api: async () => {
  34 + const data = await get${simpleClassName}List({});
  35 + data.unshift({
  36 + id: 0,
  37 + ${treeNameColumn.javaField}: '顶级${table.classComment}',
  38 + });
  39 + return handleTree(data);
  40 + },
  41 + labelField: '${treeNameColumn.javaField}',
  42 + valueField: 'id',
  43 + childrenField: 'children',
  44 + placeholder: '请选择上级${table.classComment}',
  45 + treeDefaultExpandAll: true,
  46 + },
  47 + rules: 'selectRequired',
  48 + },
  49 +#end
  50 +#foreach($column in $columns)
  51 +#if ($column.createOperation || $column.updateOperation)
  52 +#if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 树表中已经添加了父ID字段,这里排除
  53 + #set ($dictType = $column.dictType)
  54 + #set ($javaType = $column.javaType)
  55 + #set ($javaField = $column.javaField)
  56 + #set ($comment = $column.columnComment)
  57 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  58 + #set ($dictMethod = "number")
  59 + #elseif ($javaType == "String")
  60 + #set ($dictMethod = "string")
  61 + #elseif ($javaType == "Boolean")
  62 + #set ($dictMethod = "boolean")
  63 + #end
  64 + {
  65 + fieldName: '${javaField}',
  66 + label: '${comment}',
  67 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  68 + rules: 'required',
  69 + #end
  70 + #if ($column.htmlType == "input")
  71 + component: 'Input',
  72 + componentProps: {
  73 + placeholder: '请输入${comment}',
  74 + },
  75 + #elseif($column.htmlType == "imageUpload")## 图片上传
  76 + component: 'ImageUpload',
  77 + #elseif($column.htmlType == "fileUpload")## 文件上传
  78 + component: 'FileUpload',
  79 + #elseif($column.htmlType == "editor")## 文本编辑器
  80 + component: 'RichTextarea',
  81 + #elseif($column.htmlType == "select")## 下拉框
  82 + component: 'Select',
  83 + componentProps: {
  84 + #if ("" != $dictType)## 有数据字典
  85 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  86 + #else##没数据字典
  87 + options: [],
  88 + #end
  89 + placeholder: '请选择${comment}',
  90 + },
  91 + #elseif($column.htmlType == "checkbox")## 多选框
  92 + component: 'Checkbox',
  93 + componentProps: {
  94 + #if ("" != $dictType)## 有数据字典
  95 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  96 + #else##没数据字典
  97 + options: [],
  98 + #end
  99 + },
  100 + #elseif($column.htmlType == "radio")## 单选框
  101 + component: 'RadioGroup',
  102 + componentProps: {
  103 + #if ("" != $dictType)## 有数据字典
  104 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  105 + #else##没数据字典
  106 + options: [],
  107 + #end
  108 + buttonStyle: 'solid',
  109 + optionType: 'button',
  110 + },
  111 + #elseif($column.htmlType == "datetime")## 时间框
  112 + component: 'DatePicker',
  113 + componentProps: {
  114 + showTime: true,
  115 + format: 'YYYY-MM-DD HH:mm:ss',
  116 + valueFormat: 'x',
  117 + },
  118 + #elseif($column.htmlType == "textarea")## 文本域
  119 + component: 'TextArea',
  120 + componentProps: {
  121 + placeholder: '请输入${comment}',
  122 + },
  123 + #elseif($column.htmlType == "inputNumber")## 数字输入框
  124 + component: 'InputNumber',
  125 + componentProps: {
  126 + min: 0,
  127 + placeholder: '请输入${comment}',
  128 + },
  129 + #end
  130 + },
  131 +#end
  132 +#end
  133 +#end
  134 + ];
  135 +}
  136 +
  137 +#if ($importEnable)
  138 +/** 导入的表单 */
  139 +export function useImportFormSchema(): VbenFormSchema[] {
  140 + return [
  141 + {
  142 + fieldName: 'file',
  143 + label: '${table.classComment}数据',
  144 + component: 'Upload',
  145 + rules: 'required',
  146 + help: '仅允许导入 xls、xlsx 格式文件',
  147 + },
  148 + ];
  149 +}
  150 +
  151 +#end
  152 +/** 列表的搜索表单 */
  153 +export function useGridFormSchema(): VbenFormSchema[] {
  154 + return [
  155 +#foreach($column in $columns)
  156 +#if ($column.listOperation)
  157 + #set ($dictType = $column.dictType)
  158 + #set ($javaType = $column.javaType)
  159 + #set ($javaField = $column.javaField)
  160 + #set ($comment = $column.columnComment)
  161 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  162 + #set ($dictMethod = "number")
  163 + #elseif ($javaType == "String")
  164 + #set ($dictMethod = "string")
  165 + #elseif ($javaType == "Boolean")
  166 + #set ($dictMethod = "boolean")
  167 + #end
  168 + {
  169 + fieldName: '${javaField}',
  170 + label: '${comment}',
  171 + #if ($column.htmlType == "input" || $column.htmlType == "textarea" || $column.htmlType == "editor")
  172 + component: 'Input',
  173 + componentProps: {
  174 + allowClear: true,
  175 + placeholder: '请输入${comment}',
  176 + },
  177 + #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
  178 + component: 'Select',
  179 + componentProps: {
  180 + allowClear: true,
  181 + #if ("" != $dictType)## 设置了 dictType 数据字典的情况
  182 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  183 + #else## 未设置 dictType 数据字典的情况
  184 + options: [],
  185 + #end
  186 + placeholder: '请选择${comment}',
  187 + },
  188 + #elseif($column.htmlType == "datetime")
  189 + component: 'RangePicker',
  190 + componentProps: {
  191 + ...getRangePickerDefaultProps(),
  192 + allowClear: true,
  193 + },
  194 + #end
  195 + },
  196 +#end
  197 +#end
  198 + ];
  199 +}
  200 +
  201 +/** 列表的字段 */
  202 +export function useGridColumns(): VxeTableGridOptions<${apiName}.${simpleClassName}>['columns'] {
  203 + return [
  204 +#if ($table.templateType != 2 && $deleteBatchEnable)
  205 + { type: 'checkbox', width: 40 },
  206 +#end
  207 +#if ($table.templateType == 12) ## 内嵌情况
  208 + { type: 'expand', width: 80, slots: { content: 'expand_content' } },
  209 +#end
  210 +#foreach($column in $columns)
  211 +#if ($column.listOperationResult)
  212 + #set ($dictType = $column.dictType)
  213 + #set ($javaField = $column.javaField)
  214 + #set ($comment = $column.columnComment)
  215 + {
  216 + field: '${javaField}',
  217 + title: '${comment}',
  218 + minWidth: 120,
  219 + #if ($column.javaType == "LocalDateTime")## 时间类型
  220 + formatter: 'formatDateTime',
  221 + #elseif("" != $dictType)## 数据字典
  222 + cellRender: {
  223 + name: 'CellDict',
  224 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  225 + },
  226 + #end
  227 + #if (${table.templateType} == 2 && $column.id == $treeNameColumn.id)## 树表特有:标记树节点列
  228 + treeNode: true,
  229 + #end
  230 + },
  231 +#end
  232 +#end
  233 + {
  234 + title: '操作',
  235 + width: 200,
  236 + fixed: 'right',
  237 + slots: { default: 'actions' },
  238 + },
  239 + ];
  240 +}
  241 +
  242 +## 标准模式和内嵌模式时,主子关系一对一则生成表单schema,一对多则生成列表schema(内嵌模式时表单schema也要生成)。erp 模式时都生成
  243 +## 特殊:主子表专属逻辑
  244 +#foreach ($subTable in $subTables)
  245 + #set ($index = $foreach.count - 1)
  246 + #set ($subColumns = $subColumnsList.get($index))##当前字段数组
  247 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  248 + #set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
  249 + #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  250 +// ==================== 子表($subTable.classComment) ====================
  251 +
  252 +#if ($table.templateType == 11) ## erp 情况
  253 +/** 新增/修改的表单 */
  254 +export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
  255 + return [
  256 + {
  257 + fieldName: 'id',
  258 + component: 'Input',
  259 + dependencies: {
  260 + triggerFields: [''],
  261 + show: () => false,
  262 + },
  263 + },
  264 + #foreach($column in $subColumns)
  265 + #if ($column.createOperation || $column.updateOperation)
  266 + #if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 树表中已经添加了父ID字段,这里排除
  267 + #set ($dictType = $column.dictType)
  268 + #set ($javaType = $column.javaType)
  269 + #set ($javaField = $column.javaField)
  270 + #set ($comment = $column.columnComment)
  271 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  272 + #set ($dictMethod = "number")
  273 + #elseif ($javaType == "String")
  274 + #set ($dictMethod = "string")
  275 + #elseif ($javaType == "Boolean")
  276 + #set ($dictMethod = "boolean")
  277 + #end
  278 + #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  279 + #else
  280 + {
  281 + fieldName: '${javaField}',
  282 + label: '${comment}',
  283 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  284 + rules: 'required',
  285 + #end
  286 + #if ($column.htmlType == "input")
  287 + component: 'Input',
  288 + componentProps: {
  289 + placeholder: '请输入${comment}',
  290 + },
  291 + #elseif($column.htmlType == "imageUpload")## 图片上传
  292 + component: 'ImageUpload',
  293 + #elseif($column.htmlType == "fileUpload")## 文件上传
  294 + component: 'FileUpload',
  295 + #elseif($column.htmlType == "editor")## 文本编辑器
  296 + component: 'RichTextarea',
  297 + #elseif($column.htmlType == "select")## 下拉框
  298 + component: 'Select',
  299 + componentProps: {
  300 + #if ("" != $dictType)## 有数据字典
  301 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  302 + #else##没数据字典
  303 + options: [],
  304 + #end
  305 + placeholder: '请选择${comment}',
  306 + },
  307 + #elseif($column.htmlType == "checkbox")## 多选框
  308 + component: 'Checkbox',
  309 + componentProps: {
  310 + #if ("" != $dictType)## 有数据字典
  311 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  312 + #else##没数据字典
  313 + options: [],
  314 + #end
  315 + },
  316 + #elseif($column.htmlType == "radio")## 单选框
  317 + component: 'RadioGroup',
  318 + componentProps: {
  319 + #if ("" != $dictType)## 有数据字典
  320 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  321 + #else##没数据字典
  322 + options: [],
  323 + #end
  324 + buttonStyle: 'solid',
  325 + optionType: 'button',
  326 + },
  327 + #elseif($column.htmlType == "datetime")## 时间框
  328 + component: 'DatePicker',
  329 + componentProps: {
  330 + showTime: true,
  331 + format: 'YYYY-MM-DD HH:mm:ss',
  332 + valueFormat: 'x',
  333 + },
  334 + #elseif($column.htmlType == "textarea")## 文本域
  335 + component: 'TextArea',
  336 + componentProps: {
  337 + placeholder: '请输入${comment}',
  338 + },
  339 + #elseif($column.htmlType == "inputNumber")## 数字输入框
  340 + component: 'InputNumber',
  341 + componentProps: {
  342 + min: 0,
  343 + placeholder: '请输入${comment}',
  344 + },
  345 + #end
  346 + },
  347 + #end
  348 + #end
  349 + #end
  350 + #end
  351 + ];
  352 +}
  353 +
  354 +/** 列表的搜索表单 */
  355 +export function use${subSimpleClassName}GridFormSchema(): VbenFormSchema[] {
  356 + return [
  357 + #foreach($column in $subColumns)
  358 + #if ($column.listOperation)
  359 + #set ($dictType = $column.dictType)
  360 + #set ($javaType = $column.javaType)
  361 + #set ($javaField = $column.javaField)
  362 + #set ($comment = $column.columnComment)
  363 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  364 + #set ($dictMethod = "number")
  365 + #elseif ($javaType == "String")
  366 + #set ($dictMethod = "string")
  367 + #elseif ($javaType == "Boolean")
  368 + #set ($dictMethod = "boolean")
  369 + #end
  370 + {
  371 + fieldName: '${javaField}',
  372 + label: '${comment}',
  373 + #if ($column.htmlType == "input" || $column.htmlType == "textarea" || $column.htmlType == "editor")
  374 + component: 'Input',
  375 + componentProps: {
  376 + allowClear: true,
  377 + placeholder: '请输入${comment}',
  378 + },
  379 + #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
  380 + component: 'Select',
  381 + componentProps: {
  382 + allowClear: true,
  383 + #if ("" != $dictType)## 设置了 dictType 数据字典的情况
  384 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  385 + #else## 未设置 dictType 数据字典的情况
  386 + options: [],
  387 + #end
  388 + placeholder: '请选择${comment}',
  389 + },
  390 + #elseif($column.htmlType == "datetime")
  391 + component: 'RangePicker',
  392 + componentProps: {
  393 + ...getRangePickerDefaultProps(),
  394 + allowClear: true,
  395 + },
  396 + #end
  397 + },
  398 + #end
  399 + #end
  400 + ];
  401 +}
  402 +
  403 +/** 列表的字段 */
  404 +export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${apiName}.${subSimpleClassName}>['columns'] {
  405 + return [
  406 + #if ($table.templateType != 2 && $deleteBatchEnable)
  407 + { type: 'checkbox', width: 40 },
  408 + #end
  409 + #foreach($column in $subColumns)
  410 + #if ($column.listOperationResult)
  411 + #set ($dictType = $column.dictType)
  412 + #set ($javaField = $column.javaField)
  413 + #set ($comment = $column.columnComment)
  414 + {
  415 + field: '${javaField}',
  416 + title: '${comment}',
  417 + minWidth: 120,
  418 + #if ($column.javaType == "LocalDateTime")## 时间类型
  419 + formatter: 'formatDateTime',
  420 + #elseif("" != $dictType)## 数据字典
  421 + cellRender: {
  422 + name: 'CellDict',
  423 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  424 + },
  425 + #end
  426 + },
  427 + #end
  428 + #end
  429 + {
  430 + title: '操作',
  431 + width: 200,
  432 + fixed: 'right',
  433 + slots: { default: 'actions' },
  434 + },
  435 + ];
  436 +}
  437 +
  438 +#else
  439 + #if ($subTable.subJoinMany) ## 一对多
  440 + /** 新增/修改列表的字段 */
  441 + export function use${subSimpleClassName}GridEditColumns(): VxeTableGridOptions<${apiName}.${subSimpleClassName}>['columns'] {
  442 + return [
  443 + #foreach($column in $subColumns)
  444 + #if ($column.createOperation || $column.updateOperation)
  445 + #if (!$column.primaryKey && $column.listOperationResult && $column.id != $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  446 + #set ($dictType = $column.dictType)
  447 + #set ($javaField = $column.javaField)
  448 + #set ($comment = $column.columnComment)
  449 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  450 + #set ($dictMethod = "number")
  451 + #elseif ($javaType == "String")
  452 + #set ($dictMethod = "string")
  453 + #elseif ($javaType == "Boolean")
  454 + #set ($dictMethod = "boolean")
  455 + #end
  456 + {
  457 + field: '${javaField}',
  458 + title: '${comment}',
  459 + minWidth: 120,
  460 + slots: { default: '${javaField}' },
  461 + #if ($column.htmlType == "select" || $column.htmlType == "checkbox" || $column.htmlType == "radio")
  462 + #if ("" != $dictType)## 有数据字典
  463 + params: {
  464 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  465 + },
  466 + #else
  467 + params: {
  468 + options: [],
  469 + },
  470 + #end
  471 + #end
  472 + },
  473 + #end
  474 + #end
  475 + #end
  476 + {
  477 + title: '操作',
  478 + width: 200,
  479 + fixed: 'right',
  480 + slots: { default: 'actions' },
  481 + },
  482 + ];
  483 + }
  484 +
  485 + #else
  486 + /** 新增/修改的表单 */
  487 + export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] {
  488 + return [
  489 + {
  490 + fieldName: 'id',
  491 + component: 'Input',
  492 + dependencies: {
  493 + triggerFields: [''],
  494 + show: () => false,
  495 + },
  496 + },
  497 + #foreach($column in $subColumns)
  498 + #if ($column.createOperation || $column.updateOperation)
  499 + #if (!$column.primaryKey && ($table.templateType != 2 || ($table.templateType == 2 && $column.id != $treeParentColumn.id)))## 树表中已经添加了父ID字段,这里排除
  500 + #set ($dictType = $column.dictType)
  501 + #set ($javaType = $column.javaType)
  502 + #set ($javaField = $column.javaField)
  503 + #set ($comment = $column.columnComment)
  504 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  505 + #set ($dictMethod = "number")
  506 + #elseif ($javaType == "String")
  507 + #set ($dictMethod = "string")
  508 + #elseif ($javaType == "Boolean")
  509 + #set ($dictMethod = "boolean")
  510 + #end
  511 + #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  512 + #else
  513 + {
  514 + fieldName: '${javaField}',
  515 + label: '${comment}',
  516 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  517 + rules: 'required',
  518 + #end
  519 + #if ($column.htmlType == "input")
  520 + component: 'Input',
  521 + componentProps: {
  522 + placeholder: '请输入${comment}',
  523 + },
  524 + #elseif($column.htmlType == "imageUpload")## 图片上传
  525 + component: 'ImageUpload',
  526 + #elseif($column.htmlType == "fileUpload")## 文件上传
  527 + component: 'FileUpload',
  528 + #elseif($column.htmlType == "editor")## 文本编辑器
  529 + component: 'RichTextarea',
  530 + #elseif($column.htmlType == "select")## 下拉框
  531 + component: 'Select',
  532 + componentProps: {
  533 + #if ("" != $dictType)## 有数据字典
  534 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  535 + #else##没数据字典
  536 + options: [],
  537 + #end
  538 + placeholder: '请选择${comment}',
  539 + },
  540 + #elseif($column.htmlType == "checkbox")## 多选框
  541 + component: 'Checkbox',
  542 + componentProps: {
  543 + #if ("" != $dictType)## 有数据字典
  544 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  545 + #else##没数据字典
  546 + options: [],
  547 + #end
  548 + },
  549 + #elseif($column.htmlType == "radio")## 单选框
  550 + component: 'RadioGroup',
  551 + componentProps: {
  552 + #if ("" != $dictType)## 有数据字典
  553 + options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
  554 + #else##没数据字典
  555 + options: [],
  556 + #end
  557 + buttonStyle: 'solid',
  558 + optionType: 'button',
  559 + },
  560 + #elseif($column.htmlType == "datetime")## 时间框
  561 + component: 'DatePicker',
  562 + componentProps: {
  563 + showTime: true,
  564 + format: 'YYYY-MM-DD HH:mm:ss',
  565 + valueFormat: 'x',
  566 + },
  567 + #elseif($column.htmlType == "textarea")## 文本域
  568 + component: 'TextArea',
  569 + componentProps: {
  570 + placeholder: '请输入${comment}',
  571 + },
  572 + #elseif($column.htmlType == "inputNumber")## 数字输入框
  573 + component: 'InputNumber',
  574 + componentProps: {
  575 + min: 0,
  576 + placeholder: '请输入${comment}',
  577 + },
  578 + #end
  579 + },
  580 + #end
  581 + #end
  582 + #end
  583 + #end
  584 + ];
  585 + }
  586 +
  587 + #end
  588 + #if ($table.templateType == 12) ## 内嵌情况
  589 + /** 列表的字段 */
  590 + export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] {
  591 + return [
  592 + #foreach($column in $subColumns)
  593 + #if ($column.listOperationResult)
  594 + #set ($dictType = $column.dictType)
  595 + #set ($javaField = $column.javaField)
  596 + #set ($comment = $column.columnComment)
  597 + {
  598 + field: '${javaField}',
  599 + title: '${comment}',
  600 + minWidth: 120,
  601 + #if ($column.javaType == "LocalDateTime")## 时间类型
  602 + formatter: 'formatDateTime',
  603 + #elseif("" != $dictType)## 数据字典
  604 + cellRender: {
  605 + name: 'CellDict',
  606 + props: { type: DICT_TYPE.$dictType.toUpperCase() },
  607 + },
  608 + #end
  609 + },
  610 + #end
  611 + #end
  612 + ];
  613 + }
  614 + #end
  615 +#end
  616 +#end
0 \ No newline at end of file 617 \ No newline at end of file
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/form.vue.vm 0 → 100644
  1 +#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
  2 +<script lang="ts" setup>
  3 +import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
  4 +
  5 +import { computed, ref } from 'vue';
  6 +
  7 +import { useVbenModal } from '@vben/common-ui';
  8 +
  9 +import { message#if ($table.templateType == 11), Tabs#end } from 'antdv-next';
  10 +
  11 +import { useVbenForm } from '#/adapter/form';
  12 +import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
  13 +import { $t } from '#/locales';
  14 +## 特殊:主子表专属逻辑
  15 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  16 + #foreach ($subSimpleClassName in $subSimpleClassNames)
  17 + #set ($index = $foreach.count - 1)
  18 + #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  19 + import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
  20 + #end
  21 +#end
  22 +
  23 +import { useFormSchema } from '../data';
  24 +
  25 +const emit = defineEmits(['success']);
  26 +const formData = ref<${apiName}.${simpleClassName}>();
  27 +const getTitle = computed(() => {
  28 + return formData.value?.id
  29 + ? $t('ui.actionTitle.edit', ['${table.classComment}'])
  30 + : $t('ui.actionTitle.create', ['${table.classComment}']);
  31 +});
  32 +## 特殊:主子表专属逻辑
  33 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  34 + #if ( $subTables && $subTables.size() > 0 )
  35 +
  36 + /** 子表的表单 */
  37 + const subTabsName = ref('$subClassNameVars.get(0)')
  38 + #foreach ($subClassNameVar in $subClassNameVars)
  39 + #set ($index = $foreach.count - 1)
  40 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  41 + const ${subClassNameVar}FormRef = ref<InstanceType<typeof ${subSimpleClassName}Form>>()
  42 + #end
  43 + #end
  44 +#end
  45 +
  46 +const [Form, formApi] = useVbenForm({
  47 + commonConfig: {
  48 + componentProps: {
  49 + class: 'w-full',
  50 + },
  51 + formItemClass: 'col-span-2',
  52 + labelWidth: 80,
  53 + },
  54 + layout: 'horizontal',
  55 + schema: useFormSchema(),
  56 + showDefaultActions: false,
  57 +});
  58 +
  59 +const [Modal, modalApi] = useVbenModal({
  60 + async onConfirm() {
  61 + const { valid } = await formApi.validate();
  62 + if (!valid) {
  63 + return;
  64 + }
  65 +## 特殊:主子表专属逻辑
  66 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  67 + #if ( $subTables && $subTables.size() > 0 )
  68 + // 校验子表单
  69 + #foreach ($subTable in $subTables)
  70 + #set ($index = $foreach.count - 1)
  71 + #set ($subClassNameVar = $subClassNameVars.get($index))
  72 + #if ($subTable.subJoinMany) ## 一对多
  73 + ## TODO 列表值校验?
  74 + #else
  75 + const ${subClassNameVar}Valid = await ${subClassNameVar}FormRef.value?.validate();
  76 + if (!${subClassNameVar}Valid) {
  77 + subTabsName.value = '${subClassNameVar}';
  78 + return;
  79 + }
  80 + #end
  81 + #end
  82 + #end
  83 +#end
  84 + modalApi.lock();
  85 + // 提交表单
  86 + const data = (await formApi.getValues()) as ${apiName}.${simpleClassName};
  87 +## 特殊:主子表专属逻辑
  88 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  89 + #if ( $subTables && $subTables.size() > 0 )
  90 + // 拼接子表的数据
  91 + #foreach ($subTable in $subTables)
  92 + #set ($index = $foreach.count - 1)
  93 + #set ($subClassNameVar = $subClassNameVars.get($index))
  94 + #if ($subTable.subJoinMany)
  95 + data.${subClassNameVar}s = ${subClassNameVar}FormRef.value?.getData();
  96 + #else
  97 + data.${subClassNameVar} = await ${subClassNameVar}FormRef.value?.getValues();
  98 + #end
  99 + #end
  100 + #end
  101 +#end
  102 + try {
  103 + await (formData.value?.id ? update${simpleClassName}(data) : create${simpleClassName}(data));
  104 + // 关闭并提示
  105 + await modalApi.close();
  106 + emit('success');
  107 + message.success($t('ui.actionMessage.operationSuccess'));
  108 + } finally {
  109 + modalApi.unlock();
  110 + }
  111 + },
  112 + async onOpenChange(isOpen: boolean) {
  113 + if (!isOpen) {
  114 + formData.value = undefined;
  115 + return;
  116 + }
  117 + // 加载数据
  118 + const data = modalApi.getData<${apiName}.${simpleClassName}>();
  119 + if (!data || !data.id) {
  120 +#if (${table.templateType} == 2)## 树表特有
  121 + // 设置上级
  122 + await formApi.setValues(data);
  123 +#end
  124 + return;
  125 + }
  126 + modalApi.lock();
  127 + try {
  128 + formData.value = await get${simpleClassName}(data.id);
  129 + // 设置到 values
  130 + await formApi.setValues(formData.value);
  131 + } finally {
  132 + modalApi.unlock();
  133 + }
  134 + },
  135 +});
  136 +</script>
  137 +
  138 +<template>
  139 + <Modal :title="getTitle">
  140 + <Form class="mx-4" />
  141 +## 特殊:主子表专属逻辑
  142 +#if ( $table.templateType == 10 || $table.templateType == 12 )
  143 + <!-- 子表的表单 -->
  144 + <Tabs v-model:active-key="subTabsName">
  145 + #foreach ($subTable in $subTables)
  146 + #set ($index = $foreach.count - 1)
  147 + #set ($subClassNameVar = $subClassNameVars.get($index))
  148 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  149 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  150 + <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
  151 + <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData?.id" />
  152 + </TabPane>
  153 + #end
  154 + </Tabs>
  155 +#end
  156 + </Modal>
  157 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/import.vue.vm 0 → 100644
  1 +<script lang="ts" setup>
  2 +import type { FileType } from 'antdv-next/es/upload/interface';
  3 +
  4 +import { useVbenModal } from '@vben/common-ui';
  5 +import { downloadFileFromBlobPart } from '@vben/utils';
  6 +
  7 +import { Button, message, Upload } from 'antdv-next';
  8 +
  9 +import { useVbenForm } from '#/adapter/form';
  10 +import { import${simpleClassName}, import${simpleClassName}Template } from '#/api/${table.moduleName}/${table.businessName}';
  11 +import { $t } from '#/locales';
  12 +
  13 +import { useImportFormSchema } from '../data';
  14 +
  15 +const emit = defineEmits(['success']);
  16 +
  17 +const [Form, formApi] = useVbenForm({
  18 + commonConfig: {
  19 + formItemClass: 'col-span-2',
  20 + labelWidth: 120,
  21 + },
  22 + layout: 'horizontal',
  23 + schema: useImportFormSchema(),
  24 + showDefaultActions: false,
  25 +});
  26 +
  27 +const [Modal, modalApi] = useVbenModal({
  28 + async onConfirm() {
  29 + const { valid } = await formApi.validate();
  30 + if (!valid) {
  31 + return;
  32 + }
  33 + modalApi.lock();
  34 + // 提交表单
  35 + const data = await formApi.getValues();
  36 + try {
  37 + await import${simpleClassName}(data.file);
  38 + // 关闭并提示
  39 + await modalApi.close();
  40 + emit('success');
  41 + message.success($t('ui.actionMessage.operationSuccess'));
  42 + } finally {
  43 + modalApi.unlock();
  44 + }
  45 + },
  46 +});
  47 +
  48 +/** 上传前 */
  49 +function beforeUpload(file: FileType) {
  50 + formApi.setFieldValue('file', file);
  51 + return false;
  52 +}
  53 +
  54 +/** 下载模板 */
  55 +async function handleDownload() {
  56 + const data = await import${simpleClassName}Template();
  57 + downloadFileFromBlobPart({ fileName: '${table.classComment}导入模板.xls', source: data });
  58 +}
  59 +</script>
  60 +
  61 +<template>
  62 + <Modal title="导入${table.classComment}" class="w-1/3">
  63 + <Form class="mx-4">
  64 + <template #file>
  65 + <div class="w-full">
  66 + <Upload
  67 + :max-count="1"
  68 + accept=".xls,.xlsx"
  69 + :before-upload="beforeUpload"
  70 + >
  71 + <Button type="primary"> 选择 Excel 文件 </Button>
  72 + </Upload>
  73 + </div>
  74 + </template>
  75 + </Form>
  76 + <template #prepend-footer>
  77 + <div class="flex flex-auto items-center">
  78 + <Button @click="handleDownload"> 下载导入模板 </Button>
  79 + </div>
  80 + </template>
  81 + </Modal>
  82 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/index.vue.vm 0 → 100644
  1 +#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
  2 +<script lang="ts" setup>
  3 +import type { VxeTableGridOptions } from '#/adapter/vxe-table';
  4 +import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
  5 +
  6 +import { ref } from 'vue';
  7 +
  8 +import {#if ($table.templateType != 2 && $deleteBatchEnable) confirm,#end Page, useVbenModal } from '@vben/common-ui';
  9 +import { downloadFileFromBlobPart#if ($table.templateType != 2 && $deleteBatchEnable), isEmpty#end } from '@vben/utils';
  10 +
  11 +import { message#if ($table.templateType == 11), Tabs#end } from 'antdv-next';
  12 +
  13 +import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
  14 +#if (${table.templateType} == 2)## 树表接口
  15 +import {
  16 + delete${simpleClassName},
  17 + export${simpleClassName},
  18 + get${simpleClassName}List,
  19 +} from '#/api/${table.moduleName}/${table.businessName}';
  20 +#else## 标准表接口
  21 +import {
  22 + delete${simpleClassName},#if ($deleteBatchEnable)
  23 +
  24 + delete${simpleClassName}List,#end
  25 + export${simpleClassName},
  26 + get${simpleClassName}Page,
  27 +} from '#/api/${table.moduleName}/${table.businessName}';
  28 +#end
  29 +#if ($importEnable)
  30 +import ${simpleClassName}Import from './modules/import-form.vue';
  31 +#end
  32 +import { $t } from '#/locales';
  33 +
  34 +import { useGridColumns, useGridFormSchema } from './data';
  35 +import Form from './modules/form.vue';
  36 +## 特殊:主子表专属逻辑
  37 +#if ( $table.templateType == 11 || $table.templateType == 12 )
  38 + #foreach ($subSimpleClassName in $subSimpleClassNames)
  39 + #set ($index = $foreach.count - 1)
  40 + #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
  41 +import ${subSimpleClassName}List from './modules/${subSimpleClassName_strikeCase}-list.vue';
  42 + #end
  43 +#end
  44 +
  45 +#if ($table.templateType == 12 || $table.templateType == 11) ## 内嵌和erp情况
  46 +/** 子表的列表 */
  47 +const subTabsName = ref('$subClassNameVars.get(0)')
  48 +#if ($table.templateType == 11)
  49 +const select${simpleClassName} = ref<${apiName}.${simpleClassName}>();
  50 +#end
  51 +#end
  52 +const [FormModal, formModalApi] = useVbenModal({
  53 + connectedComponent: Form,
  54 + destroyOnClose: true,
  55 +});
  56 +#if ($importEnable)
  57 +const [ImportFormModal, importFormModalApi] = useVbenModal({
  58 + connectedComponent: ${simpleClassName}Import,
  59 + destroyOnClose: true,
  60 +});
  61 +
  62 +/** 导入${table.classComment} */
  63 +function handleImport() {
  64 + importFormModalApi.open();
  65 +}
  66 +#end
  67 +#if (${table.templateType} == 2)## 树表特有:控制表格展开收缩
  68 +
  69 +/** 切换树形展开/收缩状态 */
  70 +const isExpanded = ref(true);
  71 +function handleExpand() {
  72 + isExpanded.value = !isExpanded.value;
  73 + gridApi.grid.setAllTreeExpand(isExpanded.value);
  74 +}
  75 +#end
  76 +
  77 +/** 刷新表格 */
  78 +function handleRefresh() {
  79 +#if ($table.templateType == 12) ## 内嵌情况
  80 + gridApi.reload();
  81 +#else
  82 + gridApi.query();
  83 +#end
  84 +}
  85 +
  86 +/** 创建${table.classComment} */
  87 +function handleCreate() {
  88 + formModalApi.setData(null).open();
  89 +}
  90 +#if (${table.templateType} == 2)## 树表特有:新增下级
  91 +
  92 +/** 添加下级${table.classComment} */
  93 +function handleAppend(row: ${apiName}.${simpleClassName}) {
  94 + formModalApi.setData({ ${treeParentColumn.javaField}: row.id }).open();
  95 +}
  96 +#end
  97 +
  98 +/** 编辑${table.classComment} */
  99 +function handleEdit(row: ${apiName}.${simpleClassName}) {
  100 + formModalApi.setData(row).open();
  101 +}
  102 +
  103 +/** 删除${table.classComment} */
  104 +async function handleDelete(row: ${apiName}.${simpleClassName}) {
  105 + const hideLoading = message.loading({
  106 + content: $t('ui.actionMessage.deleting', [row.id]),
  107 + duration: 0,
  108 + });
  109 + try {
  110 + await delete${simpleClassName}(row.id!);
  111 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  112 + handleRefresh();
  113 + } finally {
  114 + hideLoading();
  115 + }
  116 +}
  117 +
  118 +#if ($table.templateType != 2 && $deleteBatchEnable)
  119 +/** 批量删除${table.classComment} */
  120 +async function handleDeleteBatch() {
  121 + await confirm($t('ui.actionMessage.deleteBatchConfirm'));
  122 + const hideLoading = message.loading({
  123 + content: $t('ui.actionMessage.deletingBatch'),
  124 + duration: 0,
  125 + });
  126 + try {
  127 + await delete${simpleClassName}List(checkedIds.value);
  128 + checkedIds.value = [];
  129 + message.success($t('ui.actionMessage.deleteSuccess'));
  130 + handleRefresh();
  131 + } finally {
  132 + hideLoading();
  133 + }
  134 +}
  135 +
  136 +const checkedIds = ref<number[]>([]);
  137 +function handleRowCheckboxChange({
  138 + records,
  139 +}: {
  140 + records: ${apiName}.${simpleClassName}[];
  141 +}) {
  142 + checkedIds.value = records.map((item) => item.id!);
  143 +}
  144 +#end
  145 +
  146 +/** 导出表格 */
  147 +async function handleExport() {
  148 + const data = await export${simpleClassName}(await gridApi.formApi.getValues());
  149 + downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data });
  150 +}
  151 +
  152 +
  153 +const [Grid, gridApi] = useVbenVxeGrid({
  154 + formOptions: {
  155 + schema: useGridFormSchema(),
  156 + },
  157 + gridOptions: {
  158 + columns: useGridColumns(),
  159 +#if (${table.templateType} == 11)
  160 + height: '600px',
  161 +#else
  162 + height: 'auto',
  163 +#end
  164 +#if (${table.templateType} == 2)## 树表设置
  165 + pagerConfig: {
  166 + enabled: false,
  167 + },
  168 +#else## 标准表设置
  169 + keepSource: true,
  170 +#end
  171 + proxyConfig: {
  172 + ajax: {
  173 +#if (${table.templateType} == 2)## 树表数据加载
  174 + query: async (_, formValues) => {
  175 + return await get${simpleClassName}List(formValues);
  176 + },
  177 +#else## 标准表数据加载
  178 + query: async ({ page }, formValues) => {
  179 + return await get${simpleClassName}Page({
  180 + pageNo: page.currentPage,
  181 + pageSize: page.pageSize,
  182 + ...formValues,
  183 + });
  184 + },
  185 +#end
  186 + },
  187 + },
  188 + rowConfig: {
  189 + keyField: 'id',
  190 + isHover: true,
  191 +#if (${table.templateType} == 11)
  192 + isCurrent: true,
  193 +#end
  194 + },
  195 + toolbarConfig: {
  196 + refresh: true,
  197 + search: true,
  198 + },
  199 +#if (${table.templateType} == 2)## 树表设置
  200 + treeConfig: {
  201 + parentField: '${treeParentColumn.javaField}',
  202 + rowField: 'id',
  203 + transform: true,
  204 + expandAll: true,
  205 + reserve: true,
  206 + },
  207 +#end
  208 + } as VxeTableGridOptions<${apiName}.${simpleClassName}>,
  209 +#if (${table.templateType} == 11 || (${table.templateType} != 2 && $deleteBatchEnable))
  210 + gridEvents: {
  211 + #if(${table.templateType} == 11)
  212 + cellClick: ({ row }: { row: ${apiName}.${simpleClassName}}) => {
  213 + select${simpleClassName}.value = row;
  214 + },
  215 + #end
  216 + #if (${table.templateType} != 2 && $deleteBatchEnable)
  217 + checkboxAll: handleRowCheckboxChange,
  218 + checkboxChange: handleRowCheckboxChange,
  219 + #end
  220 + },
  221 +#end
  222 +});
  223 +</script>
  224 +
  225 +<template>
  226 + <Page auto-content-height>
  227 + <FormModal @success="handleRefresh" />
  228 +#if ($importEnable)
  229 + <ImportFormModal @success="handleRefresh" />
  230 +#end
  231 +#if ($table.templateType == 11) ## erp情况
  232 + <div>
  233 +#end
  234 + <Grid table-title="${table.classComment}列表">
  235 + #if ($table.templateType == 12) ## 内嵌情况
  236 + <template #expand_content="{ row }">
  237 + <!-- 子表的表单 -->
  238 + <Tabs v-model:active-key="subTabsName" class="mx-8">
  239 + #foreach ($subTable in $subTables)
  240 + #set ($index = $foreach.count - 1)
  241 + #set ($subClassNameVar = $subClassNameVars.get($index))
  242 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  243 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  244 + <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
  245 + <${subSimpleClassName}List :${subJoinColumn_strikeCase}="row?.id" />
  246 + </TabPane>
  247 + #end
  248 + </Tabs>
  249 + </template>
  250 + #end
  251 + <template #toolbar-tools>
  252 + <TableAction
  253 + :actions="[
  254 + {
  255 + label: $t('ui.actionTitle.create', ['${table.classComment}']),
  256 + type: 'primary',
  257 + icon: ACTION_ICON.ADD,
  258 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
  259 + onClick: handleCreate,
  260 + },
  261 + #if (${table.templateType} == 2)## 树表特有:展开/收缩按钮
  262 + {
  263 + label: isExpanded ? '收缩' : '展开',
  264 + type: 'primary',
  265 + onClick: handleExpand,
  266 + },
  267 + #end
  268 +#if ($importEnable)
  269 + {
  270 + label: '导入',
  271 + type: 'primary',
  272 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:import'],
  273 + onClick: handleImport,
  274 + },
  275 +#end
  276 + {
  277 + label: $t('ui.actionTitle.export'),
  278 + type: 'primary',
  279 + icon: ACTION_ICON.DOWNLOAD,
  280 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:export'],
  281 + onClick: handleExport,
  282 + },
  283 + #if ($table.templateType != 2 && $deleteBatchEnable)
  284 + {
  285 + label: $t('ui.actionTitle.deleteBatch'),
  286 + type: 'primary',
  287 + danger: true,
  288 + icon: ACTION_ICON.DELETE,
  289 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
  290 + disabled: isEmpty(checkedIds),
  291 + onClick: handleDeleteBatch,
  292 + },
  293 + #end
  294 + ]"
  295 + />
  296 + </template>
  297 + <template #actions="{ row }">
  298 + <TableAction
  299 + :actions="[
  300 + #if (${table.templateType} == 2)## 树表特有:新增下级
  301 + {
  302 + label: '新增下级',
  303 + type: 'link',
  304 + icon: ACTION_ICON.ADD,
  305 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
  306 + onClick: handleAppend.bind(null, row),
  307 + },
  308 + #end
  309 + {
  310 + label: $t('common.edit'),
  311 + type: 'link',
  312 + icon: ACTION_ICON.EDIT,
  313 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:update'],
  314 + onClick: handleEdit.bind(null, row),
  315 + },
  316 + {
  317 + label: $t('common.delete'),
  318 + type: 'link',
  319 + danger: true,
  320 + icon: ACTION_ICON.DELETE,
  321 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
  322 + popConfirm: {
  323 + title: $t('ui.actionMessage.deleteConfirm', [row.id]),
  324 + confirm: handleDelete.bind(null, row),
  325 + },
  326 + },
  327 + ]"
  328 + />
  329 + </template>
  330 + </Grid>
  331 +#if ($table.templateType == 11) ## erp情况
  332 + <!-- 子表的表单 -->
  333 + <Tabs v-model:active-key="subTabsName" class="mt-2">
  334 + #foreach ($subTable in $subTables)
  335 + #set ($index = $foreach.count - 1)
  336 + #set ($subClassNameVar = $subClassNameVars.get($index))
  337 + #set ($subSimpleClassName = $subSimpleClassNames.get($index))
  338 + #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index))
  339 + <TabPane key="$subClassNameVar" tab="${subTable.classComment}" force-render>
  340 + <${subSimpleClassName}List :${subJoinColumn_strikeCase}="select${simpleClassName}?.id" />
  341 + </TabPane>
  342 + #end
  343 + </Tabs>
  344 + </div>
  345 +#end
  346 + </Page>
  347 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_erp.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
  6 +<script lang="ts" setup>
  7 + import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
  8 +
  9 + import { useVbenModal } from '@vben/common-ui';
  10 + import { message } from 'antdv-next';
  11 +
  12 + import { computed, ref } from 'vue';
  13 + import { $t } from '#/locales';
  14 + import { useVbenForm } from '#/adapter/form';
  15 + import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${table.businessName}';
  16 +
  17 + import { use${subSimpleClassName}FormSchema } from '../data';
  18 +
  19 + const emit = defineEmits(['success']);
  20 + const formData = ref<${apiName}.${subSimpleClassName}>();
  21 + const getTitle = computed(() => {
  22 + return formData.value?.id
  23 + ? $t('ui.actionTitle.edit', ['${subTable.classComment}'])
  24 + : $t('ui.actionTitle.create', ['${subTable.classComment}']);
  25 + });
  26 +
  27 + const [Form, formApi] = useVbenForm({
  28 + commonConfig: {
  29 + componentProps: {
  30 + class: 'w-full',
  31 + },
  32 + formItemClass: 'col-span-2',
  33 + labelWidth: 80,
  34 + },
  35 + layout: 'horizontal',
  36 + schema: use${subSimpleClassName}FormSchema(),
  37 + showDefaultActions: false
  38 + });
  39 +
  40 + const [Modal, modalApi] = useVbenModal({
  41 + async onConfirm() {
  42 + const { valid } = await formApi.validate();
  43 + if (!valid) {
  44 + return;
  45 + }
  46 + modalApi.lock();
  47 + // 提交表单
  48 + const data = (await formApi.getValues()) as ${apiName}.${subSimpleClassName};
  49 + data.${subJoinColumn.javaField} = formData.value?.${subJoinColumn.javaField};
  50 + try {
  51 + await (formData.value?.id ? update${subSimpleClassName}(data) : create${subSimpleClassName}(data));
  52 + // 关闭并提示
  53 + await modalApi.close();
  54 + emit('success');
  55 + message.success( $t('ui.actionMessage.operationSuccess') );
  56 + } finally {
  57 + modalApi.unlock();
  58 + }
  59 + },
  60 + async onOpenChange(isOpen: boolean) {
  61 + if (!isOpen) {
  62 + formData.value = undefined;
  63 + return;
  64 + }
  65 + // 加载数据
  66 + let data = modalApi.getData<${apiName}.${subSimpleClassName}>();
  67 + if (!data) {
  68 + return;
  69 + }
  70 + if (data.id) {
  71 + modalApi.lock();
  72 + try {
  73 + data = await get${subSimpleClassName}(data.id);
  74 + } finally {
  75 + modalApi.unlock();
  76 + }
  77 + }
  78 + // 设置到 values
  79 + formData.value = data;
  80 + await formApi.setValues(formData.value);
  81 + },
  82 + });
  83 +</script>
  84 +
  85 +<template>
  86 + <Modal :title="getTitle">
  87 + <Form class="mx-4" />
  88 + </Modal>
  89 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_inner.vue.vm 0 → 100644
  1 +## 主表的 normal 和 inner 使用相同的 form 表单
  2 +#parse("codegen/vue3_vben5_antd/schema/views/modules/form_sub_normal.vue.vm")
0 \ No newline at end of file 3 \ No newline at end of file
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_normal.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +#set ($subClassNameVar = $subClassNameVars.get($subIndex))
  6 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  7 +#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
  8 +<script lang="ts" setup>
  9 + import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
  10 +
  11 + import { computed, ref, h, onMounted, watch, nextTick } from 'vue';
  12 +
  13 + import { $t } from '#/locales';
  14 +
  15 +#if ($subTable.subJoinMany) ## 一对多
  16 +import { Plus } from "@vben/icons";
  17 +import { Button, Tabs, Checkbox, Input, TextArea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'antdv-next';
  18 +import { ImageUpload, FileUpload } from "#/components/upload";
  19 +import { useVbenVxeGrid } from '#/adapter/vxe-table';
  20 +import { use${subSimpleClassName}GridEditColumns } from '../data';
  21 +import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
  22 +#else
  23 +import { useVbenForm } from '#/adapter/form';
  24 +import { use${subSimpleClassName}FormSchema } from '../data';
  25 +import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
  26 +#end
  27 +
  28 +const props = defineProps<{
  29 + ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
  30 +}>()
  31 +
  32 +#if ($subTable.subJoinMany) ## 一对多
  33 +const [Grid, gridApi] = useVbenVxeGrid({
  34 +gridOptions: {
  35 + columns: use${subSimpleClassName}GridEditColumns(),
  36 + border: true,
  37 + showOverflow: true,
  38 + autoResize: true,
  39 + keepSource: true,
  40 + rowConfig: {
  41 + keyField: 'id',
  42 + },
  43 + pagerConfig: {
  44 + enabled: false,
  45 + },
  46 + toolbarConfig: {
  47 + enabled: false,
  48 + },
  49 +},
  50 +});
  51 +
  52 +/** 添加${subTable.classComment} */
  53 +const handleAdd = async () => {
  54 + await gridApi.grid.insertAt({} as ${apiName}.${subSimpleClassName}, -1);
  55 +}
  56 +
  57 +/** 删除${subTable.classComment} */
  58 +const handleDelete = async (row: ${apiName}.${subSimpleClassName}) => {
  59 + await gridApi.grid.remove(row);
  60 +}
  61 +
  62 +/** 提供获取表格数据的方法供父组件调用 */
  63 +defineExpose({
  64 + getData: (): ${apiName}.${subSimpleClassName}[] => {
  65 + const data = gridApi.grid.getData() as ${apiName}.${subSimpleClassName}[];
  66 + const removeRecords = gridApi.grid.getRemoveRecords() as ${apiName}.${subSimpleClassName}[];
  67 + const insertRecords = gridApi.grid.getInsertRecords() as ${apiName}.${subSimpleClassName}[];
  68 + return data
  69 + .filter((row) => !removeRecords.some((removed) => removed.id === row.id))
  70 + .concat(insertRecords.map((row: any) => ({ ...row, id: undefined })));
  71 + },
  72 +});
  73 +
  74 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  75 +watch(
  76 + () => props.${subJoinColumn.javaField},
  77 + async (val) => {
  78 + if (!val) {
  79 + return;
  80 + }
  81 + await nextTick();
  82 + await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
  83 + },
  84 + { immediate: true },
  85 +);
  86 +#else
  87 +const [Form, formApi] = useVbenForm({
  88 + commonConfig: {
  89 + componentProps: {
  90 + class: 'w-full',
  91 + },
  92 + formItemClass: 'col-span-2',
  93 + labelWidth: 80,
  94 + },
  95 + layout: 'horizontal',
  96 + schema: use${subSimpleClassName}FormSchema(),
  97 + showDefaultActions: false
  98 +});
  99 +
  100 +/** 暴露出表单校验方法和表单值获取方法 */
  101 +defineExpose({
  102 + validate: async () => {
  103 + const { valid } = await formApi.validate();
  104 + return valid;
  105 + },
  106 + getValues: formApi.getValues,
  107 +});
  108 +
  109 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  110 +watch(
  111 + () => props.${subJoinColumn.javaField},
  112 + async (val) => {
  113 + if (!val) {
  114 + return;
  115 + }
  116 + await nextTick();
  117 + await formApi.setValues(await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
  118 + },
  119 + { immediate: true },
  120 +);
  121 +#end
  122 +</script>
  123 +
  124 +<template>
  125 +#if ($subTable.subJoinMany) ## 一对多
  126 + <Grid class="mx-4">
  127 + #foreach($column in $subColumns)
  128 + #if ($column.createOperation || $column.updateOperation)
  129 + #set ($javaField = $column.javaField)
  130 + #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
  131 + #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  132 + <template #${javaField}="{ row }">
  133 + <Input v-model:value="row.${javaField}" />
  134 + </template>
  135 + #elseif($column.htmlType == "imageUpload")## 图片上传
  136 + <template #${javaField}="{ row }">
  137 + <ImageUpload v-model:value="row.${javaField}" />
  138 + </template>
  139 + #elseif($column.htmlType == "fileUpload")## 文件上传
  140 + <template #${javaField}="{ row }">
  141 + <FileUpload v-model:value="row.${javaField}" />
  142 + </template>
  143 + #elseif($column.htmlType == "select")## 下拉框
  144 + <template #${javaField}="{ row, column }">
  145 + <Select v-model:value="row.${javaField}" class="w-full">
  146 + <SelectOption v-for="option in column.params.options" :key="option.value" :value="option.value">
  147 + {{ option.label }}
  148 + </SelectOption>
  149 + </Select>
  150 + </template>
  151 + #elseif($column.htmlType == "checkbox")## 多选框
  152 + <template #${javaField}="{ row, column }">
  153 + <CheckboxGroup v-model:value="row.${javaField}" :options="column.params.options" />
  154 + </template>
  155 + #elseif($column.htmlType == "radio")## 单选框
  156 + <template #${javaField}="{ row, column }">
  157 + <RadioGroup v-model:value="row.${javaField}" :options="column.params.options" />
  158 + </template>
  159 + #elseif($column.htmlType == "datetime")## 时间框
  160 + <template #${javaField}="{ row }">
  161 + <DatePicker
  162 + v-model:value="row.${javaField}"
  163 + :showTime="true"
  164 + format="YYYY-MM-DD HH:mm:ss"
  165 + valueFormat='x'
  166 + />
  167 + </template>
  168 + #elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 文本框
  169 + <template #${javaField}="{ row }">
  170 + <TextArea v-model:value="row.${javaField}" />
  171 + </template>
  172 + #end
  173 + #end
  174 + #end
  175 + <template #actions="{ row }">
  176 + <Button
  177 + size="small"
  178 + type="link"
  179 + danger
  180 + @click="handleDelete(row)"
  181 + v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:delete']"
  182 + >
  183 + {{ $t('ui.actionTitle.delete') }}
  184 + </Button>
  185 + </template>
  186 + </Grid>
  187 + <div class="flex justify-center -mt-4">
  188 + <Button :icon="h(Plus)" type="primary" ghost @click="handleAdd" v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:create']">
  189 + {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
  190 + </Button>
  191 + </div>
  192 +#else
  193 + <Form class="mx-4" />
  194 +#end
  195 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_erp.vue.vm 0 → 100644
  1 +#set ($subTable = $subTables.get($subIndex))##当前表
  2 +#set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组
  3 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  4 +#set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
  5 +#set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段
  6 +#set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex))
  7 +#set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
  8 +#set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api")
  9 +<script lang="ts" setup>
  10 +import type { VxeTableGridOptions } from '#/adapter/vxe-table';
  11 +import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}';
  12 +
  13 +#if ($table.templateType == 11) ## erp
  14 +import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
  15 +#end
  16 +import { confirm, useVbenModal } from '@vben/common-ui';
  17 +import { message } from 'antdv-next';
  18 +import { ref, computed, nextTick,watch } from 'vue';
  19 +import { $t } from '#/locales';
  20 +import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
  21 +
  22 +#if ($table.templateType == 11) ## erp
  23 +import { delete${subSimpleClassName},#if ($deleteBatchEnable) delete${subSimpleClassName}List,#end get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${table.businessName}';
  24 +import { use${subSimpleClassName}GridFormSchema, use${subSimpleClassName}GridColumns } from '../data';
  25 +import { isEmpty } from '@vben/utils';
  26 +#else
  27 +#if ($subTable.subJoinMany) ## 一对多
  28 +import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
  29 +#else
  30 +import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}';
  31 +#end
  32 +import { use${subSimpleClassName}GridColumns } from '../data';
  33 +#end
  34 +
  35 +const props = defineProps<{
  36 + ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段)
  37 +}>()
  38 +
  39 +#if ($table.templateType == 11) ## erp
  40 +const [FormModal, formModalApi] = useVbenModal({
  41 + connectedComponent: ${subSimpleClassName}Form,
  42 + destroyOnClose: true,
  43 +});
  44 +
  45 +/** 创建${subTable.classComment} */
  46 +function handleCreate() {
  47 + if (!props.${subJoinColumn.javaField}){
  48 + message.warning("请先选择一个${table.classComment}!")
  49 + return
  50 + }
  51 + formModalApi.setData({${subJoinColumn.javaField}: props.${subJoinColumn.javaField}}).open();
  52 +}
  53 +
  54 +/** 编辑${subTable.classComment} */
  55 +function handleEdit(row: ${apiName}.${subSimpleClassName}) {
  56 + formModalApi.setData(row).open();
  57 +}
  58 +
  59 +/** 删除${subTable.classComment} */
  60 +async function handleDelete(row: ${apiName}.${subSimpleClassName}) {
  61 + const hideLoading = message.loading({
  62 + content: $t('ui.actionMessage.deleting', [row.id]),
  63 + duration: 0,
  64 + });
  65 + try {
  66 + await delete${subSimpleClassName}(row.id!);
  67 + message.success($t('ui.actionMessage.deleteSuccess', [row.id]));
  68 + handleRefresh();
  69 + } finally {
  70 + hideLoading();
  71 + }
  72 +}
  73 +
  74 +#if ($deleteBatchEnable)
  75 +/** 批量删除${subTable.classComment} */
  76 +async function handleDeleteBatch() {
  77 + await confirm($t('ui.actionMessage.deleteBatchConfirm'));
  78 + const hideLoading = message.loading({
  79 + content: $t('ui.actionMessage.deletingBatch'),
  80 + duration: 0,
  81 + });
  82 + try {
  83 + await delete${subSimpleClassName}List(checkedIds.value);
  84 + checkedIds.value = [];
  85 + message.success($t('ui.actionMessage.deleteSuccess'));
  86 + handleRefresh();
  87 + } finally {
  88 + hideLoading();
  89 + }
  90 +}
  91 +
  92 +const checkedIds = ref<number[]>([])
  93 +function handleRowCheckboxChange({
  94 + records,
  95 +}: {
  96 + records: ${apiName}.${subSimpleClassName}[];
  97 +}) {
  98 + checkedIds.value = records.map((item) => item.id!);
  99 +}
  100 +#end
  101 +
  102 +#end
  103 +const [Grid, gridApi] = useVbenVxeGrid({
  104 +#if ($table.templateType == 11)
  105 + formOptions: {
  106 + schema: use${subSimpleClassName}GridFormSchema(),
  107 + },
  108 +#end
  109 + gridOptions: {
  110 +#if ($table.templateType == 11)
  111 + columns: use${subSimpleClassName}GridColumns(),
  112 + proxyConfig: {
  113 + ajax: {
  114 + query: async ({ page }, formValues) => {
  115 + if (!props.${subJoinColumn.javaField}){
  116 + return []
  117 + }
  118 + return await get${subSimpleClassName}Page({
  119 + pageNo: page.currentPage,
  120 + pageSize: page.pageSize,
  121 + ${subJoinColumn.javaField}: props.${subJoinColumn.javaField},
  122 + ...formValues,
  123 + });
  124 + },
  125 + },
  126 + },
  127 + pagerConfig: {
  128 + enabled: true,
  129 + },
  130 + toolbarConfig: {
  131 + refresh: true,
  132 + search: true,
  133 + },
  134 +#else
  135 + columns: use${subSimpleClassName}GridColumns(),
  136 + pagerConfig: {
  137 + enabled: false,
  138 + },
  139 + toolbarConfig: {
  140 + enabled: false,
  141 + },
  142 +#end
  143 + height: '600px',
  144 + rowConfig: {
  145 + keyField: 'id',
  146 + isHover: true,
  147 + },
  148 + } as VxeTableGridOptions<${apiName}.${subSimpleClassName}>,
  149 + #if (${table.templateType} == 11 && $deleteBatchEnable)
  150 + gridEvents:{
  151 + checkboxAll: handleRowCheckboxChange,
  152 + checkboxChange: handleRowCheckboxChange,
  153 + }
  154 + #end
  155 +});
  156 +
  157 +/** 刷新表格 */
  158 +async function handleRefresh() {
  159 +#if ($table.templateType == 11) ## erp
  160 + await gridApi.query();
  161 +#else
  162 + #if ($subTable.subJoinMany) ## 一对多
  163 + await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
  164 + #else
  165 + await gridApi.grid.loadData([await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)]);
  166 + #end
  167 +#end
  168 +}
  169 +
  170 +/** 监听主表的关联字段的变化,加载对应的子表数据 */
  171 +watch(
  172 + () => props.${subJoinColumn.javaField},
  173 + async (val) => {
  174 + if (!val) {
  175 + return;
  176 + }
  177 + await nextTick();
  178 + await handleRefresh()
  179 + },
  180 + { immediate: true },
  181 +);
  182 +</script>
  183 +
  184 +<template>
  185 + #if ($table.templateType == 11) ## erp
  186 + <FormModal @success="handleRefresh" />
  187 + <Grid table-title="${subTable.classComment}列表">
  188 + <template #toolbar-tools>
  189 + <TableAction
  190 + :actions="[
  191 + {
  192 + label: $t('ui.actionTitle.create', ['${table.classComment}']),
  193 + type: 'primary',
  194 + icon: ACTION_ICON.ADD,
  195 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:create'],
  196 + onClick: handleCreate,
  197 + },
  198 + #if ($table.templateType == 11 && $deleteBatchEnable)
  199 + {
  200 + label: $t('ui.actionTitle.deleteBatch'),
  201 + type: 'primary',
  202 + danger: true,
  203 + icon: ACTION_ICON.DELETE,
  204 + disabled: isEmpty(checkedIds),
  205 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
  206 + onClick: handleDeleteBatch,
  207 + },
  208 + #end
  209 + ]"
  210 + />
  211 + </template>
  212 + <template #actions="{ row }">
  213 + <TableAction
  214 + :actions="[
  215 + {
  216 + label: $t('common.edit'),
  217 + type: 'link',
  218 + icon: ACTION_ICON.EDIT,
  219 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:update'],
  220 + onClick: handleEdit.bind(null, row),
  221 + },
  222 + {
  223 + label: $t('common.delete'),
  224 + type: 'link',
  225 + danger: true,
  226 + icon: ACTION_ICON.DELETE,
  227 + auth: ['${table.moduleName}:${simpleClassName_strikeCase}:delete'],
  228 + popConfirm: {
  229 + title: $t('ui.actionMessage.deleteConfirm', [row.id]),
  230 + confirm: handleDelete.bind(null, row),
  231 + },
  232 + },
  233 + ]"
  234 + />
  235 + </template>
  236 + </Grid>
  237 + #else
  238 + <Grid table-title="${subTable.classComment}列表" />
  239 + #end
  240 +</template>
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_inner.vue.vm 0 → 100644
  1 +## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点:
  2 +## 1)inner 使用 list 不分页,erp 使用 page 分页
  3 +## 2)erp 支持单个子表的新增、修改、删除,inner 不支持
  4 +#parse("codegen/vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm")
0 \ No newline at end of file 5 \ No newline at end of file