Commit f6b5ef06d9481d3d4141463c18ed26f278ef256b

Authored by YunaiV
1 parent adbec22e

feat(codegen):uniapp 表单生成器对齐 @wot-ui/ui 2.x + 修测试快照撞名

form 模板全量对齐 2.x:
- :rules/formRules → :schema/createFormSchema(2.x wd-form 只认 schema)
- 字段统一包 wd-form-item;下拉字典 → yd-form-picker 独立;radio shape→type
- 日期时间 → wd-form-item 触发 + wd-datetime-picker 弹层 + xxxVisible;
  LocalDateTime 用 formatDateTime、Date/LocalDate 用 formatDate(import 按需)
- 图片/文件上传 → yd-upload-img/file(原误生成文本框);小数补 precision
- 包名 wot-design-uni(未装)→ @wot-ui/ui(form + detail)

search-form:日期范围 → yd-search-date-range;radio shape→type
字典 import 按实际用量门控(纯 select 不越界)
writeResult:同名快照撞名补父目录 + 序号兜底,assert 路径不变
yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/components/search-form.vue.vm
@@ -40,49 +40,13 @@ @@ -40,49 +40,13 @@
40 /> 40 />
41 </view> 41 </view>
42 #elseif ($column.htmlType == "datetime" && $listOperationCondition == "BETWEEN") 42 #elseif ($column.htmlType == "datetime" && $listOperationCondition == "BETWEEN")
43 - #set ($AttrName = $javaField.substring(0,1).toUpperCase() + ${javaField.substring(1)})  
44 - <view class="yd-search-form-item">  
45 - <view class="yd-search-form-label">  
46 - ${comment}  
47 - </view>  
48 - <view class="yd-search-form-date-range-container">  
49 - <view @click="visible${AttrName}[0] = true">  
50 - <view class="yd-search-form-date-range-picker">  
51 - {{ formatDate(formData.${javaField}?.[0]) || '开始日期' }}  
52 - </view>  
53 - </view>  
54 - -  
55 - <view @click="visible${AttrName}[1] = true">  
56 - <view class="yd-search-form-date-range-picker">  
57 - {{ formatDate(formData.${javaField}?.[1]) || '结束日期' }}  
58 - </view>  
59 - </view>  
60 - </view>  
61 - <wd-datetime-picker-view v-if="visible${AttrName}[0]" v-model="temp${AttrName}[0]" type="date" />  
62 - <view v-if="visible${AttrName}[0]" class="yd-search-form-date-range-actions">  
63 - <wd-button size="small" plain @click="visible${AttrName}[0] = false">  
64 - 取消  
65 - </wd-button>  
66 - <wd-button size="small" type="primary" @click="handle${AttrName}0Confirm">  
67 - 确定  
68 - </wd-button>  
69 - </view>  
70 - <wd-datetime-picker-view v-if="visible${AttrName}[1]" v-model="temp${AttrName}[1]" type="date" />  
71 - <view v-if="visible${AttrName}[1]" class="yd-search-form-date-range-actions">  
72 - <wd-button size="small" plain @click="visible${AttrName}[1] = false">  
73 - 取消  
74 - </wd-button>  
75 - <wd-button size="small" type="primary" @click="handle${AttrName}1Confirm">  
76 - 确定  
77 - </wd-button>  
78 - </view>  
79 - </view> 43 + <yd-search-date-range v-model="formData.${javaField}" label="${comment}" />
80 #elseif (($column.htmlType == "select" || $column.htmlType == "radio") && $dictType && "" != $dictType) 44 #elseif (($column.htmlType == "select" || $column.htmlType == "radio") && $dictType && "" != $dictType)
81 <view class="yd-search-form-item"> 45 <view class="yd-search-form-item">
82 <view class="yd-search-form-label"> 46 <view class="yd-search-form-label">
83 ${comment} 47 ${comment}
84 </view> 48 </view>
85 - <wd-radio-group v-model="formData.${javaField}" shape="button"> 49 + <wd-radio-group v-model="formData.${javaField}" type="button">
86 <wd-radio :value="-1"> 50 <wd-radio :value="-1">
87 全部 51 全部
88 </wd-radio> 52 </wd-radio>
@@ -236,29 +200,6 @@ const placeholder = computed(() =&gt; { @@ -236,29 +200,6 @@ const placeholder = computed(() =&gt; {
236 return conditions.length > 0 ? conditions.join(' | ') : '搜索${table.classComment}' 200 return conditions.length > 0 ? conditions.join(' | ') : '搜索${table.classComment}'
237 }) 201 })
238 202
239 -#if ($hasDateTimeBetween == 1)  
240 -#foreach($column in $columns)  
241 - #if ($column.listOperation && $column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN")  
242 - #set ($javaField = $column.javaField)  
243 - #set ($AttrName = $javaField.substring(0,1).toUpperCase() + ${javaField.substring(1)})  
244 -const visible${AttrName} = ref<[boolean, boolean]>([false, false]) // ${column.columnComment}选择器状态  
245 -const temp${AttrName} = ref<[number, number]>([Date.now(), Date.now()]) // ${column.columnComment}临时值  
246 -  
247 -/** 确认${column.columnComment}开始日期 */  
248 -function handle${AttrName}0Confirm() {  
249 - formData.${javaField} = [temp${AttrName}.value[0], formData.${javaField}?.[1]]  
250 - visible${AttrName}.value[0] = false  
251 -}  
252 -  
253 -/** 确认${column.columnComment}结束日期 */  
254 -function handle${AttrName}1Confirm() {  
255 - formData.${javaField} = [formData.${javaField}?.[0], temp${AttrName}.value[1]]  
256 - visible${AttrName}.value[1] = false  
257 -}  
258 - #end  
259 -#end  
260 -#end  
261 -  
262 /** 搜索按钮操作 */ 203 /** 搜索按钮操作 */
263 function handleSearch() { 204 function handleSearch() {
264 visible.value = false 205 visible.value = false
yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/detail/index.vue.vm
@@ -64,7 +64,7 @@ @@ -64,7 +64,7 @@
64 import type { ${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}' 64 import type { ${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
65 import { onUnload } from '@dcloudio/uni-app' 65 import { onUnload } from '@dcloudio/uni-app'
66 import { onMounted, ref } from 'vue' 66 import { onMounted, ref } from 'vue'
67 -import { useToast } from 'wot-design-uni' 67 +import { useToast } from '@wot-ui/ui/components/wd-toast'
68 import { delete${simpleClassName}, get${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}' 68 import { delete${simpleClassName}, get${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
69 import { useAccess } from '@/hooks/useAccess' 69 import { useAccess } from '@/hooks/useAccess'
70 import { navigateBackPlus } from '@/utils' 70 import { navigateBackPlus } from '@/utils'
yudao-module-infra/src/main/resources/codegen/vue3_admin_uniapp/views/form/index.vue.vm
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 9
10 <!-- 表单区域 --> 10 <!-- 表单区域 -->
11 <view> 11 <view>
12 - <wd-form ref="formRef" :model="formData" :rules="formRules"> 12 + <wd-form ref="formRef" :model="formData" :schema="formSchema">
13 <wd-cell-group border> 13 <wd-cell-group border>
14 #foreach($column in $columns) 14 #foreach($column in $columns)
15 #if (($column.createOperation || $column.updateOperation) && !$column.primaryKey) 15 #if (($column.createOperation || $column.updateOperation) && !$column.primaryKey)
@@ -25,10 +25,23 @@ @@ -25,10 +25,23 @@
25 #elseif ($javaType == "Boolean") 25 #elseif ($javaType == "Boolean")
26 #set ($dictMethod = "getBoolDictOptions") 26 #set ($dictMethod = "getBoolDictOptions")
27 #end 27 #end
28 - ## 优先判断是否有字典,有字典则使用 radio-group  
29 - #if (($column.htmlType == "select" || $column.htmlType == "radio") && $dictType && "" != $dictType)  
30 - <wd-cell title="${comment}" title-width="180rpx" prop="${javaField}" center>  
31 - <wd-radio-group v-model="formData.${javaField}" shape="button"> 28 + ## 下拉选择(字典)→ yd-form-picker,内部按 dictType 解析选项,适合选项较多
  29 + #if ($column.htmlType == "select" && $dictType && "" != $dictType)
  30 + <yd-form-picker
  31 + v-model="formData.${javaField}"
  32 + label="${comment}"
  33 + label-width="180rpx"
  34 + prop="${javaField}"
  35 + :dict-type="DICT_TYPE.${dictType.toUpperCase()}"
  36 +#if ($javaType == "String")
  37 + dict-kind="str"
  38 +#end
  39 + placeholder="请选择${comment}"
  40 + />
  41 + ## 单选(字典)→ radio-group,适合选项较少
  42 + #elseif ($column.htmlType == "radio" && $dictType && "" != $dictType)
  43 + <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}" center>
  44 + <wd-radio-group v-model="formData.${javaField}" type="button">
32 <wd-radio 45 <wd-radio
33 v-for="dict in $dictMethod(DICT_TYPE.${dictType.toUpperCase()})" 46 v-for="dict in $dictMethod(DICT_TYPE.${dictType.toUpperCase()})"
34 :key="dict.value" 47 :key="dict.value"
@@ -37,54 +50,78 @@ @@ -37,54 +50,78 @@
37 {{ dict.label }} 50 {{ dict.label }}
38 </wd-radio> 51 </wd-radio>
39 </wd-radio-group> 52 </wd-radio-group>
40 - </wd-cell> 53 + </wd-form-item>
41 ## 数字类型(无字典) 54 ## 数字类型(无字典)
42 #elseif (${javaType.toLowerCase()} == "long" || ${javaType.toLowerCase()} == "integer" || ${javaType.toLowerCase()} == "short" || ${javaType.toLowerCase()} == "double" || ${javaType.toLowerCase()} == "bigdecimal" || ${javaType.toLowerCase()} == "byte") 55 #elseif (${javaType.toLowerCase()} == "long" || ${javaType.toLowerCase()} == "integer" || ${javaType.toLowerCase()} == "short" || ${javaType.toLowerCase()} == "double" || ${javaType.toLowerCase()} == "bigdecimal" || ${javaType.toLowerCase()} == "byte")
43 - <wd-cell title="${comment}" title-width="180rpx" prop="${javaField}" center> 56 + <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
44 <wd-input-number 57 <wd-input-number
45 v-model="formData.${javaField}" 58 v-model="formData.${javaField}"
  59 +#if (${javaType.toLowerCase()} == "double" || ${javaType.toLowerCase()} == "bigdecimal")
  60 + :precision="2"
  61 + input-type="number"
  62 +#end
46 :min="0" 63 :min="0"
47 /> 64 />
48 - </wd-cell> 65 + </wd-form-item>
49 ## 布尔类型 66 ## 布尔类型
50 #elseif (${javaType.toLowerCase()} == "boolean") 67 #elseif (${javaType.toLowerCase()} == "boolean")
51 - <wd-cell title="${comment}" title-width="180rpx" prop="${javaField}" center> 68 + <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}" center>
52 <wd-switch v-model="formData.${javaField}" /> 69 <wd-switch v-model="formData.${javaField}" />
53 - </wd-cell> 70 + </wd-form-item>
54 ## 日期时间类型 71 ## 日期时间类型
55 #elseif (${javaType.toLowerCase()} == "date" || ${javaType.toLowerCase()} == "localdate" || ${javaType.toLowerCase()} == "localdatetime") 72 #elseif (${javaType.toLowerCase()} == "date" || ${javaType.toLowerCase()} == "localdate" || ${javaType.toLowerCase()} == "localdatetime")
56 #set ($pickerType = "date") 73 #set ($pickerType = "date")
57 #if (${javaType.toLowerCase()} == "localdatetime") 74 #if (${javaType.toLowerCase()} == "localdatetime")
58 #set ($pickerType = "datetime") 75 #set ($pickerType = "datetime")
59 #end 76 #end
  77 + <wd-form-item
  78 + title="${comment}"
  79 + title-width="180rpx"
  80 + prop="${javaField}"
  81 + is-link
  82 +#if ($pickerType == "datetime")
  83 + :value="formatDateTime(formData.${javaField})"
  84 +#else
  85 + :value="formatDate(formData.${javaField})"
  86 +#end
  87 + placeholder="请选择${comment}"
  88 + @click="${javaField}Visible = true"
  89 + />
60 <wd-datetime-picker 90 <wd-datetime-picker
61 v-model="formData.${javaField}" 91 v-model="formData.${javaField}"
  92 + v-model:visible="${javaField}Visible"
62 type="${pickerType}" 93 type="${pickerType}"
63 - label="${comment}"  
64 - label-width="180rpx"  
65 - prop="${javaField}"  
66 /> 94 />
67 ## 文本域 95 ## 文本域
68 #elseif ($column.htmlType == "textarea") 96 #elseif ($column.htmlType == "textarea")
69 - <wd-textarea  
70 - v-model="formData.${javaField}"  
71 - label="${comment}"  
72 - label-width="180rpx"  
73 - placeholder="请输入${comment}"  
74 - :maxlength="200"  
75 - show-word-limit  
76 - clearable  
77 - /> 97 + <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
  98 + <wd-textarea
  99 + v-model="formData.${javaField}"
  100 + clearable
  101 + placeholder="请输入${comment}"
  102 + :maxlength="200"
  103 + show-word-limit
  104 + />
  105 + </wd-form-item>
  106 + ## 图片上传 → yd-upload-img(包 wd-form-item 才能注册到 wd-form 做校验/错误展示)
  107 + #elseif ($column.htmlType == "imageUpload")
  108 + <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
  109 + <yd-upload-img v-model="formData.${javaField}" directory="${table.moduleName}/${table.businessName}" />
  110 + </wd-form-item>
  111 + ## 文件上传 → yd-upload-file
  112 + #elseif ($column.htmlType == "fileUpload")
  113 + <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
  114 + <yd-upload-file v-model="formData.${javaField}" directory="${table.moduleName}/${table.businessName}" />
  115 + </wd-form-item>
78 ## 默认:文本输入 116 ## 默认:文本输入
79 #else 117 #else
80 - <wd-input  
81 - v-model="formData.${javaField}"  
82 - label="${comment}"  
83 - label-width="180rpx"  
84 - prop="${javaField}"  
85 - clearable  
86 - placeholder="请输入${comment}"  
87 - /> 118 + <wd-form-item title="${comment}" title-width="180rpx" prop="${javaField}">
  119 + <wd-input
  120 + v-model="formData.${javaField}"
  121 + clearable
  122 + placeholder="请输入${comment}"
  123 + />
  124 + </wd-form-item>
88 #end 125 #end
89 #end 126 #end
90 #end 127 #end
@@ -107,7 +144,7 @@ @@ -107,7 +144,7 @@
107 </template> 144 </template>
108 145
109 <script lang="ts" setup> 146 <script lang="ts" setup>
110 -import type { FormInstance } from 'wot-design-uni/components/wd-form/types' 147 +import type { FormInstance } from '@wot-ui/ui/components/wd-form/types'
111 #set ($primaryJavaType = $primaryColumn.javaType.toLowerCase()) 148 #set ($primaryJavaType = $primaryColumn.javaType.toLowerCase())
112 #if(${primaryJavaType} == "long" || ${primaryJavaType} == "integer" || ${primaryJavaType} == "short" || ${primaryJavaType} == "double" || ${primaryJavaType} == "bigdecimal" || ${primaryJavaType} == "byte") 149 #if(${primaryJavaType} == "long" || ${primaryJavaType} == "integer" || ${primaryJavaType} == "short" || ${primaryJavaType} == "double" || ${primaryJavaType} == "bigdecimal" || ${primaryJavaType} == "byte")
113 #set ($primaryTsType = "number") 150 #set ($primaryTsType = "number")
@@ -115,6 +152,8 @@ import type { FormInstance } from &#39;wot-design-uni/components/wd-form/types&#39; @@ -115,6 +152,8 @@ import type { FormInstance } from &#39;wot-design-uni/components/wd-form/types&#39;
115 #set ($primaryTsType = "string") 152 #set ($primaryTsType = "string")
116 #end 153 #end
117 #set ($hasDict = 0) 154 #set ($hasDict = 0)
  155 +#set ($hasDate = 0)
  156 +#set ($hasDateTime = 0)
118 #set ($hasGetDictOptions = 0) 157 #set ($hasGetDictOptions = 0)
119 #set ($hasGetIntDictOptions = 0) 158 #set ($hasGetIntDictOptions = 0)
120 #set ($hasGetStrDictOptions = 0) 159 #set ($hasGetStrDictOptions = 0)
@@ -124,22 +163,30 @@ import type { FormInstance } from &#39;wot-design-uni/components/wd-form/types&#39; @@ -124,22 +163,30 @@ import type { FormInstance } from &#39;wot-design-uni/components/wd-form/types&#39;
124 && ($column.htmlType == "select" || $column.htmlType == "radio") 163 && ($column.htmlType == "select" || $column.htmlType == "radio")
125 && $column.dictType && "" != $column.dictType) 164 && $column.dictType && "" != $column.dictType)
126 #set ($hasDict = 1) 165 #set ($hasDict = 1)
127 - #if ($column.javaType == "Integer" || $column.javaType == "Long" || $column.javaType == "Byte" || $column.javaType == "Short") 166 + #if ($column.htmlType == "radio" && ($column.javaType == "Integer" || $column.javaType == "Long" || $column.javaType == "Byte" || $column.javaType == "Short"))
128 #set ($hasGetIntDictOptions = 1) 167 #set ($hasGetIntDictOptions = 1)
129 - #elseif ($column.javaType == "String") 168 + #elseif ($column.htmlType == "radio" && $column.javaType == "String")
130 #set ($hasGetStrDictOptions = 1) 169 #set ($hasGetStrDictOptions = 1)
131 - #elseif ($column.javaType == "Boolean") 170 + #elseif ($column.htmlType == "radio" && $column.javaType == "Boolean")
132 #set ($hasGetBoolDictOptions = 1) 171 #set ($hasGetBoolDictOptions = 1)
133 - #else 172 + #elseif ($column.htmlType == "radio")
134 #set ($hasGetDictOptions = 1) 173 #set ($hasGetDictOptions = 1)
135 #end 174 #end
136 #end 175 #end
  176 + #if (($column.createOperation || $column.updateOperation) && !$column.primaryKey
  177 + && (${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate"))
  178 + #set ($hasDate = 1)
  179 + #end
  180 + #if (($column.createOperation || $column.updateOperation) && !$column.primaryKey
  181 + && ${column.javaType.toLowerCase()} == "localdatetime")
  182 + #set ($hasDateTime = 1)
  183 + #end
137 #end 184 #end
138 import type { ${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}' 185 import type { ${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
139 import { computed, onMounted, ref } from 'vue' 186 import { computed, onMounted, ref } from 'vue'
140 -import { useToast } from 'wot-design-uni' 187 +import { useToast } from '@wot-ui/ui/components/wd-toast'
141 import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}' 188 import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '@/api/${table.moduleName}/${table.businessName}'
142 -#if ($hasDict == 1) 189 +#if ($hasGetDictOptions == 1 || $hasGetIntDictOptions == 1 || $hasGetStrDictOptions == 1 || $hasGetBoolDictOptions == 1)
143 #set ($dictImportNames = "") 190 #set ($dictImportNames = "")
144 #if ($hasGetDictOptions == 1) 191 #if ($hasGetDictOptions == 1)
145 #set ($dictImportNames = "${dictImportNames}getDictOptions, ") 192 #set ($dictImportNames = "${dictImportNames}getDictOptions, ")
@@ -161,6 +208,19 @@ import { navigateBackPlus } from &#39;@/utils&#39; @@ -161,6 +208,19 @@ import { navigateBackPlus } from &#39;@/utils&#39;
161 #if ($hasDict == 1) 208 #if ($hasDict == 1)
162 import { DICT_TYPE } from '@/utils/constants' 209 import { DICT_TYPE } from '@/utils/constants'
163 #end 210 #end
  211 +#if ($hasDate == 1 || $hasDateTime == 1)
  212 + #set ($dateImportNames = "")
  213 + #if ($hasDate == 1)
  214 + #set ($dateImportNames = "${dateImportNames}formatDate, ")
  215 + #end
  216 + #if ($hasDateTime == 1)
  217 + #set ($dateImportNames = "${dateImportNames}formatDateTime, ")
  218 + #end
  219 + #set ($dateImportNames = $dateImportNames.trim())
  220 + #set ($dateImportNames = $dateImportNames.substring(0, $dateImportNames.length() - 1))
  221 +import { $dateImportNames } from '@/utils/date'
  222 +#end
  223 +import { createFormSchema } from '@/utils/wot'
164 224
165 const props = defineProps<{ 225 const props = defineProps<{
166 id?: ${primaryTsType} | any 226 id?: ${primaryTsType} | any
@@ -196,7 +256,12 @@ const formData = ref&lt;${simpleClassName}&gt;({ @@ -196,7 +256,12 @@ const formData = ref&lt;${simpleClassName}&gt;({
196 #end 256 #end
197 #end 257 #end
198 }) // 表单数据 258 }) // 表单数据
199 -const formRules = { 259 +#foreach($column in $columns)
  260 + #if (($column.createOperation || $column.updateOperation) && !$column.primaryKey && (${column.javaType.toLowerCase()} == "date" || ${column.javaType.toLowerCase()} == "localdate" || ${column.javaType.toLowerCase()} == "localdatetime"))
  261 +const ${column.javaField}Visible = ref(false) // ${column.columnComment}选择器状态
  262 + #end
  263 +#end
  264 +const formSchema = createFormSchema({
200 #foreach($column in $columns) 265 #foreach($column in $columns)
201 #set ($javaFieldLower = $column.javaField.toLowerCase()) 266 #set ($javaFieldLower = $column.javaField.toLowerCase())
202 #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey 267 #if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey
@@ -204,7 +269,7 @@ const formRules = { @@ -204,7 +269,7 @@ const formRules = {
204 ${column.javaField}: [{ required: true, message: '${column.columnComment}不能为空' }], 269 ${column.javaField}: [{ required: true, message: '${column.columnComment}不能为空' }],
205 #end 270 #end
206 #end 271 #end
207 -} // 表单校验规则 272 +}) // 表单校验规则
208 const formRef = ref<FormInstance>() // 表单组件引用 273 const formRef = ref<FormInstance>() // 表单组件引用
209 274
210 /** 返回上一页 */ 275 /** 返回上一页 */
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineAbstractTest.java
@@ -152,10 +152,21 @@ public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest { @@ -152,10 +152,21 @@ public abstract class CodegenEngineAbstractTest extends BaseMockitoUnitTest {
152 protected void writeResult(Map<String, String> result, String basePath) { 152 protected void writeResult(Map<String, String> result, String basePath) {
153 // 写入文件内容 153 // 写入文件内容
154 List<Map<String, String>> asserts = new ArrayList<>(); 154 List<Map<String, String>> asserts = new ArrayList<>();
  155 + Set<String> usedContentPaths = new LinkedHashSet<>();
155 result.forEach((filePath, fileContent) -> { 156 result.forEach((filePath, fileContent) -> {
156 String lastFilePath = StrUtil.subAfter(filePath, '/', true); 157 String lastFilePath = StrUtil.subAfter(filePath, '/', true);
157 - String contentPath = StrUtil.subAfter(lastFilePath, '.', true)  
158 - + '/' + StrUtil.subBefore(lastFilePath, '.', true); 158 + String ext = StrUtil.subAfter(lastFilePath, '.', true);
  159 + String name = StrUtil.subBefore(lastFilePath, '.', true);
  160 + String contentPath = ext + '/' + name;
  161 + // 同名文件(如 index.vue 同时出现在 列表/form/detail)会撞名,撞名时前缀补上级目录区分;仍撞则加序号兜底,避免快照互相覆盖
  162 + if (usedContentPaths.contains(contentPath)) {
  163 + String parentDir = StrUtil.subAfter(StrUtil.subBefore(filePath, '/' + lastFilePath, true), '/', true);
  164 + contentPath = ext + '/' + parentDir + '/' + name;
  165 + for (int i = 2; usedContentPaths.contains(contentPath); i++) {
  166 + contentPath = ext + '/' + parentDir + '/' + name + '-' + i;
  167 + }
  168 + }
  169 + usedContentPaths.add(contentPath);
159 asserts.add(MapUtil.<String, String>builder().put("filePath", filePath) 170 asserts.add(MapUtil.<String, String>builder().put("filePath", filePath)
160 .put("contentPath", contentPath).build()); 171 .put("contentPath", contentPath).build());
161 FileUtil.writeUtf8String(fileContent, basePath + "/" + contentPath); 172 FileUtil.writeUtf8String(fileContent, basePath + "/" + contentPath);
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/detail/index
@@ -51,7 +51,7 @@ @@ -51,7 +51,7 @@
51 import type { Student } from '@/api/infra/demo' 51 import type { Student } from '@/api/infra/demo'
52 import { onUnload } from '@dcloudio/uni-app' 52 import { onUnload } from '@dcloudio/uni-app'
53 import { onMounted, ref } from 'vue' 53 import { onMounted, ref } from 'vue'
54 -import { useToast } from 'wot-design-uni' 54 +import { useToast } from '@wot-ui/ui/components/wd-toast'
55 import { deleteStudent, getStudent } from '@/api/infra/demo' 55 import { deleteStudent, getStudent } from '@/api/infra/demo'
56 import { useAccess } from '@/hooks/useAccess' 56 import { useAccess } from '@/hooks/useAccess'
57 import { navigateBackPlus } from '@/utils' 57 import { navigateBackPlus } from '@/utils'
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/form/index
@@ -9,45 +9,48 @@ @@ -9,45 +9,48 @@
9 9
10 <!-- 表单区域 --> 10 <!-- 表单区域 -->
11 <view> 11 <view>
12 - <wd-form ref="formRef" :model="formData" :rules="formRules"> 12 + <wd-form ref="formRef" :model="formData" :schema="formSchema">
13 <wd-cell-group border> 13 <wd-cell-group border>
14 - <wd-input  
15 - v-model="formData.name"  
16 - label="名字"  
17 - label-width="180rpx"  
18 - prop="name"  
19 - clearable  
20 - placeholder="请输入名字"  
21 - />  
22 - <wd-textarea  
23 - v-model="formData.description"  
24 - label="简介"  
25 - label-width="180rpx"  
26 - placeholder="请输入简介"  
27 - :maxlength="200"  
28 - show-word-limit  
29 - clearable 14 + <wd-form-item title="名字" title-width="180rpx" prop="name">
  15 + <wd-input
  16 + v-model="formData.name"
  17 + clearable
  18 + placeholder="请输入名字"
  19 + />
  20 + </wd-form-item>
  21 + <wd-form-item title="简介" title-width="180rpx" prop="description">
  22 + <wd-textarea
  23 + v-model="formData.description"
  24 + clearable
  25 + placeholder="请输入简介"
  26 + :maxlength="200"
  27 + show-word-limit
  28 + />
  29 + </wd-form-item>
  30 + <wd-form-item
  31 + title="出生日期"
  32 + title-width="180rpx"
  33 + prop="birthday"
  34 + is-link
  35 + :value="formatDateTime(formData.birthday)"
  36 + placeholder="请选择出生日期"
  37 + @click="birthdayVisible = true"
30 /> 38 />
31 - <wd-datetime-picker 39 + <wd-datetime-picker
32 v-model="formData.birthday" 40 v-model="formData.birthday"
  41 + v-model:visible="birthdayVisible"
33 type="datetime" 42 type="datetime"
34 - label="出生日期" 43 + />
  44 + <yd-form-picker
  45 + v-model="formData.sex"
  46 + label="性别"
35 label-width="180rpx" 47 label-width="180rpx"
36 - prop="birthday" 48 + prop="sex"
  49 + :dict-type="DICT_TYPE.SYSTEM_USER_SEX"
  50 + placeholder="请选择性别"
37 /> 51 />
38 - <wd-cell title="性别" title-width="180rpx" prop="sex" center>  
39 - <wd-radio-group v-model="formData.sex" shape="button">  
40 - <wd-radio  
41 - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)"  
42 - :key="dict.value"  
43 - :value="dict.value"  
44 - >  
45 - {{ dict.label }}  
46 - </wd-radio>  
47 - </wd-radio-group>  
48 - </wd-cell>  
49 - <wd-cell title="是否有效" title-width="180rpx" prop="enabled" center>  
50 - <wd-radio-group v-model="formData.enabled" shape="button"> 52 + <wd-form-item title="是否有效" title-width="180rpx" prop="enabled" center>
  53 + <wd-radio-group v-model="formData.enabled" type="button">
51 <wd-radio 54 <wd-radio
52 v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" 55 v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)"
53 :key="dict.value" 56 :key="dict.value"
@@ -56,31 +59,20 @@ @@ -56,31 +59,20 @@
56 {{ dict.label }} 59 {{ dict.label }}
57 </wd-radio> 60 </wd-radio>
58 </wd-radio-group> 61 </wd-radio-group>
59 - </wd-cell>  
60 - <wd-input  
61 - v-model="formData.avatar"  
62 - label="头像"  
63 - label-width="180rpx"  
64 - prop="avatar"  
65 - clearable  
66 - placeholder="请输入头像"  
67 - />  
68 - <wd-input  
69 - v-model="formData.video"  
70 - label="附件"  
71 - label-width="180rpx"  
72 - prop="video"  
73 - clearable  
74 - placeholder="请输入附件"  
75 - />  
76 - <wd-input  
77 - v-model="formData.memo"  
78 - label="备注"  
79 - label-width="180rpx"  
80 - prop="memo"  
81 - clearable  
82 - placeholder="请输入备注"  
83 - /> 62 + </wd-form-item>
  63 + <wd-form-item title="头像" title-width="180rpx" prop="avatar">
  64 + <yd-upload-img v-model="formData.avatar" directory="infra/demo" />
  65 + </wd-form-item>
  66 + <wd-form-item title="附件" title-width="180rpx" prop="video">
  67 + <yd-upload-file v-model="formData.video" directory="infra/demo" />
  68 + </wd-form-item>
  69 + <wd-form-item title="备注" title-width="180rpx" prop="memo">
  70 + <wd-input
  71 + v-model="formData.memo"
  72 + clearable
  73 + placeholder="请输入备注"
  74 + />
  75 + </wd-form-item>
84 </wd-cell-group> 76 </wd-cell-group>
85 </wd-form> 77 </wd-form>
86 </view> 78 </view>
@@ -100,14 +92,16 @@ @@ -100,14 +92,16 @@
100 </template> 92 </template>
101 93
102 <script lang="ts" setup> 94 <script lang="ts" setup>
103 -import type { FormInstance } from 'wot-design-uni/components/wd-form/types' 95 +import type { FormInstance } from '@wot-ui/ui/components/wd-form/types'
104 import type { Student } from '@/api/infra/demo' 96 import type { Student } from '@/api/infra/demo'
105 import { computed, onMounted, ref } from 'vue' 97 import { computed, onMounted, ref } from 'vue'
106 -import { useToast } from 'wot-design-uni' 98 +import { useToast } from '@wot-ui/ui/components/wd-toast'
107 import { createStudent, getStudent, updateStudent } from '@/api/infra/demo' 99 import { createStudent, getStudent, updateStudent } from '@/api/infra/demo'
108 -import { getIntDictOptions, getBoolDictOptions } from '@/hooks/useDict' 100 +import { getBoolDictOptions } from '@/hooks/useDict'
109 import { navigateBackPlus } from '@/utils' 101 import { navigateBackPlus } from '@/utils'
110 import { DICT_TYPE } from '@/utils/constants' 102 import { DICT_TYPE } from '@/utils/constants'
  103 +import { formatDateTime } from '@/utils/date'
  104 +import { createFormSchema } from '@/utils/wot'
111 105
112 const props = defineProps<{ 106 const props = defineProps<{
113 id?: number | any 107 id?: number | any
@@ -134,7 +128,8 @@ const formData = ref&lt;Student&gt;({ @@ -134,7 +128,8 @@ const formData = ref&lt;Student&gt;({
134 video: '', 128 video: '',
135 memo: '', 129 memo: '',
136 }) // 表单数据 130 }) // 表单数据
137 -const formRules = { 131 +const birthdayVisible = ref(false) // 出生日期选择器状态
  132 +const formSchema = createFormSchema({
138 name: [{ required: true, message: '名字不能为空' }], 133 name: [{ required: true, message: '名字不能为空' }],
139 description: [{ required: true, message: '简介不能为空' }], 134 description: [{ required: true, message: '简介不能为空' }],
140 birthday: [{ required: true, message: '出生日期不能为空' }], 135 birthday: [{ required: true, message: '出生日期不能为空' }],
@@ -143,7 +138,7 @@ const formRules = { @@ -143,7 +138,7 @@ const formRules = {
143 avatar: [{ required: true, message: '头像不能为空' }], 138 avatar: [{ required: true, message: '头像不能为空' }],
144 video: [{ required: true, message: '附件不能为空' }], 139 video: [{ required: true, message: '附件不能为空' }],
145 memo: [{ required: true, message: '备注不能为空' }], 140 memo: [{ required: true, message: '备注不能为空' }],
146 -} // 表单校验规则 141 +}) // 表单校验规则
147 const formRef = ref<FormInstance>() // 表单组件引用 142 const formRef = ref<FormInstance>() // 表单组件引用
148 143
149 /** 返回上一页 */ 144 /** 返回上一页 */
yudao-module-infra/src/test/resources/codegen/vue3_admin_uniapp_one/vue/search-form
@@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
31 <view class="yd-search-form-label"> 31 <view class="yd-search-form-label">
32 性别 32 性别
33 </view> 33 </view>
34 - <wd-radio-group v-model="formData.sex" shape="button"> 34 + <wd-radio-group v-model="formData.sex" type="button">
35 <wd-radio :value="-1"> 35 <wd-radio :value="-1">
36 全部 36 全部
37 </wd-radio> 37 </wd-radio>
@@ -48,7 +48,7 @@ @@ -48,7 +48,7 @@
48 <view class="yd-search-form-label"> 48 <view class="yd-search-form-label">
49 是否有效 49 是否有效
50 </view> 50 </view>
51 - <wd-radio-group v-model="formData.enabled" shape="button"> 51 + <wd-radio-group v-model="formData.enabled" type="button">
52 <wd-radio :value="-1"> 52 <wd-radio :value="-1">
53 全部 53 全部
54 </wd-radio> 54 </wd-radio>
@@ -61,42 +61,7 @@ @@ -61,42 +61,7 @@
61 </wd-radio> 61 </wd-radio>
62 </wd-radio-group> 62 </wd-radio-group>
63 </view> 63 </view>
64 - <view class="yd-search-form-item">  
65 - <view class="yd-search-form-label">  
66 - 创建时间  
67 - </view>  
68 - <view class="yd-search-form-date-range-container">  
69 - <view @click="visibleCreateTime[0] = true">  
70 - <view class="yd-search-form-date-range-picker">  
71 - {{ formatDate(formData.createTime?.[0]) || '开始日期' }}  
72 - </view>  
73 - </view>  
74 - -  
75 - <view @click="visibleCreateTime[1] = true">  
76 - <view class="yd-search-form-date-range-picker">  
77 - {{ formatDate(formData.createTime?.[1]) || '结束日期' }}  
78 - </view>  
79 - </view>  
80 - </view>  
81 - <wd-datetime-picker-view v-if="visibleCreateTime[0]" v-model="tempCreateTime[0]" type="date" />  
82 - <view v-if="visibleCreateTime[0]" class="yd-search-form-date-range-actions">  
83 - <wd-button size="small" plain @click="visibleCreateTime[0] = false">  
84 - 取消  
85 - </wd-button>  
86 - <wd-button size="small" type="primary" @click="handleCreateTime0Confirm">  
87 - 确定  
88 - </wd-button>  
89 - </view>  
90 - <wd-datetime-picker-view v-if="visibleCreateTime[1]" v-model="tempCreateTime[1]" type="date" />  
91 - <view v-if="visibleCreateTime[1]" class="yd-search-form-date-range-actions">  
92 - <wd-button size="small" plain @click="visibleCreateTime[1] = false">  
93 - 取消  
94 - </wd-button>  
95 - <wd-button size="small" type="primary" @click="handleCreateTime1Confirm">  
96 - 确定  
97 - </wd-button>  
98 - </view>  
99 - </view> 64 + <yd-search-date-range v-model="formData.createTime" label="创建时间" />
100 <view class="yd-search-form-actions"> 65 <view class="yd-search-form-actions">
101 <wd-button class="flex-1" plain @click="handleReset"> 66 <wd-button class="flex-1" plain @click="handleReset">
102 重置 67 重置
@@ -151,21 +116,6 @@ const placeholder = computed(() =&gt; { @@ -151,21 +116,6 @@ const placeholder = computed(() =&gt; {
151 return conditions.length > 0 ? conditions.join(' | ') : '搜索学生' 116 return conditions.length > 0 ? conditions.join(' | ') : '搜索学生'
152 }) 117 })
153 118
154 -const visibleCreateTime = ref<[boolean, boolean]>([false, false]) // 创建时间选择器状态  
155 -const tempCreateTime = ref<[number, number]>([Date.now(), Date.now()]) // 创建时间临时值  
156 -  
157 -/** 确认创建时间开始日期 */  
158 -function handleCreateTime0Confirm() {  
159 - formData.createTime = [tempCreateTime.value[0], formData.createTime?.[1]]  
160 - visibleCreateTime.value[0] = false  
161 -}  
162 -  
163 -/** 确认创建时间结束日期 */  
164 -function handleCreateTime1Confirm() {  
165 - formData.createTime = [formData.createTime?.[0], tempCreateTime.value[1]]  
166 - visibleCreateTime.value[1] = false  
167 -}  
168 -  
169 /** 搜索按钮操作 */ 119 /** 搜索按钮操作 */
170 function handleSearch() { 120 function handleSearch() {
171 visible.value = false 121 visible.value = false