Commit 055eb350aa121c67768f86ce0b69a6ea457e5434

Authored by YunaiV
1 parent ebb8f04f

代码生成:简化现有 crud 模版的各种 pretty 相关的判断,交给 Java 代码后置统一处理。

yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/string/StrUtils.java
... ... @@ -50,4 +50,20 @@ public class StrUtils {
50 50 return Arrays.stream(integers).boxed().collect(Collectors.toList());
51 51 }
52 52  
  53 + /**
  54 + * 移除字符串中,包含指定字符串的行
  55 + *
  56 + * @param content 字符串
  57 + * @param sequence 包含的字符串
  58 + * @return 移除后的字符串
  59 + */
  60 + public static String removeLineContains(String content, String sequence) {
  61 + if (StrUtil.isEmpty(content) || StrUtil.isEmpty(sequence)) {
  62 + return content;
  63 + }
  64 + return Arrays.stream(content.split("\n"))
  65 + .filter(line -> !line.contains(sequence))
  66 + .collect(Collectors.joining("\n"));
  67 + }
  68 +
53 69 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenTableDO.java
... ... @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
6 6 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
7 7 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
8 8 import com.baomidou.mybatisplus.annotation.KeySequence;
  9 +import com.baomidou.mybatisplus.annotation.TableField;
