Commit 8b70307ae75580f3585d2f0c7309022861d8f00b

Authored by 芋道源码
Committed by Gitee
2 parents 5af9496d c6582b2a

!1336 【功能完善】INFRA:代码生成 vben5 antd 树表、主子表模版

Merge pull request !1336 from puhui999/master-jdk17
Showing 13 changed files with 860 additions and 655 deletions
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
... ... @@ -164,8 +164,6 @@ public class CodegenEngine {
164 164 .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_SCHEMA.getType(), vue3Vben5AntdSchemaTemplatePath("views/modules/list_sub_erp.vue"), // 特殊:主子表专属逻辑
165 165 vue3FilePath("views/${table.moduleName}/${table.businessName}/modules/${subSimpleClassName_strikeCase}-list.vue"))
166 166 // VUE3_VBEN5_ANTD
167   - .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/data.ts"),
168   - vue3FilePath("views/${table.moduleName}/${table.businessName}/data.ts"))
169 167 .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/index.vue"),
170 168 vue3FilePath("views/${table.moduleName}/${table.businessName}/index.vue"))
171 169 .put(CodegenFrontTypeEnum.VUE3_VBEN5_ANTD_GENERAL.getType(), vue3Vben5AntdGeneralTemplatePath("views/form.vue"),
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/api/api.ts.vm
1 1 import type { PageParam, PageResult } from '@vben/request';
  2 +import type { Dayjs } from 'dayjs';
2 3  
3 4 import { requestClient } from '#/api/request';
4 5 #set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
... ... @@ -16,7 +17,7 @@ export namespace ${simpleClassName}Api {
16 17 #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
17 18 ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
18 19 #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
19   - ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: Date; // ${column.columnComment}
  20 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
20 21 #else
21 22 ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
22 23 #end
... ... @@ -32,7 +33,7 @@ export namespace ${simpleClassName}Api {
32 33 #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
33 34 ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
34 35 #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
35   - ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: Date; // ${column.columnComment}
  36 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
36 37 #else
37 38 ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
38 39 #end
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/views/data.ts.vm deleted
1   -import type { VxeTableGridOptions } from '@vben/plugins/vxe-table';
2   -import type { VbenFormSchema } from '#/adapter/form';
3   -import type { OnActionClickFn } from '#/adapter/vxe-table';
4   -import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
5   -
6   -import { z } from '#/adapter/form';
7   -#if(${table.templateType} == 2)## 树表需要导入这些
8   -import { get${simpleClassName}List } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
9   -import { handleTree } from '#/utils/tree';
10   -#end
11   -import { DICT_TYPE, getDictOptions } from '#/utils/dict';
12   -import { getRangePickerDefaultProps } from '#/utils/date';
13   -import { useAccess } from '@vben/access';
14   -
15   -const { hasAccessByCodes } = useAccess();
16   -
17   -/** 列表的搜索表单 */
18   -export function useGridFormSchema(): VbenFormSchema[] {
19   - return [
20   -#foreach($column in $columns)
21   -#if ($column.listOperation)
22   - #set ($dictType = $column.dictType)
23   - #set ($javaType = $column.javaType)
24   - #set ($javaField = $column.javaField)
25   - #set ($comment = $column.columnComment)
26   - #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
27   - #set ($dictMethod = "number")
28   - #elseif ($javaType == "String")
29   - #set ($dictMethod = "string")
30   - #elseif ($javaType == "Boolean")
31   - #set ($dictMethod = "boolean")
32   - #end
33   - {
34   - fieldName: '${javaField}',
35   - label: '${comment}',
36   - #if ($column.htmlType == "input" || $column.htmlType == "textarea" || $column.htmlType == "editor")
37   - component: 'Input',
38   - componentProps: {
39   - allowClear: true,
40   - placeholder: '请输入${comment}',
41   - },
42   - #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
43   - component: 'Select',
44   - componentProps: {
45   - allowClear: true,
46   - #if ("" != $dictType)## 设置了 dictType 数据字典的情况
47   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
48   - #else## 未设置 dictType 数据字典的情况
49   - options: [],
50   - #end
51   - placeholder: '请选择${comment}',
52   - },
53   - #elseif($column.htmlType == "datetime")
54   - component: 'RangePicker',
55   - componentProps: {
56   - ...getRangePickerDefaultProps(),
57   - allowClear: true,
58   - },
59   - #end
60   - },
61   -#end
62   -#end
63   - ];
64   -}
65   -
66   -/** 列表的字段 */
67   -export function useGridColumns(
68   - onActionClick?: OnActionClickFn<${simpleClassName}Api.${simpleClassName}>,
69   -): VxeTableGridOptions<${simpleClassName}Api.${simpleClassName}>['columns'] {
70   - return [
71   -#if ($table.templateType == 12) ## 内嵌情况
72   - { type: 'expand', width: 80, slots: { content: 'expand_content' } },
73   -#end
74   -#foreach($column in $columns)
75   -#if ($column.listOperationResult)
76   - #set ($dictType = $column.dictType)
77   - #set ($javaField = $column.javaField)
78   - #set ($comment = $column.columnComment)
79   - {
80   - field: '${javaField}',
81   - title: '${comment}',
82   - minWidth: 120,
83   - #if ($column.javaType == "LocalDateTime")## 时间类型
84   - formatter: 'formatDateTime',
85   - #elseif("" != $dictType)## 数据字典
86   - cellRender: {
87   - name: 'CellDict',
88   - props: { type: DICT_TYPE.$dictType.toUpperCase() },
89   - },
90   - #end
91   - #if (${table.templateType} == 2 && $column.id == $treeNameColumn.id)## 树表特有:标记树节点列
92   - treeNode: true,
93   - #end
94   - },
95   -#end
96   -#end
97   - {
98   - field: 'operation',
99   - title: '操作',
100   - minWidth: 200,
101   - align: 'center',
102   - fixed: 'right',
103   - headerAlign: 'center',
104   - showOverflow: false,
105   - cellRender: {
106   - attrs: {
107   - nameField: '${columns[0].javaField}',
108   - nameTitle: '${table.classComment}',
109   - onClick: onActionClick,
110   - },
111   - name: 'CellOperation',
112   - options: [
113   -#if (${table.templateType} == 2)## 树表特有操作
114   - {
115   - code: 'append',
116   - text: '新增下级',
117   - show: hasAccessByCodes(['${table.moduleName}:${simpleClassName_strikeCase}:create']),
118   - },
119   -#end
120   - {
121   - code: 'edit',
122   - show: hasAccessByCodes(['${table.moduleName}:${simpleClassName_strikeCase}:update']),
123   - },
124   - {
125   - code: 'delete',
126   - show: hasAccessByCodes(['${table.moduleName}:${simpleClassName_strikeCase}:delete']),
127   -#if (${table.templateType} == 2)## 树表禁止删除带有子节点的数据
128   - disabled: (row: ${simpleClassName}Api.${simpleClassName}) => {
129   - return !!(row.children && row.children.length > 0);
130   - },
131   -#end
132   - },
133   - ],
134   - },
135   - },
136   - ];
137   -}
138   -
139   -## 标准模式和内嵌模式时,主子关系一对一则生成表单schema,一对多则生成列表schema(内嵌模式时表单schema也要生成)。erp 模式时都生成
140   -## 特殊:主子表专属逻辑
141   -#foreach ($subTable in $subTables)
142   - #set ($index = $foreach.count - 1)
143   - #set ($subColumns = $subColumnsList.get($index))##当前字段数组
144   - #set ($subSimpleClassName = $subSimpleClassNames.get($index))
145   - #set ($subJoinColumn = $subJoinColumns.get($index))##当前 join 字段
146   - #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($index))
147   -// ==================== 子表($subTable.classComment) ====================
148   -
149   -#if ($table.templateType == 11) ## erp 情况
150   -/** 列表的搜索表单 */
151   -export function use${subSimpleClassName}GridFormSchema(): VbenFormSchema[] {
152   - return [
153   - #foreach($column in $subColumns)
154   - #if ($column.listOperation)
155   - #set ($dictType = $column.dictType)
156   - #set ($javaType = $column.javaType)
157   - #set ($javaField = $column.javaField)
158   - #set ($comment = $column.columnComment)
159   - #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
160   - #set ($dictMethod = "number")
161   - #elseif ($javaType == "String")
162   - #set ($dictMethod = "string")
163   - #elseif ($javaType == "Boolean")
164   - #set ($dictMethod = "boolean")
165   - #end
166   - {
167   - fieldName: '${javaField}',
168   - label: '${comment}',
169   - #if ($column.htmlType == "input" || $column.htmlType == "textarea" || $column.htmlType == "editor")
170   - component: 'Input',
171   - componentProps: {
172   - allowClear: true,
173   - placeholder: '请输入${comment}',
174   - },
175   - #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
176   - component: 'Select',
177   - componentProps: {
178   - allowClear: true,
179   - #if ("" != $dictType)## 设置了 dictType 数据字典的情况
180   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
181   - #else## 未设置 dictType 数据字典的情况
182   - options: [],
183   - #end
184   - placeholder: '请选择${comment}',
185   - },
186   - #elseif($column.htmlType == "datetime")
187   - component: 'RangePicker',
188   - componentProps: {
189   - ...getRangePickerDefaultProps(),
190   - allowClear: true,
191   - },
192   - #end
193   - },
194   - #end
195   - #end
196   - ];
197   -}
198   -
199   -/** 列表的字段 */
200   -export function use${subSimpleClassName}GridColumns(
201   - onActionClick?: OnActionClickFn<${simpleClassName}Api.${subSimpleClassName}>,
202   -): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] {
203   - return [
204   - #foreach($column in $subColumns)
205   - #if ($column.listOperationResult)
206   - #set ($dictType = $column.dictType)
207   - #set ($javaField = $column.javaField)
208   - #set ($comment = $column.columnComment)
209   - {
210   - field: '${javaField}',
211   - title: '${comment}',
212   - minWidth: 120,
213   - #if ($column.javaType == "LocalDateTime")## 时间类型
214   - formatter: 'formatDateTime',
215   - #elseif("" != $dictType)## 数据字典
216   - cellRender: {
217   - name: 'CellDict',
218   - props: { type: DICT_TYPE.$dictType.toUpperCase() },
219   - },
220   - #end
221   - },
222   - #end
223   - #end
224   - {
225   - field: 'operation',
226   - title: '操作',
227   - minWidth: 200,
228   - align: 'center',
229   - fixed: 'right',
230   - headerAlign: 'center',
231   - showOverflow: false,
232   - cellRender: {
233   - attrs: {
234   - nameField: '${columns[0].javaField}',
235   - nameTitle: '${subTable.classComment}',
236   - onClick: onActionClick,
237   - },
238   - name: 'CellOperation',
239   - options: [
240   - {
241   - code: 'edit',
242   - show: hasAccessByCodes(['${table.moduleName}:${simpleClassName_strikeCase}:update']),
243   - },
244   - {
245   - code: 'delete',
246   - show: hasAccessByCodes(['${table.moduleName}:${simpleClassName_strikeCase}:delete']),
247   - },
248   - ],
249   - },
250   - },
251   - ];
252   -}
253   -
254   -#else
255   - #if ($subTable.subJoinMany) ## 一对多
256   - /** 新增/修改列表的字段 */
257   - export function use${subSimpleClassName}GridEditColumns(
258   - onActionClick?: OnActionClickFn<${simpleClassName}Api.${subSimpleClassName}>,
259   - ): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] {
260   - return [
261   - #foreach($column in $subColumns)
262   - #if ($column.createOperation || $column.updateOperation)
263   - #if (!$column.primaryKey && $column.listOperationResult && $column.id != $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
264   - #set ($dictType = $column.dictType)
265   - #set ($javaField = $column.javaField)
266   - #set ($comment = $column.columnComment)
267   - #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
268   - #set ($dictMethod = "number")
269   - #elseif ($javaType == "String")
270   - #set ($dictMethod = "string")
271   - #elseif ($javaType == "Boolean")
272   - #set ($dictMethod = "boolean")
273   - #end
274   - {
275   - field: '${javaField}',
276   - title: '${comment}',
277   - minWidth: 120,
278   - slots: { default: '${javaField}' },
279   - #if ($column.htmlType == "select" || $column.htmlType == "checkbox" || $column.htmlType == "radio")
280   - #if ("" != $dictType)## 有数据字典
281   - params: {
282   - options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'),
283   - },
284   - #else
285   - params: {
286   - options: [],
287   - },
288   - #end
289   - #end
290   - },
291   - #end
292   - #end
293   - #end
294   - {
295   - field: 'operation',
296   - title: '操作',
297   - minWidth: 60,
298   - align: 'center',
299   - fixed: 'right',
300   - headerAlign: 'center',
301   - showOverflow: false,
302   - cellRender: {
303   - attrs: {
304   - nameField: '${columns[0].javaField}',
305   - nameTitle: '${table.classComment}',
306   - onClick: onActionClick,
307   - },
308   - name: 'CellOperation',
309   - options: [
310   - {
311   - code: 'delete',
312   - show: hasAccessByCodes(['${table.moduleName}:${simpleClassName_strikeCase}:delete']),
313   - },
314   - ],
315   - },
316   - },
317   - ];
318   - }
319   - #end
320   - #if ($table.templateType == 12) ## 内嵌情况
321   - /** 列表的字段 */
322   - export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] {
323   - return [
324   - #foreach($column in $subColumns)
325   - #if ($column.listOperationResult)
326   - #set ($dictType = $column.dictType)
327   - #set ($javaField = $column.javaField)
328   - #set ($comment = $column.columnComment)
329   - {
330   - field: '${javaField}',
331   - title: '${comment}',
332   - minWidth: 120,
333   - #if ($column.javaType == "LocalDateTime")## 时间类型
334   - formatter: 'formatDateTime',
335   - #elseif("" != $dictType)## 数据字典
336   - cellRender: {
337   - name: 'CellDict',
338   - props: { type: DICT_TYPE.$dictType.toUpperCase() },
339   - },
340   - #end
341   - },
342   - #end
343   - #end
344   - ];
345   - }
346   -
347   - #end
348   -#end
349   -#end
350 0 \ No newline at end of file
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/views/form.vue.vm
... ... @@ -5,11 +5,11 @@ import type { Rule } from &#39;ant-design-vue/es/form&#39;;
5 5 import { useVbenModal } from '@vben/common-ui';
6 6 import { Tinymce as RichTextarea } from '#/components/tinymce';
7 7 import { ImageUpload, FileUpload } from "#/components/upload";
8   -import { message, Tabs, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'ant-design-vue';
  8 +import { message, Tabs, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'ant-design-vue';
9 9 import { DICT_TYPE, getDictOptions } from '#/utils/dict';
10 10 #if($table.templateType == 2)## 树表需要导入这些
11 11 import { get${simpleClassName}List } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
12   -import { handleTree } from '#/utils/tree';
  12 +import { handleTree } from '@vben/utils'
13 13 #end
14 14 ## 特殊:主子表专属逻辑
15 15 #if ( $table.templateType == 10 || $table.templateType == 12 )
... ... @@ -25,9 +25,8 @@ import { $t } from &#39;#/locales&#39;;
25 25 import { get${simpleClassName}, create${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
26 26  
27 27 const emit = defineEmits(['success']);
  28 +
28 29 const formRef = ref();
29   -const labelCol = { span: 5 };
30   -const wrapperCol = { span: 13 };
31 30 const formData = ref<Partial<${simpleClassName}Api.${simpleClassName}>>({
32 31 #foreach ($column in $columns)
33 32 #if ($column.createOperation || $column.updateOperation)
... ... @@ -91,10 +90,12 @@ const resetForm = () =&gt; {
91 90 /** 获得${table.classComment}树 */
92 91 const get${simpleClassName}Tree = async () => {
93 92 ${classNameVar}Tree.value = []
94   - const data = await get${simpleClassName}List()
95   - const root: Tree = { id: 0, name: '顶级${table.classComment}', children: [] }
96   - root.children = handleTree(data, 'id', '${treeParentColumn.javaField}')
97   - ${classNameVar}Tree.value.push(root)
  93 + const data = await get${simpleClassName}List({});
  94 + data.unshift({
  95 + id: 0,
  96 + name: '顶级${table.classComment}',
  97 + });
  98 + ${classNameVar}Tree.value = handleTree(data);
98 99 }
99 100 #end
100 101  
... ... @@ -111,10 +112,11 @@ const [Modal, modalApi] = useVbenModal({
111 112 #if ($subTable.subJoinMany) ## 一对多
112 113 ## TODO 列表值校验?
113 114 #else
114   - const ${subClassNameVar}Valid = await ${subClassNameVar}FormRef.value?.validate();
115   - if (!${subClassNameVar}Valid) {
116   - subTabsName.value = '${subClassNameVar}';
117   - return;
  115 + try {
  116 + await ${subClassNameVar}FormRef.value?.validate()
  117 + } catch (e) {
  118 + subTabsName.value = '${subClassNameVar}'
  119 + return
118 120 }
119 121 #end
120 122 #end
... ... @@ -133,7 +135,7 @@ const [Modal, modalApi] = useVbenModal({
133 135 #if ($subTable.subJoinMany)
134 136 data.${subClassNameVar}s = ${subClassNameVar}FormRef.value?.getData();
135 137 #else
136   - data.${subClassNameVar} = await ${subClassNameVar}FormRef.value?.getValues();
  138 + data.${subClassNameVar} = ${subClassNameVar}FormRef.value?.getValues();
137 139 #end
138 140 #end
139 141 #end
... ... @@ -156,7 +158,6 @@ const [Modal, modalApi] = useVbenModal({
156 158 resetForm()
157 159 return;
158 160 }
159   -
160 161 // 加载数据
161 162 let data = modalApi.getData<${simpleClassName}Api.${simpleClassName}>();
162 163 if (!data) {
... ... @@ -185,8 +186,8 @@ const [Modal, modalApi] = useVbenModal({
185 186 ref="formRef"
186 187 :model="formData"
187 188 :rules="rules"
188   - :label-col="labelCol"
189   - :wrapper-col="wrapperCol"
  189 + :label-col="{ span: 5 }"
  190 + :wrapper-col="{ span: 18 }"
190 191 >
191 192 #foreach($column in $columns)
192 193 #if ($column.createOperation || $column.updateOperation)
... ... @@ -207,9 +208,17 @@ const [Modal, modalApi] = useVbenModal({
207 208 v-model:value="formData.${javaField}"
208 209 :treeData="${classNameVar}Tree"
209 210 #if ($treeNameColumn.javaField == "name")
210   - :fieldNames="defaultProps"
  211 + :fieldNames="{
  212 + label: 'name',
  213 + value: 'id',
  214 + children: 'children',
  215 + }"
211 216 #else
212   - :fieldNames="{...defaultProps, label: '$treeNameColumn.javaField'}"
  217 + :fieldNames="{
  218 + label: '$treeNameColumn.javaField',
  219 + value: 'id',
  220 + children: 'children',
  221 + }"
213 222 #end
214 223 checkable
215 224 treeDefaultExpandAll
... ... @@ -239,9 +248,10 @@ const [Modal, modalApi] = useVbenModal({
239 248 <Select.Option
240 249 v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
241 250 :key="dict.value"
242   - :label="dict.label"
243 251 :value="dict.value"
244   - />
  252 + >
  253 + {{ dict.label }}
  254 + </Select.Option>
245 255 #else##没数据字典
246 256 <Select.Option label="请选择字典生成" value="" />
247 257 #end
... ... @@ -254,9 +264,10 @@ const [Modal, modalApi] = useVbenModal({
254 264 <Checkbox
255 265 v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
256 266 :key="dict.value"
257   - :label="dict.label"
258 267 :value="dict.value"
259   - />
  268 + >
  269 + {{ dict.label }}
  270 + </Checkbox>
260 271 #else##没数据字典
261 272 <Checkbox label="请选择字典生成" />
262 273 #end
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/views/index.vue.vm
1 1 <script lang="ts" setup>
2 2 import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
  3 +import type { VxeTableInstance } from 'vxe-table';
3 4  
4 5 import { Page, useVbenModal } from '@vben/common-ui';
5   -import { formatDateTime } from '@vben/utils';
  6 +import { cloneDeep, formatDateTime } from '@vben/utils';
6 7 import { Button, message,Tabs,Pagination,Form,RangePicker,DatePicker,Select,Input } from 'ant-design-vue';
7 8 import { DictTag } from '#/components/dict-tag';
8 9 import { DICT_TYPE, getDictOptions } from '#/utils/dict';
... ... @@ -10,6 +11,7 @@ import ${simpleClassName}Form from &#39;./modules/form.vue&#39;;
10 11 import { Download, Plus, RefreshCw, Search } from '@vben/icons';
11 12 import { ContentWrap } from "#/components/content-wrap";
12 13 import { VxeColumn, VxeTable } from 'vxe-table';
  14 +import { TableToolbar } from '#/components/table-toolbar';
13 15 import { getRangePickerDefaultProps } from '#/utils/date';
14 16  
15 17 ## 特殊:主子表专属逻辑
... ... @@ -21,10 +23,10 @@ import { getRangePickerDefaultProps } from &#39;#/utils/date&#39;;
21 23 #end
22 24 #end
23 25  
24   -import { ref, h, reactive,onMounted } from 'vue';
  26 +import { ref, h, reactive,onMounted,nextTick } from 'vue';
25 27 import { $t } from '#/locales';
26 28 #if (${table.templateType} == 2)## 树表接口
27   -import { handleTree } from '@/utils/tree'
  29 +import { handleTree,isEmpty } from '@vben/utils'
28 30 import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
29 31 #else## 标准表接口
30 32 import { get${simpleClassName}Page, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
... ... @@ -36,11 +38,19 @@ import { downloadByData } from &#39;#/utils/download&#39;;
36 38 const subTabsName = ref('$subClassNameVars.get(0)')
37 39 #if ($table.templateType == 11)
38 40 const select${simpleClassName} = ref<${simpleClassName}Api.${simpleClassName}>();
  41 +async function onCellClick({ row }: { row: ${simpleClassName}Api.${simpleClassName} }) {
  42 + select${simpleClassName}.value = row
  43 +}
39 44 #end
40 45 #end
41 46  
42 47 const loading = ref(true) // 列表的加载中
  48 +#if ( $table.templateType == 2 )
  49 +const list = ref<any[]>([]) // 树列表的数据
  50 +#else
43 51 const list = ref<${simpleClassName}Api.${simpleClassName}[]>([]) // 列表的数据
  52 +#end
  53 +
44 54 ## 特殊:树表专属逻辑(树不需要分页接口)
45 55 #if ( $table.templateType != 2 )
46 56 const total = ref(0) // 列表的总页数
... ... @@ -69,12 +79,21 @@ const exportLoading = ref(false) // 导出的加载中
69 79 const getList = async () => {
70 80 loading.value = true
71 81 try {
  82 + const params = cloneDeep(queryParams) as any;
  83 + #foreach ($column in $columns)
  84 + #if ($column.listOperation)
  85 + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
  86 + if (params.${column.javaField} && Array.isArray(params.${column.javaField})) {
  87 + params.${column.javaField} = (params.${column.javaField} as string[]).join(',');
  88 + }
  89 + #end
  90 + #end
  91 + #end
72 92 ## 特殊:树表专属逻辑(树不需要分页接口)
73 93 #if ( $table.templateType == 2 )
74   - const data = await get${simpleClassName}List(queryParams)
75   - list.value = handleTree(data, 'id', '${treeParentColumn.javaField}')
  94 + list.value = await get${simpleClassName}List(params);
76 95 #else
77   - const data = await get${simpleClassName}Page(queryParams)
  96 + const data = await get${simpleClassName}Page(params)
78 97 list.value = data.list
79 98 total.value = data.total
80 99 #end
... ... @@ -85,7 +104,9 @@ const getList = async () =&gt; {
85 104  
86 105 /** 搜索按钮操作 */
87 106 const handleQuery = () => {
  107 +#if ( $table.templateType != 2 )
88 108 queryParams.pageNo = 1
  109 +#end
89 110 getList()
90 111 }
91 112  
... ... @@ -147,20 +168,40 @@ try {
147 168 }
148 169 }
149 170  
150   -/** 初始化 **/
151   -onMounted(() => {
152   - getList()
153   -})
  171 +/** 隐藏搜索栏 */
  172 +const hiddenSearchBar = ref(false);
  173 +const tableToolbarRef = ref<InstanceType<typeof TableToolbar>>();
  174 +const tableRef = ref<VxeTableInstance>();
  175 +
  176 +#if (${table.templateType} == 2)
  177 +/** 切换树形展开/收缩状态 */
  178 +const isExpanded = ref(true);
  179 +function toggleExpand() {
  180 + isExpanded.value = !isExpanded.value;
  181 + tableRef.value?.setAllTreeExpand(isExpanded.value);
  182 +}
  183 +#end
  184 +
  185 +/** 初始化 */
  186 +onMounted(async () => {
  187 + await getList();
  188 + await nextTick();
  189 + // 挂载 toolbar 工具栏
  190 + const table = tableRef.value;
  191 + const tableToolbar = tableToolbarRef.value;
  192 + if (table && tableToolbar) {
  193 + await table.connect(tableToolbar.getToolbarRef()!);
  194 + }
  195 +});
154 196 </script>
155 197  
156 198 <template>
157 199 <Page auto-content-height>
158 200 <FormModal @success="getList" />
159 201  
160   - <ContentWrap>
  202 + <ContentWrap v-if="!hiddenSearchBar">
161 203 <!-- 搜索工作栏 -->
162 204 <Form
163   - class="-mb-15px"
164 205 :model="queryParams"
165 206 ref="queryFormRef"
166 207 layout="inline"
... ... @@ -185,7 +226,7 @@ onMounted(() =&gt; {
185 226 placeholder="请输入${comment}"
186 227 allowClear
187 228 @pressEnter="handleQuery"
188   - class="!w-240px"
  229 + class="w-full"
189 230 />
190 231 </Form.Item>
191 232 #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")
... ... @@ -194,15 +235,16 @@ onMounted(() =&gt; {
194 235 v-model:value="queryParams.${javaField}"
195 236 placeholder="请选择${comment}"
196 237 allowClear
197   - class="!w-240px"
  238 + class="w-full"
198 239 >
199 240 #if ("" != $dictType)## 设置了 dictType 数据字典的情况
200 241 <Select.Option
201 242 v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
202 243 :key="dict.value"
203   - :label="dict.label"
204 244 :value="dict.value"
205   - />
  245 + >
  246 + {{ dict.label }}
  247 + </Select.Option>
206 248 #else## 未设置 dictType 数据字典的情况
207 249 <Select.Option label="请选择字典生成" value="" />
208 250 #end
... ... @@ -216,7 +258,7 @@ onMounted(() =&gt; {
216 258 valueFormat="YYYY-MM-DD"
217 259 placeholder="选择${comment}"
218 260 allowClear
219   - class="!w-240px"
  261 + class="w-full"
220 262 />
221 263 </Form.Item>
222 264 #else## 范围
... ... @@ -224,7 +266,7 @@ onMounted(() =&gt; {
224 266 <RangePicker
225 267 v-model:value="queryParams.${javaField}"
226 268 v-bind="getRangePickerDefaultProps()"
227   - class="!w-220px"
  269 + class="w-full"
228 270 />
229 271 </Form.Item>
230 272 #end
... ... @@ -232,8 +274,26 @@ onMounted(() =&gt; {
232 274 #end
233 275 #end
234 276 <Form.Item>
235   - <Button class="ml-2" @click="handleQuery" :icon="h(Search)">搜索</Button>
236   - <Button class="ml-2" @click="resetQuery" :icon="h(RefreshCw)">重置</Button>
  277 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  278 + <Button class="ml-2" @click="handleQuery" type="primary">
  279 + 搜索
  280 + </Button>
  281 + </Form.Item>
  282 + </Form>
  283 + </ContentWrap>
  284 +
  285 + <!-- 列表 -->
  286 + <ContentWrap title="${table.classComment}">
  287 + <template #extra>
  288 + <TableToolbar
  289 + ref="tableToolbarRef"
  290 + v-model:hidden-search="hiddenSearchBar"
  291 + >
  292 + #if (${table.templateType} == 2)
  293 + <Button @click="toggleExpand" class="mr-2">
  294 + {{ isExpanded ? '收缩' : '展开' }}
  295 + </Button>
  296 + #end
237 297 <Button
238 298 class="ml-2"
239 299 :icon="h(Plus)"
... ... @@ -241,7 +301,7 @@ onMounted(() =&gt; {
241 301 @click="onCreate"
242 302 v-access:code="['${permissionPrefix}:create']"
243 303 >
244   - {{ $t('ui.actionTitle.create', ['示例联系人']) }}
  304 + {{ $t('ui.actionTitle.create', ['${table.classComment}']) }}
245 305 </Button>
246 306 <Button
247 307 :icon="h(Download)"
... ... @@ -253,13 +313,31 @@ onMounted(() =&gt; {
253 313 >
254 314 {{ $t('ui.actionTitle.export') }}
255 315 </Button>
256   - </Form.Item>
257   - </Form>
258   - </ContentWrap>
259   -
260   - <!-- 列表 -->
261   - <ContentWrap>
262   - <vxe-table :data="list" show-overflow :loading="loading">
  316 + </TableToolbar>
  317 + </template>
  318 + <vxe-table
  319 + ref="tableRef"
  320 + :data="list"
  321 + #if ( $table.templateType == 2 )
  322 + :tree-config="{
  323 + parentField: '${treeParentColumn.javaField}',
  324 + rowField: 'id',
  325 + transform: true,
  326 + expandAll: true,
  327 + reserve: true,
  328 + }"
  329 + #end
  330 +#if ($table.templateType == 11) ## erp情况
  331 + @cell-click="onCellClick"
  332 + :row-config="{
  333 + keyField: 'id',
  334 + isHover: true,
  335 + isCurrent: true,
  336 + }"
  337 +#end
  338 + show-overflow
  339 + :loading="loading"
  340 + >
263 341 ## 特殊:主子表专属逻辑
264 342 #if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 )
265 343 <!-- 子表的列表 -->
... ... @@ -298,6 +376,8 @@ onMounted(() =&gt; {
298 376 <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
299 377 </template>
300 378 </vxe-column>
  379 + #elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField)
  380 + <vxe-column field="${javaField}" title="${comment}" align="center" tree-node/>
301 381 #else
302 382 <vxe-column field="${javaField}" title="${comment}" align="center" />
303 383 #end
... ... @@ -305,6 +385,16 @@ onMounted(() =&gt; {
305 385 #end
306 386 <vxe-column field="operation" title="操作" align="center">
307 387 <template #default="{row}">
  388 +#if ( $table.templateType == 2 )
  389 + <Button
  390 + size="small"
  391 + type="link"
  392 + @click="onAppend(row as any)"
  393 + v-access:code="['${permissionPrefix}:create']"
  394 + >
  395 + 新增下级
  396 + </Button>
  397 +#end
308 398 <Button
309 399 size="small"
310 400 type="link"
... ... @@ -316,7 +406,11 @@ onMounted(() =&gt; {
316 406 <Button
317 407 size="small"
318 408 type="link"
  409 + danger
319 410 class="ml-2"
  411 + #if ( $table.templateType == 2 )
  412 + :disabled="!isEmpty(row?.children)"
  413 + #end
320 414 @click="onDelete(row as any)"
321 415 v-access:code="['${permissionPrefix}:delete']"
322 416 >
... ... @@ -325,6 +419,7 @@ onMounted(() =&gt; {
325 419 </template>
326 420 </vxe-column>
327 421 </vxe-table>
  422 +#if ( $table.templateType != 2 )
328 423 <!-- 分页 -->
329 424 <div class="mt-2 flex justify-end">
330 425 <Pagination
... ... @@ -335,6 +430,7 @@ onMounted(() =&gt; {
335 430 @change="getList"
336 431 />
337 432 </div>
  433 +#end
338 434 </ContentWrap>
339 435  
340 436 #if ($table.templateType == 11) ## erp情况
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/views/modules/form_sub_erp.vue.vm
... ... @@ -4,49 +4,54 @@
4 4 #set ($subSimpleClassName = $subSimpleClassNames.get($subIndex))
5 5 <script lang="ts" setup>
6 6 import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
  7 + import type { Rule } from 'ant-design-vue/es/form';
7 8  
8 9 import { useVbenModal } from '@vben/common-ui';
9   - import { message } from 'ant-design-vue';
  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 'ant-design-vue';
  13 + import { DICT_TYPE, getDictOptions } from '#/utils/dict';
10 14  
11 15 import { computed, ref } from 'vue';
12 16 import { $t } from '#/locales';
13   - import { useVbenForm } from '#/adapter/form';
14   - import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
15 17  
16   - import { use${subSimpleClassName}FormSchema } from '../data';
  18 + import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
17 19  
18 20 const emit = defineEmits(['success']);
19   - const formData = ref<${simpleClassName}Api.${subSimpleClassName}>();
20 21 const getTitle = computed(() => {
21 22 return formData.value?.id
22 23 ? $t('ui.actionTitle.edit', ['${subTable.classComment}'])
23 24 : $t('ui.actionTitle.create', ['${subTable.classComment}']);
24 25 });
25 26  
26   - const [Form, formApi] = useVbenForm({
27   - commonConfig: {
28   - componentProps: {
29   - class: 'w-full',
30   - },
31   - formItemClass: 'col-span-2',
32   - labelWidth: 80,
33   - },
34   - layout: 'horizontal',
35   - schema: use${subSimpleClassName}FormSchema(),
36   - showDefaultActions: false
  27 + const formRef = ref();
  28 + const formData = ref<Partial<${simpleClassName}Api.${subSimpleClassName}>>({
  29 + #foreach ($column in $subColumns)
  30 + #if ($column.createOperation || $column.updateOperation)
  31 + #if ($column.htmlType == "checkbox")
  32 + $column.javaField: [],
  33 + #else
  34 + $column.javaField: undefined,
  35 + #end
  36 + #end
  37 + #end
37 38 });
  39 + const rules: Record<string, Rule[]> = {
  40 + #foreach ($column in $subColumns)
  41 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  42 + #set($comment=$column.columnComment)
  43 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
  44 + #end
  45 + #end
  46 + };
38 47  
39 48 const [Modal, modalApi] = useVbenModal({
40 49 async onConfirm() {
41   - const { valid } = await formApi.validate();
42   - if (!valid) {
43   - return;
44   - }
  50 + await formRef.value?.validate();
45 51  
46 52 modalApi.lock();
47 53 // 提交表单
48   - const data = (await formApi.getValues()) as ${simpleClassName}Api.${subSimpleClassName};
49   - data.${subJoinColumn.javaField} = formData.value?.${subJoinColumn.javaField};
  54 + const data = formData.value as ${simpleClassName}Api.${subSimpleClassName};
50 55 try {
51 56 await (formData.value?.id ? update${subSimpleClassName}(data) : create${subSimpleClassName}(data));
52 57 // 关闭并提示
... ... @@ -62,7 +67,7 @@
62 67 },
63 68 async onOpenChange(isOpen: boolean) {
64 69 if (!isOpen) {
65   - formData.value = undefined;
  70 + resetForm()
66 71 return;
67 72 }
68 73  
... ... @@ -81,13 +86,127 @@
81 86 }
82 87 // 设置到 values
83 88 formData.value = data;
84   - await formApi.setValues(formData.value);
85 89 },
86 90 });
  91 +
  92 + /** 重置表单 */
  93 + const resetForm = () => {
  94 + formData.value = {
  95 + #foreach ($column in $subColumns)
  96 + #if ($column.createOperation || $column.updateOperation)
  97 + #if ($column.htmlType == "checkbox")
  98 + $column.javaField: [],
  99 + #else
  100 + $column.javaField: undefined,
  101 + #end
  102 + #end
  103 + #end
  104 + };
  105 + formRef.value?.resetFields();
  106 + }
87 107 </script>
88 108  
89 109 <template>
90 110 <Modal :title="getTitle">
91   - <Form class="mx-4" />
  111 + <Form
  112 + ref="formRef"
  113 + :model="formData"
  114 + :rules="rules"
  115 + :label-col="{ span: 5 }"
  116 + :wrapper-col="{ span: 18 }"
  117 + >
  118 + #foreach($column in $subColumns)
  119 + #if ($column.createOperation || $column.updateOperation)
  120 + #set ($dictType = $column.dictType)
  121 + #set ($javaField = $column.javaField)
  122 + #set ($javaType = $column.javaType)
  123 + #set ($comment = $column.columnComment)
  124 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  125 + #set ($dictMethod = "number")
  126 + #elseif ($javaType == "String")
  127 + #set ($dictMethod = "string")
  128 + #elseif ($javaType == "Boolean")
  129 + #set ($dictMethod = "boolean")
  130 + #end
  131 + #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  132 + <Form.Item label="${comment}" name="${javaField}">
  133 + <Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  134 + </Form.Item>
  135 + #elseif($column.htmlType == "imageUpload")## 图片上传
  136 + <Form.Item label="${comment}" name="${javaField}">
  137 + <ImageUpload v-model:value="formData.${javaField}" />
  138 + </Form.Item>
  139 + #elseif($column.htmlType == "fileUpload")## 文件上传
  140 + <Form.Item label="${comment}" name="${javaField}">
  141 + <FileUpload v-model:value="formData.${javaField}" />
  142 + </Form.Item>
  143 + #elseif($column.htmlType == "editor")## 文本编辑器
  144 + <Form.Item label="${comment}" name="${javaField}">
  145 + <RichTextarea v-model="formData.${javaField}" height="500px" />
  146 + </Form.Item>
  147 + #elseif($column.htmlType == "select")## 下拉框
  148 + <Form.Item label="${comment}" name="${javaField}">
  149 + <Select v-model:value="formData.${javaField}" placeholder="请选择${comment}">
  150 + #if ("" != $dictType)## 有数据字典
  151 + <Select.Option
  152 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  153 + :key="dict.value"
  154 + :value="dict.value"
  155 + >
  156 + {{ dict.label }}
  157 + </Select.Option>
  158 + #else##没数据字典
  159 + <Select.Option label="请选择字典生成" value="" />
  160 + #end
  161 + </Select>
  162 + </Form.Item>
  163 + #elseif($column.htmlType == "checkbox")## 多选框
  164 + <Form.Item label="${comment}" name="${javaField}">
  165 + <CheckboxGroup v-model:value="formData.${javaField}">
  166 + #if ("" != $dictType)## 有数据字典
  167 + <Checkbox
  168 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  169 + :key="dict.value"
  170 + :value="dict.value"
  171 + >
  172 + {{ dict.label }}
  173 + </Checkbox>
  174 + #else##没数据字典
  175 + <Checkbox label="请选择字典生成" />
  176 + #end
  177 + </CheckboxGroup>
  178 + </Form.Item>
  179 + #elseif($column.htmlType == "radio")## 单选框
  180 + <Form.Item label="${comment}" name="${javaField}">
  181 + <RadioGroup v-model:value="formData.${javaField}">
  182 + #if ("" != $dictType)## 有数据字典
  183 + <Radio
  184 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  185 + :key="dict.value"
  186 + :value="dict.value"
  187 + >
  188 + {{ dict.label }}
  189 + </Radio>
  190 + #else##没数据字典
  191 + <Radio value="1">请选择字典生成</Radio>
  192 + #end
  193 + </RadioGroup>
  194 + </Form.Item>
  195 + #elseif($column.htmlType == "datetime")## 时间框
  196 + <Form.Item label="${comment}" name="${javaField}">
  197 + <DatePicker
  198 + v-model:value="formData.${javaField}"
  199 + valueFormat="x"
  200 + placeholder="选择${comment}"
  201 + />
  202 + </Form.Item>
  203 + #elseif($column.htmlType == "textarea")## 文本框
  204 + <Form.Item label="${comment}" name="${javaField}">
  205 + <Textarea v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  206 + </Form.Item>
  207 + #end
  208 + #end
  209 + #end
  210 + </Form>
92 211 </Modal>
93 212 </template>
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/views/modules/form_sub_inner.vue.vm
1 1 ## 主表的 normal 和 inner 使用相同的 form 表单
2   -#parse("codegen/vue3_vben5_antd/schema/views/modules/form_sub_normal.vue.vm")
3 2 \ No newline at end of file
  3 +#parse("codegen/vue3_vben5_antd/general/views/modules/form_sub_normal.vue.vm")
4 4 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/views/modules/form_sub_normal.vue.vm
... ... @@ -7,19 +7,19 @@
7 7 <script lang="ts" setup>
8 8 import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
9 9  
  10 + import { message, Tabs, Form, Input, Textarea,Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'ant-design-vue';
10 11 import { computed, ref, h, onMounted,watch,nextTick } from 'vue';
11 12 import { $t } from '#/locales';
  13 + import { DICT_TYPE, getDictOptions } from '#/utils/dict';
12 14  
13 15 #if ($subTable.subJoinMany) ## 一对多
  16 +import type { VxeTableInstance } from 'vxe-table';
14 17 import { Plus } from "@vben/icons";
15   -import { Button, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue';
16   -import type { OnActionClickParams } from '#/adapter/vxe-table';
17   -import { useVbenVxeGrid } from '#/adapter/vxe-table';
18   -import { use${subSimpleClassName}GridEditColumns } from '../data';
  18 +import { VxeColumn, VxeTable } from 'vxe-table';
19 19 import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
20 20 #else
21   -import { useVbenForm } from '#/adapter/form';
22   -import { use${subSimpleClassName}FormSchema } from '../data';
  21 +import type { Rule } from 'ant-design-vue/es/form';
  22 +import { Tinymce as RichTextarea } from '#/components/tinymce';
23 23 import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
24 24 #end
25 25  
... ... @@ -28,57 +28,27 @@ const props = defineProps&lt;{
28 28 }>()
29 29  
30 30 #if ($subTable.subJoinMany) ## 一对多
31   -/** 表格操作按钮的回调函数 */
32   -function onActionClick({
33   - code,
34   - row,
35   -}: OnActionClickParams<${simpleClassName}Api.${subSimpleClassName}>) {
36   - switch (code) {
37   - case 'delete': {
38   - onDelete(row);
39   - break;
40   - }
41   - }
42   -}
43   -
44   -const [Grid, gridApi] = useVbenVxeGrid({
45   -gridOptions: {
46   - columns: use${subSimpleClassName}GridEditColumns(onActionClick),
47   - border: true,
48   - showOverflow: true,
49   - autoResize: true,
50   - keepSource: true,
51   - rowConfig: {
52   - keyField: 'id',
53   - },
54   - pagerConfig: {
55   - enabled: false,
56   - },
57   - toolbarConfig: {
58   - enabled: false,
59   - },
60   -},
61   -});
62   -
  31 +const list = ref<${simpleClassName}Api.${subSimpleClassName}[]>([]) // 列表的数据
  32 +const tableRef = ref<VxeTableInstance>();
63 33 /** 添加${subTable.classComment} */
64 34 const onAdd = async () => {
65   - await gridApi.grid.insertAt({} as ${simpleClassName}Api.${subSimpleClassName}, -1);
  35 + await tableRef.value?.insertAt({} as ${simpleClassName}Api.${subSimpleClassName}, -1);
66 36 }
67 37  
68 38 /** 删除${subTable.classComment} */
69 39 const onDelete = async (row: ${simpleClassName}Api.${subSimpleClassName}) => {
70   - await gridApi.grid.remove(row);
  40 + await tableRef.value?.remove(row);
71 41 }
72 42  
73 43 /** 提供获取表格数据的方法供父组件调用 */
74 44 defineExpose({
75 45 getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => {
76   - const data = gridApi.grid.getData() as ${simpleClassName}Api.${subSimpleClassName}[];
77   - const removeRecords = gridApi.grid.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
78   - const insertRecords = gridApi.grid.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
  46 + const data = list.value as ${simpleClassName}Api.${subSimpleClassName}[];
  47 + const removeRecords = tableRef.value?.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
  48 + const insertRecords = tableRef.value?.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[];
79 49 return data
80 50 .filter((row) => !removeRecords.some((removed) => removed.id === row.id))
81   - .concat(insertRecords.map((row: any) => ({ ...row, id: undefined })));
  51 + ?.concat(insertRecords.map((row: any) => ({ ...row, id: undefined })));
82 52 },
83 53 });
84 54  
... ... @@ -89,32 +59,35 @@ watch(
89 59 if (!val) {
90 60 return;
91 61 }
92   - await nextTick();
93   - await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
  62 + list.value = await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
94 63 },
95 64 { immediate: true },
96 65 );
97 66 #else
98   -const [Form, formApi] = useVbenForm({
99   - commonConfig: {
100   - componentProps: {
101   - class: 'w-full',
102   - },
103   - formItemClass: 'col-span-2',
104   - labelWidth: 80,
105   - },
106   - layout: 'horizontal',
107   - schema: use${subSimpleClassName}FormSchema(),
108   - showDefaultActions: false
  67 +const formRef = ref();
  68 +const formData = ref<Partial<${simpleClassName}Api.${subSimpleClassName}>>({
  69 + #foreach ($column in $subColumns)
  70 + #if ($column.createOperation || $column.updateOperation)
  71 + #if ($column.htmlType == "checkbox")
  72 + $column.javaField: [],
  73 + #else
  74 + $column.javaField: undefined,
  75 + #end
  76 + #end
  77 + #end
109 78 });
110   -
  79 +const rules: Record<string, Rule[]> = {
  80 + #foreach ($column in $subColumns)
  81 + #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
  82 + #set($comment=$column.columnComment)
  83 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
  84 + #end
  85 + #end
  86 +};
111 87 /** 暴露出表单校验方法和表单值获取方法 */
112 88 defineExpose({
113   - validate: async () => {
114   - const { valid } = await formApi.validate();
115   - return valid;
116   - },
117   - getValues: formApi.getValues,
  89 + validate: async () => await formRef.value?.validate(),
  90 + getValues: ()=> formData.value,
118 91 });
119 92  
120 93 /** 监听主表的关联字段的变化,加载对应的子表数据 */
... ... @@ -125,7 +98,7 @@ watch(
125 98 return;
126 99 }
127 100 await nextTick();
128   - await formApi.setValues(await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
  101 + formData.value = await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
129 102 },
130 103 { immediate: true },
131 104 );
... ... @@ -134,66 +107,232 @@ watch(
134 107  
135 108 <template>
136 109 #if ($subTable.subJoinMany) ## 一对多
137   - <Grid class="mx-4">
  110 + <vxe-table ref="tableRef" :data="list" show-overflow class="mx-4">
138 111 #foreach($column in $subColumns)
139 112 #if ($column.createOperation || $column.updateOperation)
  113 + #set ($comment = $column.columnComment)
140 114 #set ($javaField = $column.javaField)
  115 + #set ($javaType = $column.javaType)
  116 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  117 + #set ($dictMethod = "number")
  118 + #elseif ($javaType == "String")
  119 + #set ($dictMethod = "string")
  120 + #elseif ($javaType == "Boolean")
  121 + #set ($dictMethod = "boolean")
  122 + #end
141 123 #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写
142 124 #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
143   - <template #${javaField}="{ row }">
144   - <Input v-model:value="row.${javaField}" />
145   - </template>
  125 + <vxe-column field="${javaField}" title="${comment}" align="center">
  126 + <template #default="{row}">
  127 + <Input v-model:value="row.${javaField}" />
  128 + </template>
  129 + </vxe-column>
  130 + #elseif($column.htmlType == "imageUpload")## 图片上传
  131 + <vxe-column field="${javaField}" title="${comment}" align="center">
  132 + <template #default="{row}">
  133 + <ImageUpload v-model:value="row.${javaField}" />
  134 + </template>
  135 + </vxe-column>
  136 + #elseif($column.htmlType == "fileUpload")## 文件上传
  137 + <vxe-column field="${javaField}" title="${comment}" align="center">
  138 + <template #default="{row}">
  139 + <FileUpload v-model:value="row.${javaField}" />
  140 + </template>
  141 + </vxe-column>
  142 + #elseif($column.htmlType == "select")## 下拉框
  143 + <vxe-column field="${javaField}" title="${comment}" align="center">
  144 + <template #default="{row}">
  145 + <Select v-model:value="row.${javaField}" placeholder="请选择${comment}">
  146 + #if ("" != $dictType)## 有数据字典
  147 + <Select.Option
  148 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  149 + :key="dict.value"
  150 + :value="dict.value"
  151 + >
  152 + {{ dict.label }}
  153 + </Select.Option>
  154 + #else##没数据字典
  155 + <Select.Option label="请选择字典生成" value="" />
  156 + #end
  157 + </Select>
  158 + </template>
  159 + </vxe-column>
  160 + #elseif($column.htmlType == "checkbox")## 多选框
  161 + <vxe-column field="${javaField}" title="${comment}" align="center">
  162 + <template #default="{row}">
  163 + <CheckboxGroup v-model:value="row.${javaField}">
  164 + #if ("" != $dictType)## 有数据字典
  165 + <Checkbox
  166 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  167 + :key="dict.value"
  168 + :value="dict.value"
  169 + >
  170 + {{ dict.label }}
  171 + </Checkbox>
  172 + #else##没数据字典
  173 + <Checkbox label="请选择字典生成" />
  174 + #end
  175 + </CheckboxGroup>
  176 + </template>
  177 + </vxe-column>
  178 + #elseif($column.htmlType == "radio")## 单选框
  179 + <vxe-column field="${javaField}" title="${comment}" align="center">
  180 + <template #default="{row}">
  181 + <RadioGroup v-model:value="row.${javaField}">
  182 + #if ("" != $dictType)## 有数据字典
  183 + <Radio
  184 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  185 + :key="dict.value"
  186 + :value="dict.value"
  187 + >
  188 + {{ dict.label }}
  189 + </Radio>
  190 + #else##没数据字典
  191 + <Radio value="1">请选择字典生成</Radio>
  192 + #end
  193 + </RadioGroup>
  194 + </template>
  195 + </vxe-column>
  196 + #elseif($column.htmlType == "datetime")## 时间框
  197 + <vxe-column field="${javaField}" title="${comment}" align="center">
  198 + <template #default="{row}">
  199 + <DatePicker
  200 + v-model:value="row.${javaField}"
  201 + :showTime="true"
  202 + format="YYYY-MM-DD HH:mm:ss"
  203 + valueFormat='x'
  204 + />
  205 + </template>
  206 + </vxe-column>
  207 + #elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 文本框
  208 + <vxe-column field="${javaField}" title="${comment}" align="center">
  209 + <template #default="{row}">
  210 + <Textarea v-model:value="row.${javaField}" />
  211 + </template>
  212 + </vxe-column>
  213 + #end
  214 + #end
  215 + #end
  216 + <vxe-column field="operation" title="操作" align="center">
  217 + <template #default="{row}">
  218 + <Button
  219 + size="small"
  220 + type="link"
  221 + danger
  222 + @click="onDelete(row as any)"
  223 + v-access:code="['${permissionPrefix}:delete']"
  224 + >
  225 + {{ $t('ui.actionTitle.delete') }}
  226 + </Button>
  227 + </template>
  228 + </vxe-column>
  229 + </vxe-table>
  230 + <div class="flex justify-center mt-4">
  231 + <Button :icon="h(Plus)" type="primary" ghost @click="onAdd" v-access:code="['${permissionPrefix}:create']">
  232 + {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
  233 + </Button>
  234 + </div>
  235 +#else
  236 + <Form
  237 + ref="formRef"
  238 + class="mx-4"
  239 + :model="formData"
  240 + :rules="rules"
  241 + :label-col="{ span: 5 }"
  242 + :wrapper-col="{ span: 18 }"
  243 + >
  244 + #foreach($column in $subColumns)
  245 + #if ($column.createOperation || $column.updateOperation)
  246 + #set ($dictType = $column.dictType)
  247 + #set ($javaField = $column.javaField)
  248 + #set ($javaType = $column.javaType)
  249 + #set ($comment = $column.columnComment)
  250 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  251 + #set ($dictMethod = "number")
  252 + #elseif ($javaType == "String")
  253 + #set ($dictMethod = "string")
  254 + #elseif ($javaType == "Boolean")
  255 + #set ($dictMethod = "boolean")
  256 + #end
  257 + #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里
  258 + <Form.Item label="${comment}" name="${javaField}">
  259 + <Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  260 + </Form.Item>
146 261 #elseif($column.htmlType == "imageUpload")## 图片上传
147   - <template #${javaField}="{ row }">
148   - <UploadImg v-model:value="row.${javaField}" />
149   - </template>
  262 + <Form.Item label="${comment}" name="${javaField}">
  263 + <ImageUpload v-model:value="formData.${javaField}" />
  264 + </Form.Item>
150 265 #elseif($column.htmlType == "fileUpload")## 文件上传
151   - <template #${javaField}="{ row }">
152   - <UploadFile v-model:value="row.${javaField}" />
153   - </template>
  266 + <Form.Item label="${comment}" name="${javaField}">
  267 + <FileUpload v-model:value="formData.${javaField}" />
  268 + </Form.Item>
154 269 #elseif($column.htmlType == "editor")## 文本编辑器
155   - <template #${javaField}="{ row }">
156   - <Textarea v-model:value="row.${javaField}" />
157   - </template>
  270 + <Form.Item label="${comment}" name="${javaField}">
  271 + <RichTextarea v-model="formData.${javaField}" height="500px" />
  272 + </Form.Item>
158 273 #elseif($column.htmlType == "select")## 下拉框
159   - <template #${javaField}="{ row, column }">
160   - <Select v-model:value="row.${javaField}" class="w-full">
161   - <Select.Option v-for="option in column.params.options" :key="option.value" :value="option.value">
162   - {{ option.label }}
163   - </Select.Option>
  274 + <Form.Item label="${comment}" name="${javaField}">
  275 + <Select v-model:value="formData.${javaField}" placeholder="请选择${comment}">
  276 + #if ("" != $dictType)## 有数据字典
  277 + <Select.Option
  278 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  279 + :key="dict.value"
  280 + :value="dict.value"
  281 + >
  282 + {{ dict.label }}
  283 + </Select.Option>
  284 + #else##没数据字典
  285 + <Select.Option label="请选择字典生成" value="" />
  286 + #end
164 287 </Select>
165   - </template>
  288 + </Form.Item>
166 289 #elseif($column.htmlType == "checkbox")## 多选框
167   - <template #${javaField}="{ row, column }">
168   - <CheckboxGroup v-model:value="row.${javaField}" :options="column.params.options" />
169   - </template>
  290 + <Form.Item label="${comment}" name="${javaField}">
  291 + <CheckboxGroup v-model:value="formData.${javaField}">
  292 + #if ("" != $dictType)## 有数据字典
  293 + <Checkbox
  294 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  295 + :key="dict.value"
  296 + :value="dict.value"
  297 + >
  298 + {{ dict.label }}
  299 + </Checkbox>
  300 + #else##没数据字典
  301 + <Checkbox label="请选择字典生成" />
  302 + #end
  303 + </CheckboxGroup>
  304 + </Form.Item>
170 305 #elseif($column.htmlType == "radio")## 单选框
171   - <template #${javaField}="{ row, column }">
172   - <RadioGroup v-model:value="row.${javaField}" :options="column.params.options" />
173   - </template>
  306 + <Form.Item label="${comment}" name="${javaField}">
  307 + <RadioGroup v-model:value="formData.${javaField}">
  308 + #if ("" != $dictType)## 有数据字典
  309 + <Radio
  310 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  311 + :key="dict.value"
  312 + :value="dict.value"
  313 + >
  314 + {{ dict.label }}
  315 + </Radio>
  316 + #else##没数据字典
  317 + <Radio value="1">请选择字典生成</Radio>
  318 + #end
  319 + </RadioGroup>
  320 + </Form.Item>
174 321 #elseif($column.htmlType == "datetime")## 时间框
175   - <template #${javaField}="{ row }">
  322 + <Form.Item label="${comment}" name="${javaField}">
176 323 <DatePicker
177   - v-model:value="row.${javaField}"
178   - :showTime="true"
179   - format="YYYY-MM-DD HH:mm:ss"
180   - valueFormat='x'
  324 + v-model:value="formData.${javaField}"
  325 + valueFormat="x"
  326 + placeholder="选择${comment}"
181 327 />
182   - </template>
  328 + </Form.Item>
183 329 #elseif($column.htmlType == "textarea")## 文本框
184   - <template #${javaField}="{ row }">
185   - <Textarea v-model:value="row.${javaField}" />
186   - </template>
  330 + <Form.Item label="${comment}" name="${javaField}">
  331 + <Textarea v-model:value="formData.${javaField}" placeholder="请输入${comment}" />
  332 + </Form.Item>
187 333 #end
188 334 #end
189 335 #end
190   - </Grid>
191   - <div class="flex justify-center -mt-4">
192   - <Button :icon="h(Plus)" type="primary" ghost @click="onAdd" v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:create']">
193   - {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
194   - </Button>
195   - </div>
196   -#else
197   - <Form class="mx-4" />
  336 + </Form>
198 337 #end
199 338 </template>
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/views/modules/list_sub_erp.vue.vm
... ... @@ -6,30 +6,37 @@
6 6 #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex))
7 7 #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写
8 8 <script lang="ts" setup>
9   - import type { OnActionClickParams, VxeTableGridOptions } from '#/adapter/vxe-table';
10 9 import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
  10 + import type { VxeTableInstance } from 'vxe-table';
  11 +
  12 + import { DictTag } from '#/components/dict-tag';
  13 + import { DICT_TYPE, getDictOptions } from '#/utils/dict';
  14 + import { VxeColumn, VxeTable } from 'vxe-table';
  15 + import { reactive,ref, h, nextTick,watch,onMounted } from 'vue';
  16 + import { cloneDeep, formatDateTime } from '@vben/utils';
  17 + import { ContentWrap } from "#/components/content-wrap";
11 18  
12 19 #if ($table.templateType == 11) ## erp
13   - import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
  20 + import { useVbenModal } from '@vben/common-ui';
  21 + import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue'
  22 + import { Tinymce as RichTextarea } from '#/components/tinymce';
  23 + import { ImageUpload, FileUpload } from "#/components/upload";
  24 + import { message,Button, Tabs,Pagination, Form, Input, Textarea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox,RangePicker, DatePicker, TreeSelect } from 'ant-design-vue';
  25 + import { DICT_TYPE, getDictOptions } from '#/utils/dict';
  26 + import { Plus } from '@vben/icons';
  27 + import { $t } from '#/locales';
  28 + import { TableToolbar } from '#/components/table-toolbar';
  29 + import { getRangePickerDefaultProps } from '#/utils/date';
14 30 #end
15   - import { useVbenModal } from '@vben/common-ui';
16   - import { Button, message } from 'ant-design-vue';
17   - import { Plus } from '@vben/icons';
18   - import { #if($table.templateType != 11)ref,#end h, nextTick,watch } from 'vue';
19   - import { $t } from '#/locales';
20   - import { useVbenVxeGrid } from '#/adapter/vxe-table';
21   -
22 31  
23 32 #if ($table.templateType == 11) ## erp
24 33 import { delete${subSimpleClassName}, get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
25   - import { use${subSimpleClassName}GridFormSchema, use${subSimpleClassName}GridColumns } from '../data';
26 34 #else
27 35 #if ($subTable.subJoinMany) ## 一对多
28 36 import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
29 37 #else
30 38 import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}';
31 39 #end
32   - import { use${subSimpleClassName}GridColumns } from '../data';
33 40 #end
34 41  
35 42 const props = defineProps<{
... ... @@ -69,90 +76,81 @@ async function onDelete(row: ${simpleClassName}Api.${subSimpleClassName}) {
69 76 content: $t('ui.actionMessage.deleteSuccess', [row.id]),
70 77 key: 'action_process_msg',
71 78 });
72   - onRefresh();
  79 + getList();
73 80 } catch {
74 81 hideLoading();
75 82 }
76 83 }
77   -
78   -/** 表格操作按钮的回调函数 */
79   -function onActionClick({
80   - code,
81   - row,
82   -}: OnActionClickParams<${simpleClassName}Api.${subSimpleClassName}>) {
83   - switch (code) {
84   - case 'edit': {
85   - onEdit(row);
86   - break;
87   - }
88   - case 'delete': {
89   - onDelete(row);
90   - break;
91   - }
92   - }
93   -}
94   -
95   -#end
96   - const [Grid, gridApi] = useVbenVxeGrid({
97   -#if ($table.templateType == 11)
98   - formOptions: {
99   - schema: use${subSimpleClassName}GridFormSchema(),
100   - },
101   -#end
102   - gridOptions: {
103   -#if ($table.templateType == 11)
104   - columns: use${subSimpleClassName}GridColumns(onActionClick),
105   - proxyConfig: {
106   - ajax: {
107   - query: async ({ page }, formValues) => {
108   - if (!props.${subJoinColumn.javaField}){
109   - return []
110   - }
111   - return await get${subSimpleClassName}Page({
112   - pageNo: page.currentPage,
113   - pageSize: page.pageSize,
114   - ${subJoinColumn.javaField}: props.${subJoinColumn.javaField},
115   - ...formValues,
116   - });
117   - },
118   - },
119   - },
120   - pagerConfig: {
121   - enabled: true,
122   - },
123   - toolbarConfig: {
124   - refresh: { code: 'query' },
125   - search: true,
126   - },
127   -#else
128   - columns: use${subSimpleClassName}GridColumns(),
129   - pagerConfig: {
130   - enabled: false,
131   - },
132   - toolbarConfig: {
133   - enabled: false,
134   - },
135 84 #end
136   - height: '600px',
137   - rowConfig: {
138   - keyField: 'id',
139   - isHover: true,
140   - },
141   - } as VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>,
142   - });
143 85  
144   -/** 刷新表格 */
145   -const onRefresh = async ()=> {
  86 + const loading = ref(true) // 列表的加载中
  87 + const list = ref<${simpleClassName}Api.${subSimpleClassName}[]>([]) // 列表的数据
146 88 #if ($table.templateType == 11) ## erp
147   - await gridApi.query();
148   -#else
149   - #if ($subTable.subJoinMany) ## 一对多
150   - await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!));
151   - #else
152   - await gridApi.grid.loadData([await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)]);
153   - #end
  89 + const total = ref(0) // 列表的总页数
154 90 #end
  91 +#if ($table.templateType == 11) ## erp
  92 + const queryFormRef = ref() // 搜索的表单
  93 + const queryParams = reactive({
  94 + pageNo: 1,
  95 + pageSize: 10,
  96 + #foreach ($column in $subColumns)
  97 + #if ($column.listOperation)
  98 + #if ($column.listOperationCondition != 'BETWEEN')
  99 + $column.javaField: undefined,
  100 + #end
  101 + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
  102 + $column.javaField: undefined,
  103 + #end
  104 + #end
  105 + #end
  106 + })
  107 +
  108 +/** 搜索按钮操作 */
  109 +const handleQuery = () => {
  110 + queryParams.pageNo = 1
  111 + getList()
  112 +}
  113 +
  114 +/** 重置按钮操作 */
  115 +const resetQuery = () => {
  116 + queryFormRef.value.resetFields()
  117 + handleQuery()
155 118 }
  119 +#end
  120 + /** 查询列表 */
  121 + const getList = async () => {
  122 + loading.value = true
  123 + try {
  124 + if (!props.${subJoinColumn.javaField}){
  125 + return []
  126 + }
  127 + ## 特殊:树表专属逻辑(树不需要分页接口)
  128 + #if ($table.templateType == 11) ## erp
  129 + const params = cloneDeep(queryParams) as any;
  130 + #foreach ($column in $columns)
  131 + #if ($column.listOperation)
  132 + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
  133 + if (params.${column.javaField} && Array.isArray(params.${column.javaField})) {
  134 + params.${column.javaField} = (params.${column.javaField} as string[]).join(',');
  135 + }
  136 + #end
  137 + #end
  138 + #end
  139 + params.${subJoinColumn.javaField} = props.${subJoinColumn.javaField};
  140 + const data = await get${subSimpleClassName}Page(params)
  141 + list.value = data.list
  142 + total.value = data.total
  143 + #else
  144 + #if ($subTable.subJoinMany) ## 一对多
  145 + list.value = await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!);
  146 + #else
  147 + list.value = [await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)];
  148 + #end
  149 + #end
  150 + } finally {
  151 + loading.value = false
  152 + }
  153 + }
156 154  
157 155 /** 监听主表的关联字段的变化,加载对应的子表数据 */
158 156 watch(
... ... @@ -162,23 +160,231 @@ const onRefresh = async ()=&gt; {
162 160 return;
163 161 }
164 162 await nextTick();
165   - await onRefresh()
  163 + await getList()
166 164 },
167 165 { immediate: true },
168 166 );
  167 +
  168 +#if ($table.templateType == 11) ## erp
  169 +/** 隐藏搜索栏 */
  170 +const hiddenSearchBar = ref(false);
  171 +const tableToolbarRef = ref<InstanceType<typeof TableToolbar>>();
  172 +const tableRef = ref<VxeTableInstance>();
  173 +
  174 +/** 初始化 */
  175 +onMounted(async () => {
  176 + await getList();
  177 + await nextTick();
  178 + // 挂载 toolbar 工具栏
  179 + const table = tableRef.value;
  180 + const tableToolbar = tableToolbarRef.value;
  181 + if (table && tableToolbar) {
  182 + await table.connect(tableToolbar.getToolbarRef()!);
  183 + }
  184 +});
  185 +#end
169 186 </script>
170 187  
171 188 <template>
172 189 #if ($table.templateType == 11) ## erp
173   - <FormModal @success="onRefresh" />
174   - <Grid table-title="${subTable.classComment}列表">
175   - <template #toolbar-tools>
176   - <Button :icon="h(Plus)" type="primary" @click="onCreate" v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:create']">
177   - {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }}
178   - </Button>
179   - </template>
180   - </Grid>
  190 + <FormModal @success="getList" />
  191 + <div class="h-[600px]">
  192 + <ContentWrap v-if="!hiddenSearchBar">
  193 + <!-- 搜索工作栏 -->
  194 + <Form
  195 + :model="queryParams"
  196 + ref="queryFormRef"
  197 + layout="inline"
  198 + >
  199 + #foreach($column in $subColumns)
  200 + #if ($column.listOperation)
  201 + #set ($dictType = $column.dictType)
  202 + #set ($javaField = $column.javaField)
  203 + #set ($javaType = $column.javaType)
  204 + #set ($comment = $column.columnComment)
  205 + #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short")
  206 + #set ($dictMethod = "number")
  207 + #elseif ($javaType == "String")
  208 + #set ($dictMethod = "string")
  209 + #elseif ($javaType == "Boolean")
  210 + #set ($dictMethod = "boolean")
  211 + #end
  212 + #if ($column.htmlType == "input")
  213 + <Form.Item label="${comment}" name="${javaField}">
  214 + <Input
  215 + v-model:value="queryParams.${javaField}"
  216 + placeholder="请输入${comment}"
  217 + allowClear
  218 + @pressEnter="handleQuery"
  219 + class="w-full"
  220 + />
  221 + </Form.Item>
  222 + #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")
  223 + <Form.Item label="${comment}" name="${javaField}">
  224 + <Select
  225 + v-model:value="queryParams.${javaField}"
  226 + placeholder="请选择${comment}"
  227 + allowClear
  228 + class="w-full"
  229 + >
  230 + #if ("" != $dictType)## 设置了 dictType 数据字典的情况
  231 + <Select.Option
  232 + v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')"
  233 + :key="dict.value"
  234 + :value="dict.value"
  235 + >
  236 + {{ dict.label }}
  237 + </Select.Option>
  238 + #else## 未设置 dictType 数据字典的情况
  239 + <Select.Option label="请选择字典生成" value="" />
  240 + #end
  241 + </Select>
  242 + </Form.Item>
  243 + #elseif($column.htmlType == "datetime")
  244 + #if ($column.listOperationCondition != "BETWEEN")## 非范围
  245 + <Form.Item label="${comment}" name="${javaField}">
  246 + <DatePicker
  247 + v-model:value="queryParams.${javaField}"
  248 + valueFormat="YYYY-MM-DD"
  249 + placeholder="选择${comment}"
  250 + allowClear
  251 + class="w-full"
  252 + />
  253 + </Form.Item>
  254 + #else## 范围
  255 + <Form.Item label="${comment}" name="${javaField}">
  256 + <RangePicker
  257 + v-model:value="queryParams.${javaField}"
  258 + v-bind="getRangePickerDefaultProps()"
  259 + class="w-full"
  260 + />
  261 + </Form.Item>
  262 + #end
  263 + #end
  264 + #end
  265 + #end
  266 + <Form.Item>
  267 + <Button class="ml-2" @click="resetQuery"> 重置 </Button>
  268 + <Button class="ml-2" @click="handleQuery" type="primary">
  269 + 搜索
  270 + </Button>
  271 + </Form.Item>
  272 + </Form>
  273 + </ContentWrap>
  274 +
  275 + <!-- 列表 -->
  276 + <ContentWrap title="${table.classComment}">
  277 + <template #extra>
  278 + <TableToolbar
  279 + ref="tableToolbarRef"
  280 + v-model:hidden-search="hiddenSearchBar"
  281 + >
  282 + <Button
  283 + class="ml-2"
  284 + :icon="h(Plus)"
  285 + type="primary"
  286 + @click="onCreate"
  287 + v-access:code="['${permissionPrefix}:create']"
  288 + >
  289 + {{ $t('ui.actionTitle.create', ['${table.classComment}']) }}
  290 + </Button>
  291 + </TableToolbar>
  292 + </template>
  293 + <vxe-table
  294 + ref="tableRef"
  295 + :data="list"
  296 + show-overflow
  297 + :loading="loading"
  298 + >
  299 + #foreach($column in $subColumns)
  300 + #if ($column.listOperationResult)
  301 + #set ($dictType=$column.dictType)
  302 + #set ($javaField = $column.javaField)
  303 + #set ($comment=$column.columnComment)
  304 + #if ($column.javaType == "LocalDateTime")## 时间类型
  305 + <vxe-column field="${javaField}" title="${comment}" align="center">
  306 + <template #default="{row}">
  307 + {{formatDateTime(row.${javaField})}}
  308 + </template>
  309 + </vxe-column>
  310 + #elseif($column.dictType && "" != $column.dictType)## 数据字典
  311 + <vxe-column field="${javaField}" title="${comment}" align="center">
  312 + <template #default="{row}">
  313 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
  314 + </template>
  315 + </vxe-column>
  316 + #elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField)
  317 + <vxe-column field="${javaField}" title="${comment}" align="center" tree-node/>
  318 + #else
  319 + <vxe-column field="${javaField}" title="${comment}" align="center" />
  320 + #end
  321 + #end
  322 + #end
  323 + <vxe-column field="operation" title="操作" align="center">
  324 + <template #default="{row}">
  325 + <Button
  326 + size="small"
  327 + type="link"
  328 + @click="onEdit(row as any)"
  329 + v-access:code="['${permissionPrefix}:update']"
  330 + >
  331 + {{ $t('ui.actionTitle.edit') }}
  332 + </Button>
  333 + <Button
  334 + size="small"
  335 + type="link"
  336 + danger
  337 + class="ml-2"
  338 + @click="onDelete(row as any)"
  339 + v-access:code="['${permissionPrefix}:delete']"
  340 + >
  341 + {{ $t('ui.actionTitle.delete') }}
  342 + </Button>
  343 + </template>
  344 + </vxe-column>
  345 + </vxe-table>
  346 + <!-- 分页 -->
  347 + <div class="mt-2 flex justify-end">
  348 + <Pagination
  349 + :total="total"
  350 + v-model:current="queryParams.pageNo"
  351 + v-model:page-size="queryParams.pageSize"
  352 + show-size-changer
  353 + @change="getList"
  354 + />
  355 + </div>
  356 + </ContentWrap>
  357 + </div>
181 358 #else
182   - <Grid table-title="${subTable.classComment}列表" />
  359 + <ContentWrap title="${subTable.classComment}列表">
  360 + <vxe-table
  361 + :data="list"
  362 + show-overflow
  363 + :loading="loading"
  364 + >
  365 + #foreach($column in $subColumns)
  366 + #if ($column.listOperationResult)
  367 + #set ($dictType=$column.dictType)
  368 + #set ($javaField = $column.javaField)
  369 + #set ($comment=$column.columnComment)
  370 + #if ($column.javaType == "LocalDateTime")## 时间类型
  371 + <vxe-column field="${javaField}" title="${comment}" align="center">
  372 + <template #default="{row}">
  373 + {{formatDateTime(row.${javaField})}}
  374 + </template>
  375 + </vxe-column>
  376 + #elseif($column.dictType && "" != $column.dictType)## 数据字典
  377 + <vxe-column field="${javaField}" title="${comment}" align="center">
  378 + <template #default="{row}">
  379 + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" />
  380 + </template>
  381 + </vxe-column>
  382 + #else
  383 + <vxe-column field="${javaField}" title="${comment}" align="center" />
  384 + #end
  385 + #end
  386 + #end
  387 + </vxe-table>
  388 + </ContentWrap>
183 389 #end
184 390 </template>
185 391 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/general/views/modules/list_sub_inner.vue.vm
1 1 ## 子表的 erp 和 inner 使用相似的 list 列表,差异主要两点:
2 2 ## 1)inner 使用 list 不分页,erp 使用 page 分页
3 3 ## 2)erp 支持单个子表的新增、修改、删除,inner 不支持
4   -#parse("codegen/vue3_vben5_antd/schema/views/modules/list_sub_erp.vue.vm")
5 4 \ No newline at end of file
  5 +#parse("codegen/vue3_vben5_antd/general/views/modules/list_sub_erp.vue.vm")
6 6 \ No newline at end of file
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/schema/api/api.ts.vm
1 1 import type { PageParam, PageResult } from '@vben/request';
  2 +import type { Dayjs } from 'dayjs';
2 3  
3 4 import { requestClient } from '#/api/request';
4 5 #set ($baseURL = "/${table.moduleName}/${simpleClassName_strikeCase}")
... ... @@ -16,7 +17,7 @@ export namespace ${simpleClassName}Api {
16 17 #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
17 18 ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
18 19 #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
19   - ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: Date; // ${column.columnComment}
  20 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
20 21 #else
21 22 ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
22 23 #end
... ... @@ -32,7 +33,7 @@ export namespace ${simpleClassName}Api {
32 33 #if(${column.javaType.toLowerCase()} == "long" || ${column.javaType.toLowerCase()} == "integer" || ${column.javaType.toLowerCase()} == "short" || ${column.javaType.toLowerCase()} == "double" || ${column.javaType.toLowerCase()} == "bigdecimal")
33 34 ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: number; // ${column.columnComment}
34 35 #elseif(${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime")
35   - ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: Date; // ${column.columnComment}
  36 + ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: string | Dayjs; // ${column.columnComment}
36 37 #else
37 38 ${column.javaField}#if($column.updateOperation && !$column.primaryKey && !$column.nullable)?#end: ${column.javaType.toLowerCase()}; // ${column.columnComment}
38 39 #end
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/schema/views/form.vue.vm
... ... @@ -21,24 +21,11 @@ import { useFormSchema } from &#39;../data&#39;;
21 21  
22 22 const emit = defineEmits(['success']);
23 23 const formData = ref<${simpleClassName}Api.${simpleClassName}>();
24   -#if (${table.templateType} == 2)## 树表特有:父ID处理
25   -const parentId = ref<number>(); // 新增下级时的父级 ID
26   -
27   -const getTitle = computed(() => {
28   - if (formData.value?.id) {
29   - return $t('ui.actionTitle.edit', ['${table.classComment}']);
30   - }
31   - return parentId.value
32   - ? $t('ui.actionTitle.create', ['下级${table.classComment}'])
33   - : $t('ui.actionTitle.create', ['${table.classComment}']);
34   -});
35   -#else## 标准表标题
36 24 const getTitle = computed(() => {
37 25 return formData.value?.id
38 26 ? $t('ui.actionTitle.edit', ['${table.classComment}'])
39 27 : $t('ui.actionTitle.create', ['${table.classComment}']);
40 28 });
41   -#end
42 29  
43 30 ## 特殊:主子表专属逻辑
44 31 #if ( $table.templateType == 10 || $table.templateType == 12 )
... ... @@ -128,7 +115,6 @@ const [Modal, modalApi] = useVbenModal({
128 115 formData.value = undefined;
129 116 return;
130 117 }
131   -
132 118 // 加载数据
133 119 let data = modalApi.getData<${simpleClassName}Api.${simpleClassName}>();
134 120 if (!data) {
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_vben5_antd/schema/views/modules/form_sub_normal.vue.vm
... ... @@ -13,6 +13,7 @@
13 13 #if ($subTable.subJoinMany) ## 一对多
14 14 import { Plus } from "@vben/icons";
15 15 import { Button, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue';
  16 +import { ImageUpload, FileUpload } from "#/components/upload";
16 17 import type { OnActionClickParams } from '#/adapter/vxe-table';
17 18 import { useVbenVxeGrid } from '#/adapter/vxe-table';
18 19 import { use${subSimpleClassName}GridEditColumns } from '../data';
... ... @@ -145,15 +146,11 @@ watch(
145 146 </template>
146 147 #elseif($column.htmlType == "imageUpload")## 图片上传
147 148 <template #${javaField}="{ row }">
148   - <UploadImg v-model:value="row.${javaField}" />
  149 + <ImageUpload v-model:value="row.${javaField}" />
149 150 </template>
150 151 #elseif($column.htmlType == "fileUpload")## 文件上传
151 152 <template #${javaField}="{ row }">
152   - <UploadFile v-model:value="row.${javaField}" />
153   - </template>
154   - #elseif($column.htmlType == "editor")## 文本编辑器
155   - <template #${javaField}="{ row }">
156   - <Textarea v-model:value="row.${javaField}" />
  153 + <FileUpload v-model:value="row.${javaField}" />
157 154 </template>
158 155 #elseif($column.htmlType == "select")## 下拉框
159 156 <template #${javaField}="{ row, column }">
... ... @@ -180,7 +177,7 @@ watch(
180 177 valueFormat='x'
181 178 />
182 179 </template>
183   - #elseif($column.htmlType == "textarea")## 文本框
  180 + #elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 文本框
184 181 <template #${javaField}="{ row }">
185 182 <Textarea v-model:value="row.${javaField}" />
186 183 </template>
... ...