Commit b3296b4e9711bc36e3e843f4a3076217ba592d0e
1 parent
e001bbbd
fix(codegen): 修复 Vben5 Antdv Next 模板兼容问题
- 修正组件根导入、子组件用法及内部模板引用 - 按实际生成分支条件导入 Tabs、FormItem、SelectOption 和 RangePicker - 修复一对一及一对多 join-select 场景的导入判定 - 补充模板类型、RangePicker helper 和稀疏主子表回归测试
Showing
15 changed files
with
576 additions
and
98 deletions
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/form.vue.vm
| 1 | +#set ($selectOptionEnable = false) | |
| 2 | +#foreach ($column in $columns) | |
| 3 | + #if (($column.createOperation || $column.updateOperation) && $column.htmlType == "select") | |
| 4 | + #set ($selectOptionEnable = true) | |
| 5 | + #end | |
| 6 | +#end | |
| 1 | 7 | <script lang="ts" setup> |
| 2 | -import type { Rule } from 'antdv-next/es/form'; | |
| 8 | +import type { Rule } from 'antdv-next'; | |
| 3 | 9 | import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; |
| 4 | 10 | |
| 5 | 11 | import { computed, ref } from 'vue'; |
| ... | ... | @@ -9,7 +15,7 @@ import { DICT_TYPE } from '@vben/constants'; |
| 9 | 15 | import { getDictOptions } from '@vben/hooks'; |
| 10 | 16 | import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 11 | 17 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 12 | -import { message, Tabs, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'antdv-next'; | |
| 18 | +import { Checkbox, CheckboxGroup, DatePicker, Form, FormItem, Input, message, Radio, RadioGroup, Select#if ($selectOptionEnable), SelectOption#end#if ( $table.templateType == 10 || $table.templateType == 12 ), TabPane, Tabs#end, TextArea, TreeSelect } from 'antdv-next'; | |
| 13 | 19 | #if($table.templateType == 2)## 树表需要导入这些 |
| 14 | 20 | import { get${simpleClassName}List } from '#/api/${table.moduleName}/${table.businessName}'; |
| 15 | 21 | import { handleTree } from '@vben/utils' |
| ... | ... | @@ -204,7 +210,7 @@ const [Modal, modalApi] = useVbenModal({ |
| 204 | 210 | #set ($dictMethod = "boolean") |
| 205 | 211 | #end |
| 206 | 212 | #if ( $table.templateType == 2 && $column.id == $treeParentColumn.id ) |
| 207 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 213 | + <FormItem label="${comment}" name="${javaField}"> | |
| 208 | 214 | <TreeSelect |
| 209 | 215 | v-model:value="formData.${javaField}" |
| 210 | 216 | :treeData="${classNameVar}Tree" |
| ... | ... | @@ -225,25 +231,25 @@ const [Modal, modalApi] = useVbenModal({ |
| 225 | 231 | treeDefaultExpandAll |
| 226 | 232 | placeholder="请选择${comment}" |
| 227 | 233 | /> |
| 228 | - </Form.Item> | |
| 234 | + </FormItem> | |
| 229 | 235 | #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 |
| 230 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 236 | + <FormItem label="${comment}" name="${javaField}"> | |
| 231 | 237 | <Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" /> |
| 232 | - </Form.Item> | |
| 238 | + </FormItem> | |
| 233 | 239 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 234 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 240 | + <FormItem label="${comment}" name="${javaField}"> | |
| 235 | 241 | <ImageUpload v-model:value="formData.${javaField}" /> |
| 236 | - </Form.Item> | |
| 242 | + </FormItem> | |
| 237 | 243 | #elseif($column.htmlType == "fileUpload")## 文件上传 |
| 238 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 244 | + <FormItem label="${comment}" name="${javaField}"> | |
| 239 | 245 | <FileUpload v-model:value="formData.${javaField}" /> |
| 240 | - </Form.Item> | |
| 246 | + </FormItem> | |
| 241 | 247 | #elseif($column.htmlType == "editor")## 文本编辑器 |
| 242 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 248 | + <FormItem label="${comment}" name="${javaField}"> | |
| 243 | 249 | <RichTextarea v-model="formData.${javaField}" height="500px" /> |
| 244 | - </Form.Item> | |
| 250 | + </FormItem> | |
| 245 | 251 | #elseif($column.htmlType == "select")## 下拉框 |
| 246 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 252 | + <FormItem label="${comment}" name="${javaField}"> | |
| 247 | 253 | <Select v-model:value="formData.${javaField}" placeholder="请选择${comment}"> |
| 248 | 254 | #if ("" != $dictType)## 有数据字典 |
| 249 | 255 | <SelectOption |
| ... | ... | @@ -257,9 +263,9 @@ const [Modal, modalApi] = useVbenModal({ |
| 257 | 263 | <SelectOption label="请选择字典生成" value="" /> |
| 258 | 264 | #end |
| 259 | 265 | </Select> |
| 260 | - </Form.Item> | |
| 266 | + </FormItem> | |
| 261 | 267 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 262 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 268 | + <FormItem label="${comment}" name="${javaField}"> | |
| 263 | 269 | <CheckboxGroup v-model:value="formData.${javaField}"> |
| 264 | 270 | #if ("" != $dictType)## 有数据字典 |
| 265 | 271 | <Checkbox |
| ... | ... | @@ -273,9 +279,9 @@ const [Modal, modalApi] = useVbenModal({ |
| 273 | 279 | <Checkbox label="请选择字典生成" /> |
| 274 | 280 | #end |
| 275 | 281 | </CheckboxGroup> |
| 276 | - </Form.Item> | |
| 282 | + </FormItem> | |
| 277 | 283 | #elseif($column.htmlType == "radio")## 单选框 |
| 278 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 284 | + <FormItem label="${comment}" name="${javaField}"> | |
| 279 | 285 | <RadioGroup v-model:value="formData.${javaField}"> |
| 280 | 286 | #if ("" != $dictType)## 有数据字典 |
| 281 | 287 | <Radio |
| ... | ... | @@ -289,19 +295,19 @@ const [Modal, modalApi] = useVbenModal({ |
| 289 | 295 | <Radio value="1">请选择字典生成</Radio> |
| 290 | 296 | #end |
| 291 | 297 | </RadioGroup> |
| 292 | - </Form.Item> | |
| 298 | + </FormItem> | |
| 293 | 299 | #elseif($column.htmlType == "datetime")## 时间框 |
| 294 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 300 | + <FormItem label="${comment}" name="${javaField}"> | |
| 295 | 301 | <DatePicker |
| 296 | 302 | v-model:value="formData.${javaField}" |
| 297 | 303 | valueFormat="x" |
| 298 | 304 | placeholder="选择${comment}" |
| 299 | 305 | /> |
| 300 | - </Form.Item> | |
| 306 | + </FormItem> | |
| 301 | 307 | #elseif($column.htmlType == "textarea")## 文本框 |
| 302 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 308 | + <FormItem label="${comment}" name="${javaField}"> | |
| 303 | 309 | <TextArea v-model:value="formData.${javaField}" placeholder="请输入${comment}" /> |
| 304 | - </Form.Item> | |
| 310 | + </FormItem> | |
| 305 | 311 | #end |
| 306 | 312 | #end |
| 307 | 313 | #end | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/import.vue.vm
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { FileType } from 'antdv-next/es/upload/interface'; | |
| 3 | - | |
| 4 | 2 | import { ref } from 'vue'; |
| 5 | 3 | |
| 6 | 4 | import { useVbenModal } from '@vben/common-ui'; |
| ... | ... | @@ -43,8 +41,8 @@ const [Modal, modalApi] = useVbenModal({ |
| 43 | 41 | }); |
| 44 | 42 | |
| 45 | 43 | /** 上传前:拦截 antd Upload 的自动上传,文件存到 ref */ |
| 46 | -function beforeUpload(file: FileType) { | |
| 47 | - fileRef.value = file as unknown as File; | |
| 44 | +function beforeUpload(file: File) { | |
| 45 | + fileRef.value = file; | |
| 48 | 46 | return false; |
| 49 | 47 | } |
| 50 | 48 | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/index.vue.vm
| 1 | +#set ($rangePickerEnable = false) | |
| 2 | +#set ($selectOptionEnable = false) | |
| 3 | +#foreach ($column in $columns) | |
| 4 | + #if ($column.listOperation && $column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN") | |
| 5 | + #set ($rangePickerEnable = true) | |
| 6 | + #end | |
| 7 | + #if ($column.listOperation && ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")) | |
| 8 | + #set ($selectOptionEnable = true) | |
| 9 | + #end | |
| 10 | +#end | |
| 1 | 11 | <script lang="ts" setup> |
| 2 | 12 | import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; |
| 3 | 13 | |
| ... | ... | @@ -8,12 +18,14 @@ import { DICT_TYPE } from '@vben/constants'; |
| 8 | 18 | import { getDictOptions } from '@vben/hooks'; |
| 9 | 19 | import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table'; |
| 10 | 20 | import { cloneDeep, downloadFileFromBlobPart, formatDateTime, isEmpty } from '@vben/utils'; |
| 11 | -import { Button, Card, message, Tabs, Pagination, Form, RangePicker, DatePicker, Select, Input } from 'antdv-next'; | |
| 21 | +import { Button, Card, DatePicker, Form, FormItem, Input, message, Pagination#if ($rangePickerEnable), DateRangePicker as RangePicker#end, Select#if ($selectOptionEnable), SelectOption#end#if ( $table.templateType == 11 || $table.templateType == 12 ), TabPane, Tabs#end } from 'antdv-next'; | |
| 12 | 22 | import ${simpleClassName}Form from './modules/form.vue'; |
| 13 | 23 | import { Download, Plus, RefreshCw, Search, Trash2 } from '@vben/icons'; |
| 14 | 24 | import { DictTag } from '#/components/dict-tag'; |
| 15 | 25 | import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 26 | +#if ($rangePickerEnable) | |
| 16 | 27 | import { getRangePickerDefaultProps } from '#/utils/rangePickerProps'; |
| 28 | +#end | |
| 17 | 29 | |
| 18 | 30 | ## 特殊:主子表专属逻辑 |
| 19 | 31 | #if ( $table.templateType == 11 || $table.templateType == 12 ) |
| ... | ... | @@ -249,7 +261,7 @@ onMounted(() => { |
| 249 | 261 | #set ($dictMethod = "boolean") |
| 250 | 262 | #end |
| 251 | 263 | #if ($column.htmlType == "input") |
| 252 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 264 | + <FormItem label="${comment}" name="${javaField}"> | |
| 253 | 265 | <Input |
| 254 | 266 | v-model:value="queryParams.${javaField}" |
| 255 | 267 | placeholder="请输入${comment}" |
| ... | ... | @@ -257,9 +269,9 @@ onMounted(() => { |
| 257 | 269 | @pressEnter="handleQuery" |
| 258 | 270 | class="w-full" |
| 259 | 271 | /> |
| 260 | - </Form.Item> | |
| 272 | + </FormItem> | |
| 261 | 273 | #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox") |
| 262 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 274 | + <FormItem label="${comment}" name="${javaField}"> | |
| 263 | 275 | <Select |
| 264 | 276 | v-model:value="queryParams.${javaField}" |
| 265 | 277 | placeholder="请选择${comment}" |
| ... | ... | @@ -278,10 +290,10 @@ onMounted(() => { |
| 278 | 290 | <SelectOption label="请选择字典生成" value="" /> |
| 279 | 291 | #end |
| 280 | 292 | </Select> |
| 281 | - </Form.Item> | |
| 293 | + </FormItem> | |
| 282 | 294 | #elseif($column.htmlType == "datetime") |
| 283 | 295 | #if ($column.listOperationCondition != "BETWEEN")## 非范围 |
| 284 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 296 | + <FormItem label="${comment}" name="${javaField}"> | |
| 285 | 297 | <DatePicker |
| 286 | 298 | v-model:value="queryParams.${javaField}" |
| 287 | 299 | valueFormat="YYYY-MM-DD" |
| ... | ... | @@ -289,25 +301,25 @@ onMounted(() => { |
| 289 | 301 | allowClear |
| 290 | 302 | class="w-full" |
| 291 | 303 | /> |
| 292 | - </Form.Item> | |
| 304 | + </FormItem> | |
| 293 | 305 | #else## 范围 |
| 294 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 306 | + <FormItem label="${comment}" name="${javaField}"> | |
| 295 | 307 | <RangePicker |
| 296 | 308 | v-model:value="queryParams.${javaField}" |
| 297 | 309 | v-bind="getRangePickerDefaultProps()" |
| 298 | 310 | class="w-full" |
| 299 | 311 | /> |
| 300 | - </Form.Item> | |
| 312 | + </FormItem> | |
| 301 | 313 | #end |
| 302 | 314 | #end |
| 303 | 315 | #end |
| 304 | 316 | #end |
| 305 | - <Form.Item> | |
| 317 | + <FormItem> | |
| 306 | 318 | <Button class="ml-2" @click="resetQuery"> 重置 </Button> |
| 307 | 319 | <Button class="ml-2" @click="handleQuery" type="primary"> |
| 308 | 320 | 搜索 |
| 309 | 321 | </Button> |
| 310 | - </Form.Item> | |
| 322 | + </FormItem> | |
| 311 | 323 | </Form> |
| 312 | 324 | </Card> |
| 313 | 325 | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_erp.vue.vm
| ... | ... | @@ -2,8 +2,14 @@ |
| 2 | 2 | #set ($subColumns = $subColumnsList.get($subIndex))##当前字段数组 |
| 3 | 3 | #set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 |
| 4 | 4 | #set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) |
| 5 | +#set ($selectOptionEnable = false) | |
| 6 | +#foreach ($column in $subColumns) | |
| 7 | + #if (($column.createOperation || $column.updateOperation) && $column.htmlType == "select") | |
| 8 | + #set ($selectOptionEnable = true) | |
| 9 | + #end | |
| 10 | +#end | |
| 5 | 11 | <script lang="ts" setup> |
| 6 | -import type { Rule } from 'antdv-next/es/form'; | |
| 12 | +import type { Rule } from 'antdv-next'; | |
| 7 | 13 | import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; |
| 8 | 14 | |
| 9 | 15 | import { computed, ref } from 'vue'; |
| ... | ... | @@ -13,7 +19,7 @@ import { DICT_TYPE } from '@vben/constants'; |
| 13 | 19 | import { getDictOptions } from '@vben/hooks'; |
| 14 | 20 | import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 15 | 21 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 16 | -import { message, Tabs, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker, TreeSelect } from 'antdv-next'; | |
| 22 | +import { Checkbox, CheckboxGroup, DatePicker, Form, FormItem, Input, message, Radio, RadioGroup, Select#if ($selectOptionEnable), SelectOption#end, TextArea, TreeSelect } from 'antdv-next'; | |
| 17 | 23 | |
| 18 | 24 | import { $t } from '#/locales'; |
| 19 | 25 | |
| ... | ... | @@ -130,23 +136,23 @@ function resetForm(){ |
| 130 | 136 | #set ($dictMethod = "boolean") |
| 131 | 137 | #end |
| 132 | 138 | #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 |
| 133 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 139 | + <FormItem label="${comment}" name="${javaField}"> | |
| 134 | 140 | <Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" /> |
| 135 | - </Form.Item> | |
| 141 | + </FormItem> | |
| 136 | 142 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 137 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 143 | + <FormItem label="${comment}" name="${javaField}"> | |
| 138 | 144 | <ImageUpload v-model:value="formData.${javaField}" /> |
| 139 | - </Form.Item> | |
| 145 | + </FormItem> | |
| 140 | 146 | #elseif($column.htmlType == "fileUpload")## 文件上传 |
| 141 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 147 | + <FormItem label="${comment}" name="${javaField}"> | |
| 142 | 148 | <FileUpload v-model:value="formData.${javaField}" /> |
| 143 | - </Form.Item> | |
| 149 | + </FormItem> | |
| 144 | 150 | #elseif($column.htmlType == "editor")## 文本编辑器 |
| 145 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 151 | + <FormItem label="${comment}" name="${javaField}"> | |
| 146 | 152 | <RichTextarea v-model="formData.${javaField}" height="500px" /> |
| 147 | - </Form.Item> | |
| 153 | + </FormItem> | |
| 148 | 154 | #elseif($column.htmlType == "select")## 下拉框 |
| 149 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 155 | + <FormItem label="${comment}" name="${javaField}"> | |
| 150 | 156 | <Select v-model:value="formData.${javaField}" placeholder="请选择${comment}"> |
| 151 | 157 | #if ("" != $dictType)## 有数据字典 |
| 152 | 158 | <SelectOption |
| ... | ... | @@ -160,9 +166,9 @@ function resetForm(){ |
| 160 | 166 | <SelectOption label="请选择字典生成" value="" /> |
| 161 | 167 | #end |
| 162 | 168 | </Select> |
| 163 | - </Form.Item> | |
| 169 | + </FormItem> | |
| 164 | 170 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 165 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 171 | + <FormItem label="${comment}" name="${javaField}"> | |
| 166 | 172 | <CheckboxGroup v-model:value="formData.${javaField}"> |
| 167 | 173 | #if ("" != $dictType)## 有数据字典 |
| 168 | 174 | <Checkbox |
| ... | ... | @@ -176,9 +182,9 @@ function resetForm(){ |
| 176 | 182 | <Checkbox label="请选择字典生成" /> |
| 177 | 183 | #end |
| 178 | 184 | </CheckboxGroup> |
| 179 | - </Form.Item> | |
| 185 | + </FormItem> | |
| 180 | 186 | #elseif($column.htmlType == "radio")## 单选框 |
| 181 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 187 | + <FormItem label="${comment}" name="${javaField}"> | |
| 182 | 188 | <RadioGroup v-model:value="formData.${javaField}"> |
| 183 | 189 | #if ("" != $dictType)## 有数据字典 |
| 184 | 190 | <Radio |
| ... | ... | @@ -192,19 +198,19 @@ function resetForm(){ |
| 192 | 198 | <Radio value="1">请选择字典生成</Radio> |
| 193 | 199 | #end |
| 194 | 200 | </RadioGroup> |
| 195 | - </Form.Item> | |
| 201 | + </FormItem> | |
| 196 | 202 | #elseif($column.htmlType == "datetime")## 时间框 |
| 197 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 203 | + <FormItem label="${comment}" name="${javaField}"> | |
| 198 | 204 | <DatePicker |
| 199 | 205 | v-model:value="formData.${javaField}" |
| 200 | 206 | valueFormat="x" |
| 201 | 207 | placeholder="选择${comment}" |
| 202 | 208 | /> |
| 203 | - </Form.Item> | |
| 209 | + </FormItem> | |
| 204 | 210 | #elseif($column.htmlType == "textarea")## 文本框 |
| 205 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 211 | + <FormItem label="${comment}" name="${javaField}"> | |
| 206 | 212 | <TextArea v-model:value="formData.${javaField}" placeholder="请输入${comment}" /> |
| 207 | - </Form.Item> | |
| 213 | + </FormItem> | |
| 208 | 214 | #end |
| 209 | 215 | #end |
| 210 | 216 | #end | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_inner.vue.vm
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_normal.vue.vm
| ... | ... | @@ -4,6 +4,12 @@ |
| 4 | 4 | #set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) |
| 5 | 5 | #set ($subClassNameVar = $subClassNameVars.get($subIndex)) |
| 6 | 6 | #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 |
| 7 | +#set ($selectOptionEnable = false) | |
| 8 | +#foreach ($column in $subColumns) | |
| 9 | + #if (($column.createOperation || $column.updateOperation) && (!$subTable.subJoinMany || $column.id != $subJoinColumn.id) && $column.htmlType == "select") | |
| 10 | + #set ($selectOptionEnable = true) | |
| 11 | + #end | |
| 12 | +#end | |
| 7 | 13 | <script lang="ts" setup> |
| 8 | 14 | import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; |
| 9 | 15 | |
| ... | ... | @@ -12,7 +18,7 @@ import { computed, ref, h, onMounted, watch, nextTick } from 'vue'; |
| 12 | 18 | import { DICT_TYPE } from '@vben/constants'; |
| 13 | 19 | import { getDictOptions } from '@vben/hooks'; |
| 14 | 20 | |
| 15 | -import { message, Tabs, Form, Input, TextArea, Button, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, DatePicker } from 'antdv-next'; | |
| 21 | +import { Button, Checkbox, CheckboxGroup, DatePicker#if (!$subTable.subJoinMany), Form, FormItem#end, Input, Radio, RadioGroup, Select#if ($selectOptionEnable), SelectOption#end, TextArea } from 'antdv-next'; | |
| 16 | 22 | import { $t } from '#/locales'; |
| 17 | 23 | |
| 18 | 24 | #if ($subTable.subJoinMany) ## 一对多 |
| ... | ... | @@ -22,7 +28,7 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 22 | 28 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 23 | 29 | import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}'; |
| 24 | 30 | #else |
| 25 | -import type { Rule } from 'antdv-next/es/form'; | |
| 31 | +import type { Rule } from 'antdv-next'; | |
| 26 | 32 | import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 27 | 33 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 28 | 34 | import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}'; |
| ... | ... | @@ -264,23 +270,23 @@ watch( |
| 264 | 270 | #set ($dictMethod = "boolean") |
| 265 | 271 | #end |
| 266 | 272 | #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 |
| 267 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 273 | + <FormItem label="${comment}" name="${javaField}"> | |
| 268 | 274 | <Input v-model:value="formData.${javaField}" placeholder="请输入${comment}" /> |
| 269 | - </Form.Item> | |
| 275 | + </FormItem> | |
| 270 | 276 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 271 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 277 | + <FormItem label="${comment}" name="${javaField}"> | |
| 272 | 278 | <ImageUpload v-model:value="formData.${javaField}" /> |
| 273 | - </Form.Item> | |
| 279 | + </FormItem> | |
| 274 | 280 | #elseif($column.htmlType == "fileUpload")## 文件上传 |
| 275 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 281 | + <FormItem label="${comment}" name="${javaField}"> | |
| 276 | 282 | <FileUpload v-model:value="formData.${javaField}" /> |
| 277 | - </Form.Item> | |
| 283 | + </FormItem> | |
| 278 | 284 | #elseif($column.htmlType == "editor")## 文本编辑器 |
| 279 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 285 | + <FormItem label="${comment}" name="${javaField}"> | |
| 280 | 286 | <RichTextarea v-model="formData.${javaField}" height="500px" /> |
| 281 | - </Form.Item> | |
| 287 | + </FormItem> | |
| 282 | 288 | #elseif($column.htmlType == "select")## 下拉框 |
| 283 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 289 | + <FormItem label="${comment}" name="${javaField}"> | |
| 284 | 290 | <Select v-model:value="formData.${javaField}" placeholder="请选择${comment}"> |
| 285 | 291 | #if ("" != $dictType)## 有数据字典 |
| 286 | 292 | <SelectOption |
| ... | ... | @@ -294,9 +300,9 @@ watch( |
| 294 | 300 | <SelectOption label="请选择字典生成" value="" /> |
| 295 | 301 | #end |
| 296 | 302 | </Select> |
| 297 | - </Form.Item> | |
| 303 | + </FormItem> | |
| 298 | 304 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 299 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 305 | + <FormItem label="${comment}" name="${javaField}"> | |
| 300 | 306 | <CheckboxGroup v-model:value="formData.${javaField}"> |
| 301 | 307 | #if ("" != $dictType)## 有数据字典 |
| 302 | 308 | <Checkbox |
| ... | ... | @@ -310,9 +316,9 @@ watch( |
| 310 | 316 | <Checkbox label="请选择字典生成" /> |
| 311 | 317 | #end |
| 312 | 318 | </CheckboxGroup> |
| 313 | - </Form.Item> | |
| 319 | + </FormItem> | |
| 314 | 320 | #elseif($column.htmlType == "radio")## 单选框 |
| 315 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 321 | + <FormItem label="${comment}" name="${javaField}"> | |
| 316 | 322 | <RadioGroup v-model:value="formData.${javaField}"> |
| 317 | 323 | #if ("" != $dictType)## 有数据字典 |
| 318 | 324 | <Radio |
| ... | ... | @@ -326,19 +332,19 @@ watch( |
| 326 | 332 | <Radio value="1">请选择字典生成</Radio> |
| 327 | 333 | #end |
| 328 | 334 | </RadioGroup> |
| 329 | - </Form.Item> | |
| 335 | + </FormItem> | |
| 330 | 336 | #elseif($column.htmlType == "datetime")## 时间框 |
| 331 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 337 | + <FormItem label="${comment}" name="${javaField}"> | |
| 332 | 338 | <DatePicker |
| 333 | 339 | v-model:value="formData.${javaField}" |
| 334 | 340 | valueFormat="x" |
| 335 | 341 | placeholder="选择${comment}" |
| 336 | 342 | /> |
| 337 | - </Form.Item> | |
| 343 | + </FormItem> | |
| 338 | 344 | #elseif($column.htmlType == "textarea")## 文本框 |
| 339 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 345 | + <FormItem label="${comment}" name="${javaField}"> | |
| 340 | 346 | <TextArea v-model:value="formData.${javaField}" placeholder="请输入${comment}" /> |
| 341 | - </Form.Item> | |
| 347 | + </FormItem> | |
| 342 | 348 | #end |
| 343 | 349 | #end |
| 344 | 350 | #end | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_erp.vue.vm
| ... | ... | @@ -5,6 +5,16 @@ |
| 5 | 5 | #set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 |
| 6 | 6 | #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex)) |
| 7 | 7 | #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 |
| 8 | +#set ($rangePickerEnable = false) | |
| 9 | +#set ($selectOptionEnable = false) | |
| 10 | +#foreach ($column in $subColumns) | |
| 11 | + #if ($column.listOperation && $column.htmlType == "datetime" && $column.listOperationCondition == "BETWEEN") | |
| 12 | + #set ($rangePickerEnable = true) | |
| 13 | + #end | |
| 14 | + #if ($column.listOperation && ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox")) | |
| 15 | + #set ($selectOptionEnable = true) | |
| 16 | + #end | |
| 17 | +#end | |
| 8 | 18 | <script lang="ts" setup> |
| 9 | 19 | import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; |
| 10 | 20 | import type { VxeTableInstance } from '#/adapter/vxe-table'; |
| ... | ... | @@ -15,7 +25,9 @@ import { DICT_TYPE } from '@vben/constants'; |
| 15 | 25 | import { getDictOptions } from '@vben/hooks'; |
| 16 | 26 | |
| 17 | 27 | import { DictTag } from '#/components/dict-tag'; |
| 28 | +#if ($table.templateType == 11 && $rangePickerEnable) | |
| 18 | 29 | import { getRangePickerDefaultProps } from '#/utils/rangePickerProps'; |
| 30 | +#end | |
| 19 | 31 | import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 20 | 32 | import { formatDateTime } from '@vben/utils'; |
| 21 | 33 | |
| ... | ... | @@ -25,7 +37,7 @@ import { useTableToolbar, VbenVxeTableToolbar } from '@vben/plugins/vxe-table'; |
| 25 | 37 | import ${subSimpleClassName}Form from './${subSimpleClassName_strikeCase}-form.vue' |
| 26 | 38 | import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 27 | 39 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 28 | -import { message, Button, Card, Tabs, Pagination, Form, Input, TextArea, Select, RadioGroup, Radio, CheckboxGroup, Checkbox, RangePicker, DatePicker, TreeSelect } from 'antdv-next'; | |
| 40 | +import { Button, Card, Checkbox, CheckboxGroup, DatePicker, Form, FormItem, Input, message, Pagination, Radio, RadioGroup#if ($rangePickerEnable), DateRangePicker as RangePicker#end, Select#if ($selectOptionEnable), SelectOption#end, TextArea, TreeSelect } from 'antdv-next'; | |
| 29 | 41 | import { Plus, Trash2 } from '@vben/icons'; |
| 30 | 42 | import { $t } from '#/locales'; |
| 31 | 43 | #end |
| ... | ... | @@ -224,7 +236,7 @@ onMounted(() => { |
| 224 | 236 | #set ($dictMethod = "boolean") |
| 225 | 237 | #end |
| 226 | 238 | #if ($column.htmlType == "input") |
| 227 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 239 | + <FormItem label="${comment}" name="${javaField}"> | |
| 228 | 240 | <Input |
| 229 | 241 | v-model:value="queryParams.${javaField}" |
| 230 | 242 | placeholder="请输入${comment}" |
| ... | ... | @@ -232,9 +244,9 @@ onMounted(() => { |
| 232 | 244 | @pressEnter="handleQuery" |
| 233 | 245 | class="w-full" |
| 234 | 246 | /> |
| 235 | - </Form.Item> | |
| 247 | + </FormItem> | |
| 236 | 248 | #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox") |
| 237 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 249 | + <FormItem label="${comment}" name="${javaField}"> | |
| 238 | 250 | <Select |
| 239 | 251 | v-model:value="queryParams.${javaField}" |
| 240 | 252 | placeholder="请选择${comment}" |
| ... | ... | @@ -253,10 +265,10 @@ onMounted(() => { |
| 253 | 265 | <SelectOption label="请选择字典生成" value="" /> |
| 254 | 266 | #end |
| 255 | 267 | </Select> |
| 256 | - </Form.Item> | |
| 268 | + </FormItem> | |
| 257 | 269 | #elseif($column.htmlType == "datetime") |
| 258 | 270 | #if ($column.listOperationCondition != "BETWEEN")## 非范围 |
| 259 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 271 | + <FormItem label="${comment}" name="${javaField}"> | |
| 260 | 272 | <DatePicker |
| 261 | 273 | v-model:value="queryParams.${javaField}" |
| 262 | 274 | valueFormat="YYYY-MM-DD" |
| ... | ... | @@ -264,25 +276,25 @@ onMounted(() => { |
| 264 | 276 | allowClear |
| 265 | 277 | class="w-full" |
| 266 | 278 | /> |
| 267 | - </Form.Item> | |
| 279 | + </FormItem> | |
| 268 | 280 | #else## 范围 |
| 269 | - <Form.Item label="${comment}" name="${javaField}"> | |
| 281 | + <FormItem label="${comment}" name="${javaField}"> | |
| 270 | 282 | <RangePicker |
| 271 | 283 | v-model:value="queryParams.${javaField}" |
| 272 | 284 | v-bind="getRangePickerDefaultProps()" |
| 273 | 285 | class="w-full" |
| 274 | 286 | /> |
| 275 | - </Form.Item> | |
| 287 | + </FormItem> | |
| 276 | 288 | #end |
| 277 | 289 | #end |
| 278 | 290 | #end |
| 279 | 291 | #end |
| 280 | - <Form.Item> | |
| 292 | + <FormItem> | |
| 281 | 293 | <Button class="ml-2" @click="resetQuery"> 重置 </Button> |
| 282 | 294 | <Button class="ml-2" @click="handleQuery" type="primary"> |
| 283 | 295 | 搜索 |
| 284 | 296 | </Button> |
| 285 | - </Form.Item> | |
| 297 | + </FormItem> | |
| 286 | 298 | </Form> |
| 287 | 299 | </Card> |
| 288 | 300 | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/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/general/views/modules/list_sub_erp.vue.vm") | |
| 5 | 4 | \ No newline at end of file |
| 5 | +#parse("codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_erp.vue.vm") | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/form.vue.vm
| ... | ... | @@ -6,7 +6,7 @@ import { computed, ref } from 'vue'; |
| 6 | 6 | |
| 7 | 7 | import { useVbenModal } from '@vben/common-ui'; |
| 8 | 8 | |
| 9 | -import { message#if ($table.templateType == 11), Tabs#end } from 'antdv-next'; | |
| 9 | +import { message#if ($table.templateType == 10 || $table.templateType == 12), TabPane, Tabs#end } from 'antdv-next'; | |
| 10 | 10 | |
| 11 | 11 | import { useVbenForm } from '#/adapter/form'; |
| 12 | 12 | import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/import.vue.vm
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { FileType } from 'antdv-next/es/upload/interface'; | |
| 3 | - | |
| 4 | 2 | import { useVbenModal } from '@vben/common-ui'; |
| 5 | 3 | import { downloadFileFromBlobPart } from '@vben/utils'; |
| 6 | 4 | |
| ... | ... | @@ -46,7 +44,7 @@ const [Modal, modalApi] = useVbenModal({ |
| 46 | 44 | }); |
| 47 | 45 | |
| 48 | 46 | /** 上传前 */ |
| 49 | -function beforeUpload(file: FileType) { | |
| 47 | +function beforeUpload(file: File) { | |
| 50 | 48 | formApi.setFieldValue('file', file); |
| 51 | 49 | return false; |
| 52 | 50 | } | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/index.vue.vm
| ... | ... | @@ -8,7 +8,7 @@ import { ref } from 'vue'; |
| 8 | 8 | import {#if ($table.templateType != 2 && $deleteBatchEnable) confirm,#end Page, useVbenModal } from '@vben/common-ui'; |
| 9 | 9 | import { downloadFileFromBlobPart#if ($table.templateType != 2 && $deleteBatchEnable), isEmpty#end } from '@vben/utils'; |
| 10 | 10 | |
| 11 | -import { message#if ($table.templateType == 11), Tabs#end } from 'antdv-next'; | |
| 11 | +import { message#if ($table.templateType == 11 || $table.templateType == 12), TabPane, Tabs#end } from 'antdv-next'; | |
| 12 | 12 | |
| 13 | 13 | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| 14 | 14 | #if (${table.templateType} == 2)## 树表接口 | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_inner.vue.vm
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_normal.vue.vm
| ... | ... | @@ -5,6 +5,12 @@ |
| 5 | 5 | #set ($subClassNameVar = $subClassNameVars.get($subIndex)) |
| 6 | 6 | #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 |
| 7 | 7 | #set ($apiName = "${table.moduleName.substring(0,1).toUpperCase()}${table.moduleName.substring(1)}${simpleClassName}Api") |
| 8 | +#set ($selectOptionEnable = false) | |
| 9 | +#foreach ($column in $subColumns) | |
| 10 | + #if (($column.createOperation || $column.updateOperation) && $column.id != $subJoinColumn.id && $column.htmlType == "select") | |
| 11 | + #set ($selectOptionEnable = true) | |
| 12 | + #end | |
| 13 | +#end | |
| 8 | 14 | <script lang="ts" setup> |
| 9 | 15 | import type { ${apiName} } from '#/api/${table.moduleName}/${table.businessName}'; |
| 10 | 16 | |
| ... | ... | @@ -14,7 +20,19 @@ |
| 14 | 20 | |
| 15 | 21 | #if ($subTable.subJoinMany) ## 一对多 |
| 16 | 22 | import { Plus } from "@vben/icons"; |
| 17 | -import { Button, Tabs, Checkbox, Input, TextArea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'antdv-next'; | |
| 23 | +import { | |
| 24 | + Button, | |
| 25 | + Checkbox, | |
| 26 | + CheckboxGroup, | |
| 27 | + DatePicker, | |
| 28 | + Input, | |
| 29 | + RadioGroup, | |
| 30 | + Select, | |
| 31 | +#if ($selectOptionEnable) | |
| 32 | + SelectOption, | |
| 33 | +#end | |
| 34 | + TextArea, | |
| 35 | +} from 'antdv-next'; | |
| 18 | 36 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 19 | 37 | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| 20 | 38 | import { use${subSimpleClassName}GridEditColumns } from '../data'; | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/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_antdv_next/schema/views/modules/list_sub_erp.vue.vm") | ... | ... |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineVben5AntdvNextTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.service.codegen.inner; | |
| 2 | + | |
| 3 | +import cn.hutool.core.io.resource.ResourceUtil; | |
| 4 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; | |
| 5 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | |
| 6 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; | |
| 7 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; | |
| 8 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 9 | +import org.junit.jupiter.api.Test; | |
| 10 | + | |
| 11 | +import java.util.Arrays; | |
| 12 | +import java.util.List; | |
| 13 | +import java.util.Map; | |
| 14 | +import java.util.regex.Pattern; | |
| 15 | + | |
| 16 | +import static org.junit.jupiter.api.Assertions.assertEquals; | |
| 17 | +import static org.junit.jupiter.api.Assertions.assertFalse; | |
| 18 | +import static org.junit.jupiter.api.Assertions.assertNotNull; | |
| 19 | +import static org.junit.jupiter.api.Assertions.assertTrue; | |
| 20 | + | |
| 21 | +/** | |
| 22 | + * {@link CodegenEngine} 的 Vue3 + Vben5 + Antdv Next 单元测试 | |
| 23 | + * | |
| 24 | + * @author 芋道源码 | |
| 25 | + */ | |
| 26 | +public class CodegenEngineVben5AntdvNextTest extends CodegenEngineAbstractTest { | |
| 27 | + | |
| 28 | + private static final Pattern ANTDV_NEXT_VALUE_IMPORT_PATTERN = Pattern.compile( | |
| 29 | + "import\\s*\\{([^}]*)}\\s*from\\s*'antdv-next';?", Pattern.DOTALL); | |
| 30 | + private static final Pattern RANGE_PICKER_COMPONENT_PATTERN = Pattern.compile("<RangePicker\\b"); | |
| 31 | + private static final Pattern RANGE_PICKER_HELPER_BINDING_PATTERN = Pattern.compile( | |
| 32 | + "\\bv-bind\\s*=\\s*([\"'])\\s*getRangePickerDefaultProps\\s*\\(\\s*\\)\\s*\\1"); | |
| 33 | + private static final Pattern RANGE_PICKER_HELPER_CALL_PATTERN = Pattern.compile( | |
| 34 | + "\\bgetRangePickerDefaultProps\\s*\\(\\s*\\)"); | |
| 35 | + private static final Pattern RANGE_PICKER_HELPER_IMPORT_PATTERN = Pattern.compile( | |
| 36 | + "import\\s*\\{[^}]*\\bgetRangePickerDefaultProps\\b[^}]*}" | |
| 37 | + + "\\s*from\\s*'#/utils(?:/rangePickerProps)?';?", Pattern.DOTALL); | |
| 38 | + private static final Pattern SCHEMA_RANGE_PICKER_COMPONENT_PATTERN = Pattern.compile( | |
| 39 | + "\\bcomponent\\s*:\\s*([\"'])RangePicker\\1"); | |
| 40 | + private static final Pattern SCHEMA_RANGE_PICKER_HELPER_SPREAD_PATTERN = Pattern.compile( | |
| 41 | + "\\.\\.\\.\\s*getRangePickerDefaultProps\\s*\\(\\s*\\)"); | |
| 42 | + | |
| 43 | + private static final String IMPORT_FORM_PATH = | |
| 44 | + "yudao-ui-admin-vben/src/views/infra/demo/modules/import-form.vue"; | |
| 45 | + private static final String SCHEMA_DATA_PATH = | |
| 46 | + "yudao-ui-admin-vben/src/views/infra/demo/data.ts"; | |
| 47 | + private static final String STUDENT_CONTACT_FORM_PATH = | |
| 48 | + "yudao-ui-admin-vben/src/views/infra/demo/modules/student-contact-form.vue"; | |
| 49 | + private static final String STUDENT_TEACHER_FORM_PATH = | |
| 50 | + "yudao-ui-admin-vben/src/views/infra/demo/modules/student-teacher-form.vue"; | |
| 51 | + | |
| 52 | + private static final List<String> INNER_TEMPLATE_PATHS = Arrays.asList( | |
| 53 | + "codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_inner.vue.vm", | |
| 54 | + "codegen/vue3_vben5_antdv_next/general/views/modules/list_sub_inner.vue.vm", | |
| 55 | + "codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_inner.vue.vm", | |
| 56 | + "codegen/vue3_vben5_antdv_next/schema/views/modules/list_sub_inner.vue.vm"); | |
| 57 | + | |
| 58 | + @Test | |
| 59 | + public void testExecute_schemaMasterNormal() { | |
| 60 | + // 调用 | |
| 61 | + Map<String, String> result = executeMaster(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), | |
| 62 | + CodegenTemplateTypeEnum.MASTER_NORMAL); | |
| 63 | + | |
| 64 | + // 断言 | |
| 65 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 66 | + assertSchemaRangePickerGenerated(result); | |
| 67 | + assertTabsGenerated(result); | |
| 68 | + } | |
| 69 | + | |
| 70 | + @Test | |
| 71 | + public void testExecute_schemaMasterErp() { | |
| 72 | + // 调用 | |
| 73 | + Map<String, String> result = executeMaster(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), | |
| 74 | + CodegenTemplateTypeEnum.MASTER_ERP); | |
| 75 | + | |
| 76 | + // 断言 | |
| 77 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 78 | + assertSchemaRangePickerGenerated(result); | |
| 79 | + assertTabsGenerated(result); | |
| 80 | + } | |
| 81 | + | |
| 82 | + @Test | |
| 83 | + public void testExecute_schemaMasterInner() { | |
| 84 | + // 调用 | |
| 85 | + Map<String, String> result = executeMaster(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType(), | |
| 86 | + CodegenTemplateTypeEnum.MASTER_INNER); | |
| 87 | + | |
| 88 | + // 断言 | |
| 89 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 90 | + assertSchemaRangePickerGenerated(result); | |
| 91 | + assertTabsGenerated(result); | |
| 92 | + } | |
| 93 | + | |
| 94 | + @Test | |
| 95 | + public void testExecute_generalTree() { | |
| 96 | + // 调用 | |
| 97 | + Map<String, String> result = executeTree(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType()); | |
| 98 | + | |
| 99 | + // 断言 | |
| 100 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 101 | + assertRuleGenerated(result); | |
| 102 | + assertComponentGenerated(result, "FormItem"); | |
| 103 | + assertComponentGenerated(result, "TreeSelect"); | |
| 104 | + } | |
| 105 | + | |
| 106 | + @Test | |
| 107 | + public void testExecute_generalMasterNormal() { | |
| 108 | + // 调用 | |
| 109 | + Map<String, String> result = executeMaster(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), | |
| 110 | + CodegenTemplateTypeEnum.MASTER_NORMAL); | |
| 111 | + | |
| 112 | + // 断言 | |
| 113 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 114 | + assertRuleGenerated(result); | |
| 115 | + assertGeneralCrudComponentsGenerated(result); | |
| 116 | + assertTabsGenerated(result); | |
| 117 | + } | |
| 118 | + | |
| 119 | + @Test | |
| 120 | + public void testExecute_generalMasterNormal_oneToOneJoinColumnOnlySelect() { | |
| 121 | + // 调用 | |
| 122 | + Map<String, String> result = executeGeneralMasterNormalWithOneToOneJoinSelect(); | |
| 123 | + | |
| 124 | + // 断言 | |
| 125 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 126 | + String content = result.get(STUDENT_TEACHER_FORM_PATH); | |
| 127 | + assertNotNull(content, STUDENT_TEACHER_FORM_PATH + ":未生成一对一子表表单"); | |
| 128 | + assertTrue(content.contains("<Select v-model:value=\"formData.studentId\""), | |
| 129 | + STUDENT_TEACHER_FORM_PATH + ":应渲染 join 列的 Select 组件"); | |
| 130 | + assertTrue(content.contains("<SelectOption"), STUDENT_TEACHER_FORM_PATH + ":应渲染 SelectOption 组件"); | |
| 131 | + assertRootValueImport(STUDENT_TEACHER_FORM_PATH, content, "\\bSelectOption\\b"); | |
| 132 | + } | |
| 133 | + | |
| 134 | + @Test | |
| 135 | + public void testExecute_generalMasterNormal_oneToManyJoinColumnOnlySelect() { | |
| 136 | + // 调用 | |
| 137 | + Map<String, String> result = executeGeneralMasterNormalWithOneToManyJoinSelect(); | |
| 138 | + | |
| 139 | + // 断言 | |
| 140 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 141 | + String content = result.get(STUDENT_CONTACT_FORM_PATH); | |
| 142 | + assertNotNull(content, STUDENT_CONTACT_FORM_PATH + ":未生成一对多子表表单"); | |
| 143 | + assertTrue(content.contains("<VxeTable"), STUDENT_CONTACT_FORM_PATH + ":应生成一对多子表表格"); | |
| 144 | + assertFalse(content.contains("<VxeColumn field=\"studentId\""), | |
| 145 | + STUDENT_CONTACT_FORM_PATH + ":不应生成 join 列"); | |
| 146 | + assertFalse(content.contains("<Select v-model:value=\"row.studentId\""), | |
| 147 | + STUDENT_CONTACT_FORM_PATH + ":不应渲染 join 列的 Select 组件"); | |
| 148 | + assertFalse(content.contains("<SelectOption"), STUDENT_CONTACT_FORM_PATH + ":不应渲染 SelectOption 组件"); | |
| 149 | + assertFalse(createRootImportPattern("import\\s*\\{", "\\bSelectOption\\b").matcher(content).find(), | |
| 150 | + STUDENT_CONTACT_FORM_PATH + ":不应导入 SelectOption 组件"); | |
| 151 | + } | |
| 152 | + | |
| 153 | + @Test | |
| 154 | + public void testExecute_generalMasterInner() { | |
| 155 | + // 调用 | |
| 156 | + Map<String, String> result = executeMaster(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), | |
| 157 | + CodegenTemplateTypeEnum.MASTER_INNER); | |
| 158 | + | |
| 159 | + // 断言 | |
| 160 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 161 | + assertRuleGenerated(result); | |
| 162 | + assertGeneralCrudComponentsGenerated(result); | |
| 163 | + assertTabsGenerated(result); | |
| 164 | + } | |
| 165 | + | |
| 166 | + @Test | |
| 167 | + public void testExecute_generalMasterErp() { | |
| 168 | + // 调用 | |
| 169 | + Map<String, String> result = executeMaster(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType(), | |
| 170 | + CodegenTemplateTypeEnum.MASTER_ERP); | |
| 171 | + | |
| 172 | + // 断言 | |
| 173 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 174 | + assertRuleGenerated(result); | |
| 175 | + assertGeneralCrudComponentsGenerated(result); | |
| 176 | + assertTabsGenerated(result); | |
| 177 | + } | |
| 178 | + | |
| 179 | + @Test | |
| 180 | + public void testExecute_oneImportEnable() { | |
| 181 | + // 开启 import 开关 | |
| 182 | + codegenProperties.setImportEnable(true); | |
| 183 | + codegenEngine.initGlobalBindingMap(); | |
| 184 | + | |
| 185 | + // 调用并断言 | |
| 186 | + assertImportFormCompatibleWithAntdvNext( | |
| 187 | + executeOne(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_SCHEMA.getType())); | |
| 188 | + assertImportFormCompatibleWithAntdvNext( | |
| 189 | + executeOne(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType())); | |
| 190 | + } | |
| 191 | + | |
| 192 | + @Test | |
| 193 | + public void testInnerTemplatesParseAntdvNext() { | |
| 194 | + INNER_TEMPLATE_PATHS.forEach(path -> { | |
| 195 | + String template = ResourceUtil.readUtf8Str(path); | |
| 196 | + assertFalse(template.contains("codegen/vue3_vben5_antd/"), path + ":不应引用 Ant Design Vue 模板"); | |
| 197 | + assertTrue(template.contains("codegen/vue3_vben5_antdv_next/"), path + ":应引用 Antdv Next 模板"); | |
| 198 | + }); | |
| 199 | + } | |
| 200 | + | |
| 201 | + private Map<String, String> executeOne(Integer frontType) { | |
| 202 | + CodegenTableDO table = getTable("student") | |
| 203 | + .setFrontType(frontType) | |
| 204 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | |
| 205 | + return codegenEngine.execute(DbType.MYSQL, table, getColumnList("student"), null, null); | |
| 206 | + } | |
| 207 | + | |
| 208 | + private Map<String, String> executeTree(Integer frontType) { | |
| 209 | + CodegenTableDO table = getTable("category") | |
| 210 | + .setFrontType(frontType) | |
| 211 | + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()); | |
| 212 | + return codegenEngine.execute(DbType.MYSQL, table, getColumnList("category"), null, null); | |
| 213 | + } | |
| 214 | + | |
| 215 | + private Map<String, String> executeGeneralMasterNormalWithOneToOneJoinSelect() { | |
| 216 | + return executeGeneralMasterNormalWithJoinSelect("teacher", 200L, false); | |
| 217 | + } | |
| 218 | + | |
| 219 | + private Map<String, String> executeGeneralMasterNormalWithOneToManyJoinSelect() { | |
| 220 | + return executeGeneralMasterNormalWithJoinSelect("contact", 100L, true); | |
| 221 | + } | |
| 222 | + | |
| 223 | + private Map<String, String> executeGeneralMasterNormalWithJoinSelect(String subTableName, | |
| 224 | + Long subJoinColumnId, | |
| 225 | + boolean subJoinMany) { | |
| 226 | + CodegenTableDO table = getTable("student") | |
| 227 | + .setFrontType(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType()) | |
| 228 | + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()); | |
| 229 | + CodegenTableDO subTable = getTable(subTableName) | |
| 230 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | |
| 231 | + .setFrontType(CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL.getType()) | |
| 232 | + .setSubJoinColumnId(subJoinColumnId).setSubJoinMany(subJoinMany); | |
| 233 | + List<CodegenColumnDO> subColumns = getColumnList(subTableName); | |
| 234 | + // 稀疏场景:join 列是唯一的 select,避免其它 select 掩盖 join 列对导入判定的影响。 | |
| 235 | + subColumns.forEach(column -> { | |
| 236 | + if (subJoinColumnId.equals(column.getId())) { | |
| 237 | + column.setHtmlType("select"); | |
| 238 | + column.setDictType(""); | |
| 239 | + } else if ("select".equals(column.getHtmlType())) { | |
| 240 | + column.setHtmlType("input"); | |
| 241 | + } | |
| 242 | + }); | |
| 243 | + return codegenEngine.execute(DbType.MYSQL, table, getColumnList("student"), | |
| 244 | + List.of(subTable), List.of(subColumns)); | |
| 245 | + } | |
| 246 | + | |
| 247 | + private Map<String, String> executeMaster(Integer frontType, CodegenTemplateTypeEnum templateType) { | |
| 248 | + // 准备参数 | |
| 249 | + CodegenTableDO table = getTable("student") | |
| 250 | + .setFrontType(frontType) | |
| 251 | + .setTemplateType(templateType.getType()); | |
| 252 | + List<CodegenColumnDO> columns = getColumnList("student"); | |
| 253 | + // 准备参数(子表) | |
| 254 | + CodegenTableDO contactTable = getTable("contact") | |
| 255 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | |
| 256 | + .setFrontType(frontType) | |
| 257 | + .setSubJoinColumnId(100L).setSubJoinMany(true); | |
| 258 | + List<CodegenColumnDO> contactColumns = getColumnList("contact"); | |
| 259 | + // 准备参数(班主任) | |
| 260 | + CodegenTableDO teacherTable = getTable("teacher") | |
| 261 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()) | |
| 262 | + .setFrontType(frontType) | |
| 263 | + .setSubJoinColumnId(200L).setSubJoinMany(false); | |
| 264 | + List<CodegenColumnDO> teacherColumns = getColumnList("teacher"); | |
| 265 | + | |
| 266 | + // 调用 | |
| 267 | + return codegenEngine.execute(DbType.MYSQL, table, columns, | |
| 268 | + Arrays.asList(contactTable, teacherTable), Arrays.asList(contactColumns, teacherColumns)); | |
| 269 | + } | |
| 270 | + | |
| 271 | + private static void assertGeneratedCodeCompatibleWithAntdvNext(Map<String, String> result) { | |
| 272 | + assertTrue(result.values().stream().anyMatch(content -> content.contains("from 'antdv-next")), | |
| 273 | + "生成结果应使用 antdv-next"); | |
| 274 | + result.forEach((filePath, content) -> { | |
| 275 | + assertFalse(content.contains("ant-design-vue"), filePath + ":不应使用 ant-design-vue"); | |
| 276 | + assertFalse(content.contains("antdv-next/es/"), filePath + ":不应使用未导出的 antdv-next 深层路径"); | |
| 277 | + assertFalse(content.contains("<Form.Item"), filePath + ":不应使用 Form.Item"); | |
| 278 | + assertFalse(content.contains("</Form.Item>"), filePath + ":不应使用 Form.Item"); | |
| 279 | + assertRootValueImportsSorted(filePath, content); | |
| 280 | + assertRootValueImportMatchesUsage(filePath, content, | |
| 281 | + "\\bDateRangePicker\\s+as\\s+RangePicker\\b", "<RangePicker\\b", "RangePicker"); | |
| 282 | + assertRootValueImportMatchesUsage(filePath, content, | |
| 283 | + "\\bFormItem\\b", "<FormItem\\b", "FormItem"); | |
| 284 | + assertRootValueImportMatchesUsage(filePath, content, | |
| 285 | + "\\bSelectOption\\b", "<SelectOption\\b", "SelectOption"); | |
| 286 | + assertRootValueImportMatchesUsage(filePath, content, | |
| 287 | + "\\bTabPane\\b", "<TabPane\\b", "TabPane"); | |
| 288 | + assertRootValueImportMatchesUsage(filePath, content, | |
| 289 | + "\\bTabs\\b", "<Tabs\\b", "Tabs"); | |
| 290 | + assertRootTypeImportMatchesUsage(filePath, content, | |
| 291 | + "\\bRule\\b", "\\bRule\\b", "Rule"); | |
| 292 | + assertRangePickerHelperImportMatchesUsage(filePath, content); | |
| 293 | + if (filePath.endsWith(".vue")) { | |
| 294 | + assertRangePickerHelperBindingMatchesComponent(filePath, content); | |
| 295 | + } else if (filePath.endsWith(".ts")) { | |
| 296 | + assertSchemaRangePickerHelperMatchesComponent(filePath, content); | |
| 297 | + } | |
| 298 | + }); | |
| 299 | + } | |
| 300 | + | |
| 301 | + private static void assertImportFormCompatibleWithAntdvNext(Map<String, String> result) { | |
| 302 | + assertGeneratedCodeCompatibleWithAntdvNext(result); | |
| 303 | + String content = result.get(IMPORT_FORM_PATH); | |
| 304 | + assertNotNull(content, IMPORT_FORM_PATH + ":未生成导入表单"); | |
| 305 | + assertTrue(content.contains("<Upload"), IMPORT_FORM_PATH + ":应生成 Upload 组件"); | |
| 306 | + assertRootValueImport(IMPORT_FORM_PATH, content, "\\bUpload\\b"); | |
| 307 | + assertTrue(content.contains("beforeUpload(file: File)"), IMPORT_FORM_PATH + ":上传参数应使用原生 File 类型"); | |
| 308 | + assertFalse(content.contains("UploadFile"), IMPORT_FORM_PATH + ":不应使用上传列表项类型 UploadFile"); | |
| 309 | + assertFalse(content.contains("as unknown as File"), IMPORT_FORM_PATH + ":不应通过双重断言转换上传文件"); | |
| 310 | + assertFalse(content.contains("FileType"), IMPORT_FORM_PATH + ":不应继续使用旧 FileType"); | |
| 311 | + } | |
| 312 | + | |
| 313 | + private static void assertTabsGenerated(Map<String, String> result) { | |
| 314 | + assertComponentGenerated(result, "Tabs"); | |
| 315 | + assertComponentGenerated(result, "TabPane"); | |
| 316 | + } | |
| 317 | + | |
| 318 | + private static void assertGeneralCrudComponentsGenerated(Map<String, String> result) { | |
| 319 | + assertComponentGenerated(result, "FormItem"); | |
| 320 | + assertComponentGenerated(result, "RangePicker"); | |
| 321 | + assertComponentGenerated(result, "SelectOption"); | |
| 322 | + } | |
| 323 | + | |
| 324 | + private static void assertRuleGenerated(Map<String, String> result) { | |
| 325 | + assertTrue(result.values().stream().map(CodegenEngineVben5AntdvNextTest::removeAntdvNextRootImports) | |
| 326 | + .anyMatch(content -> Pattern.compile("\\bRule\\b").matcher(content).find()), | |
| 327 | + "生成结果应包含 Rule 类型校验规则"); | |
| 328 | + } | |
| 329 | + | |
| 330 | + private static void assertSchemaRangePickerGenerated(Map<String, String> result) { | |
| 331 | + String content = result.get(SCHEMA_DATA_PATH); | |
| 332 | + assertNotNull(content, SCHEMA_DATA_PATH + ":未生成 Schema 配置"); | |
| 333 | + long componentCount = countMatches(SCHEMA_RANGE_PICKER_COMPONENT_PATTERN, content); | |
| 334 | + assertTrue(componentCount > 0, SCHEMA_DATA_PATH + ":应生成 RangePicker 组件配置"); | |
| 335 | + } | |
| 336 | + | |
| 337 | + private static void assertComponentGenerated(Map<String, String> result, String component) { | |
| 338 | + assertTrue(result.values().stream().anyMatch(content -> content.contains("<" + component)), | |
| 339 | + "生成结果应包含 " + component + " 组件"); | |
| 340 | + } | |
| 341 | + | |
| 342 | + private static void assertRootValueImportMatchesUsage(String filePath, String content, | |
| 343 | + String expectedImportRegex, String usageRegex, | |
| 344 | + String bindingName) { | |
| 345 | + assertRootImportMatchesUsage(filePath, content, "import\\s*\\{", expectedImportRegex, | |
| 346 | + usageRegex, bindingName); | |
| 347 | + } | |
| 348 | + | |
| 349 | + private static void assertRootTypeImportMatchesUsage(String filePath, String content, | |
| 350 | + String expectedImportRegex, String usageRegex, | |
| 351 | + String bindingName) { | |
| 352 | + assertRootImportMatchesUsage(filePath, content, "import\\s+type\\s*\\{", expectedImportRegex, | |
| 353 | + usageRegex, bindingName); | |
| 354 | + } | |
| 355 | + | |
| 356 | + private static void assertRootImportMatchesUsage(String filePath, String content, String importPrefix, | |
| 357 | + String expectedImportRegex, String usageRegex, | |
| 358 | + String bindingName) { | |
| 359 | + boolean imported = createRootImportPattern(importPrefix, expectedImportRegex).matcher(content).find(); | |
| 360 | + boolean used = Pattern.compile(usageRegex).matcher(removeAntdvNextRootImports(content)).find(); | |
| 361 | + assertEquals(used, imported, filePath + ":" + bindingName + (used ? " 缺少合法根导入" : " 存在孤立根导入")); | |
| 362 | + } | |
| 363 | + | |
| 364 | + private static String removeAntdvNextRootImports(String content) { | |
| 365 | + Pattern pattern = Pattern.compile("import\\s+(?:type\\s+)?\\{[^}]*}\\s*from\\s*'antdv-next';?", | |
| 366 | + Pattern.DOTALL); | |
| 367 | + return pattern.matcher(content).replaceAll(""); | |
| 368 | + } | |
| 369 | + | |
| 370 | + private static void assertRootValueImport(String filePath, String content, String expectedRegex) { | |
| 371 | + assertRootImport(filePath, content, "import\\s*\\{", expectedRegex); | |
| 372 | + } | |
| 373 | + | |
| 374 | + private static void assertRootValueImportsSorted(String filePath, String content) { | |
| 375 | + var matcher = ANTDV_NEXT_VALUE_IMPORT_PATTERN.matcher(content); | |
| 376 | + while (matcher.find()) { | |
| 377 | + List<String> actual = Arrays.stream(matcher.group(1).split(",")) | |
| 378 | + .map(String::trim) | |
| 379 | + .filter(item -> !item.isEmpty()) | |
| 380 | + .map(item -> item.replaceFirst("^.*\\s+as\\s+", "")) | |
| 381 | + .toList(); | |
| 382 | + List<String> expected = actual.stream().sorted(String.CASE_INSENSITIVE_ORDER).toList(); | |
| 383 | + assertEquals(expected, actual, filePath + ":antdv-next 命名导入未按 natural 顺序排列"); | |
| 384 | + } | |
| 385 | + } | |
| 386 | + | |
| 387 | + private static void assertRangePickerHelperImportMatchesUsage(String filePath, String content) { | |
| 388 | + boolean imported = RANGE_PICKER_HELPER_IMPORT_PATTERN.matcher(content).find(); | |
| 389 | + boolean called = RANGE_PICKER_HELPER_CALL_PATTERN.matcher(content).find(); | |
| 390 | + assertEquals(called, imported, | |
| 391 | + filePath + ":getRangePickerDefaultProps() 调用与导入不一致"); | |
| 392 | + } | |
| 393 | + | |
| 394 | + private static void assertRangePickerHelperBindingMatchesComponent(String filePath, String content) { | |
| 395 | + long componentCount = countMatches(RANGE_PICKER_COMPONENT_PATTERN, content); | |
| 396 | + long bindingCount = countMatches(RANGE_PICKER_HELPER_BINDING_PATTERN, content); | |
| 397 | + assertEquals(componentCount, bindingCount, | |
| 398 | + filePath + ":RangePicker 与 getRangePickerDefaultProps() 绑定数量不一致"); | |
| 399 | + } | |
| 400 | + | |
| 401 | + private static void assertSchemaRangePickerHelperMatchesComponent(String filePath, String content) { | |
| 402 | + long componentCount = countMatches(SCHEMA_RANGE_PICKER_COMPONENT_PATTERN, content); | |
| 403 | + long helperSpreadCount = countMatches(SCHEMA_RANGE_PICKER_HELPER_SPREAD_PATTERN, content); | |
| 404 | + assertEquals(componentCount, helperSpreadCount, | |
| 405 | + filePath + ":Schema RangePicker 与 getRangePickerDefaultProps() 展开数量不一致"); | |
| 406 | + } | |
| 407 | + | |
| 408 | + private static long countMatches(Pattern pattern, String content) { | |
| 409 | + return pattern.matcher(content).results().count(); | |
| 410 | + } | |
| 411 | + | |
| 412 | + private static void assertRootImport(String filePath, String content, String importPrefix, String expectedRegex) { | |
| 413 | + Pattern pattern = createRootImportPattern(importPrefix, expectedRegex); | |
| 414 | + assertTrue(pattern.matcher(content).find(), filePath + ":缺少合法的 antdv-next 根导入 " + expectedRegex); | |
| 415 | + } | |
| 416 | + | |
| 417 | + private static Pattern createRootImportPattern(String importPrefix, String expectedRegex) { | |
| 418 | + return Pattern.compile(importPrefix + "[^}]*" + expectedRegex | |
| 419 | + + "[^}]*}\\s*from\\s*'antdv-next';?", Pattern.DOTALL); | |
| 420 | + } | |
| 421 | + | |
| 422 | +} | ... | ... |