9 10 import com.baomidou.mybatisplus.annotation.TableId;
10 11 import com.baomidou.mybatisplus.annotation.TableName;
11 12 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
... ... @@ -123,12 +124,14 @@ public class CodegenTableDO extends BaseDO {
123 124 *
124 125 * 关联 {@link CodegenTableDO#getId()}
125 126 */
  127 + @TableField(exist = false)
126 128 private Long masterTableId;
127 129 /**
128 130 * 【自己】子表关联主表的字段编号
129 131 *
130 132 * 关联 {@link CodegenColumnDO#getId()}
131 133 */
  134 + @TableField(exist = false)
132 135 private Long subJoinColumnId;
133 136 /**
134 137 * 主表与子表是否一对多
... ... @@ -136,6 +139,7 @@ public class CodegenTableDO extends BaseDO {
136 139 * true:一对多
137 140 * false:一对一
138 141 */
  142 + @TableField(exist = false)
139 143 private Boolean subJoinMany;
140 144  
141 145 }
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.infra.service.codegen.inner;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.map.MapUtil;
5   -import cn.hutool.core.util.ObjUtil;
6 5 import cn.hutool.core.util.StrUtil;
7 6 import cn.hutool.extra.template.TemplateConfig;
8 7 import cn.hutool.extra.template.TemplateEngine;
... ... @@ -15,6 +14,7 @@ import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
15 14 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
16 15 import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
17 16 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
  17 +import cn.iocoder.yudao.framework.common.util.string.StrUtils;
18 18 import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
19 19 import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
20 20 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
... ... @@ -27,7 +27,6 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
27 27 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
28 28 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum;
29 29 import cn.iocoder.yudao.module.infra.enums.codegen.CodegenSceneEnum;
30   -import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum;
31 30 import cn.iocoder.yudao.module.infra.framework.codegen.config.CodegenProperties;
32 31 import com.google.common.annotations.VisibleForTesting;
33 32 import com.google.common.collect.ImmutableTable;
... ... @@ -224,11 +223,43 @@ public class CodegenEngine {
224 223 String filePath, Map<String, Object> bindingMap) {
225 224 filePath = formatFilePath(filePath, bindingMap);
226 225 String content = templateEngine.getTemplate(vmPath).render(bindingMap);
227   - // 去除字段后面多余的 , 逗号
228   - content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
  226 + // 格式化代码
  227 + content = prettyCode(content);
229 228 result.put(filePath, content);
230 229 }
231 230  
  231 + /**
  232 + * 格式化生成后的代码
  233 + *
  234 + * 因为尽量让 vm 模版简单,所以统一的处理都在这个方法。
  235 + * 如果不处理,Vue 的 Pretty 格式校验可能会报错
  236 + *
  237 + * @param content 格式化前的代码
  238 + * @return 格式化后的代码
  239 + */
  240 + private String prettyCode(String content) {
  241 + // Vue 界面:去除字段后面多余的 , 逗号,解决前端的 Pretty 代码格式检查的报错
  242 + content = content.replaceAll(",\n}", "\n}").replaceAll(",\n }", "\n }");
  243 + // Vue 界面:去除多的 dateFormatter,只有一个的情况下,说明没使用到
  244 + if (StrUtil.count(content, "dateFormatter") == 1) {
  245 + content = StrUtils.removeLineContains(content, "dateFormatter");
  246 + }
  247 + // Vue 界面:去除多的 dict 相关,只有一个的情况下,说明没使用到
  248 + if (StrUtil.count(content, "getIntDictOptions") == 1) {
  249 + content = content.replace("getIntDictOptions, ", "");
  250 + }
  251 + if (StrUtil.count(content, "getStrDictOptions") == 1) {
  252 + content = content.replace("getStrDictOptions, ", "");
  253 + }
  254 + if (StrUtil.count(content, "getBoolDictOptions") == 1) {
  255 + content = content.replace("getBoolDictOptions, ", "");
  256 + }
  257 + if (StrUtil.count(content, "DICT_TYPE.") == 0) {
  258 + content = StrUtils.removeLineContains(content, "DICT_TYPE");
  259 + }
  260 + return content;
  261 + }
  262 +
232 263 private Map<String, Object> initBindingMap(CodegenTableDO table, List<CodegenColumnDO> columns,
233 264 List<CodegenTableDO> subTables, List<List<CodegenColumnDO>> subColumnsList) {
234 265 // 创建 bindingMap
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/baseVO.vm
... ... @@ -6,9 +6,11 @@ import java.util.*;
6 6 #foreach ($column in $columns)
7 7 #if (${column.javaType} == "BigDecimal")
8 8 import java.math.BigDecimal;
  9 +#break
9 10 #end
10 11 #if (${column.javaType} == "LocalDateTime")
11 12 import java.time.LocalDateTime;
  13 +#break
12 14 #end
13 15 #end
14 16 import javax.validation.constraints.*;
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/controller/vo/excelVO.vm
... ... @@ -6,9 +6,11 @@ import java.util.*;
6 6 #foreach ($column in $columns)
7 7 #if (${column.javaType} == "BigDecimal")
8 8 import java.math.BigDecimal;
  9 +#break
9 10 #end
10 11 #if (${column.javaType} == "LocalDateTime")
11 12 import java.time.LocalDateTime;
  13 +#break
12 14 #end
13 15 #end
14 16  
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/java/service/serviceImpl.vm
... ... @@ -48,7 +48,7 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
48 48  
49 49 @Override
50 50 ## 特殊:主子表专属逻辑
51   -#if ( $subTables.size() > 0)
  51 +#if ( $subTables && $subTables.size() > 0 )
52 52 @Transactional(rollbackFor = Exception.class)
53 53 #end
54 54 public ${primaryColumn.javaType} create${simpleClassName}(${sceneEnum.prefixClass}${table.className}CreateReqVO createReqVO) {
... ... @@ -56,7 +56,7 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
56 56 ${table.className}DO ${classNameVar} = ${table.className}Convert.INSTANCE.convert(createReqVO);
57 57 ${classNameVar}Mapper.insert(${classNameVar});
58 58 ## 特殊:主子表专属逻辑
59   -#if ( $subTables.size() > 0)
  59 +#if ( $subTables && $subTables.size() > 0)
60 60  
61 61 // 插入子表($subTable.classComment)
62 62 #foreach ($subTable in $subTables)
... ... @@ -77,7 +77,7 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
77 77  
78 78 @Override
79 79 ## 特殊:主子表专属逻辑
80   -#if ( $subTables.size() > 0)
  80 +#if ( $subTables && $subTables.size() > 0)
81 81 @Transactional(rollbackFor = Exception.class)
82 82 #end
83 83 public void update${simpleClassName}(${sceneEnum.prefixClass}${table.className}UpdateReqVO updateReqVO) {
... ... @@ -87,7 +87,7 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
87 87 ${table.className}DO updateObj = ${table.className}Convert.INSTANCE.convert(updateReqVO);
88 88 ${classNameVar}Mapper.updateById(updateObj);
89 89 ## 特殊:主子表专属逻辑
90   -#if ( $subTables.size() > 0)
  90 +#if ( $subTables && $subTables.size() > 0)
91 91  
92 92 // 更新子表
93 93 #foreach ($subTable in $subTables)
... ... @@ -106,7 +106,7 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
106 106  
107 107 @Override
108 108 ## 特殊:主子表专属逻辑
109   -#if ( $subTables.size() > 0)
  109 +#if ( $subTables && $subTables.size() > 0)
110 110 @Transactional(rollbackFor = Exception.class)
111 111 #end
112 112 public void delete${simpleClassName}(${primaryColumn.javaType} id) {
... ... @@ -115,7 +115,7 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
115 115 // 删除
116 116 ${classNameVar}Mapper.deleteById(id);
117 117 ## 特殊:主子表专属逻辑
118   -#if ( $subTables.size() > 0)
  118 +#if ( $subTables && $subTables.size() > 0)
119 119  
120 120 // 删除子表
121 121 #foreach ($subTable in $subTables)
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/form_sub.vue.vm 0 → 100644
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/components/list_sub.vue.vm 0 → 100644
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/form.vue.vm
... ... @@ -7,7 +7,6 @@
7 7 label-width="100px"
8 8 v-loading="formLoading"
9 9 >
10   -#set ($dictMethods = [])## 使用到的 dict 字典方法
11 10 #foreach($column in $columns)
12 11 #if ($column.createOperation || $column.updateOperation)
13 12 #set ($dictType = $column.dictType)
... ... @@ -45,9 +44,6 @@
45 44 <el-form-item label="${comment}" prop="${javaField}">
46 45 <el-select v-model="formData.${javaField}" placeholder="请选择${comment}">
47 46 #if ("" != $dictType)## 有数据字典
48   - #if (!$dictMethods.contains($dictMethod))## 如果不存在,则添加到 dictMethods 数组中,后续好 import
49   - #set($ignore = $dictMethods.add($dictMethod) )
50   - #end
51 47 <el-option
52 48 v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
53 49 :key="dict.value"
... ... @@ -63,9 +59,6 @@
63 59 <el-form-item label="${comment}" prop="${javaField}">
64 60 <el-checkbox-group v-model="formData.${javaField}">
65 61 #if ("" != $dictType)## 有数据字典
66   - #if (!$dictMethods.contains($dictMethod))## 如果不存在,则添加到 dictMethods 数组中,后续好 import
67   - #set($ignore = $dictMethods.add($dictMethod) )
68   - #end
69 62 <el-checkbox
70 63 v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
71 64 :key="dict.value"
... ... @@ -82,9 +75,6 @@
82 75 <el-form-item label="${comment}" prop="${javaField}">
83 76 <el-radio-group v-model="formData.${javaField}">
84 77 #if ("" != $dictType)## 有数据字典
85   - #if (!$dictMethods.contains($dictMethod))## 如果不存在,则添加到 dictMethods 数组中,后续好 import
86   - #set($ignore = $dictMethods.add($dictMethod) )
87   - #end
88 78 <el-radio
89 79 v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
90 80 :key="dict.value"
... ... @@ -121,9 +111,7 @@
121 111 </Dialog>
122 112 </template>
123 113 <script setup lang="ts">
124   -#if ($dictMethods.size() > 0)
125   -import { DICT_TYPE#foreach ($dictMethod in $dictMethods), ${dictMethod}#end } from '@/utils/dict'
126   -#end
  114 +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
127 115 import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
128 116  
129 117 const { t } = useI18n() // 国际化
... ... @@ -134,33 +122,21 @@ const dialogTitle = ref(&#39;&#39;) // 弹窗的标题
134 122 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
135 123 const formType = ref('') // 表单的类型:create - 新增;update - 修改
136 124 const formData = ref({
137   -#set ($listOperationLastIndex = -1)## 求最后一个需要 , 的地方
138   -#foreach ($column in $columns)
139   - #if ($column.createOperation || $column.updateOperation)
140   - #set ($listOperationLastIndex = $foreach.index)
141   - #end
142   -#end
143 125 #foreach ($column in $columns)
144 126 #if ($column.createOperation || $column.updateOperation)
145 127 #if ($column.htmlType == "checkbox")
146   - $column.javaField: []#if($foreach.index < $listOperationLastIndex),#end
  128 + $column.javaField: [],
147 129 #else
148   - $column.javaField: undefined#if($foreach.index < $listOperationLastIndex),#end
  130 + $column.javaField: undefined,
149 131 #end
150 132 #end
151 133 #end
152 134 })
153 135 const formRules = reactive({
154   -#set ($listOperationLastIndex = -1)## 求最后一个需要 , 的地方
155   -#foreach ($column in $columns)
156   - #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
157   - #set ($listOperationLastIndex = $foreach.index)
158   - #end
159   -#end
160 136 #foreach ($column in $columns)
161 137 #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !${column.primaryKey})## 创建或者更新操作 && 要求非空 && 非主键
162 138 #set($comment=$column.columnComment)
163   - $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }]#if($foreach.index < $listOperationLastIndex),#end
  139 + $column.javaField: [{ required: true, message: '${comment}不能为空', trigger: #if($column.htmlType == 'select')'change'#else'blur'#end }],
164 140 #end
165 141 #end
166 142 })
... ... @@ -188,9 +164,7 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
188 164 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
189 165 const submitForm = async () => {
190 166 // 校验表单
191   - if (!formRef) return
192   - const valid = await formRef.value.validate()
193   - if (!valid) return
  167 + await formRef.value.validate()
194 168 // 提交请求
195 169 formLoading.value = true
196 170 try {
... ... @@ -213,18 +187,12 @@ const submitForm = async () =&gt; {
213 187 /** 重置表单 */
214 188 const resetForm = () => {
215 189 formData.value = {
216   -#set ($listOperationLastIndex = -1)## 求最后一个需要 , 的地方
217   -#foreach ($column in $columns)
218   - #if ($column.createOperation || $column.updateOperation)
219   - #set ($listOperationLastIndex = $foreach.index)
220   - #end
221   -#end
222 190 #foreach ($column in $columns)
223 191 #if ($column.createOperation || $column.updateOperation)
224 192 #if ($column.htmlType == "checkbox")
225   - $column.javaField: []#if($foreach.index < $listOperationLastIndex),#end
  193 + $column.javaField: [],
226 194 #else
227   - $column.javaField: undefined#if($foreach.index < $listOperationLastIndex),#end
  195 + $column.javaField: undefined,
228 196 #end
229 197 #end
230 198 #end
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3/views/index.vue.vm
... ... @@ -8,7 +8,6 @@
8 8 :inline="true"
9 9 label-width="68px"
10 10 >
11   - #set ($dictMethods = [])## 使用到的 dict 字典方法
12 11 #foreach($column in $columns)
13 12 #if ($column.listOperation)
14 13 #set ($dictType = $column.dictType)
... ... @@ -36,20 +35,13 @@
36 35 </el-form-item>
37 36 #elseif ($column.htmlType == "select" || $column.htmlType == "radio")
38 37 <el-form-item label="${comment}" prop="${javaField}">
39   - #if ($javaField.length() + $comment.length() > 8)
40 38 <el-select
41 39 v-model="queryParams.${javaField}"
42 40 placeholder="请选择${comment}"
43 41 clearable
44 42 class="!w-240px"
45 43 >
46   - #else
47   - <el-select v-model="queryParams.${javaField}" placeholder="请选择${comment}" clearable class="!w-240px">
48   - #end
49 44 #if ("" != $dictType)## 设置了 dictType 数据字典的情况
50   - #if (!$dictMethods.contains($dictMethod))## 如果不存在,则添加到 dictMethods 数组中,后续好 import
51   - #set($ignore = $dictMethods.add($dictMethod) )
52   - #end
53 45 <el-option
54 46 v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())"
55 47 :key="dict.value"
... ... @@ -92,16 +84,12 @@
92 84 <el-form-item>
93 85 <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
94 86 <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
95   - #if ($permissionPrefix.length() <= 12)
96   - <el-button type="primary" @click="openForm('create')" v-hasPermi="['${permissionPrefix}:create']">
97   - #else
98 87 <el-button
99 88 type="primary"
100 89 plain
101 90 @click="openForm('create')"
102 91 v-hasPermi="['${permissionPrefix}:create']"
103 92 >
104   - #end
105 93 <Icon icon="ep:plus" class="mr-5px" /> 新增
106 94 </el-button>
107 95 <el-button
... ... @@ -180,15 +168,8 @@
180 168 </template>
181 169  
182 170 <script setup lang="ts">
183   -#if ($dictMethods.size() > 0)
184   -import { DICT_TYPE#foreach ($dictMethod in $dictMethods), ${dictMethod}#end } from '@/utils/dict'
185   -#end
186   -#foreach ($column in $columns)
187   - #if ($column.listOperationResult && $column.htmlType == "datetime")
  171 +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
188 172 import { dateFormatter } from '@/utils/formatTime'
189   - #break
190   - #end
191   -#end
192 173 import download from '@/utils/download'
193 174 import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
194 175 import ${simpleClassName}Form from './${simpleClassName}Form.vue'
... ... @@ -204,19 +185,13 @@ const list = ref([]) // 列表的数据
204 185 const queryParams = reactive({
205 186 pageNo: 1,
206 187 pageSize: 10,
207   - #set ($listOperationLastIndex = -1)## 求最后一个需要 , 的地方
208   - #foreach ($column in $columns)
209   - #if ($column.listOperation)
210   - #set ($listOperationLastIndex = $foreach.index)
211   - #end
212   - #end
213 188 #foreach ($column in $columns)
214 189 #if ($column.listOperation)
215 190 #if ($column.listOperationCondition != 'BETWEEN')
216   - $column.javaField: null#if($foreach.index < $listOperationLastIndex),#end
  191 + $column.javaField: null,
217 192 #end
218 193 #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN")
219   - $column.javaField: []#if($foreach.index < $listOperationLastIndex),#end
  194 + $column.javaField: [],
220 195 #end
221 196 #end
222 197 #end
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/data.ts.vm
1 1 import type { CrudSchema } from '@/hooks/web/useCrudSchemas'
2   -#foreach ($column in $columns)
3   - #if ($column.listOperationResult && $column.htmlType == "datetime")
4 2 import { dateFormatter } from '@/utils/formatTime'
5   - #break
6   - #end
7   -#end
8 3  
9 4 // 表单校验
10 5 export const rules = reactive({
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/form.vue.vm
... ... @@ -8,7 +8,7 @@
8 8 </Dialog>
9 9 </template>
10 10 <script setup lang="ts">
11   - import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
  11 +import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}'
12 12 import { rules, allSchemas } from './${classNameVar}.data'
13 13 const { t } = useI18n() // 国际化
14 14 const message = useMessage() // 消息弹窗
... ...