Commit 3ed98e152a0c3efd22dcd26dfeecbbdb60bfb52f
1 parent
c8a584c5
fix(infra): 修复前端代码生成模板的组件绑定与主子表行为
修复 Vben5 字典控件、日期及树选择属性、导入文件移除和 API 导入路径。 修复主子表数据获取、临时编号、必填校验和主表切换后的旧数据残留。 补齐工具方法与组件导入,修正 Ele 工具栏标签及 Vue3 单选多选绑定。 同步 Vue2 组件标签与 prop 声明、旧 Vben 日期范围格式。 更新生成快照,增加跨前端组件契约测试。 验证:85 条 CodegenEngine 测试、138 份 Vue 模板编译通过; Codex、Qwen、DeepSeek 三路评审通过。
Showing
120 changed files
with
3131 additions
and
1753 deletions
yudao-module-infra/src/main/resources/codegen/vue/views/components/form_sub_normal.vue.vm
| ... | ... | @@ -244,9 +244,13 @@ |
| 244 | 244 | Editor, |
| 245 | 245 | #end |
| 246 | 246 | }, |
| 247 | - props:[ | |
| 248 | - '${subJoinColumn.javaField}' | |
| 249 | - ],// ${subJoinColumn.columnComment}(主表的关联字段) | |
| 247 | + props: { | |
| 248 | + // ${subJoinColumn.columnComment}(主表的关联字段) | |
| 249 | + ${subJoinColumn.javaField}: { | |
| 250 | + type: #if ($subJoinColumn.javaType == "String")String#else Number#end, | |
| 251 | + default: undefined | |
| 252 | + } | |
| 253 | + }, | |
| 250 | 254 | data() { |
| 251 | 255 | return { |
| 252 | 256 | // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue/views/components/list_sub_erp.vue.vm
| ... | ... | @@ -78,7 +78,7 @@ |
| 78 | 78 | </el-table> |
| 79 | 79 | #if ($table.templateType == 11) |
| 80 | 80 | <!-- 分页组件 --> |
| 81 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 81 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 82 | 82 | @pagination="getList"/> |
| 83 | 83 | <!-- 对话框(添加 / 修改) --> |
| 84 | 84 | <${subSimpleClassName}Form ref="formRef" @success="getList" /> |
| ... | ... | @@ -98,9 +98,13 @@ |
| 98 | 98 | ${subSimpleClassName}Form |
| 99 | 99 | }, |
| 100 | 100 | #end |
| 101 | - props:[ | |
| 102 | - '${subJoinColumn.javaField}' | |
| 103 | - ],// ${subJoinColumn.columnComment}(主表的关联字段) | |
| 101 | + props: { | |
| 102 | + // ${subJoinColumn.columnComment}(主表的关联字段) | |
| 103 | + ${subJoinColumn.javaField}: { | |
| 104 | + type: #if ($subJoinColumn.javaType == "String")String#else Number#end, | |
| 105 | + default: undefined | |
| 106 | + } | |
| 107 | + }, | |
| 104 | 108 | data() { |
| 105 | 109 | return { |
| 106 | 110 | // 遮罩层 | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue/views/index.vue.vm
| ... | ... | @@ -86,7 +86,7 @@ |
| 86 | 86 | </el-button> |
| 87 | 87 | </el-col> |
| 88 | 88 | #end |
| 89 | - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | |
| 89 | + <RightToolbar :showSearch.sync="showSearch" @queryTable="getList"></RightToolbar> | |
| 90 | 90 | </el-row> |
| 91 | 91 | #if ($importEnable) |
| 92 | 92 | <input ref="importFileRef" type="file" style="display: none" accept=".xls,.xlsx" @change="handleImportFileChange" /> |
| ... | ... | @@ -186,7 +186,7 @@ |
| 186 | 186 | ## 特殊:树表专属逻辑(树不需要分页) |
| 187 | 187 | #if ( $table.templateType != 2 ) |
| 188 | 188 | <!-- 分页组件 --> |
| 189 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 189 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 190 | 190 | @pagination="getList"/> |
| 191 | 191 | #end |
| 192 | 192 | <!-- 对话框(添加 / 修改) --> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3/views/components/form_sub_erp.vue.vm
yudao-module-infra/src/main/resources/codegen/vue3/views/components/form_sub_normal.vue.vm
| ... | ... | @@ -111,7 +111,7 @@ |
| 111 | 111 | <el-radio |
| 112 | 112 | v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())" |
| 113 | 113 | :key="dict.value" |
| 114 | - :label="dict.value" | |
| 114 | + :value="dict.value" | |
| 115 | 115 | > |
| 116 | 116 | {{ dict.label }} |
| 117 | 117 | </el-radio> |
| ... | ... | @@ -233,7 +233,7 @@ |
| 233 | 233 | <el-radio |
| 234 | 234 | v-for="dict in $dictMethod(DICT_TYPE.$dictType.toUpperCase())" |
| 235 | 235 | :key="dict.value" |
| 236 | - :label="dict.value" | |
| 236 | + :value="dict.value" | |
| 237 | 237 | > |
| 238 | 238 | {{ dict.label }} |
| 239 | 239 | </el-radio> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3/views/form.vue.vm
yudao-module-infra/src/main/resources/codegen/vue3_vben/views/data.ts.vm
| ... | ... | @@ -78,6 +78,12 @@ export const searchFormSchema: FormSchema[] = [ |
| 78 | 78 | }, |
| 79 | 79 | #elseif($column.htmlType == "datetime") |
| 80 | 80 | component: 'RangePicker', |
| 81 | + componentProps: { | |
| 82 | + showTime: true, | |
| 83 | + format: 'YYYY-MM-DD HH:mm:ss', | |
| 84 | + valueFormat: 'YYYY-MM-DD HH:mm:ss', | |
| 85 | + allowClear: true, | |
| 86 | + }, | |
| 81 | 87 | #end |
| 82 | 88 | colProps: { span: 8 }, |
| 83 | 89 | }, | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/general/views/form.vue.vm
| ... | ... | @@ -112,7 +112,10 @@ const [Modal, modalApi] = useVbenModal({ |
| 112 | 112 | #set ($index = $foreach.count - 1) |
| 113 | 113 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 114 | 114 | #if ($subTable.subJoinMany) ## 一对多 |
| 115 | - ## TODO 列表值校验? | |
| 115 | + if (!${subClassNameVar}FormRef.value?.validate()) { | |
| 116 | + subTabsName.value = '${subClassNameVar}'; | |
| 117 | + return; | |
| 118 | + } | |
| 116 | 119 | #else |
| 117 | 120 | try { |
| 118 | 121 | await ${subClassNameVar}FormRef.value?.validate() | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/general/views/import.vue.vm
| ... | ... | @@ -48,6 +48,11 @@ function beforeUpload(file: FileType) { |
| 48 | 48 | return false; |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | +/** 移除文件 */ | |
| 52 | +function handleRemove() { | |
| 53 | + fileRef.value = null; | |
| 54 | +} | |
| 55 | + | |
| 51 | 56 | /** 下载导入模板 */ |
| 52 | 57 | async function handleDownload() { |
| 53 | 58 | const data = await import${simpleClassName}Template(); |
| ... | ... | @@ -58,7 +63,12 @@ async function handleDownload() { |
| 58 | 63 | <template> |
| 59 | 64 | <Modal title="导入${table.classComment}" class="w-1/3"> |
| 60 | 65 | <div class="mx-4"> |
| 61 | - <Upload :max-count="1" accept=".xls,.xlsx" :before-upload="beforeUpload"> | |
| 66 | + <Upload | |
| 67 | + :max-count="1" | |
| 68 | + accept=".xls,.xlsx" | |
| 69 | + :before-upload="beforeUpload" | |
| 70 | + :on-remove="handleRemove" | |
| 71 | + > | |
| 62 | 72 | <Button type="primary"> 选择 Excel 文件 </Button> |
| 63 | 73 | </Upload> |
| 64 | 74 | </div> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/general/views/index.vue.vm
| ... | ... | @@ -65,12 +65,7 @@ const queryParams = reactive({ |
| 65 | 65 | #end |
| 66 | 66 | #foreach ($column in $columns) |
| 67 | 67 | #if ($column.listOperation) |
| 68 | - #if ($column.listOperationCondition != 'BETWEEN') | |
| 69 | - $column.javaField: undefined, | |
| 70 | - #end | |
| 71 | - #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") | |
| 72 | - $column.javaField: undefined, | |
| 73 | - #end | |
| 68 | + $column.javaField: undefined, | |
| 74 | 69 | #end |
| 75 | 70 | #end |
| 76 | 71 | }) |
| ... | ... | @@ -197,7 +192,17 @@ function handleRowCheckboxChange({ |
| 197 | 192 | async function handleExport() { |
| 198 | 193 | try { |
| 199 | 194 | exportLoading.value = true; |
| 200 | - const data = await export${simpleClassName}(queryParams); | |
| 195 | + const params = cloneDeep(queryParams) as any; | |
| 196 | + #foreach ($column in $columns) | |
| 197 | + #if ($column.listOperation) | |
| 198 | + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") | |
| 199 | + if (params.${column.javaField} && Array.isArray(params.${column.javaField})) { | |
| 200 | + params.${column.javaField} = (params.${column.javaField} as string[]).join(','); | |
| 201 | + } | |
| 202 | + #end | |
| 203 | + #end | |
| 204 | + #end | |
| 205 | + const data = await export${simpleClassName}(params); | |
| 201 | 206 | downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data }); |
| 202 | 207 | }finally { |
| 203 | 208 | exportLoading.value = false; | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/general/views/modules/form_sub_normal.vue.vm
| ... | ... | @@ -46,25 +46,54 @@ async function handleDelete(row: ${simpleClassName}Api.${subSimpleClassName}) { |
| 46 | 46 | await tableRef.value?.remove(row); |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 50 | -defineExpose({ | |
| 51 | - getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => { | |
| 52 | - const data = list.value as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 53 | - const removeRecords = tableRef.value?.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 54 | - const insertRecords = tableRef.value?.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 55 | - return [ | |
| 56 | - ...data.filter( | |
| 57 | - (row) => !removeRecords.some((removed) => removed.id === row.id), | |
| 58 | - ), | |
| 59 | - ...insertRecords.map((row: any) => ({ ...row, id: undefined })), | |
| 60 | - ]; | |
| 61 | - }, | |
| 62 | -}); | |
| 49 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 50 | +function getData(): ${simpleClassName}Api.${subSimpleClassName}[] { | |
| 51 | + const table = tableRef.value; | |
| 52 | + if (!table) { | |
| 53 | + return []; | |
| 54 | + } | |
| 55 | + const { fullData } = table.getTableData(); | |
| 56 | + const inserted = new Set(table.getInsertRecords()); | |
| 57 | + return fullData.map((row) => | |
| 58 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 59 | + ); | |
| 60 | +} | |
| 61 | + | |
| 62 | +#set ($hasRequiredColumn = false) | |
| 63 | +#foreach ($column in $subColumns) | |
| 64 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 65 | +#set ($hasRequiredColumn = true) | |
| 66 | +#end | |
| 67 | +#end | |
| 68 | +/** 校验子表必填字段 */ | |
| 69 | +function validate(): boolean { | |
| 70 | +#if ($hasRequiredColumn) | |
| 71 | + for (const [index, row] of getData().entries()) { | |
| 72 | +#foreach ($column in $subColumns) | |
| 73 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 74 | + if ( | |
| 75 | + row.${column.javaField} === null || | |
| 76 | + row.${column.javaField} === undefined || | |
| 77 | + (typeof row.${column.javaField} === 'string' && String(row.${column.javaField}).trim() === '') || | |
| 78 | + (Array.isArray(row.${column.javaField}) && row.${column.javaField}.length === 0) | |
| 79 | + ) { | |
| 80 | + message.error(`第 #[[${index + 1}]]# 行:${column.columnComment}不能为空`); | |
| 81 | + return false; | |
| 82 | + } | |
| 83 | +#end | |
| 84 | +#end | |
| 85 | + } | |
| 86 | +#end | |
| 87 | + return true; | |
| 88 | +} | |
| 89 | + | |
| 90 | +defineExpose({ getData, validate }); | |
| 63 | 91 | |
| 64 | 92 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 65 | 93 | watch( |
| 66 | 94 | () => props.${subJoinColumn.javaField}, |
| 67 | 95 | async (val) => { |
| 96 | + list.value = []; | |
| 68 | 97 | if (!val) { |
| 69 | 98 | return; |
| 70 | 99 | } |
| ... | ... | @@ -103,6 +132,17 @@ defineExpose({ |
| 103 | 132 | watch( |
| 104 | 133 | () => props.${subJoinColumn.javaField}, |
| 105 | 134 | async (val) => { |
| 135 | + formData.value = { | |
| 136 | +#foreach ($column in $subColumns) | |
| 137 | +#if ($column.createOperation || $column.updateOperation) | |
| 138 | +#if ($column.htmlType == "checkbox") | |
| 139 | + $column.javaField: [], | |
| 140 | +#else | |
| 141 | + $column.javaField: undefined, | |
| 142 | +#end | |
| 143 | +#end | |
| 144 | +#end | |
| 145 | + }; | |
| 106 | 146 | if (!val) { |
| 107 | 147 | return; |
| 108 | 148 | } |
| ... | ... | @@ -120,6 +160,7 @@ watch( |
| 120 | 160 | #foreach($column in $subColumns) |
| 121 | 161 | #if ($column.createOperation || $column.updateOperation) |
| 122 | 162 | #set ($comment = $column.columnComment) |
| 163 | + #set ($dictType = $column.dictType) | |
| 123 | 164 | #set ($javaField = $column.javaField) |
| 124 | 165 | #set ($javaType = $column.javaType) |
| 125 | 166 | #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/data.ts.vm
| ... | ... | @@ -36,7 +36,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 36 | 36 | id: 0, |
| 37 | 37 | ${treeNameColumn.javaField}: '顶级${table.classComment}', |
| 38 | 38 | }); |
| 39 | - return handleTree(data); | |
| 39 | + return handleTree(data, 'id', '${treeParentColumn.javaField}'); | |
| 40 | 40 | }, |
| 41 | 41 | labelField: '${treeNameColumn.javaField}', |
| 42 | 42 | valueField: 'id', |
| ... | ... | @@ -89,7 +89,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 89 | 89 | placeholder: '请选择${comment}', |
| 90 | 90 | }, |
| 91 | 91 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 92 | - component: 'Checkbox', | |
| 92 | + component: 'CheckboxGroup', | |
| 93 | 93 | componentProps: { |
| 94 | 94 | #if ("" != $dictType)## 有数据字典 |
| 95 | 95 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -306,7 +306,7 @@ export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] { |
| 306 | 306 | placeholder: '请选择${comment}', |
| 307 | 307 | }, |
| 308 | 308 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 309 | - component: 'Checkbox', | |
| 309 | + component: 'CheckboxGroup', | |
| 310 | 310 | componentProps: { |
| 311 | 311 | #if ("" != $dictType)## 有数据字典 |
| 312 | 312 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -446,6 +446,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 446 | 446 | #if ($column.createOperation || $column.updateOperation) |
| 447 | 447 | #if (!$column.primaryKey && $column.listOperationResult && $column.id != $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写 |
| 448 | 448 | #set ($dictType = $column.dictType) |
| 449 | + #set ($javaType = $column.javaType) | |
| 449 | 450 | #set ($javaField = $column.javaField) |
| 450 | 451 | #set ($comment = $column.columnComment) |
| 451 | 452 | #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") |
| ... | ... | @@ -540,7 +541,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 540 | 541 | placeholder: '请选择${comment}', |
| 541 | 542 | }, |
| 542 | 543 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 543 | - component: 'Checkbox', | |
| 544 | + component: 'CheckboxGroup', | |
| 544 | 545 | componentProps: { |
| 545 | 546 | #if ("" != $dictType)## 有数据字典 |
| 546 | 547 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -590,7 +591,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 590 | 591 | #end |
| 591 | 592 | #if ($table.templateType == 12) ## 内嵌情况 |
| 592 | 593 | /** 列表的字段 */ |
| 593 | - export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] { | |
| 594 | + export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${apiName}.${subSimpleClassName}>['columns'] { | |
| 594 | 595 | return [ |
| 595 | 596 | #foreach($column in $subColumns) |
| 596 | 597 | #if ($column.listOperationResult) | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/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 'ant-design-vue'; | |
| 9 | +import { message#if ($table.templateType == 10 || $table.templateType == 12), Tabs#end } from 'ant-design-vue'; | |
| 10 | 10 | |
| 11 | 11 | import { useVbenForm } from '#/adapter/form'; |
| 12 | 12 | import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; |
| ... | ... | @@ -69,15 +69,11 @@ const [Modal, modalApi] = useVbenModal({ |
| 69 | 69 | #foreach ($subTable in $subTables) |
| 70 | 70 | #set ($index = $foreach.count - 1) |
| 71 | 71 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 72 | - #if ($subTable.subJoinMany) ## 一对多 | |
| 73 | - ## TODO 列表值校验? | |
| 74 | - #else | |
| 75 | 72 | const ${subClassNameVar}Valid = await ${subClassNameVar}FormRef.value?.validate(); |
| 76 | 73 | if (!${subClassNameVar}Valid) { |
| 77 | 74 | subTabsName.value = '${subClassNameVar}'; |
| 78 | 75 | return; |
| 79 | 76 | } |
| 80 | - #end | |
| 81 | 77 | #end |
| 82 | 78 | #end |
| 83 | 79 | #end | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/import.vue.vm
| ... | ... | @@ -51,6 +51,11 @@ function beforeUpload(file: FileType) { |
| 51 | 51 | return false; |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | +/** 移除文件 */ | |
| 55 | +function handleRemove() { | |
| 56 | + formApi.setFieldValue('file', undefined); | |
| 57 | +} | |
| 58 | + | |
| 54 | 59 | /** 下载模板 */ |
| 55 | 60 | async function handleDownload() { |
| 56 | 61 | const data = await import${simpleClassName}Template(); |
| ... | ... | @@ -67,6 +72,7 @@ async function handleDownload() { |
| 67 | 72 | :max-count="1" |
| 68 | 73 | accept=".xls,.xlsx" |
| 69 | 74 | :before-upload="beforeUpload" |
| 75 | + :on-remove="handleRemove" | |
| 70 | 76 | > |
| 71 | 77 | <Button type="primary"> 选择 Excel 文件 </Button> |
| 72 | 78 | </Upload> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antd/schema/views/modules/form_sub_normal.vue.vm
| ... | ... | @@ -14,7 +14,7 @@ |
| 14 | 14 | |
| 15 | 15 | #if ($subTable.subJoinMany) ## 一对多 |
| 16 | 16 | import { Plus } from "@vben/icons"; |
| 17 | -import { Button, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue'; | |
| 17 | +import { Button, Checkbox, CheckboxGroup, DatePicker, Input, message, RadioGroup, Select, Tabs, Textarea } from 'ant-design-vue'; | |
| 18 | 18 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 19 | 19 | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| 20 | 20 | import { use${subSimpleClassName}GridEditColumns } from '../data'; |
| ... | ... | @@ -59,26 +59,54 @@ const handleDelete = async (row: ${apiName}.${subSimpleClassName}) => { |
| 59 | 59 | await gridApi.grid.remove(row); |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 63 | -defineExpose({ | |
| 64 | - getData: (): ${apiName}.${subSimpleClassName}[] => { | |
| 65 | - const data = gridApi.grid.getData() as ${apiName}.${subSimpleClassName}[]; | |
| 66 | - const removeRecords = gridApi.grid.getRemoveRecords() as ${apiName}.${subSimpleClassName}[]; | |
| 67 | - const insertRecords = gridApi.grid.getInsertRecords() as ${apiName}.${subSimpleClassName}[]; | |
| 68 | - return data | |
| 69 | - .filter((row) => !removeRecords.some((removed) => removed.id === row.id)) | |
| 70 | - .concat(insertRecords.map((row: any) => ({ ...row, id: undefined }))); | |
| 71 | - }, | |
| 72 | -}); | |
| 62 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 63 | +function getData(): ${apiName}.${subSimpleClassName}[] { | |
| 64 | + const { fullData } = gridApi.grid.getTableData(); | |
| 65 | + const inserted = new Set(gridApi.grid.getInsertRecords()); | |
| 66 | + return fullData.map((row) => | |
| 67 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 68 | + ); | |
| 69 | +} | |
| 70 | + | |
| 71 | +#set ($hasRequiredColumn = false) | |
| 72 | +#foreach ($column in $subColumns) | |
| 73 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 74 | +#set ($hasRequiredColumn = true) | |
| 75 | +#end | |
| 76 | +#end | |
| 77 | +/** 校验子表必填字段 */ | |
| 78 | +function validate(): boolean { | |
| 79 | +#if ($hasRequiredColumn) | |
| 80 | + for (const [index, row] of getData().entries()) { | |
| 81 | +#foreach ($column in $subColumns) | |
| 82 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 83 | + if ( | |
| 84 | + row.${column.javaField} === null || | |
| 85 | + row.${column.javaField} === undefined || | |
| 86 | + (typeof row.${column.javaField} === 'string' && String(row.${column.javaField}).trim() === '') || | |
| 87 | + (Array.isArray(row.${column.javaField}) && row.${column.javaField}.length === 0) | |
| 88 | + ) { | |
| 89 | + message.error(`第 #[[${index + 1}]]# 行:${column.columnComment}不能为空`); | |
| 90 | + return false; | |
| 91 | + } | |
| 92 | +#end | |
| 93 | +#end | |
| 94 | + } | |
| 95 | +#end | |
| 96 | + return true; | |
| 97 | +} | |
| 98 | + | |
| 99 | +defineExpose({ getData, validate }); | |
| 73 | 100 | |
| 74 | 101 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 75 | 102 | watch( |
| 76 | 103 | () => props.${subJoinColumn.javaField}, |
| 77 | 104 | async (val) => { |
| 105 | + await nextTick(); | |
| 78 | 106 | if (!val) { |
| 107 | + await gridApi.grid.loadData([]); | |
| 79 | 108 | return; |
| 80 | 109 | } |
| 81 | - await nextTick(); | |
| 82 | 110 | await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!)); |
| 83 | 111 | }, |
| 84 | 112 | { immediate: true }, |
| ... | ... | @@ -110,10 +138,11 @@ defineExpose({ |
| 110 | 138 | watch( |
| 111 | 139 | () => props.${subJoinColumn.javaField}, |
| 112 | 140 | async (val) => { |
| 141 | + await nextTick(); | |
| 142 | + await formApi.resetForm(); | |
| 113 | 143 | if (!val) { |
| 114 | 144 | return; |
| 115 | 145 | } |
| 116 | - await nextTick(); | |
| 117 | 146 | await formApi.setValues(await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)); |
| 118 | 147 | }, |
| 119 | 148 | { immediate: true }, | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/form.vue.vm
| ... | ... | @@ -118,7 +118,10 @@ const [Modal, modalApi] = useVbenModal({ |
| 118 | 118 | #set ($index = $foreach.count - 1) |
| 119 | 119 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 120 | 120 | #if ($subTable.subJoinMany) ## 一对多 |
| 121 | - ## TODO 列表值校验? | |
| 121 | + if (!${subClassNameVar}FormRef.value?.validate()) { | |
| 122 | + subTabsName.value = '${subClassNameVar}'; | |
| 123 | + return; | |
| 124 | + } | |
| 122 | 125 | #else |
| 123 | 126 | try { |
| 124 | 127 | await ${subClassNameVar}FormRef.value?.validate() | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/import.vue.vm
| ... | ... | @@ -46,6 +46,11 @@ function beforeUpload(file: File) { |
| 46 | 46 | return false; |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | +/** 移除文件 */ | |
| 50 | +function handleRemove() { | |
| 51 | + fileRef.value = null; | |
| 52 | +} | |
| 53 | + | |
| 49 | 54 | /** 下载导入模板 */ |
| 50 | 55 | async function handleDownload() { |
| 51 | 56 | const data = await import${simpleClassName}Template(); |
| ... | ... | @@ -56,7 +61,8 @@ async function handleDownload() { |
| 56 | 61 | <template> |
| 57 | 62 | <Modal title="导入${table.classComment}" class="w-1/3"> |
| 58 | 63 | <div class="mx-4"> |
| 59 | - <Upload :max-count="1" accept=".xls,.xlsx" :before-upload="beforeUpload"> | |
| 64 | + <Upload :max-count="1" accept=".xls,.xlsx" :before-upload="beforeUpload" | |
| 65 | + :on-remove="handleRemove"> | |
| 60 | 66 | <Button type="primary"> 选择 Excel 文件 </Button> |
| 61 | 67 | </Upload> |
| 62 | 68 | </div> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/index.vue.vm
| ... | ... | @@ -77,12 +77,7 @@ const queryParams = reactive({ |
| 77 | 77 | #end |
| 78 | 78 | #foreach ($column in $columns) |
| 79 | 79 | #if ($column.listOperation) |
| 80 | - #if ($column.listOperationCondition != 'BETWEEN') | |
| 81 | - $column.javaField: undefined, | |
| 82 | - #end | |
| 83 | - #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") | |
| 84 | - $column.javaField: undefined, | |
| 85 | - #end | |
| 80 | + $column.javaField: undefined, | |
| 86 | 81 | #end |
| 87 | 82 | #end |
| 88 | 83 | }) |
| ... | ... | @@ -209,7 +204,17 @@ function handleRowCheckboxChange({ |
| 209 | 204 | async function handleExport() { |
| 210 | 205 | try { |
| 211 | 206 | exportLoading.value = true; |
| 212 | - const data = await export${simpleClassName}(queryParams); | |
| 207 | + const params = cloneDeep(queryParams) as any; | |
| 208 | + #foreach ($column in $columns) | |
| 209 | + #if ($column.listOperation) | |
| 210 | + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") | |
| 211 | + if (params.${column.javaField} && Array.isArray(params.${column.javaField})) { | |
| 212 | + params.${column.javaField} = (params.${column.javaField} as string[]).join(','); | |
| 213 | + } | |
| 214 | + #end | |
| 215 | + #end | |
| 216 | + #end | |
| 217 | + const data = await export${simpleClassName}(params); | |
| 213 | 218 | downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data }); |
| 214 | 219 | }finally { |
| 215 | 220 | exportLoading.value = false; | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/general/views/modules/form_sub_normal.vue.vm
| ... | ... | @@ -18,7 +18,7 @@ import { computed, ref, h, onMounted, watch, nextTick } from 'vue'; |
| 18 | 18 | import { DICT_TYPE } from '@vben/constants'; |
| 19 | 19 | import { getDictOptions } from '@vben/hooks'; |
| 20 | 20 | |
| 21 | -import { Button, Checkbox, CheckboxGroup, DatePicker#if (!$subTable.subJoinMany), Form, FormItem#end, Input, Radio, RadioGroup, Select#if ($selectOptionEnable), SelectOption#end, TextArea } from 'antdv-next'; | |
| 21 | +import { Button, Checkbox, CheckboxGroup, DatePicker#if (!$subTable.subJoinMany), Form, FormItem#end, Input#if ($subTable.subJoinMany), message#end, Radio, RadioGroup, Select#if ($selectOptionEnable), SelectOption#end, TextArea } from 'antdv-next'; | |
| 22 | 22 | import { $t } from '#/locales'; |
| 23 | 23 | |
| 24 | 24 | #if ($subTable.subJoinMany) ## 一对多 |
| ... | ... | @@ -52,25 +52,54 @@ async function handleDelete(row: ${simpleClassName}Api.${subSimpleClassName}) { |
| 52 | 52 | await tableRef.value?.remove(row); |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 56 | -defineExpose({ | |
| 57 | - getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => { | |
| 58 | - const data = list.value as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 59 | - const removeRecords = tableRef.value?.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 60 | - const insertRecords = tableRef.value?.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 61 | - return [ | |
| 62 | - ...data.filter( | |
| 63 | - (row) => !removeRecords.some((removed) => removed.id === row.id), | |
| 64 | - ), | |
| 65 | - ...insertRecords.map((row: any) => ({ ...row, id: undefined })), | |
| 66 | - ]; | |
| 67 | - }, | |
| 68 | -}); | |
| 55 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 56 | +function getData(): ${simpleClassName}Api.${subSimpleClassName}[] { | |
| 57 | + const table = tableRef.value; | |
| 58 | + if (!table) { | |
| 59 | + return []; | |
| 60 | + } | |
| 61 | + const { fullData } = table.getTableData(); | |
| 62 | + const inserted = new Set(table.getInsertRecords()); | |
| 63 | + return fullData.map((row) => | |
| 64 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 65 | + ); | |
| 66 | +} | |
| 67 | + | |
| 68 | +#set ($hasRequiredColumn = false) | |
| 69 | +#foreach ($column in $subColumns) | |
| 70 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 71 | +#set ($hasRequiredColumn = true) | |
| 72 | +#end | |
| 73 | +#end | |
| 74 | +/** 校验子表必填字段 */ | |
| 75 | +function validate(): boolean { | |
| 76 | +#if ($hasRequiredColumn) | |
| 77 | + for (const [index, row] of getData().entries()) { | |
| 78 | +#foreach ($column in $subColumns) | |
| 79 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 80 | + if ( | |
| 81 | + row.${column.javaField} === null || | |
| 82 | + row.${column.javaField} === undefined || | |
| 83 | + (typeof row.${column.javaField} === 'string' && String(row.${column.javaField}).trim() === '') || | |
| 84 | + (Array.isArray(row.${column.javaField}) && row.${column.javaField}.length === 0) | |
| 85 | + ) { | |
| 86 | + message.error(`第 #[[${index + 1}]]# 行:${column.columnComment}不能为空`); | |
| 87 | + return false; | |
| 88 | + } | |
| 89 | +#end | |
| 90 | +#end | |
| 91 | + } | |
| 92 | +#end | |
| 93 | + return true; | |
| 94 | +} | |
| 95 | + | |
| 96 | +defineExpose({ getData, validate }); | |
| 69 | 97 | |
| 70 | 98 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 71 | 99 | watch( |
| 72 | 100 | () => props.${subJoinColumn.javaField}, |
| 73 | 101 | async (val) => { |
| 102 | + list.value = []; | |
| 74 | 103 | if (!val) { |
| 75 | 104 | return; |
| 76 | 105 | } |
| ... | ... | @@ -109,6 +138,17 @@ defineExpose({ |
| 109 | 138 | watch( |
| 110 | 139 | () => props.${subJoinColumn.javaField}, |
| 111 | 140 | async (val) => { |
| 141 | + formData.value = { | |
| 142 | +#foreach ($column in $subColumns) | |
| 143 | +#if ($column.createOperation || $column.updateOperation) | |
| 144 | +#if ($column.htmlType == "checkbox") | |
| 145 | + $column.javaField: [], | |
| 146 | +#else | |
| 147 | + $column.javaField: undefined, | |
| 148 | +#end | |
| 149 | +#end | |
| 150 | +#end | |
| 151 | + }; | |
| 112 | 152 | if (!val) { |
| 113 | 153 | return; |
| 114 | 154 | } |
| ... | ... | @@ -126,6 +166,7 @@ watch( |
| 126 | 166 | #foreach($column in $subColumns) |
| 127 | 167 | #if ($column.createOperation || $column.updateOperation) |
| 128 | 168 | #set ($comment = $column.columnComment) |
| 169 | + #set ($dictType = $column.dictType) | |
| 129 | 170 | #set ($javaField = $column.javaField) |
| 130 | 171 | #set ($javaType = $column.javaType) |
| 131 | 172 | #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/data.ts.vm
| ... | ... | @@ -36,7 +36,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 36 | 36 | id: 0, |
| 37 | 37 | ${treeNameColumn.javaField}: '顶级${table.classComment}', |
| 38 | 38 | }); |
| 39 | - return handleTree(data); | |
| 39 | + return handleTree(data, 'id', '${treeParentColumn.javaField}'); | |
| 40 | 40 | }, |
| 41 | 41 | labelField: '${treeNameColumn.javaField}', |
| 42 | 42 | valueField: 'id', |
| ... | ... | @@ -89,7 +89,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 89 | 89 | placeholder: '请选择${comment}', |
| 90 | 90 | }, |
| 91 | 91 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 92 | - component: 'Checkbox', | |
| 92 | + component: 'CheckboxGroup', | |
| 93 | 93 | componentProps: { |
| 94 | 94 | #if ("" != $dictType)## 有数据字典 |
| 95 | 95 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -305,7 +305,7 @@ export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] { |
| 305 | 305 | placeholder: '请选择${comment}', |
| 306 | 306 | }, |
| 307 | 307 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 308 | - component: 'Checkbox', | |
| 308 | + component: 'CheckboxGroup', | |
| 309 | 309 | componentProps: { |
| 310 | 310 | #if ("" != $dictType)## 有数据字典 |
| 311 | 311 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -444,6 +444,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 444 | 444 | #if ($column.createOperation || $column.updateOperation) |
| 445 | 445 | #if (!$column.primaryKey && $column.listOperationResult && $column.id != $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写 |
| 446 | 446 | #set ($dictType = $column.dictType) |
| 447 | + #set ($javaType = $column.javaType) | |
| 447 | 448 | #set ($javaField = $column.javaField) |
| 448 | 449 | #set ($comment = $column.columnComment) |
| 449 | 450 | #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") |
| ... | ... | @@ -538,7 +539,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 538 | 539 | placeholder: '请选择${comment}', |
| 539 | 540 | }, |
| 540 | 541 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 541 | - component: 'Checkbox', | |
| 542 | + component: 'CheckboxGroup', | |
| 542 | 543 | componentProps: { |
| 543 | 544 | #if ("" != $dictType)## 有数据字典 |
| 544 | 545 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -587,7 +588,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 587 | 588 | #end |
| 588 | 589 | #if ($table.templateType == 12) ## 内嵌情况 |
| 589 | 590 | /** 列表的字段 */ |
| 590 | - export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] { | |
| 591 | + export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${apiName}.${subSimpleClassName}>['columns'] { | |
| 591 | 592 | return [ |
| 592 | 593 | #foreach($column in $subColumns) |
| 593 | 594 | #if ($column.listOperationResult) | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/form.vue.vm
| ... | ... | @@ -69,15 +69,11 @@ const [Modal, modalApi] = useVbenModal({ |
| 69 | 69 | #foreach ($subTable in $subTables) |
| 70 | 70 | #set ($index = $foreach.count - 1) |
| 71 | 71 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 72 | - #if ($subTable.subJoinMany) ## 一对多 | |
| 73 | - ## TODO 列表值校验? | |
| 74 | - #else | |
| 75 | 72 | const ${subClassNameVar}Valid = await ${subClassNameVar}FormRef.value?.validate(); |
| 76 | 73 | if (!${subClassNameVar}Valid) { |
| 77 | 74 | subTabsName.value = '${subClassNameVar}'; |
| 78 | 75 | return; |
| 79 | 76 | } |
| 80 | - #end | |
| 81 | 77 | #end |
| 82 | 78 | #end |
| 83 | 79 | #end | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/import.vue.vm
| ... | ... | @@ -49,6 +49,11 @@ function beforeUpload(file: File) { |
| 49 | 49 | return false; |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | +/** 移除文件 */ | |
| 53 | +function handleRemove() { | |
| 54 | + formApi.setFieldValue('file', undefined); | |
| 55 | +} | |
| 56 | + | |
| 52 | 57 | /** 下载模板 */ |
| 53 | 58 | async function handleDownload() { |
| 54 | 59 | const data = await import${simpleClassName}Template(); |
| ... | ... | @@ -65,6 +70,7 @@ async function handleDownload() { |
| 65 | 70 | :max-count="1" |
| 66 | 71 | accept=".xls,.xlsx" |
| 67 | 72 | :before-upload="beforeUpload" |
| 73 | + :on-remove="handleRemove" | |
| 68 | 74 | > |
| 69 | 75 | <Button type="primary"> 选择 Excel 文件 </Button> |
| 70 | 76 | </Upload> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_antdv_next/schema/views/modules/form_sub_normal.vue.vm
| ... | ... | @@ -26,6 +26,7 @@ import { |
| 26 | 26 | CheckboxGroup, |
| 27 | 27 | DatePicker, |
| 28 | 28 | Input, |
| 29 | + message, | |
| 29 | 30 | RadioGroup, |
| 30 | 31 | Select, |
| 31 | 32 | #if ($selectOptionEnable) |
| ... | ... | @@ -77,26 +78,54 @@ const handleDelete = async (row: ${apiName}.${subSimpleClassName}) => { |
| 77 | 78 | await gridApi.grid.remove(row); |
| 78 | 79 | } |
| 79 | 80 | |
| 80 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 81 | -defineExpose({ | |
| 82 | - getData: (): ${apiName}.${subSimpleClassName}[] => { | |
| 83 | - const data = gridApi.grid.getData() as ${apiName}.${subSimpleClassName}[]; | |
| 84 | - const removeRecords = gridApi.grid.getRemoveRecords() as ${apiName}.${subSimpleClassName}[]; | |
| 85 | - const insertRecords = gridApi.grid.getInsertRecords() as ${apiName}.${subSimpleClassName}[]; | |
| 86 | - return data | |
| 87 | - .filter((row) => !removeRecords.some((removed) => removed.id === row.id)) | |
| 88 | - .concat(insertRecords.map((row: any) => ({ ...row, id: undefined }))); | |
| 89 | - }, | |
| 90 | -}); | |
| 81 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 82 | +function getData(): ${apiName}.${subSimpleClassName}[] { | |
| 83 | + const { fullData } = gridApi.grid.getTableData(); | |
| 84 | + const inserted = new Set(gridApi.grid.getInsertRecords()); | |
| 85 | + return fullData.map((row) => | |
| 86 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 87 | + ); | |
| 88 | +} | |
| 89 | + | |
| 90 | +#set ($hasRequiredColumn = false) | |
| 91 | +#foreach ($column in $subColumns) | |
| 92 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 93 | +#set ($hasRequiredColumn = true) | |
| 94 | +#end | |
| 95 | +#end | |
| 96 | +/** 校验子表必填字段 */ | |
| 97 | +function validate(): boolean { | |
| 98 | +#if ($hasRequiredColumn) | |
| 99 | + for (const [index, row] of getData().entries()) { | |
| 100 | +#foreach ($column in $subColumns) | |
| 101 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 102 | + if ( | |
| 103 | + row.${column.javaField} === null || | |
| 104 | + row.${column.javaField} === undefined || | |
| 105 | + (typeof row.${column.javaField} === 'string' && String(row.${column.javaField}).trim() === '') || | |
| 106 | + (Array.isArray(row.${column.javaField}) && row.${column.javaField}.length === 0) | |
| 107 | + ) { | |
| 108 | + message.error(`第 #[[${index + 1}]]# 行:${column.columnComment}不能为空`); | |
| 109 | + return false; | |
| 110 | + } | |
| 111 | +#end | |
| 112 | +#end | |
| 113 | + } | |
| 114 | +#end | |
| 115 | + return true; | |
| 116 | +} | |
| 117 | + | |
| 118 | +defineExpose({ getData, validate }); | |
| 91 | 119 | |
| 92 | 120 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 93 | 121 | watch( |
| 94 | 122 | () => props.${subJoinColumn.javaField}, |
| 95 | 123 | async (val) => { |
| 124 | + await nextTick(); | |
| 96 | 125 | if (!val) { |
| 126 | + await gridApi.grid.loadData([]); | |
| 97 | 127 | return; |
| 98 | 128 | } |
| 99 | - await nextTick(); | |
| 100 | 129 | await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!)); |
| 101 | 130 | }, |
| 102 | 131 | { immediate: true }, |
| ... | ... | @@ -128,10 +157,11 @@ defineExpose({ |
| 128 | 157 | watch( |
| 129 | 158 | () => props.${subJoinColumn.javaField}, |
| 130 | 159 | async (val) => { |
| 160 | + await nextTick(); | |
| 161 | + await formApi.resetForm(); | |
| 131 | 162 | if (!val) { |
| 132 | 163 | return; |
| 133 | 164 | } |
| 134 | - await nextTick(); | |
| 135 | 165 | await formApi.setValues(await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)); |
| 136 | 166 | }, |
| 137 | 167 | { immediate: true }, | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/views/form.vue.vm
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 2 | +import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { useVbenModal } from '@vben/common-ui'; |
| ... | ... | @@ -9,7 +9,7 @@ import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 9 | 9 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 10 | 10 | import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCheckboxGroup, ElCheckbox, ElDatePicker, ElTreeSelect } from 'element-plus'; |
| 11 | 11 | #if($table.templateType == 2)## 树表需要导入这些 |
| 12 | -import { get${simpleClassName}List } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 12 | +import { get${simpleClassName}List } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 13 | 13 | import { handleTree } from '@vben/utils' |
| 14 | 14 | #end |
| 15 | 15 | ## 特殊:主子表专属逻辑 |
| ... | ... | @@ -23,7 +23,7 @@ import { handleTree } from '@vben/utils' |
| 23 | 23 | |
| 24 | 24 | import { computed, ref, reactive } from 'vue'; |
| 25 | 25 | import { $t } from '#/locales'; |
| 26 | -import { get${simpleClassName}, create${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 26 | +import { get${simpleClassName}, create${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 27 | 27 | |
| 28 | 28 | const emit = defineEmits(['success']); |
| 29 | 29 | |
| ... | ... | @@ -111,7 +111,10 @@ const [Modal, modalApi] = useVbenModal({ |
| 111 | 111 | #set ($index = $foreach.count - 1) |
| 112 | 112 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 113 | 113 | #if ($subTable.subJoinMany) ## 一对多 |
| 114 | - ## TODO 列表值校验? | |
| 114 | + if (!${subClassNameVar}FormRef.value?.validate()) { | |
| 115 | + subTabsName.value = '${subClassNameVar}'; | |
| 116 | + return; | |
| 117 | + } | |
| 115 | 118 | #else |
| 116 | 119 | try { |
| 117 | 120 | await ${subClassNameVar}FormRef.value?.validate() |
| ... | ... | @@ -180,7 +183,7 @@ const [Modal, modalApi] = useVbenModal({ |
| 180 | 183 | |
| 181 | 184 | <template> |
| 182 | 185 | <Modal :title="getTitle"> |
| 183 | - <el-form | |
| 186 | + <ElForm | |
| 184 | 187 | ref="formRef" |
| 185 | 188 | :model="formData" |
| 186 | 189 | :rules="rules" |
| ... | ... | @@ -201,8 +204,8 @@ const [Modal, modalApi] = useVbenModal({ |
| 201 | 204 | #set ($dictMethod = "boolean") |
| 202 | 205 | #end |
| 203 | 206 | #if ( $table.templateType == 2 && $column.id == $treeParentColumn.id ) |
| 204 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 205 | - <el-tree-select | |
| 207 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 208 | + <ElTreeSelect | |
| 206 | 209 | v-model="formData.${javaField}" |
| 207 | 210 | :data="${classNameVar}Tree" |
| 208 | 211 | #if ($treeNameColumn.javaField == "name") |
| ... | ... | @@ -222,100 +225,100 @@ const [Modal, modalApi] = useVbenModal({ |
| 222 | 225 | default-expand-all |
| 223 | 226 | placeholder="请选择${comment}" |
| 224 | 227 | /> |
| 225 | - </el-form-item> | |
| 228 | + </ElFormItem> | |
| 226 | 229 | #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 |
| 227 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 228 | - <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" /> | |
| 229 | - </el-form-item> | |
| 230 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 231 | + <ElInput v-model="formData.${javaField}" placeholder="请输入${comment}" /> | |
| 232 | + </ElFormItem> | |
| 230 | 233 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 231 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 234 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 232 | 235 | <ImageUpload v-model="formData.${javaField}" /> |
| 233 | - </el-form-item> | |
| 236 | + </ElFormItem> | |
| 234 | 237 | #elseif($column.htmlType == "fileUpload")## 文件上传 |
| 235 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 238 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 236 | 239 | <FileUpload v-model="formData.${javaField}" /> |
| 237 | - </el-form-item> | |
| 240 | + </ElFormItem> | |
| 238 | 241 | #elseif($column.htmlType == "editor")## 文本编辑器 |
| 239 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 242 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 240 | 243 | <RichTextarea v-model="formData.${javaField}" height="500px" /> |
| 241 | - </el-form-item> | |
| 244 | + </ElFormItem> | |
| 242 | 245 | #elseif($column.htmlType == "select")## 下拉框 |
| 243 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 244 | - <el-select v-model="formData.${javaField}" placeholder="请选择${comment}"> | |
| 246 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 247 | + <ElSelect v-model="formData.${javaField}" placeholder="请选择${comment}"> | |
| 245 | 248 | #if ("" != $dictType)## 有数据字典 |
| 246 | - <el-option | |
| 249 | + <ElOption | |
| 247 | 250 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 248 | 251 | :key="dict.value" |
| 249 | 252 | :value="dict.value" |
| 250 | 253 | :label="dict.label" |
| 251 | 254 | /> |
| 252 | 255 | #else##没数据字典 |
| 253 | - <el-option label="请选择字典生成" value="" /> | |
| 256 | + <ElOption label="请选择字典生成" value="" /> | |
| 254 | 257 | #end |
| 255 | - </el-select> | |
| 256 | - </el-form-item> | |
| 258 | + </ElSelect> | |
| 259 | + </ElFormItem> | |
| 257 | 260 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 258 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 259 | - <el-checkbox-group v-model="formData.${javaField}"> | |
| 261 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 262 | + <ElCheckboxGroup v-model="formData.${javaField}"> | |
| 260 | 263 | #if ("" != $dictType)## 有数据字典 |
| 261 | - <el-checkbox | |
| 264 | + <ElCheckbox | |
| 262 | 265 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 263 | 266 | :key="dict.value" |
| 264 | - :label="dict.value" | |
| 267 | + :value="dict.value" | |
| 265 | 268 | > |
| 266 | 269 | {{ dict.label }} |
| 267 | - </el-checkbox> | |
| 270 | + </ElCheckbox> | |
| 268 | 271 | #else##没数据字典 |
| 269 | - <el-checkbox label="请选择字典生成" /> | |
| 272 | + <ElCheckbox label="请选择字典生成" /> | |
| 270 | 273 | #end |
| 271 | - </el-checkbox-group> | |
| 272 | - </el-form-item> | |
| 274 | + </ElCheckboxGroup> | |
| 275 | + </ElFormItem> | |
| 273 | 276 | #elseif($column.htmlType == "radio")## 单选框 |
| 274 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 275 | - <el-radio-group v-model="formData.${javaField}"> | |
| 277 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 278 | + <ElRadioGroup v-model="formData.${javaField}"> | |
| 276 | 279 | #if ("" != $dictType)## 有数据字典 |
| 277 | - <el-radio | |
| 280 | + <ElRadio | |
| 278 | 281 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 279 | 282 | :key="dict.value" |
| 280 | - :label="dict.value" | |
| 283 | + :value="dict.value" | |
| 281 | 284 | > |
| 282 | 285 | {{ dict.label }} |
| 283 | - </el-radio> | |
| 286 | + </ElRadio> | |
| 284 | 287 | #else##没数据字典 |
| 285 | - <el-radio :label="1">请选择字典生成</el-radio> | |
| 288 | + <ElRadio :label="1">请选择字典生成</ElRadio> | |
| 286 | 289 | #end |
| 287 | - </el-radio-group> | |
| 288 | - </el-form-item> | |
| 290 | + </ElRadioGroup> | |
| 291 | + </ElFormItem> | |
| 289 | 292 | #elseif($column.htmlType == "datetime")## 时间框 |
| 290 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 291 | - <el-date-picker | |
| 293 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 294 | + <ElDatePicker | |
| 292 | 295 | v-model="formData.${javaField}" |
| 293 | 296 | value-format="x" |
| 294 | 297 | placeholder="选择${comment}" |
| 295 | 298 | /> |
| 296 | - </el-form-item> | |
| 299 | + </ElFormItem> | |
| 297 | 300 | #elseif($column.htmlType == "textarea")## 文本框 |
| 298 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 299 | - <el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" /> | |
| 300 | - </el-form-item> | |
| 301 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 302 | + <ElInput v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" /> | |
| 303 | + </ElFormItem> | |
| 301 | 304 | #end |
| 302 | 305 | #end |
| 303 | 306 | #end |
| 304 | - </el-form> | |
| 307 | + </ElForm> | |
| 305 | 308 | ## 特殊:主子表专属逻辑 |
| 306 | 309 | #if ( $table.templateType == 10 || $table.templateType == 12 ) |
| 307 | 310 | <!-- 子表的表单 --> |
| 308 | - <el-tabs v-model="subTabsName"> | |
| 311 | + <ElTabs v-model="subTabsName"> | |
| 309 | 312 | #foreach ($subTable in $subTables) |
| 310 | 313 | #set ($index = $foreach.count - 1) |
| 311 | 314 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 312 | 315 | #set ($subSimpleClassName = $subSimpleClassNames.get($index)) |
| 313 | 316 | #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) |
| 314 | - <el-tab-pane name="$subClassNameVar" label="${subTable.classComment}"> | |
| 317 | + <ElTabPane name="$subClassNameVar" label="${subTable.classComment}"> | |
| 315 | 318 | <${subSimpleClassName}Form ref="${subClassNameVar}FormRef" :${subJoinColumn_strikeCase}="formData?.id" /> |
| 316 | - </el-tab-pane> | |
| 319 | + </ElTabPane> | |
| 317 | 320 | #end |
| 318 | - </el-tabs> | |
| 321 | + </ElTabs> | |
| 319 | 322 | #end |
| 320 | 323 | </Modal> |
| 321 | 324 | </template> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/views/import.vue.vm
| ... | ... | @@ -47,6 +47,16 @@ function handleChange(file: any) { |
| 47 | 47 | } |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | +/** 移除文件 */ | |
| 51 | +function handleRemove() { | |
| 52 | + fileRef.value = null; | |
| 53 | +} | |
| 54 | + | |
| 55 | +/** 超出文件数量 */ | |
| 56 | +function handleExceed() { | |
| 57 | + ElMessage.warning('只能选择一个文件,请先移除已选文件'); | |
| 58 | +} | |
| 59 | + | |
| 50 | 60 | /** 下载导入模板 */ |
| 51 | 61 | async function handleDownload() { |
| 52 | 62 | const data = await import${simpleClassName}Template(); |
| ... | ... | @@ -61,6 +71,8 @@ async function handleDownload() { |
| 61 | 71 | :limit="1" |
| 62 | 72 | accept=".xls,.xlsx" |
| 63 | 73 | :on-change="handleChange" |
| 74 | + :on-remove="handleRemove" | |
| 75 | + :on-exceed="handleExceed" | |
| 64 | 76 | :auto-upload="false" |
| 65 | 77 | > |
| 66 | 78 | <ElButton type="primary"> 选择 Excel 文件 </ElButton> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/views/index.vue.vm
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 2 | +import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 3 | 3 | |
| 4 | 4 | import { ref, h, reactive, onMounted, nextTick } from 'vue'; |
| 5 | 5 | |
| ... | ... | @@ -26,10 +26,10 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 26 | 26 | import { $t } from '#/locales'; |
| 27 | 27 | #if (${table.templateType} == 2)## 树表接口 |
| 28 | 28 | import { handleTree,isEmpty } from '@vben/utils' |
| 29 | -import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 29 | +import { get${simpleClassName}List, delete${simpleClassName}, export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 30 | 30 | #else## 标准表接口 |
| 31 | 31 | import { isEmpty } from '@vben/utils'; |
| 32 | -import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}List,#end export${simpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 32 | +import { get${simpleClassName}Page, delete${simpleClassName},#if ($deleteBatchEnable) delete${simpleClassName}List,#end export${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 33 | 33 | #end |
| 34 | 34 | #if ($importEnable) |
| 35 | 35 | import ${simpleClassName}Import from './modules/import-form.vue'; |
| ... | ... | @@ -65,12 +65,7 @@ const queryParams = reactive({ |
| 65 | 65 | #end |
| 66 | 66 | #foreach ($column in $columns) |
| 67 | 67 | #if ($column.listOperation) |
| 68 | - #if ($column.listOperationCondition != 'BETWEEN') | |
| 69 | - $column.javaField: undefined, | |
| 70 | - #end | |
| 71 | - #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") | |
| 72 | - $column.javaField: undefined, | |
| 73 | - #end | |
| 68 | + $column.javaField: undefined, | |
| 74 | 69 | #end |
| 75 | 70 | #end |
| 76 | 71 | }) |
| ... | ... | @@ -195,7 +190,17 @@ function handleRowCheckboxChange({ |
| 195 | 190 | async function handleExport() { |
| 196 | 191 | try { |
| 197 | 192 | exportLoading.value = true; |
| 198 | - const data = await export${simpleClassName}(queryParams); | |
| 193 | + const params = cloneDeep(queryParams) as any; | |
| 194 | + #foreach ($column in $columns) | |
| 195 | + #if ($column.listOperation) | |
| 196 | + #if ($column.htmlType == "datetime" || $column.listOperationCondition == "BETWEEN") | |
| 197 | + if (params.${column.javaField} && Array.isArray(params.${column.javaField})) { | |
| 198 | + params.${column.javaField} = (params.${column.javaField} as string[]).join(','); | |
| 199 | + } | |
| 200 | + #end | |
| 201 | + #end | |
| 202 | + #end | |
| 203 | + const data = await export${simpleClassName}(params); | |
| 199 | 204 | downloadFileFromBlobPart({ fileName: '${table.classComment}.xls', source: data }); |
| 200 | 205 | }finally { |
| 201 | 206 | exportLoading.value = false; |
| ... | ... | @@ -228,7 +233,7 @@ onMounted(() => { |
| 228 | 233 | |
| 229 | 234 | <ContentWrap v-if="!hiddenSearchBar"> |
| 230 | 235 | <!-- 搜索工作栏 --> |
| 231 | - <el-form | |
| 236 | + <ElForm | |
| 232 | 237 | :model="queryParams" |
| 233 | 238 | ref="queryFormRef" |
| 234 | 239 | inline |
| ... | ... | @@ -247,49 +252,49 @@ onMounted(() => { |
| 247 | 252 | #set ($dictMethod = "boolean") |
| 248 | 253 | #end |
| 249 | 254 | #if ($column.htmlType == "input") |
| 250 | - <el-form-item label="${comment}"> | |
| 251 | - <el-input | |
| 255 | + <ElFormItem label="${comment}"> | |
| 256 | + <ElInput | |
| 252 | 257 | v-model="queryParams.${javaField}" |
| 253 | 258 | placeholder="请输入${comment}" |
| 254 | 259 | clearable |
| 255 | 260 | @keyup.enter="handleQuery" |
| 256 | 261 | class="!w-[240px]" |
| 257 | 262 | /> |
| 258 | - </el-form-item> | |
| 263 | + </ElFormItem> | |
| 259 | 264 | #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox") |
| 260 | - <el-form-item label="${comment}"> | |
| 261 | - <el-select | |
| 265 | + <ElFormItem label="${comment}"> | |
| 266 | + <ElSelect | |
| 262 | 267 | v-model="queryParams.${javaField}" |
| 263 | 268 | placeholder="请选择${comment}" |
| 264 | 269 | clearable |
| 265 | 270 | class="!w-[240px]" |
| 266 | 271 | > |
| 267 | 272 | #if ("" != $dictType)## 设置了 dictType 数据字典的情况 |
| 268 | - <el-option | |
| 273 | + <ElOption | |
| 269 | 274 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 270 | 275 | :key="dict.value" |
| 271 | 276 | :value="dict.value" |
| 272 | 277 | :label="dict.label" |
| 273 | 278 | /> |
| 274 | 279 | #else## 未设置 dictType 数据字典的情况 |
| 275 | - <el-option label="请选择字典生成" value="" /> | |
| 280 | + <ElOption label="请选择字典生成" value="" /> | |
| 276 | 281 | #end |
| 277 | - </el-select> | |
| 278 | - </el-form-item> | |
| 282 | + </ElSelect> | |
| 283 | + </ElFormItem> | |
| 279 | 284 | #elseif($column.htmlType == "datetime") |
| 280 | 285 | #if ($column.listOperationCondition != "BETWEEN")## 非范围 |
| 281 | - <el-form-item label="${comment}"> | |
| 282 | - <el-date-picker | |
| 286 | + <ElFormItem label="${comment}"> | |
| 287 | + <ElDatePicker | |
| 283 | 288 | v-model="queryParams.${javaField}" |
| 284 | 289 | value-format="YYYY-MM-DD" |
| 285 | 290 | placeholder="选择${comment}" |
| 286 | 291 | clearable |
| 287 | 292 | class="!w-[240px]" |
| 288 | 293 | /> |
| 289 | - </el-form-item> | |
| 294 | + </ElFormItem> | |
| 290 | 295 | #else## 范围 |
| 291 | - <el-form-item label="${comment}"> | |
| 292 | - <el-date-picker | |
| 296 | + <ElFormItem label="${comment}"> | |
| 297 | + <ElDatePicker | |
| 293 | 298 | v-model="queryParams.${javaField}" |
| 294 | 299 | type="daterange" |
| 295 | 300 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -298,33 +303,33 @@ onMounted(() => { |
| 298 | 303 | end-placeholder="结束日期" |
| 299 | 304 | class="!w-[240px]" |
| 300 | 305 | /> |
| 301 | - </el-form-item> | |
| 306 | + </ElFormItem> | |
| 302 | 307 | #end |
| 303 | 308 | #end |
| 304 | 309 | #end |
| 305 | 310 | #end |
| 306 | - <el-form-item> | |
| 307 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 308 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 311 | + <ElFormItem> | |
| 312 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 313 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 309 | 314 | 搜索 |
| 310 | - </el-button> | |
| 311 | - </el-form-item> | |
| 312 | - </el-form> | |
| 315 | + </ElButton> | |
| 316 | + </ElFormItem> | |
| 317 | + </ElForm> | |
| 313 | 318 | </ContentWrap> |
| 314 | 319 | |
| 315 | 320 | <!-- 列表 --> |
| 316 | 321 | <ContentWrap title="${table.classComment}"> |
| 317 | 322 | <template #extra> |
| 318 | - <TableToolbar | |
| 323 | + <VbenVxeTableToolbar | |
| 319 | 324 | ref="tableToolbarRef" |
| 320 | 325 | v-model:hidden-search="hiddenSearchBar" |
| 321 | 326 | > |
| 322 | 327 | #if (${table.templateType} == 2) |
| 323 | - <el-button @click="handleExpand" class="mr-2"> | |
| 328 | + <ElButton @click="handleExpand" class="mr-2"> | |
| 324 | 329 | {{ isExpanded ? '收缩' : '展开' }} |
| 325 | - </el-button> | |
| 330 | + </ElButton> | |
| 326 | 331 | #end |
| 327 | - <el-button | |
| 332 | + <ElButton | |
| 328 | 333 | class="ml-2" |
| 329 | 334 | :icon="h(Plus)" |
| 330 | 335 | type="primary" |
| ... | ... | @@ -332,18 +337,18 @@ onMounted(() => { |
| 332 | 337 | v-access:code="['${permissionPrefix}:create']" |
| 333 | 338 | > |
| 334 | 339 | {{ $t('ui.actionTitle.create', ['${table.classComment}']) }} |
| 335 | - </el-button> | |
| 340 | + </ElButton> | |
| 336 | 341 | #if ($importEnable) |
| 337 | - <el-button | |
| 342 | + <ElButton | |
| 338 | 343 | class="ml-2" |
| 339 | 344 | type="primary" |
| 340 | 345 | @click="handleImport" |
| 341 | 346 | v-access:code="['${permissionPrefix}:import']" |
| 342 | 347 | > |
| 343 | 348 | 导入 |
| 344 | - </el-button> | |
| 349 | + </ElButton> | |
| 345 | 350 | #end |
| 346 | - <el-button | |
| 351 | + <ElButton | |
| 347 | 352 | :icon="h(Download)" |
| 348 | 353 | type="primary" |
| 349 | 354 | class="ml-2" |
| ... | ... | @@ -352,9 +357,9 @@ onMounted(() => { |
| 352 | 357 | v-access:code="['${permissionPrefix}:export']" |
| 353 | 358 | > |
| 354 | 359 | {{ $t('ui.actionTitle.export') }} |
| 355 | - </el-button> | |
| 360 | + </ElButton> | |
| 356 | 361 | #if ($table.templateType != 2 && $deleteBatchEnable) |
| 357 | - <el-button | |
| 362 | + <ElButton | |
| 358 | 363 | :icon="h(Trash2)" |
| 359 | 364 | type="danger" |
| 360 | 365 | class="ml-2" |
| ... | ... | @@ -363,11 +368,11 @@ onMounted(() => { |
| 363 | 368 | v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:delete']" |
| 364 | 369 | > |
| 365 | 370 | 批量删除 |
| 366 | - </el-button> | |
| 371 | + </ElButton> | |
| 367 | 372 | #end |
| 368 | - </TableToolbar> | |
| 373 | + </VbenVxeTableToolbar> | |
| 369 | 374 | </template> |
| 370 | - <vxe-table | |
| 375 | + <VxeTable | |
| 371 | 376 | ref="tableRef" |
| 372 | 377 | :data="list" |
| 373 | 378 | #if ( $table.templateType == 2 ) |
| ... | ... | @@ -395,27 +400,27 @@ onMounted(() => { |
| 395 | 400 | #end |
| 396 | 401 | > |
| 397 | 402 | #if ($table.templateType != 2 && $deleteBatchEnable) |
| 398 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 403 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 399 | 404 | #end |
| 400 | 405 | ## 特殊:主子表专属逻辑 |
| 401 | 406 | #if ( $table.templateType == 12 && $subTables && $subTables.size() > 0 ) |
| 402 | 407 | <!-- 子表的列表 --> |
| 403 | - <vxe-column type="expand" width="60"> | |
| 408 | + <VxeColumn type="expand" width="60"> | |
| 404 | 409 | <template #content="{ row }"> |
| 405 | 410 | <!-- 子表的表单 --> |
| 406 | - <el-tabs v-model="subTabsName" class="mx-8"> | |
| 411 | + <ElTabs v-model="subTabsName" class="mx-8"> | |
| 407 | 412 | #foreach ($subTable in $subTables) |
| 408 | 413 | #set ($index = $foreach.count - 1) |
| 409 | 414 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 410 | 415 | #set ($subSimpleClassName = $subSimpleClassNames.get($index)) |
| 411 | 416 | #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) |
| 412 | - <el-tab-pane name="$subClassNameVar" label="${subTable.classComment}"> | |
| 417 | + <ElTabPane name="$subClassNameVar" label="${subTable.classComment}"> | |
| 413 | 418 | <${subSimpleClassName}List :${subJoinColumn_strikeCase}="row?.id" /> |
| 414 | - </el-tab-pane> | |
| 419 | + </ElTabPane> | |
| 415 | 420 | #end |
| 416 | - </el-tabs> | |
| 421 | + </ElTabs> | |
| 417 | 422 | </template> |
| 418 | - </vxe-column> | |
| 423 | + </VxeColumn> | |
| 419 | 424 | #end |
| 420 | 425 | #foreach($column in $columns) |
| 421 | 426 | #if ($column.listOperationResult) |
| ... | ... | @@ -424,28 +429,28 @@ onMounted(() => { |
| 424 | 429 | #set ($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) |
| 425 | 430 | #set ($comment=$column.columnComment) |
| 426 | 431 | #if ($column.javaType == "LocalDateTime")## 时间类型 |
| 427 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 432 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 428 | 433 | <template #default="{row}"> |
| 429 | 434 | {{formatDateTime(row.${javaField})}} |
| 430 | 435 | </template> |
| 431 | - </vxe-column> | |
| 436 | + </VxeColumn> | |
| 432 | 437 | #elseif($column.dictType && "" != $column.dictType)## 数据字典 |
| 433 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 438 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 434 | 439 | <template #default="{row}"> |
| 435 | 440 | <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" /> |
| 436 | 441 | </template> |
| 437 | - </vxe-column> | |
| 442 | + </VxeColumn> | |
| 438 | 443 | #elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField) |
| 439 | - <vxe-column field="${javaField}" title="${comment}" align="center" tree-node/> | |
| 444 | + <VxeColumn field="${javaField}" title="${comment}" align="center" tree-node/> | |
| 440 | 445 | #else |
| 441 | - <vxe-column field="${javaField}" title="${comment}" align="center" /> | |
| 446 | + <VxeColumn field="${javaField}" title="${comment}" align="center" /> | |
| 442 | 447 | #end |
| 443 | 448 | #end |
| 444 | 449 | #end |
| 445 | - <vxe-column field="operation" title="操作" align="center"> | |
| 450 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 446 | 451 | <template #default="{row}"> |
| 447 | 452 | #if ( $table.templateType == 2 ) |
| 448 | - <el-button | |
| 453 | + <ElButton | |
| 449 | 454 | size="small" |
| 450 | 455 | type="primary" |
| 451 | 456 | link |
| ... | ... | @@ -453,9 +458,9 @@ onMounted(() => { |
| 453 | 458 | v-access:code="['${permissionPrefix}:create']" |
| 454 | 459 | > |
| 455 | 460 | 新增下级 |
| 456 | - </el-button> | |
| 461 | + </ElButton> | |
| 457 | 462 | #end |
| 458 | - <el-button | |
| 463 | + <ElButton | |
| 459 | 464 | size="small" |
| 460 | 465 | type="primary" |
| 461 | 466 | link |
| ... | ... | @@ -463,8 +468,8 @@ onMounted(() => { |
| 463 | 468 | v-access:code="['${permissionPrefix}:update']" |
| 464 | 469 | > |
| 465 | 470 | {{ $t('ui.actionTitle.edit') }} |
| 466 | - </el-button> | |
| 467 | - <el-button | |
| 471 | + </ElButton> | |
| 472 | + <ElButton | |
| 468 | 473 | size="small" |
| 469 | 474 | type="danger" |
| 470 | 475 | link |
| ... | ... | @@ -476,14 +481,14 @@ onMounted(() => { |
| 476 | 481 | v-access:code="['${permissionPrefix}:delete']" |
| 477 | 482 | > |
| 478 | 483 | {{ $t('ui.actionTitle.delete') }} |
| 479 | - </el-button> | |
| 484 | + </ElButton> | |
| 480 | 485 | </template> |
| 481 | - </vxe-column> | |
| 482 | - </vxe-table> | |
| 486 | + </VxeColumn> | |
| 487 | + </VxeTable> | |
| 483 | 488 | #if ( $table.templateType != 2 ) |
| 484 | 489 | <!-- 分页 --> |
| 485 | 490 | <div class="mt-2 flex justify-end"> |
| 486 | - <el-pagination | |
| 491 | + <ElPagination | |
| 487 | 492 | :total="total" |
| 488 | 493 | v-model:current-page="queryParams.pageNo" |
| 489 | 494 | v-model:page-size="queryParams.pageSize" |
| ... | ... | @@ -498,17 +503,17 @@ onMounted(() => { |
| 498 | 503 | #if ($table.templateType == 11) ## erp情况 |
| 499 | 504 | <ContentWrap> |
| 500 | 505 | <!-- 子表的表单 --> |
| 501 | - <el-tabs v-model="subTabsName"> | |
| 506 | + <ElTabs v-model="subTabsName"> | |
| 502 | 507 | #foreach ($subTable in $subTables) |
| 503 | 508 | #set ($index = $foreach.count - 1) |
| 504 | 509 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 505 | 510 | #set ($subSimpleClassName = $subSimpleClassNames.get($index)) |
| 506 | 511 | #set ($subJoinColumn_strikeCase = $subJoinColumn_strikeCases.get($index)) |
| 507 | - <el-tab-pane name="$subClassNameVar" label="${subTable.classComment}"> | |
| 512 | + <ElTabPane name="$subClassNameVar" label="${subTable.classComment}"> | |
| 508 | 513 | <${subSimpleClassName}List :${subJoinColumn_strikeCase}="select${simpleClassName}?.id" /> |
| 509 | - </el-tab-pane> | |
| 514 | + </ElTabPane> | |
| 510 | 515 | #end |
| 511 | - </el-tabs> | |
| 516 | + </ElTabs> | |
| 512 | 517 | </ContentWrap> |
| 513 | 518 | #end |
| 514 | 519 | </Page> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/views/modules/form_sub_erp.vue.vm
| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | #set ($subJoinColumn = $subJoinColumns.get($subIndex))##当前 join 字段 |
| 4 | 4 | #set ($subSimpleClassName = $subSimpleClassNames.get($subIndex)) |
| 5 | 5 | <script lang="ts" setup> |
| 6 | - import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 6 | + import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 7 | 7 | import type { FormRules } from 'element-plus'; |
| 8 | 8 | |
| 9 | 9 | import { computed, ref, reactive } from 'vue'; |
| ... | ... | @@ -17,7 +17,7 @@ |
| 17 | 17 | |
| 18 | 18 | import { $t } from '#/locales'; |
| 19 | 19 | |
| 20 | - import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 20 | + import { get${subSimpleClassName}, create${subSimpleClassName}, update${subSimpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 21 | 21 | |
| 22 | 22 | const emit = defineEmits(['success']); |
| 23 | 23 | const getTitle = computed(() => { |
| ... | ... | @@ -107,7 +107,7 @@ |
| 107 | 107 | |
| 108 | 108 | <template> |
| 109 | 109 | <Modal :title="getTitle"> |
| 110 | - <el-form | |
| 110 | + <ElForm | |
| 111 | 111 | ref="formRef" |
| 112 | 112 | :model="formData" |
| 113 | 113 | :rules="rules" |
| ... | ... | @@ -128,83 +128,83 @@ |
| 128 | 128 | #set ($dictMethod = "boolean") |
| 129 | 129 | #end |
| 130 | 130 | #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 |
| 131 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 132 | - <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" /> | |
| 133 | - </el-form-item> | |
| 131 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 132 | + <ElInput v-model="formData.${javaField}" placeholder="请输入${comment}" /> | |
| 133 | + </ElFormItem> | |
| 134 | 134 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 135 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 135 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 136 | 136 | <ImageUpload v-model="formData.${javaField}" /> |
| 137 | - </el-form-item> | |
| 137 | + </ElFormItem> | |
| 138 | 138 | #elseif($column.htmlType == "fileUpload")## 文件上传 |
| 139 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 139 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 140 | 140 | <FileUpload v-model="formData.${javaField}" /> |
| 141 | - </el-form-item> | |
| 141 | + </ElFormItem> | |
| 142 | 142 | #elseif($column.htmlType == "editor")## 文本编辑器 |
| 143 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 143 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 144 | 144 | <RichTextarea v-model="formData.${javaField}" height="500px" /> |
| 145 | - </el-form-item> | |
| 145 | + </ElFormItem> | |
| 146 | 146 | #elseif($column.htmlType == "select")## 下拉框 |
| 147 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 148 | - <el-select v-model="formData.${javaField}" placeholder="请选择${comment}"> | |
| 147 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 148 | + <ElSelect v-model="formData.${javaField}" placeholder="请选择${comment}"> | |
| 149 | 149 | #if ("" != $dictType)## 有数据字典 |
| 150 | - <el-option | |
| 150 | + <ElOption | |
| 151 | 151 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 152 | 152 | :key="dict.value" |
| 153 | 153 | :value="dict.value" |
| 154 | 154 | :label="dict.label" |
| 155 | 155 | /> |
| 156 | 156 | #else##没数据字典 |
| 157 | - <el-option label="请选择字典生成" value="" /> | |
| 157 | + <ElOption label="请选择字典生成" value="" /> | |
| 158 | 158 | #end |
| 159 | - </el-select> | |
| 160 | - </el-form-item> | |
| 159 | + </ElSelect> | |
| 160 | + </ElFormItem> | |
| 161 | 161 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 162 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 163 | - <el-checkbox-group v-model="formData.${javaField}"> | |
| 162 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 163 | + <ElCheckboxGroup v-model="formData.${javaField}"> | |
| 164 | 164 | #if ("" != $dictType)## 有数据字典 |
| 165 | - <el-checkbox | |
| 165 | + <ElCheckbox | |
| 166 | 166 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 167 | 167 | :key="dict.value" |
| 168 | - :label="dict.value" | |
| 168 | + :value="dict.value" | |
| 169 | 169 | > |
| 170 | 170 | {{ dict.label }} |
| 171 | - </el-checkbox> | |
| 171 | + </ElCheckbox> | |
| 172 | 172 | #else##没数据字典 |
| 173 | - <el-checkbox label="请选择字典生成" /> | |
| 173 | + <ElCheckbox label="请选择字典生成" /> | |
| 174 | 174 | #end |
| 175 | - </el-checkbox-group> | |
| 176 | - </el-form-item> | |
| 175 | + </ElCheckboxGroup> | |
| 176 | + </ElFormItem> | |
| 177 | 177 | #elseif($column.htmlType == "radio")## 单选框 |
| 178 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 179 | - <el-radio-group v-model="formData.${javaField}"> | |
| 178 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 179 | + <ElRadioGroup v-model="formData.${javaField}"> | |
| 180 | 180 | #if ("" != $dictType)## 有数据字典 |
| 181 | - <el-radio | |
| 181 | + <ElRadio | |
| 182 | 182 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 183 | 183 | :key="dict.value" |
| 184 | - :label="dict.value" | |
| 184 | + :value="dict.value" | |
| 185 | 185 | > |
| 186 | 186 | {{ dict.label }} |
| 187 | - </el-radio> | |
| 187 | + </ElRadio> | |
| 188 | 188 | #else##没数据字典 |
| 189 | - <el-radio :label="1">请选择字典生成</el-radio> | |
| 189 | + <ElRadio :label="1">请选择字典生成</ElRadio> | |
| 190 | 190 | #end |
| 191 | - </el-radio-group> | |
| 192 | - </el-form-item> | |
| 191 | + </ElRadioGroup> | |
| 192 | + </ElFormItem> | |
| 193 | 193 | #elseif($column.htmlType == "datetime")## 时间框 |
| 194 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 195 | - <el-date-picker | |
| 194 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 195 | + <ElDatePicker | |
| 196 | 196 | v-model="formData.${javaField}" |
| 197 | 197 | value-format="x" |
| 198 | 198 | placeholder="选择${comment}" |
| 199 | 199 | /> |
| 200 | - </el-form-item> | |
| 200 | + </ElFormItem> | |
| 201 | 201 | #elseif($column.htmlType == "textarea")## 文本框 |
| 202 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 203 | - <el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" /> | |
| 204 | - </el-form-item> | |
| 202 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 203 | + <ElInput v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" /> | |
| 204 | + </ElFormItem> | |
| 205 | 205 | #end |
| 206 | 206 | #end |
| 207 | 207 | #end |
| 208 | - </el-form> | |
| 208 | + </ElForm> | |
| 209 | 209 | </Modal> |
| 210 | 210 | </template> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/views/modules/form_sub_normal.vue.vm
| ... | ... | @@ -5,26 +5,61 @@ |
| 5 | 5 | #set ($subClassNameVar = $subClassNameVars.get($subIndex)) |
| 6 | 6 | #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 |
| 7 | 7 | <script lang="ts" setup> |
| 8 | -import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 8 | +#if ($subTable.subJoinMany) | |
| 9 | +import type { VxeTableInstance } from '#/adapter/vxe-table'; | |
| 10 | +#else | |
| 11 | +import type { FormRules } from 'element-plus'; | |
| 12 | +#end | |
| 13 | +import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 9 | 14 | |
| 10 | -import { computed, ref, reactive, h, onMounted,watch,nextTick } from 'vue'; | |
| 15 | +#if ($subTable.subJoinMany) | |
| 16 | +import { ref, watch } from 'vue'; | |
| 17 | +#else | |
| 18 | +import { nextTick, reactive, ref, watch } from 'vue'; | |
| 19 | +#end | |
| 11 | 20 | |
| 12 | 21 | import { DICT_TYPE } from '@vben/constants'; |
| 13 | 22 | import { getDictOptions } from '@vben/hooks'; |
| 23 | +#if ($subTable.subJoinMany) | |
| 24 | +import { Plus } from '@vben/icons'; | |
| 25 | +#end | |
| 14 | 26 | |
| 15 | -import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElButton, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCheckboxGroup, ElCheckbox, ElDatePicker } from 'element-plus'; | |
| 16 | -import { $t } from '#/locales'; | |
| 27 | +#set ($hasCheckbox = false) | |
| 28 | +#foreach ($column in $subColumns) | |
| 29 | +#if (($column.createOperation || $column.updateOperation) && $column.id != $subJoinColumn.id && $column.htmlType == "checkbox") | |
| 30 | +#set ($hasCheckbox = true) | |
| 31 | +#end | |
| 32 | +#end | |
| 33 | +import { | |
| 34 | +#if ($subTable.subJoinMany) | |
| 35 | + ElButton, | |
| 36 | +#else | |
| 37 | + ElForm, | |
| 38 | + ElFormItem, | |
| 39 | +#end | |
| 40 | +#if ($hasCheckbox) | |
| 41 | + ElCheckbox, | |
| 42 | + ElCheckboxGroup, | |
| 43 | +#end | |
| 44 | + ElDatePicker, | |
| 45 | + ElInput, | |
| 46 | +#if ($subTable.subJoinMany) | |
| 47 | + ElMessage, | |
| 48 | +#end | |
| 49 | + ElOption, | |
| 50 | + ElRadio, | |
| 51 | + ElRadioGroup, | |
| 52 | + ElSelect, | |
| 53 | +} from 'element-plus'; | |
| 17 | 54 | |
| 18 | 55 | #if ($subTable.subJoinMany) ## 一对多 |
| 19 | -import type { VxeTableInstance } from '#/adapter/vxe-table'; | |
| 20 | -import { Plus } from "@vben/icons"; | |
| 21 | 56 | import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 22 | -import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 57 | +import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 23 | 58 | #else |
| 24 | -import type { FormRules } from 'element-plus'; | |
| 25 | 59 | import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 26 | -import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 60 | +import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 27 | 61 | #end |
| 62 | +import { $t } from '#/locales'; | |
| 28 | 63 | |
| 29 | 64 | const props = defineProps<{ |
| 30 | 65 | ${subJoinColumn.javaField}?: number // ${subJoinColumn.columnComment}(主表的关联字段) |
| ... | ... | @@ -43,24 +78,54 @@ async function onDelete(row: ${simpleClassName}Api.${subSimpleClassName}) { |
| 43 | 78 | await tableRef.value?.remove(row); |
| 44 | 79 | } |
| 45 | 80 | |
| 46 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 47 | -defineExpose({ | |
| 48 | - getData: (): ${simpleClassName}Api.${subSimpleClassName}[] => { | |
| 49 | - const data = list.value as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 50 | - const removeRecords = tableRef.value?.getRemoveRecords() as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 51 | - const insertRecords = tableRef.value?.getInsertRecords() as ${simpleClassName}Api.${subSimpleClassName}[]; | |
| 52 | - return [ | |
| 53 | - ...data.filter( | |
| 54 | - (row) => !removeRecords.some((removed) => removed.id === row.id), | |
| 55 | - ), | |
| 56 | - ...insertRecords.map((row: any) => ({ ...row, id: undefined })), | |
| 57 | - }, | |
| 58 | -}); | |
| 81 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 82 | +function getData(): ${simpleClassName}Api.${subSimpleClassName}[] { | |
| 83 | + const table = tableRef.value; | |
| 84 | + if (!table) { | |
| 85 | + return []; | |
| 86 | + } | |
| 87 | + const { fullData } = table.getTableData(); | |
| 88 | + const inserted = new Set(table.getInsertRecords()); | |
| 89 | + return fullData.map((row) => | |
| 90 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 91 | + ); | |
| 92 | +} | |
| 93 | + | |
| 94 | +#set ($hasRequiredColumn = false) | |
| 95 | +#foreach ($column in $subColumns) | |
| 96 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 97 | +#set ($hasRequiredColumn = true) | |
| 98 | +#end | |
| 99 | +#end | |
| 100 | +/** 校验子表必填字段 */ | |
| 101 | +function validate(): boolean { | |
| 102 | +#if ($hasRequiredColumn) | |
| 103 | + for (const [index, row] of getData().entries()) { | |
| 104 | +#foreach ($column in $subColumns) | |
| 105 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 106 | + if ( | |
| 107 | + row.${column.javaField} === null || | |
| 108 | + row.${column.javaField} === undefined || | |
| 109 | + (typeof row.${column.javaField} === 'string' && String(row.${column.javaField}).trim() === '') || | |
| 110 | + (Array.isArray(row.${column.javaField}) && row.${column.javaField}.length === 0) | |
| 111 | + ) { | |
| 112 | + ElMessage.error(`第 #[[${index + 1}]]# 行:${column.columnComment}不能为空`); | |
| 113 | + return false; | |
| 114 | + } | |
| 115 | +#end | |
| 116 | +#end | |
| 117 | + } | |
| 118 | +#end | |
| 119 | + return true; | |
| 120 | +} | |
| 121 | + | |
| 122 | +defineExpose({ getData, validate }); | |
| 59 | 123 | |
| 60 | 124 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 61 | 125 | watch( |
| 62 | 126 | () => props.${subJoinColumn.javaField}, |
| 63 | 127 | async (val) => { |
| 128 | + list.value = []; | |
| 64 | 129 | if (!val) { |
| 65 | 130 | return; |
| 66 | 131 | } |
| ... | ... | @@ -99,6 +164,17 @@ defineExpose({ |
| 99 | 164 | watch( |
| 100 | 165 | () => props.${subJoinColumn.javaField}, |
| 101 | 166 | async (val) => { |
| 167 | + formData.value = { | |
| 168 | +#foreach ($column in $subColumns) | |
| 169 | +#if ($column.createOperation || $column.updateOperation) | |
| 170 | +#if ($column.htmlType == "checkbox") | |
| 171 | + $column.javaField: [], | |
| 172 | +#else | |
| 173 | + $column.javaField: undefined, | |
| 174 | +#end | |
| 175 | +#end | |
| 176 | +#end | |
| 177 | + }; | |
| 102 | 178 | if (!val) { |
| 103 | 179 | return; |
| 104 | 180 | } |
| ... | ... | @@ -112,10 +188,11 @@ watch( |
| 112 | 188 | |
| 113 | 189 | <template> |
| 114 | 190 | #if ($subTable.subJoinMany) ## 一对多 |
| 115 | - <vxe-table ref="tableRef" :data="list" show-overflow class="mx-4"> | |
| 191 | + <VxeTable ref="tableRef" :data="list" show-overflow class="mx-4"> | |
| 116 | 192 | #foreach($column in $subColumns) |
| 117 | 193 | #if ($column.createOperation || $column.updateOperation) |
| 118 | 194 | #set ($comment = $column.columnComment) |
| 195 | + #set ($dictType = $column.dictType) | |
| 119 | 196 | #set ($javaField = $column.javaField) |
| 120 | 197 | #set ($javaType = $column.javaType) |
| 121 | 198 | #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") |
| ... | ... | @@ -127,99 +204,99 @@ watch( |
| 127 | 204 | #end |
| 128 | 205 | #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写 |
| 129 | 206 | #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 |
| 130 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 207 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 131 | 208 | <template #default="{row}"> |
| 132 | - <el-input v-model="row.${javaField}" /> | |
| 209 | + <ElInput v-model="row.${javaField}" /> | |
| 133 | 210 | </template> |
| 134 | - </vxe-column> | |
| 211 | + </VxeColumn> | |
| 135 | 212 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 136 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 213 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 137 | 214 | <template #default="{row}"> |
| 138 | 215 | <ImageUpload v-model="row.${javaField}" /> |
| 139 | 216 | </template> |
| 140 | - </vxe-column> | |
| 217 | + </VxeColumn> | |
| 141 | 218 | #elseif($column.htmlType == "fileUpload")## 文件上传 |
| 142 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 219 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 143 | 220 | <template #default="{row}"> |
| 144 | 221 | <FileUpload v-model="row.${javaField}" /> |
| 145 | 222 | </template> |
| 146 | - </vxe-column> | |
| 223 | + </VxeColumn> | |
| 147 | 224 | #elseif($column.htmlType == "select")## 下拉框 |
| 148 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 225 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 149 | 226 | <template #default="{row}"> |
| 150 | - <el-select v-model="row.${javaField}" placeholder="请选择${comment}"> | |
| 227 | + <ElSelect v-model="row.${javaField}" placeholder="请选择${comment}"> | |
| 151 | 228 | #if ("" != $dictType)## 有数据字典 |
| 152 | - <el-option | |
| 229 | + <ElOption | |
| 153 | 230 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 154 | 231 | :key="dict.value" |
| 155 | 232 | :value="dict.value" |
| 156 | 233 | :label="dict.label" |
| 157 | 234 | /> |
| 158 | 235 | #else##没数据字典 |
| 159 | - <el-option label="请选择字典生成" value="" /> | |
| 236 | + <ElOption label="请选择字典生成" value="" /> | |
| 160 | 237 | #end |
| 161 | - </el-select> | |
| 238 | + </ElSelect> | |
| 162 | 239 | </template> |
| 163 | - </vxe-column> | |
| 240 | + </VxeColumn> | |
| 164 | 241 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 165 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 242 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 166 | 243 | <template #default="{row}"> |
| 167 | - <el-checkbox-group v-model="row.${javaField}"> | |
| 244 | + <ElCheckboxGroup v-model="row.${javaField}"> | |
| 168 | 245 | #if ("" != $dictType)## 有数据字典 |
| 169 | - <el-checkbox | |
| 246 | + <ElCheckbox | |
| 170 | 247 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 171 | 248 | :key="dict.value" |
| 172 | - :label="dict.value" | |
| 249 | + :value="dict.value" | |
| 173 | 250 | > |
| 174 | 251 | {{ dict.label }} |
| 175 | - </el-checkbox> | |
| 252 | + </ElCheckbox> | |
| 176 | 253 | #else##没数据字典 |
| 177 | - <el-checkbox label="请选择字典生成" /> | |
| 254 | + <ElCheckbox label="请选择字典生成" /> | |
| 178 | 255 | #end |
| 179 | - </el-checkbox-group> | |
| 256 | + </ElCheckboxGroup> | |
| 180 | 257 | </template> |
| 181 | - </vxe-column> | |
| 258 | + </VxeColumn> | |
| 182 | 259 | #elseif($column.htmlType == "radio")## 单选框 |
| 183 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 260 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 184 | 261 | <template #default="{row}"> |
| 185 | - <el-radio-group v-model="row.${javaField}"> | |
| 262 | + <ElRadioGroup v-model="row.${javaField}"> | |
| 186 | 263 | #if ("" != $dictType)## 有数据字典 |
| 187 | - <el-radio | |
| 264 | + <ElRadio | |
| 188 | 265 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 189 | 266 | :key="dict.value" |
| 190 | - :label="dict.value" | |
| 267 | + :value="dict.value" | |
| 191 | 268 | > |
| 192 | 269 | {{ dict.label }} |
| 193 | - </el-radio> | |
| 270 | + </ElRadio> | |
| 194 | 271 | #else##没数据字典 |
| 195 | - <el-radio :label="1">请选择字典生成</el-radio> | |
| 272 | + <ElRadio :label="1">请选择字典生成</ElRadio> | |
| 196 | 273 | #end |
| 197 | - </el-radio-group> | |
| 274 | + </ElRadioGroup> | |
| 198 | 275 | </template> |
| 199 | - </vxe-column> | |
| 276 | + </VxeColumn> | |
| 200 | 277 | #elseif($column.htmlType == "datetime")## 时间框 |
| 201 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 278 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 202 | 279 | <template #default="{row}"> |
| 203 | - <el-date-picker | |
| 280 | + <ElDatePicker | |
| 204 | 281 | v-model="row.${javaField}" |
| 205 | 282 | type="datetime" |
| 206 | 283 | value-format="x" |
| 207 | 284 | format="YYYY-MM-DD HH:mm:ss" |
| 208 | 285 | /> |
| 209 | 286 | </template> |
| 210 | - </vxe-column> | |
| 287 | + </VxeColumn> | |
| 211 | 288 | #elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 文本框 |
| 212 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 289 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 213 | 290 | <template #default="{row}"> |
| 214 | - <el-input v-model="row.${javaField}" type="textarea" /> | |
| 291 | + <ElInput v-model="row.${javaField}" type="textarea" /> | |
| 215 | 292 | </template> |
| 216 | - </vxe-column> | |
| 293 | + </VxeColumn> | |
| 217 | 294 | #end |
| 218 | 295 | #end |
| 219 | 296 | #end |
| 220 | - <vxe-column field="operation" title="操作" align="center"> | |
| 297 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 221 | 298 | <template #default="{row}"> |
| 222 | - <el-button | |
| 299 | + <ElButton | |
| 223 | 300 | size="small" |
| 224 | 301 | type="danger" |
| 225 | 302 | link |
| ... | ... | @@ -227,17 +304,17 @@ watch( |
| 227 | 304 | v-access:code="['${permissionPrefix}:delete']" |
| 228 | 305 | > |
| 229 | 306 | {{ $t('ui.actionTitle.delete') }} |
| 230 | - </el-button> | |
| 307 | + </ElButton> | |
| 231 | 308 | </template> |
| 232 | - </vxe-column> | |
| 233 | - </vxe-table> | |
| 309 | + </VxeColumn> | |
| 310 | + </VxeTable> | |
| 234 | 311 | <div class="flex justify-center mt-4"> |
| 235 | - <el-button :icon="h(Plus)" type="primary" plain @click="handleAdd" v-access:code="['${permissionPrefix}:create']"> | |
| 312 | + <ElButton :icon="Plus" type="primary" plain @click="handleAdd" v-access:code="['${permissionPrefix}:create']"> | |
| 236 | 313 | {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }} |
| 237 | - </el-button> | |
| 314 | + </ElButton> | |
| 238 | 315 | </div> |
| 239 | 316 | #else |
| 240 | - <el-form | |
| 317 | + <ElForm | |
| 241 | 318 | ref="formRef" |
| 242 | 319 | class="mx-4" |
| 243 | 320 | :model="formData" |
| ... | ... | @@ -259,83 +336,83 @@ watch( |
| 259 | 336 | #set ($dictMethod = "boolean") |
| 260 | 337 | #end |
| 261 | 338 | #if ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 |
| 262 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 263 | - <el-input v-model="formData.${javaField}" placeholder="请输入${comment}" /> | |
| 264 | - </el-form-item> | |
| 339 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 340 | + <ElInput v-model="formData.${javaField}" placeholder="请输入${comment}" /> | |
| 341 | + </ElFormItem> | |
| 265 | 342 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 266 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 343 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 267 | 344 | <ImageUpload v-model="formData.${javaField}" /> |
| 268 | - </el-form-item> | |
| 345 | + </ElFormItem> | |
| 269 | 346 | #elseif($column.htmlType == "fileUpload")## 文件上传 |
| 270 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 347 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 271 | 348 | <FileUpload v-model="formData.${javaField}" /> |
| 272 | - </el-form-item> | |
| 349 | + </ElFormItem> | |
| 273 | 350 | #elseif($column.htmlType == "editor")## 文本编辑器 |
| 274 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 351 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 275 | 352 | <RichTextarea v-model="formData.${javaField}" height="500px" /> |
| 276 | - </el-form-item> | |
| 353 | + </ElFormItem> | |
| 277 | 354 | #elseif($column.htmlType == "select")## 下拉框 |
| 278 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 279 | - <el-select v-model="formData.${javaField}" placeholder="请选择${comment}"> | |
| 355 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 356 | + <ElSelect v-model="formData.${javaField}" placeholder="请选择${comment}"> | |
| 280 | 357 | #if ("" != $dictType)## 有数据字典 |
| 281 | - <el-option | |
| 358 | + <ElOption | |
| 282 | 359 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 283 | 360 | :key="dict.value" |
| 284 | 361 | :value="dict.value" |
| 285 | 362 | :label="dict.label" |
| 286 | 363 | /> |
| 287 | 364 | #else##没数据字典 |
| 288 | - <el-option label="请选择字典生成" value="" /> | |
| 365 | + <ElOption label="请选择字典生成" value="" /> | |
| 289 | 366 | #end |
| 290 | - </el-select> | |
| 291 | - </el-form-item> | |
| 367 | + </ElSelect> | |
| 368 | + </ElFormItem> | |
| 292 | 369 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 293 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 294 | - <el-checkbox-group v-model="formData.${javaField}"> | |
| 370 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 371 | + <ElCheckboxGroup v-model="formData.${javaField}"> | |
| 295 | 372 | #if ("" != $dictType)## 有数据字典 |
| 296 | - <el-checkbox | |
| 373 | + <ElCheckbox | |
| 297 | 374 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 298 | 375 | :key="dict.value" |
| 299 | - :label="dict.value" | |
| 376 | + :value="dict.value" | |
| 300 | 377 | > |
| 301 | 378 | {{ dict.label }} |
| 302 | - </el-checkbox> | |
| 379 | + </ElCheckbox> | |
| 303 | 380 | #else##没数据字典 |
| 304 | - <el-checkbox label="请选择字典生成" /> | |
| 381 | + <ElCheckbox label="请选择字典生成" /> | |
| 305 | 382 | #end |
| 306 | - </el-checkbox-group> | |
| 307 | - </el-form-item> | |
| 383 | + </ElCheckboxGroup> | |
| 384 | + </ElFormItem> | |
| 308 | 385 | #elseif($column.htmlType == "radio")## 单选框 |
| 309 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 310 | - <el-radio-group v-model="formData.${javaField}"> | |
| 386 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 387 | + <ElRadioGroup v-model="formData.${javaField}"> | |
| 311 | 388 | #if ("" != $dictType)## 有数据字典 |
| 312 | - <el-radio | |
| 389 | + <ElRadio | |
| 313 | 390 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 314 | 391 | :key="dict.value" |
| 315 | - :label="dict.value" | |
| 392 | + :value="dict.value" | |
| 316 | 393 | > |
| 317 | 394 | {{ dict.label }} |
| 318 | - </el-radio> | |
| 395 | + </ElRadio> | |
| 319 | 396 | #else##没数据字典 |
| 320 | - <el-radio :label="1">请选择字典生成</el-radio> | |
| 397 | + <ElRadio :label="1">请选择字典生成</ElRadio> | |
| 321 | 398 | #end |
| 322 | - </el-radio-group> | |
| 323 | - </el-form-item> | |
| 399 | + </ElRadioGroup> | |
| 400 | + </ElFormItem> | |
| 324 | 401 | #elseif($column.htmlType == "datetime")## 时间框 |
| 325 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 326 | - <el-date-picker | |
| 402 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 403 | + <ElDatePicker | |
| 327 | 404 | v-model="formData.${javaField}" |
| 328 | 405 | value-format="x" |
| 329 | 406 | placeholder="选择${comment}" |
| 330 | 407 | /> |
| 331 | - </el-form-item> | |
| 408 | + </ElFormItem> | |
| 332 | 409 | #elseif($column.htmlType == "textarea")## 文本框 |
| 333 | - <el-form-item label="${comment}" prop="${javaField}"> | |
| 334 | - <el-input v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" /> | |
| 335 | - </el-form-item> | |
| 410 | + <ElFormItem label="${comment}" prop="${javaField}"> | |
| 411 | + <ElInput v-model="formData.${javaField}" type="textarea" placeholder="请输入${comment}" /> | |
| 412 | + </ElFormItem> | |
| 336 | 413 | #end |
| 337 | 414 | #end |
| 338 | 415 | #end |
| 339 | - </el-form> | |
| 416 | + </ElForm> | |
| 340 | 417 | #end |
| 341 | 418 | </template> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/general/views/modules/list_sub_erp.vue.vm
| ... | ... | @@ -6,13 +6,14 @@ |
| 6 | 6 | #set ($subSimpleClassName_strikeCase = $subSimpleClassName_strikeCases.get($subIndex)) |
| 7 | 7 | #set ($SubJoinColumnName = $subJoinColumn.javaField.substring(0,1).toUpperCase() + ${subJoinColumn.javaField.substring(1)})##首字母大写 |
| 8 | 8 | <script lang="ts" setup> |
| 9 | - import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 9 | + import type { ${simpleClassName}Api } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 10 | 10 | import type { VxeTableInstance } from '#/adapter/vxe-table'; |
| 11 | 11 | |
| 12 | 12 | import { reactive,ref, h, nextTick,watch,onMounted } from 'vue'; |
| 13 | 13 | |
| 14 | 14 | import { DICT_TYPE } from '@vben/constants'; |
| 15 | 15 | import { getDictOptions } from '@vben/hooks'; |
| 16 | +import { formatDateTime } from '@vben/utils'; | |
| 16 | 17 | |
| 17 | 18 | import { DictTag } from '#/components/dict-tag'; |
| 18 | 19 | import { getRangePickerDefaultProps } from '#/utils'; |
| ... | ... | @@ -31,13 +32,13 @@ |
| 31 | 32 | #end |
| 32 | 33 | |
| 33 | 34 | #if ($table.templateType == 11) ## erp |
| 34 | - import { delete${subSimpleClassName},#if ($deleteBatchEnable) delete${subSimpleClassName}List,#end get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 35 | - import { isEmpty } from '@vben/utils'; | |
| 35 | + import { delete${subSimpleClassName},#if ($deleteBatchEnable) delete${subSimpleClassName}List,#end get${subSimpleClassName}Page } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 36 | + import { cloneDeep, isEmpty } from '@vben/utils'; | |
| 36 | 37 | #else |
| 37 | 38 | #if ($subTable.subJoinMany) ## 一对多 |
| 38 | - import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 39 | + import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 39 | 40 | #else |
| 40 | - import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${simpleClassName_strikeCase}'; | |
| 41 | + import { get${subSimpleClassName}By${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}'; | |
| 41 | 42 | #end |
| 42 | 43 | #end |
| 43 | 44 | |
| ... | ... | @@ -203,7 +204,7 @@ onMounted(() => { |
| 203 | 204 | <div class="h-[600px]"> |
| 204 | 205 | <ContentWrap v-if="!hiddenSearchBar"> |
| 205 | 206 | <!-- 搜索工作栏 --> |
| 206 | - <el-form | |
| 207 | + <ElForm | |
| 207 | 208 | :model="queryParams" |
| 208 | 209 | ref="queryFormRef" |
| 209 | 210 | inline |
| ... | ... | @@ -222,49 +223,49 @@ onMounted(() => { |
| 222 | 223 | #set ($dictMethod = "boolean") |
| 223 | 224 | #end |
| 224 | 225 | #if ($column.htmlType == "input") |
| 225 | - <el-form-item label="${comment}"> | |
| 226 | - <el-input | |
| 226 | + <ElFormItem label="${comment}"> | |
| 227 | + <ElInput | |
| 227 | 228 | v-model="queryParams.${javaField}" |
| 228 | 229 | placeholder="请输入${comment}" |
| 229 | 230 | clearable |
| 230 | 231 | @keyup.enter="handleQuery" |
| 231 | 232 | class="!w-[240px]" |
| 232 | 233 | /> |
| 233 | - </el-form-item> | |
| 234 | + </ElFormItem> | |
| 234 | 235 | #elseif ($column.htmlType == "select" || $column.htmlType == "radio" || $column.htmlType == "checkbox") |
| 235 | - <el-form-item label="${comment}"> | |
| 236 | - <el-select | |
| 236 | + <ElFormItem label="${comment}"> | |
| 237 | + <ElSelect | |
| 237 | 238 | v-model="queryParams.${javaField}" |
| 238 | 239 | placeholder="请选择${comment}" |
| 239 | 240 | clearable |
| 240 | 241 | class="!w-[240px]" |
| 241 | 242 | > |
| 242 | 243 | #if ("" != $dictType)## 设置了 dictType 数据字典的情况 |
| 243 | - <el-option | |
| 244 | + <ElOption | |
| 244 | 245 | v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod')" |
| 245 | 246 | :key="dict.value" |
| 246 | 247 | :value="dict.value" |
| 247 | 248 | :label="dict.label" |
| 248 | 249 | /> |
| 249 | 250 | #else## 未设置 dictType 数据字典的情况 |
| 250 | - <el-option label="请选择字典生成" value="" /> | |
| 251 | + <ElOption label="请选择字典生成" value="" /> | |
| 251 | 252 | #end |
| 252 | - </el-select> | |
| 253 | - </el-form-item> | |
| 253 | + </ElSelect> | |
| 254 | + </ElFormItem> | |
| 254 | 255 | #elseif($column.htmlType == "datetime") |
| 255 | 256 | #if ($column.listOperationCondition != "BETWEEN")## 非范围 |
| 256 | - <el-form-item label="${comment}"> | |
| 257 | - <el-date-picker | |
| 257 | + <ElFormItem label="${comment}"> | |
| 258 | + <ElDatePicker | |
| 258 | 259 | v-model="queryParams.${javaField}" |
| 259 | 260 | value-format="YYYY-MM-DD" |
| 260 | 261 | placeholder="选择${comment}" |
| 261 | 262 | clearable |
| 262 | 263 | class="!w-[240px]" |
| 263 | 264 | /> |
| 264 | - </el-form-item> | |
| 265 | + </ElFormItem> | |
| 265 | 266 | #else## 范围 |
| 266 | - <el-form-item label="${comment}"> | |
| 267 | - <el-date-picker | |
| 267 | + <ElFormItem label="${comment}"> | |
| 268 | + <ElDatePicker | |
| 268 | 269 | v-model="queryParams.${javaField}" |
| 269 | 270 | type="daterange" |
| 270 | 271 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -273,18 +274,18 @@ onMounted(() => { |
| 273 | 274 | end-placeholder="结束日期" |
| 274 | 275 | class="!w-[240px]" |
| 275 | 276 | /> |
| 276 | - </el-form-item> | |
| 277 | + </ElFormItem> | |
| 277 | 278 | #end |
| 278 | 279 | #end |
| 279 | 280 | #end |
| 280 | 281 | #end |
| 281 | - <el-form-item> | |
| 282 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 283 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 282 | + <ElFormItem> | |
| 283 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 284 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 284 | 285 | 搜索 |
| 285 | - </el-button> | |
| 286 | - </el-form-item> | |
| 287 | - </el-form> | |
| 286 | + </ElButton> | |
| 287 | + </ElFormItem> | |
| 288 | + </ElForm> | |
| 288 | 289 | </ContentWrap> |
| 289 | 290 | |
| 290 | 291 | <!-- 列表 --> |
| ... | ... | @@ -294,7 +295,7 @@ onMounted(() => { |
| 294 | 295 | ref="tableToolbarRef" |
| 295 | 296 | v-model:hidden-search="hiddenSearchBar" |
| 296 | 297 | > |
| 297 | - <el-button | |
| 298 | + <ElButton | |
| 298 | 299 | class="ml-2" |
| 299 | 300 | :icon="h(Plus)" |
| 300 | 301 | type="primary" |
| ... | ... | @@ -302,9 +303,9 @@ onMounted(() => { |
| 302 | 303 | v-access:code="['${permissionPrefix}:create']" |
| 303 | 304 | > |
| 304 | 305 | {{ $t('ui.actionTitle.create', ['${table.classComment}']) }} |
| 305 | - </el-button> | |
| 306 | + </ElButton> | |
| 306 | 307 | #if ($deleteBatchEnable) |
| 307 | - <el-button | |
| 308 | + <ElButton | |
| 308 | 309 | :icon="h(Trash2)" |
| 309 | 310 | type="danger" |
| 310 | 311 | class="ml-2" |
| ... | ... | @@ -313,11 +314,11 @@ onMounted(() => { |
| 313 | 314 | v-access:code="['${table.moduleName}:${simpleClassName_strikeCase}:delete']" |
| 314 | 315 | > |
| 315 | 316 | 批量删除 |
| 316 | - </el-button> | |
| 317 | + </ElButton> | |
| 317 | 318 | #end |
| 318 | - </TableToolbar> | |
| 319 | + </VbenVxeTableToolbar> | |
| 319 | 320 | </template> |
| 320 | - <vxe-table | |
| 321 | + <VxeTable | |
| 321 | 322 | ref="tableRef" |
| 322 | 323 | :data="list" |
| 323 | 324 | show-overflow |
| ... | ... | @@ -328,7 +329,7 @@ onMounted(() => { |
| 328 | 329 | #end |
| 329 | 330 | > |
| 330 | 331 | #if ($deleteBatchEnable) |
| 331 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 332 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 332 | 333 | #end |
| 333 | 334 | #foreach($column in $subColumns) |
| 334 | 335 | #if ($column.listOperationResult) |
| ... | ... | @@ -336,27 +337,27 @@ onMounted(() => { |
| 336 | 337 | #set ($javaField = $column.javaField) |
| 337 | 338 | #set ($comment=$column.columnComment) |
| 338 | 339 | #if ($column.javaType == "LocalDateTime")## 时间类型 |
| 339 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 340 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 340 | 341 | <template #default="{row}"> |
| 341 | 342 | {{formatDateTime(row.${javaField})}} |
| 342 | 343 | </template> |
| 343 | - </vxe-column> | |
| 344 | + </VxeColumn> | |
| 344 | 345 | #elseif($column.dictType && "" != $column.dictType)## 数据字典 |
| 345 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 346 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 346 | 347 | <template #default="{row}"> |
| 347 | 348 | <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" /> |
| 348 | 349 | </template> |
| 349 | - </vxe-column> | |
| 350 | + </VxeColumn> | |
| 350 | 351 | #elseif ($table.templateType == 2 && $javaField == $treeNameColumn.javaField) |
| 351 | - <vxe-column field="${javaField}" title="${comment}" align="center" tree-node/> | |
| 352 | + <VxeColumn field="${javaField}" title="${comment}" align="center" tree-node/> | |
| 352 | 353 | #else |
| 353 | - <vxe-column field="${javaField}" title="${comment}" align="center" /> | |
| 354 | + <VxeColumn field="${javaField}" title="${comment}" align="center" /> | |
| 354 | 355 | #end |
| 355 | 356 | #end |
| 356 | 357 | #end |
| 357 | - <vxe-column field="operation" title="操作" align="center"> | |
| 358 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 358 | 359 | <template #default="{row}"> |
| 359 | - <el-button | |
| 360 | + <ElButton | |
| 360 | 361 | size="small" |
| 361 | 362 | type="primary" |
| 362 | 363 | link |
| ... | ... | @@ -364,8 +365,8 @@ onMounted(() => { |
| 364 | 365 | v-access:code="['${permissionPrefix}:update']" |
| 365 | 366 | > |
| 366 | 367 | {{ $t('ui.actionTitle.edit') }} |
| 367 | - </el-button> | |
| 368 | - <el-button | |
| 368 | + </ElButton> | |
| 369 | + <ElButton | |
| 369 | 370 | size="small" |
| 370 | 371 | type="danger" |
| 371 | 372 | link |
| ... | ... | @@ -374,13 +375,13 @@ onMounted(() => { |
| 374 | 375 | v-access:code="['${permissionPrefix}:delete']" |
| 375 | 376 | > |
| 376 | 377 | {{ $t('ui.actionTitle.delete') }} |
| 377 | - </el-button> | |
| 378 | + </ElButton> | |
| 378 | 379 | </template> |
| 379 | - </vxe-column> | |
| 380 | - </vxe-table> | |
| 380 | + </VxeColumn> | |
| 381 | + </VxeTable> | |
| 381 | 382 | <!-- 分页 --> |
| 382 | 383 | <div class="mt-2 flex justify-end"> |
| 383 | - <el-pagination | |
| 384 | + <ElPagination | |
| 384 | 385 | :total="total" |
| 385 | 386 | v-model:current-page="queryParams.pageNo" |
| 386 | 387 | v-model:page-size="queryParams.pageSize" |
| ... | ... | @@ -394,7 +395,7 @@ onMounted(() => { |
| 394 | 395 | </div> |
| 395 | 396 | #else |
| 396 | 397 | <ContentWrap title="${subTable.classComment}列表"> |
| 397 | - <vxe-table | |
| 398 | + <VxeTable | |
| 398 | 399 | :data="list" |
| 399 | 400 | show-overflow |
| 400 | 401 | :loading="loading" |
| ... | ... | @@ -405,23 +406,23 @@ onMounted(() => { |
| 405 | 406 | #set ($javaField = $column.javaField) |
| 406 | 407 | #set ($comment=$column.columnComment) |
| 407 | 408 | #if ($column.javaType == "LocalDateTime")## 时间类型 |
| 408 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 409 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 409 | 410 | <template #default="{row}"> |
| 410 | 411 | {{formatDateTime(row.${javaField})}} |
| 411 | 412 | </template> |
| 412 | - </vxe-column> | |
| 413 | + </VxeColumn> | |
| 413 | 414 | #elseif($column.dictType && "" != $column.dictType)## 数据字典 |
| 414 | - <vxe-column field="${javaField}" title="${comment}" align="center"> | |
| 415 | + <VxeColumn field="${javaField}" title="${comment}" align="center"> | |
| 415 | 416 | <template #default="{row}"> |
| 416 | 417 | <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="row.${javaField}" /> |
| 417 | 418 | </template> |
| 418 | - </vxe-column> | |
| 419 | + </VxeColumn> | |
| 419 | 420 | #else |
| 420 | - <vxe-column field="${javaField}" title="${comment}" align="center" /> | |
| 421 | + <VxeColumn field="${javaField}" title="${comment}" align="center" /> | |
| 421 | 422 | #end |
| 422 | 423 | #end |
| 423 | 424 | #end |
| 424 | - </vxe-table> | |
| 425 | + </VxeTable> | |
| 425 | 426 | </ContentWrap> |
| 426 | 427 | #end |
| 427 | 428 | </template> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/data.ts.vm
| ... | ... | @@ -36,13 +36,14 @@ export function useFormSchema(): VbenFormSchema[] { |
| 36 | 36 | id: 0, |
| 37 | 37 | ${treeNameColumn.javaField}: '顶级${table.classComment}', |
| 38 | 38 | }); |
| 39 | - return handleTree(data); | |
| 39 | + return handleTree(data, 'id', '${treeParentColumn.javaField}'); | |
| 40 | 40 | }, |
| 41 | 41 | labelField: '${treeNameColumn.javaField}', |
| 42 | 42 | valueField: 'id', |
| 43 | 43 | childrenField: 'children', |
| 44 | 44 | placeholder: '请选择上级${table.classComment}', |
| 45 | - treeDefaultExpandAll: true, | |
| 45 | + defaultExpandAll: true, | |
| 46 | + checkStrictly: true, | |
| 46 | 47 | }, |
| 47 | 48 | rules: 'selectRequired', |
| 48 | 49 | }, |
| ... | ... | @@ -89,7 +90,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 89 | 90 | placeholder: '请选择${comment}', |
| 90 | 91 | }, |
| 91 | 92 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 92 | - component: 'Checkbox', | |
| 93 | + component: 'CheckboxGroup', | |
| 93 | 94 | componentProps: { |
| 94 | 95 | #if ("" != $dictType)## 有数据字典 |
| 95 | 96 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -105,13 +106,12 @@ export function useFormSchema(): VbenFormSchema[] { |
| 105 | 106 | #else##没数据字典 |
| 106 | 107 | options: [], |
| 107 | 108 | #end |
| 108 | - buttonStyle: 'solid', | |
| 109 | - optionType: 'button', | |
| 109 | + isButton: true, | |
| 110 | 110 | }, |
| 111 | 111 | #elseif($column.htmlType == "datetime")## 时间框 |
| 112 | 112 | component: 'DatePicker', |
| 113 | 113 | componentProps: { |
| 114 | - showTime: true, | |
| 114 | + type: 'datetime', | |
| 115 | 115 | format: 'YYYY-MM-DD HH:mm:ss', |
| 116 | 116 | valueFormat: 'x', |
| 117 | 117 | class: '!w-full', |
| ... | ... | @@ -308,7 +308,7 @@ export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] { |
| 308 | 308 | placeholder: '请选择${comment}', |
| 309 | 309 | }, |
| 310 | 310 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 311 | - component: 'Checkbox', | |
| 311 | + component: 'CheckboxGroup', | |
| 312 | 312 | componentProps: { |
| 313 | 313 | #if ("" != $dictType)## 有数据字典 |
| 314 | 314 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -324,13 +324,12 @@ export function use${subSimpleClassName}FormSchema(): VbenFormSchema[] { |
| 324 | 324 | #else##没数据字典 |
| 325 | 325 | options: [], |
| 326 | 326 | #end |
| 327 | - buttonStyle: 'solid', | |
| 328 | - optionType: 'button', | |
| 327 | + isButton: true, | |
| 329 | 328 | }, |
| 330 | 329 | #elseif($column.htmlType == "datetime")## 时间框 |
| 331 | 330 | component: 'DatePicker', |
| 332 | 331 | componentProps: { |
| 333 | - showTime: true, | |
| 332 | + type: 'datetime', | |
| 334 | 333 | format: 'YYYY-MM-DD HH:mm:ss', |
| 335 | 334 | valueFormat: 'x', |
| 336 | 335 | class: '!w-full', |
| ... | ... | @@ -450,6 +449,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 450 | 449 | #if ($column.createOperation || $column.updateOperation) |
| 451 | 450 | #if (!$column.primaryKey && $column.listOperationResult && $column.id != $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写 |
| 452 | 451 | #set ($dictType = $column.dictType) |
| 452 | + #set ($javaType = $column.javaType) | |
| 453 | 453 | #set ($javaField = $column.javaField) |
| 454 | 454 | #set ($comment = $column.columnComment) |
| 455 | 455 | #if ($javaType == "Integer" || $javaType == "Long" || $javaType == "Byte" || $javaType == "Short") |
| ... | ... | @@ -544,7 +544,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 544 | 544 | placeholder: '请选择${comment}', |
| 545 | 545 | }, |
| 546 | 546 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 547 | - component: 'Checkbox', | |
| 547 | + component: 'CheckboxGroup', | |
| 548 | 548 | componentProps: { |
| 549 | 549 | #if ("" != $dictType)## 有数据字典 |
| 550 | 550 | options: getDictOptions(DICT_TYPE.$dictType.toUpperCase(), '$dictMethod'), |
| ... | ... | @@ -560,13 +560,12 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 560 | 560 | #else##没数据字典 |
| 561 | 561 | options: [], |
| 562 | 562 | #end |
| 563 | - buttonStyle: 'solid', | |
| 564 | - optionType: 'button', | |
| 563 | + isButton: true, | |
| 565 | 564 | }, |
| 566 | 565 | #elseif($column.htmlType == "datetime")## 时间框 |
| 567 | 566 | component: 'DatePicker', |
| 568 | 567 | componentProps: { |
| 569 | - showTime: true, | |
| 568 | + type: 'datetime', | |
| 570 | 569 | format: 'YYYY-MM-DD HH:mm:ss', |
| 571 | 570 | valueFormat: 'x', |
| 572 | 571 | class: '!w-full', |
| ... | ... | @@ -596,7 +595,7 @@ export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${api |
| 596 | 595 | #end |
| 597 | 596 | #if ($table.templateType == 12) ## 内嵌情况 |
| 598 | 597 | /** 列表的字段 */ |
| 599 | - export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${simpleClassName}Api.${subSimpleClassName}>['columns'] { | |
| 598 | + export function use${subSimpleClassName}GridColumns(): VxeTableGridOptions<${apiName}.${subSimpleClassName}>['columns'] { | |
| 600 | 599 | return [ |
| 601 | 600 | #foreach($column in $subColumns) |
| 602 | 601 | #if ($column.listOperationResult) | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/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 { ElMessage#if ($table.templateType == 11), ElTabs, ElTabPane#end } from 'element-plus'; | |
| 9 | +import { ElMessage#if ($table.templateType == 10 || $table.templateType == 12), ElTabPane, ElTabs#end } from 'element-plus'; | |
| 10 | 10 | |
| 11 | 11 | import { useVbenForm } from '#/adapter/form'; |
| 12 | 12 | import { create${simpleClassName}, get${simpleClassName}, update${simpleClassName} } from '#/api/${table.moduleName}/${table.businessName}'; |
| ... | ... | @@ -69,15 +69,11 @@ const [Modal, modalApi] = useVbenModal({ |
| 69 | 69 | #foreach ($subTable in $subTables) |
| 70 | 70 | #set ($index = $foreach.count - 1) |
| 71 | 71 | #set ($subClassNameVar = $subClassNameVars.get($index)) |
| 72 | - #if ($subTable.subJoinMany) ## 一对多 | |
| 73 | - ## TODO 列表值校验? | |
| 74 | - #else | |
| 75 | 72 | const ${subClassNameVar}Valid = await ${subClassNameVar}FormRef.value?.validate(); |
| 76 | 73 | if (!${subClassNameVar}Valid) { |
| 77 | 74 | subTabsName.value = '${subClassNameVar}'; |
| 78 | 75 | return; |
| 79 | 76 | } |
| 80 | - #end | |
| 81 | 77 | #end |
| 82 | 78 | #end |
| 83 | 79 | #end | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/import.vue.vm
| ... | ... | @@ -50,6 +50,16 @@ function handleChange(file: any) { |
| 50 | 50 | } |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | +/** 移除文件 */ | |
| 54 | +function handleRemove() { | |
| 55 | + formApi.setFieldValue('file', undefined); | |
| 56 | +} | |
| 57 | + | |
| 58 | +/** 超出文件数量 */ | |
| 59 | +function handleExceed() { | |
| 60 | + ElMessage.warning('只能选择一个文件,请先移除已选文件'); | |
| 61 | +} | |
| 62 | + | |
| 53 | 63 | /** 下载模板 */ |
| 54 | 64 | async function handleDownload() { |
| 55 | 65 | const data = await import${simpleClassName}Template(); |
| ... | ... | @@ -66,6 +76,8 @@ async function handleDownload() { |
| 66 | 76 | :limit="1" |
| 67 | 77 | accept=".xls,.xlsx" |
| 68 | 78 | :on-change="handleChange" |
| 79 | + :on-remove="handleRemove" | |
| 80 | + :on-exceed="handleExceed" | |
| 69 | 81 | :auto-upload="false" |
| 70 | 82 | > |
| 71 | 83 | <ElButton type="primary"> 选择 Excel 文件 </ElButton> | ... | ... |
yudao-module-infra/src/main/resources/codegen/vue3_vben5_ele/schema/views/modules/form_sub_normal.vue.vm
| ... | ... | @@ -14,10 +14,9 @@ |
| 14 | 14 | |
| 15 | 15 | #if ($subTable.subJoinMany) ## 一对多 |
| 16 | 16 | import { Plus } from "@vben/icons"; |
| 17 | -import { ElButton, ElTabs, ElTabPane, ElCheckbox, ElInput, ElSelect, ElOption, ElRadioGroup, ElCheckboxGroup, ElDatePicker } from 'element-plus'; | |
| 17 | +import { ElButton, ElCheckbox, ElCheckboxGroup, ElDatePicker, ElInput, ElMessage, ElOption, ElRadio, ElRadioGroup, ElSelect, ElTabPane, ElTabs } from 'element-plus'; | |
| 18 | 18 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 19 | -import type { OnActionClickParams } from '#/adapter/vxe-table'; | |
| 20 | -import { useVbenVxeGrid } from '#/adapter/vxe-table'; | |
| 19 | +import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; | |
| 21 | 20 | import { use${subSimpleClassName}GridEditColumns } from '../data'; |
| 22 | 21 | import { get${subSimpleClassName}ListBy${SubJoinColumnName} } from '#/api/${table.moduleName}/${table.businessName}'; |
| 23 | 22 | #else |
| ... | ... | @@ -31,22 +30,9 @@ const props = defineProps<{ |
| 31 | 30 | }>() |
| 32 | 31 | |
| 33 | 32 | #if ($subTable.subJoinMany) ## 一对多 |
| 34 | -/** 表格操作按钮的回调函数 */ | |
| 35 | -function onActionClick({ | |
| 36 | - code, | |
| 37 | - row, | |
| 38 | -}: OnActionClickParams<${apiName}.${subSimpleClassName}>) { | |
| 39 | - switch (code) { | |
| 40 | - case 'delete': { | |
| 41 | - onDelete(row); | |
| 42 | - break; | |
| 43 | - } | |
| 44 | - } | |
| 45 | -} | |
| 46 | - | |
| 47 | 33 | const [Grid, gridApi] = useVbenVxeGrid({ |
| 48 | 34 | gridOptions: { |
| 49 | - columns: use${subSimpleClassName}GridEditColumns(onActionClick), | |
| 35 | + columns: use${subSimpleClassName}GridEditColumns(), | |
| 50 | 36 | border: true, |
| 51 | 37 | showOverflow: true, |
| 52 | 38 | autoResize: true, |
| ... | ... | @@ -65,7 +51,7 @@ gridOptions: { |
| 65 | 51 | |
| 66 | 52 | /** 添加${subTable.classComment} */ |
| 67 | 53 | const onAdd = async () => { |
| 68 | - await gridApi.grid.insertAt({} as ${simpleClassName}Api.${subSimpleClassName}, -1); | |
| 54 | + await gridApi.grid.insertAt({} as ${apiName}.${subSimpleClassName}, -1); | |
| 69 | 55 | } |
| 70 | 56 | |
| 71 | 57 | /** 删除${subTable.classComment} */ |
| ... | ... | @@ -73,26 +59,54 @@ const onDelete = async (row: ${apiName}.${subSimpleClassName}) => { |
| 73 | 59 | await gridApi.grid.remove(row); |
| 74 | 60 | } |
| 75 | 61 | |
| 76 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 77 | -defineExpose({ | |
| 78 | - getData: (): ${apiName}.${subSimpleClassName}[] => { | |
| 79 | - const data = gridApi.grid.getData() as ${apiName}.${subSimpleClassName}[]; | |
| 80 | - const removeRecords = gridApi.grid.getRemoveRecords() as ${apiName}.${subSimpleClassName}[]; | |
| 81 | - const insertRecords = gridApi.grid.getInsertRecords() as ${apiName}.${subSimpleClassName}[]; | |
| 82 | - return data | |
| 83 | - .filter((row) => !removeRecords.some((removed) => removed.id === row.id)) | |
| 84 | - .concat(insertRecords.map((row: any) => ({ ...row, id: undefined }))); | |
| 85 | - }, | |
| 86 | -}); | |
| 62 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 63 | +function getData(): ${apiName}.${subSimpleClassName}[] { | |
| 64 | + const { fullData } = gridApi.grid.getTableData(); | |
| 65 | + const inserted = new Set(gridApi.grid.getInsertRecords()); | |
| 66 | + return fullData.map((row) => | |
| 67 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 68 | + ); | |
| 69 | +} | |
| 70 | + | |
| 71 | +#set ($hasRequiredColumn = false) | |
| 72 | +#foreach ($column in $subColumns) | |
| 73 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 74 | +#set ($hasRequiredColumn = true) | |
| 75 | +#end | |
| 76 | +#end | |
| 77 | +/** 校验子表必填字段 */ | |
| 78 | +function validate(): boolean { | |
| 79 | +#if ($hasRequiredColumn) | |
| 80 | + for (const [index, row] of getData().entries()) { | |
| 81 | +#foreach ($column in $subColumns) | |
| 82 | +#if (($column.createOperation || $column.updateOperation) && !$column.nullable && !$column.primaryKey && $column.id != $subJoinColumn.id) | |
| 83 | + if ( | |
| 84 | + row.${column.javaField} === null || | |
| 85 | + row.${column.javaField} === undefined || | |
| 86 | + (typeof row.${column.javaField} === 'string' && String(row.${column.javaField}).trim() === '') || | |
| 87 | + (Array.isArray(row.${column.javaField}) && row.${column.javaField}.length === 0) | |
| 88 | + ) { | |
| 89 | + ElMessage.error(`第 #[[${index + 1}]]# 行:${column.columnComment}不能为空`); | |
| 90 | + return false; | |
| 91 | + } | |
| 92 | +#end | |
| 93 | +#end | |
| 94 | + } | |
| 95 | +#end | |
| 96 | + return true; | |
| 97 | +} | |
| 98 | + | |
| 99 | +defineExpose({ getData, validate }); | |
| 87 | 100 | |
| 88 | 101 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 89 | 102 | watch( |
| 90 | 103 | () => props.${subJoinColumn.javaField}, |
| 91 | 104 | async (val) => { |
| 105 | + await nextTick(); | |
| 92 | 106 | if (!val) { |
| 107 | + await gridApi.grid.loadData([]); | |
| 93 | 108 | return; |
| 94 | 109 | } |
| 95 | - await nextTick(); | |
| 96 | 110 | await gridApi.grid.loadData(await get${subSimpleClassName}ListBy${SubJoinColumnName}(props.${subJoinColumn.javaField}!)); |
| 97 | 111 | }, |
| 98 | 112 | { immediate: true }, |
| ... | ... | @@ -124,10 +138,11 @@ defineExpose({ |
| 124 | 138 | watch( |
| 125 | 139 | () => props.${subJoinColumn.javaField}, |
| 126 | 140 | async (val) => { |
| 141 | + await nextTick(); | |
| 142 | + await formApi.resetForm(); | |
| 127 | 143 | if (!val) { |
| 128 | 144 | return; |
| 129 | 145 | } |
| 130 | - await nextTick(); | |
| 131 | 146 | await formApi.setValues(await get${subSimpleClassName}By${SubJoinColumnName}(props.${subJoinColumn.javaField}!)); |
| 132 | 147 | }, |
| 133 | 148 | { immediate: true }, |
| ... | ... | @@ -144,7 +159,7 @@ watch( |
| 144 | 159 | #if ( $column.id == $subJoinColumn.id) ## 特殊:忽略主子表的 join 字段,不用填写 |
| 145 | 160 | #elseif ($column.htmlType == "input" && !$column.primaryKey)## 忽略主键,不用在表单里 |
| 146 | 161 | <template #${javaField}="{ row }"> |
| 147 | - <el-input v-model="row.${javaField}" /> | |
| 162 | + <ElInput v-model="row.${javaField}" /> | |
| 148 | 163 | </template> |
| 149 | 164 | #elseif($column.htmlType == "imageUpload")## 图片上传 |
| 150 | 165 | <template #${javaField}="{ row }"> |
| ... | ... | @@ -156,29 +171,29 @@ watch( |
| 156 | 171 | </template> |
| 157 | 172 | #elseif($column.htmlType == "select")## 下拉框 |
| 158 | 173 | <template #${javaField}="{ row, column }"> |
| 159 | - <el-select v-model="row.${javaField}" class="w-full"> | |
| 160 | - <el-option v-for="option in column.params.options" :key="option.value" :value="option.value" :label="option.label" /> | |
| 161 | - </el-select> | |
| 174 | + <ElSelect v-model="row.${javaField}" class="w-full"> | |
| 175 | + <ElOption v-for="option in column.params.options" :key="option.value" :value="option.value" :label="option.label" /> | |
| 176 | + </ElSelect> | |
| 162 | 177 | </template> |
| 163 | 178 | #elseif($column.htmlType == "checkbox")## 多选框 |
| 164 | 179 | <template #${javaField}="{ row, column }"> |
| 165 | - <el-checkbox-group v-model="row.${javaField}"> | |
| 166 | - <el-checkbox v-for="option in column.params.options" :key="option.value" :label="option.value"> | |
| 180 | + <ElCheckboxGroup v-model="row.${javaField}"> | |
| 181 | + <ElCheckbox v-for="option in column.params.options" :key="option.value" :value="option.value"> | |
| 167 | 182 | {{ option.label }} |
| 168 | - </el-checkbox> | |
| 169 | - </el-checkbox-group> | |
| 183 | + </ElCheckbox> | |
| 184 | + </ElCheckboxGroup> | |
| 170 | 185 | </template> |
| 171 | 186 | #elseif($column.htmlType == "radio")## 单选框 |
| 172 | 187 | <template #${javaField}="{ row, column }"> |
| 173 | - <el-radio-group v-model="row.${javaField}"> | |
| 174 | - <el-radio v-for="option in column.params.options" :key="option.value" :label="option.value"> | |
| 188 | + <ElRadioGroup v-model="row.${javaField}"> | |
| 189 | + <ElRadio v-for="option in column.params.options" :key="option.value" :value="option.value"> | |
| 175 | 190 | {{ option.label }} |
| 176 | - </el-radio> | |
| 177 | - </el-radio-group> | |
| 191 | + </ElRadio> | |
| 192 | + </ElRadioGroup> | |
| 178 | 193 | </template> |
| 179 | 194 | #elseif($column.htmlType == "datetime")## 时间框 |
| 180 | 195 | <template #${javaField}="{ row }"> |
| 181 | - <el-date-picker | |
| 196 | + <ElDatePicker | |
| 182 | 197 | v-model="row.${javaField}" |
| 183 | 198 | type="datetime" |
| 184 | 199 | value-format="x" |
| ... | ... | @@ -187,16 +202,29 @@ watch( |
| 187 | 202 | </template> |
| 188 | 203 | #elseif($column.htmlType == "textarea" || $column.htmlType == "editor")## 文本框 |
| 189 | 204 | <template #${javaField}="{ row }"> |
| 190 | - <el-input v-model="row.${javaField}" type="textarea" /> | |
| 205 | + <ElInput v-model="row.${javaField}" type="textarea" /> | |
| 191 | 206 | </template> |
| 192 | 207 | #end |
| 193 | 208 | #end |
| 194 | 209 | #end |
| 210 | + <template #actions="{ row }"> | |
| 211 | + <TableAction | |
| 212 | + :actions="[ | |
| 213 | + { | |
| 214 | + label: $t('common.delete'), | |
| 215 | + type: 'danger', link: true, | |
| 216 | + icon: ACTION_ICON.DELETE, | |
| 217 | + auth: ['${permissionPrefix}:delete'], | |
| 218 | + onClick: onDelete.bind(null, row), | |
| 219 | + }, | |
| 220 | + ]" | |
| 221 | + /> | |
| 222 | + </template> | |
| 195 | 223 | </Grid> |
| 196 | 224 | <div class="flex justify-center -mt-4"> |
| 197 | - <el-button :icon="Plus" type="primary" plain @click="onAdd" v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:create']"> | |
| 225 | + <ElButton :icon="Plus" type="primary" plain @click="onAdd" v-access:code="['${subTable.moduleName}:${simpleClassName_strikeCase}:create']"> | |
| 198 | 226 | {{ $t('ui.actionTitle.create', ['${subTable.classComment}']) }} |
| 199 | - </el-button> | |
| 227 | + </ElButton> | |
| 200 | 228 | </div> |
| 201 | 229 | #else |
| 202 | 230 | <Form class="mx-4" /> | ... | ... |
yudao-module-infra/src/test/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngineFrontendContractTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.infra.service.codegen.inner; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO; | |
| 4 | +import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO; | |
| 5 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenFrontTypeEnum; | |
| 6 | +import cn.iocoder.yudao.module.infra.enums.codegen.CodegenTemplateTypeEnum; | |
| 7 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 8 | +import org.junit.jupiter.api.Test; | |
| 9 | +import org.junit.jupiter.params.ParameterizedTest; | |
| 10 | +import org.junit.jupiter.params.provider.EnumSource; | |
| 11 | + | |
| 12 | +import java.util.List; | |
| 13 | +import java.util.Map; | |
| 14 | + | |
| 15 | +import static org.junit.jupiter.api.Assertions.*; | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * {@link CodegenEngine} 的前端组件契约回归测试 | |
| 19 | + * | |
| 20 | + * @author 芋道源码 | |
| 21 | + */ | |
| 22 | +public class CodegenEngineFrontendContractTest extends CodegenEngineAbstractTest { | |
| 23 | + | |
| 24 | + @ParameterizedTest | |
| 25 | + @EnumSource(value = CodegenFrontTypeEnum.class, names = { | |
| 26 | + "VUE3_VBEN5_ANTD_SCHEMA", "VUE3_VBEN5_ANTDV_NEXT_SCHEMA", "VUE3_VBEN5_EP_SCHEMA"}) | |
| 27 | + public void testExecute_dictionaryControls(CodegenFrontTypeEnum frontType) { | |
| 28 | + // 准备参数:同一字典的多选、单选和数字必填字段 | |
| 29 | + CodegenTableDO table = getTable("student").setFrontType(frontType.getType()) | |
| 30 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | |
| 31 | + List<CodegenColumnDO> columns = getColumnList("student"); | |
| 32 | + columns.add(new CodegenColumnDO().setJavaField("tags").setJavaType("String") | |
| 33 | + .setColumnComment("标签").setDictType("system_user_sex").setHtmlType("checkbox") | |
| 34 | + .setCreateOperation(true).setUpdateOperation(true).setNullable(false).setPrimaryKey(false)); | |
| 35 | + columns.add(new CodegenColumnDO().setJavaField("status").setJavaType("Integer") | |
| 36 | + .setColumnComment("状态").setDictType("system_user_sex").setHtmlType("radio") | |
| 37 | + .setCreateOperation(true).setUpdateOperation(true).setNullable(false).setPrimaryKey(false)); | |
| 38 | + columns.add(new CodegenColumnDO().setJavaField("amount").setJavaType("Integer") | |
| 39 | + .setColumnComment("金额").setHtmlType("inputNumber").setDictType("") | |
| 40 | + .setCreateOperation(true).setUpdateOperation(true).setNullable(false).setPrimaryKey(false)); | |
| 41 | + | |
| 42 | + // 调用 | |
| 43 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, columns, null, null); | |
| 44 | + // 调试用:导出真实生成结果,供前端组件验证 | |
| 45 | + String outputPath = System.getProperty("codegen.contractOutput"); | |
| 46 | + if (outputPath != null) { | |
| 47 | + writeResult(result, outputPath + "/" + frontType.name()); | |
| 48 | + } | |
| 49 | + // 断言:组选项不能变成 boolean Checkbox,必填数字不能被 Zod 推导为 null | |
| 50 | + String data = findFile(result, "/data.ts"); | |
| 51 | + assertTrue(data.contains("component: 'CheckboxGroup'")); | |
| 52 | + assertFalse(data.contains("component: 'Checkbox',")); | |
| 53 | + assertTrue(data.contains("rules: 'required'")); | |
| 54 | + assertFalse(data.contains("z.number(")); | |
| 55 | + if (frontType == CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA) { | |
| 56 | + assertTrue(data.contains("isButton: true")); | |
| 57 | + assertFalse(data.contains("buttonStyle:")); | |
| 58 | + assertFalse(data.contains("optionType:")); | |
| 59 | + assertFalse(data.contains("allowClear:")); | |
| 60 | + } else { | |
| 61 | + assertTrue(data.contains("optionType: 'button'")); | |
| 62 | + assertFalse(data.contains("clearable:")); | |
| 63 | + } | |
| 64 | + } | |
| 65 | + | |
| 66 | + @Test | |
| 67 | + public void testExecute_eleTreeParentSelectable() { | |
| 68 | + // 准备参数 | |
| 69 | + CodegenTableDO table = getTable("category").setFrontType(CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA.getType()) | |
| 70 | + .setTemplateType(CodegenTemplateTypeEnum.TREE.getType()); | |
| 71 | + // 调用 | |
| 72 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, getColumnList("category"), null, null); | |
| 73 | + // 断言:父节点可作为上级,使用 Element Plus 属性 | |
| 74 | + String data = findFile(result, "/data.ts"); | |
| 75 | + assertTrue(data.contains("defaultExpandAll: true")); | |
| 76 | + assertTrue(data.contains("checkStrictly: true")); | |
| 77 | + assertFalse(data.contains("treeDefaultExpandAll")); | |
| 78 | + } | |
| 79 | + | |
| 80 | + @ParameterizedTest | |
| 81 | + @EnumSource(value = CodegenFrontTypeEnum.class, names = { | |
| 82 | + "VUE3_VBEN5_ANTD_SCHEMA", "VUE3_VBEN5_ANTD_GENERAL", | |
| 83 | + "VUE3_VBEN5_ANTDV_NEXT_SCHEMA", "VUE3_VBEN5_ANTDV_NEXT_GENERAL", | |
| 84 | + "VUE3_VBEN5_EP_SCHEMA", "VUE3_VBEN5_EP_GENERAL"}) | |
| 85 | + public void testExecute_importRemovalClearsPayload(CodegenFrontTypeEnum frontType) { | |
| 86 | + // 准备参数 | |
| 87 | + codegenProperties.setImportEnable(true); | |
| 88 | + codegenEngine.initGlobalBindingMap(); | |
| 89 | + CodegenTableDO table = getTable("student").setFrontType(frontType.getType()) | |
| 90 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | |
| 91 | + // 调用 | |
| 92 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, getColumnList("student"), null, null); | |
| 93 | + // 断言:移除可视文件时也清空提交来源 | |
| 94 | + String form = findFile(result, "/import-form.vue"); | |
| 95 | + assertTrue(form.contains(":on-remove=\"handleRemove\"")); | |
| 96 | + assertTrue(form.contains("formApi.setFieldValue('file', undefined)") || form.contains("fileRef.value = null")); | |
| 97 | + if (frontType == CodegenFrontTypeEnum.VUE3_VBEN5_EP_SCHEMA | |
| 98 | + || frontType == CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL) { | |
| 99 | + assertTrue(form.contains(":on-exceed=\"handleExceed\"")); | |
| 100 | + } | |
| 101 | + } | |
| 102 | + | |
| 103 | + @ParameterizedTest | |
| 104 | + @EnumSource(value = CodegenFrontTypeEnum.class, names = { | |
| 105 | + "VUE3_VBEN5_ANTD_SCHEMA", "VUE3_VBEN5_ANTD_GENERAL", | |
| 106 | + "VUE3_VBEN5_ANTDV_NEXT_SCHEMA", "VUE3_VBEN5_ANTDV_NEXT_GENERAL", | |
| 107 | + "VUE3_VBEN5_EP_SCHEMA", "VUE3_VBEN5_EP_GENERAL"}) | |
| 108 | + public void testExecute_masterChildEditing(CodegenFrontTypeEnum frontType) { | |
| 109 | + // 准备参数:一对多联系人和一对一班主任 | |
| 110 | + CodegenTableDO table = getTable("student").setFrontType(frontType.getType()) | |
| 111 | + .setTemplateType(CodegenTemplateTypeEnum.MASTER_NORMAL.getType()); | |
| 112 | + CodegenTableDO contact = getTable("contact").setFrontType(frontType.getType()) | |
| 113 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()).setSubJoinColumnId(100L).setSubJoinMany(true); | |
| 114 | + CodegenTableDO teacher = getTable("teacher").setFrontType(frontType.getType()) | |
| 115 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()).setSubJoinColumnId(200L).setSubJoinMany(false); | |
| 116 | + // 调用 | |
| 117 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, getColumnList("student"), | |
| 118 | + List.of(contact, teacher), List.of(getColumnList("contact"), getColumnList("teacher"))); | |
| 119 | + // 断言:新增和删除以当前表格为准,不重复追加,新增临时编号不提交 | |
| 120 | + String form = findFile(result, "/student-contact-form.vue"); | |
| 121 | + assertTrue(form.contains("getTableData()")); | |
| 122 | + assertTrue(form.contains("inserted.has(row) ? { ...row, id: undefined } : { ...row }")); | |
| 123 | + assertFalse(form.contains("getRemoveRecords()")); | |
| 124 | + assertFalse(form.contains(".concat(insertRecords")); | |
| 125 | + assertFalse(form.contains("$dictType")); | |
| 126 | + assertTrue(form.contains("getStudentContactListByStudentId")); | |
| 127 | + if (frontType.name().endsWith("SCHEMA")) { | |
| 128 | + assertTrue(form.contains("<template #actions=")); | |
| 129 | + } | |
| 130 | + result.forEach((path, content) -> { | |
| 131 | + if (path.endsWith(".vue") || path.endsWith("data.ts")) { | |
| 132 | + assertFalse(content.contains("#/api/infra/student"), path + ":API 导入必须匹配生成目录"); | |
| 133 | + assertFalse(content.contains("VxeTableGridOptions<StudentApi.StudentContact>") && content.contains("import type { InfraStudentApi }"), | |
| 134 | + path + ":子表命名空间应与导入一致"); | |
| 135 | + } | |
| 136 | + }); | |
| 137 | + if (frontType == CodegenFrontTypeEnum.VUE3_VBEN5_ANTDV_NEXT_GENERAL) { | |
| 138 | + assertTrue(form.matches("(?s).*import\\s*\\{[^}]*\\bmessage\\b[^}]*}\\s*from 'antdv-next'.*"), | |
| 139 | + "子表校验提示必须导入实际的消息组件"); | |
| 140 | + } | |
| 141 | + if (frontType == CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL) { | |
| 142 | + assertTrue(form.contains(":icon=\"Plus\"")); | |
| 143 | + assertFalse(form.contains("h(Plus)"), "图标使用导入的组件,避免未绑定的 h"); | |
| 144 | + } | |
| 145 | + assertTrue(form.contains("function validate(): boolean")); | |
| 146 | + assertTrue(form.contains("=== undefined")); | |
| 147 | + assertTrue(form.contains("loadData([])") || form.contains("list.value = []")); | |
| 148 | + String parentForm = findFile(result, "/modules/form.vue"); | |
| 149 | + assertTrue(parentForm.contains("studentContactFormRef.value?.validate()")); | |
| 150 | + assertFalse(parentForm.contains("TODO 列表值校验")); | |
| 151 | + } | |
| 152 | + | |
| 153 | + @ParameterizedTest | |
| 154 | + @EnumSource(value = CodegenTemplateTypeEnum.class, names = { "MASTER_ERP", "MASTER_INNER" }) | |
| 155 | + public void testExecute_eleChildListImports(CodegenTemplateTypeEnum templateType) { | |
| 156 | + // 准备参数 | |
| 157 | + CodegenFrontTypeEnum frontType = CodegenFrontTypeEnum.VUE3_VBEN5_EP_GENERAL; | |
| 158 | + CodegenTableDO table = getTable("student").setFrontType(frontType.getType()) | |
| 159 | + .setTemplateType(templateType.getType()); | |
| 160 | + CodegenTableDO contact = getTable("contact").setFrontType(frontType.getType()) | |
| 161 | + .setTemplateType(CodegenTemplateTypeEnum.SUB.getType()).setSubJoinColumnId(100L).setSubJoinMany(true); | |
| 162 | + // 调用 | |
| 163 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, getColumnList("student"), | |
| 164 | + List.of(contact), List.of(getColumnList("contact"))); | |
| 165 | + // 断言:ERP 子表查询实际调用的工具必须导入 | |
| 166 | + String index = findFile(result, "/index.vue"); | |
| 167 | + assertTrue(index.contains("<VbenVxeTableToolbar")); | |
| 168 | + assertTrue(index.contains("</VbenVxeTableToolbar>")); | |
| 169 | + assertFalse(index.contains("<TableToolbar")); | |
| 170 | + String list = findFile(result, "/student-contact-list.vue"); | |
| 171 | + if (templateType == CodegenTemplateTypeEnum.MASTER_ERP) { | |
| 172 | + assertTrue(list.contains("<VbenVxeTableToolbar")); | |
| 173 | + assertTrue(list.contains("</VbenVxeTableToolbar>")); | |
| 174 | + assertFalse(list.contains("</TableToolbar>")); | |
| 175 | + assertTrue(list.contains("cloneDeep(queryParams)")); | |
| 176 | + assertTrue(list.matches("(?s).*import\\s*\\{[^}]*\\bcloneDeep\\b[^}]*}\\s*from '@vben/utils'.*")); | |
| 177 | + } | |
| 178 | + assertTrue(list.contains("formatDateTime(row.")); | |
| 179 | + assertTrue(list.matches("(?s).*import\\s*\\{[^}]*\\bformatDateTime\\b[^}]*}\\s*from '@vben/utils'.*")); | |
| 180 | + } | |
| 181 | + | |
| 182 | + @Test | |
| 183 | + public void testExecute_vue3ImportUploadResponse() { | |
| 184 | + // 准备参数 | |
| 185 | + codegenProperties.setImportEnable(true); | |
| 186 | + codegenEngine.initGlobalBindingMap(); | |
| 187 | + CodegenTableDO table = getTable("student").setFrontType(CodegenFrontTypeEnum.VUE3_ELEMENT_PLUS.getType()) | |
| 188 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | |
| 189 | + // 调用 | |
| 190 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, getColumnList("student"), null, null); | |
| 191 | + // 断言 | |
| 192 | + String form = findFile(result, "/StudentImportForm.vue"); | |
| 193 | + assertTrue(form.contains("const res = await StudentApi.importStudent(formData)")); | |
| 194 | + assertTrue(form.contains("const data = res.data")); | |
| 195 | + } | |
| 196 | + | |
| 197 | + | |
| 198 | + @Test | |
| 199 | + public void testExecute_vben2DateRangeFormat() { | |
| 200 | + // 准备参数 | |
| 201 | + CodegenTableDO table = getTable("student").setFrontType(CodegenFrontTypeEnum.VUE3_VBEN2_ANTD_SCHEMA.getType()) | |
| 202 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | |
| 203 | + // 调用 | |
| 204 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, getColumnList("student"), null, null); | |
| 205 | + // 断言:查询区间提交后端需要的时间字符串 | |
| 206 | + String data = findFile(result, ".data.ts"); | |
| 207 | + assertTrue(data.contains("valueFormat: 'YYYY-MM-DD HH:mm:ss'")); | |
| 208 | + assertTrue(data.contains("allowClear: true")); | |
| 209 | + } | |
| 210 | + | |
| 211 | + @Test | |
| 212 | + public void testExecute_uniappPaginationContract() { | |
| 213 | + // 准备参数 | |
| 214 | + CodegenTableDO table = getTable("student").setFrontType(CodegenFrontTypeEnum.VUE3_ADMIN_UNIAPP_WOT.getType()) | |
| 215 | + .setTemplateType(CodegenTemplateTypeEnum.ONE.getType()); | |
| 216 | + // 调用 | |
| 217 | + Map<String, String> result = codegenEngine.execute(DbType.MYSQL, table, getColumnList("student"), null, null); | |
| 218 | + // 断言:移动端已有分页/失败恢复契约保持有效,避免机械套用 PC 组件写法 | |
| 219 | + String api = findFile(result, "/index.ts"); | |
| 220 | + assertTrue(api.contains("params: PageParam")); | |
| 221 | + assertFalse(api.contains("PageReqVO")); | |
| 222 | + String list = result.entrySet().stream() | |
| 223 | + .filter(entry -> entry.getKey().endsWith("/index.vue") && entry.getValue().contains("<z-paging")) | |
| 224 | + .findFirst().orElseThrow().getValue(); | |
| 225 | + assertTrue(list.contains("completeByTotal(data.list, data.total)")); | |
| 226 | + assertTrue(list.contains("complete(false)")); | |
| 227 | + assertTrue(list.contains("uni.$off(")); | |
| 228 | + } | |
| 229 | + | |
| 230 | + private static String findFile(Map<String, String> result, String suffix) { | |
| 231 | + return result.entrySet().stream().filter(entry -> entry.getKey().endsWith(suffix)) | |
| 232 | + .findFirst().orElseThrow(() -> new AssertionError("缺少生成文件:" + suffix)).getValue(); | |
| 233 | + } | |
| 234 | +} | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_erp/vue/index
| ... | ... | @@ -35,12 +35,11 @@ const total = ref(0) // 列表的总页数 |
| 35 | 35 | const queryParams = reactive({ |
| 36 | 36 | pageNo: 1, |
| 37 | 37 | pageSize: 10, |
| 38 | - name: undefined, | |
| 39 | - birthday: undefined, | |
| 40 | - birthday: undefined, | |
| 41 | - sex: undefined, | |
| 42 | - enabled: undefined, | |
| 43 | - createTime: undefined, | |
| 38 | + name: undefined, | |
| 39 | + birthday: undefined, | |
| 40 | + sex: undefined, | |
| 41 | + enabled: undefined, | |
| 42 | + createTime: undefined, | |
| 44 | 43 | }) |
| 45 | 44 | const queryFormRef = ref() // 搜索的表单 |
| 46 | 45 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -136,7 +135,14 @@ function handleRowCheckboxChange({ |
| 136 | 135 | async function handleExport() { |
| 137 | 136 | try { |
| 138 | 137 | exportLoading.value = true; |
| 139 | - const data = await exportStudent(queryParams); | |
| 138 | + const params = cloneDeep(queryParams) as any; | |
| 139 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 140 | + params.birthday = (params.birthday as string[]).join(','); | |
| 141 | + } | |
| 142 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 143 | + params.createTime = (params.createTime as string[]).join(','); | |
| 144 | + } | |
| 145 | + const data = await exportStudent(params); | |
| 140 | 146 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 141 | 147 | }finally { |
| 142 | 148 | exportLoading.value = false; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/vue/form
| ... | ... | @@ -72,7 +72,11 @@ const [Modal, modalApi] = useVbenModal({ |
| 72 | 72 | async onConfirm() { |
| 73 | 73 | await formRef.value?.validate(); |
| 74 | 74 | // 校验子表单 |
| 75 | - try { | |
| 75 | + if (!studentContactFormRef.value?.validate()) { | |
| 76 | + subTabsName.value = 'studentContact'; | |
| 77 | + return; | |
| 78 | + } | |
| 79 | + try { | |
| 76 | 80 | await studentTeacherFormRef.value?.validate() |
| 77 | 81 | } catch (e) { |
| 78 | 82 | subTabsName.value = 'studentTeacher' | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/vue/index
| ... | ... | @@ -31,12 +31,11 @@ const total = ref(0) // 列表的总页数 |
| 31 | 31 | const queryParams = reactive({ |
| 32 | 32 | pageNo: 1, |
| 33 | 33 | pageSize: 10, |
| 34 | - name: undefined, | |
| 35 | - birthday: undefined, | |
| 36 | - birthday: undefined, | |
| 37 | - sex: undefined, | |
| 38 | - enabled: undefined, | |
| 39 | - createTime: undefined, | |
| 34 | + name: undefined, | |
| 35 | + birthday: undefined, | |
| 36 | + sex: undefined, | |
| 37 | + enabled: undefined, | |
| 38 | + createTime: undefined, | |
| 40 | 39 | }) |
| 41 | 40 | const queryFormRef = ref() // 搜索的表单 |
| 42 | 41 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -132,7 +131,14 @@ function handleRowCheckboxChange({ |
| 132 | 131 | async function handleExport() { |
| 133 | 132 | try { |
| 134 | 133 | exportLoading.value = true; |
| 135 | - const data = await exportStudent(queryParams); | |
| 134 | + const params = cloneDeep(queryParams) as any; | |
| 135 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 136 | + params.birthday = (params.birthday as string[]).join(','); | |
| 137 | + } | |
| 138 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 139 | + params.createTime = (params.createTime as string[]).join(','); | |
| 140 | + } | |
| 141 | + const data = await exportStudent(params); | |
| 136 | 142 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 137 | 143 | }finally { |
| 138 | 144 | exportLoading.value = false; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/vue/student-contact-form
| ... | ... | @@ -32,25 +32,96 @@ async function handleDelete(row: StudentApi.StudentContact) { |
| 32 | 32 | await tableRef.value?.remove(row); |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 36 | -defineExpose({ | |
| 37 | - getData: (): StudentApi.StudentContact[] => { | |
| 38 | - const data = list.value as StudentApi.StudentContact[]; | |
| 39 | - const removeRecords = tableRef.value?.getRemoveRecords() as StudentApi.StudentContact[]; | |
| 40 | - const insertRecords = tableRef.value?.getInsertRecords() as StudentApi.StudentContact[]; | |
| 41 | - return [ | |
| 42 | - ...data.filter( | |
| 43 | - (row) => !removeRecords.some((removed) => removed.id === row.id), | |
| 44 | - ), | |
| 45 | - ...insertRecords.map((row: any) => ({ ...row, id: undefined })), | |
| 46 | - ]; | |
| 47 | - }, | |
| 48 | -}); | |
| 35 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 36 | +function getData(): StudentApi.StudentContact[] { | |
| 37 | + const table = tableRef.value; | |
| 38 | + if (!table) { | |
| 39 | + return []; | |
| 40 | + } | |
| 41 | + const { fullData } = table.getTableData(); | |
| 42 | + const inserted = new Set(table.getInsertRecords()); | |
| 43 | + return fullData.map((row) => | |
| 44 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 45 | + ); | |
| 46 | +} | |
| 47 | + | |
| 48 | +/** 校验子表必填字段 */ | |
| 49 | +function validate(): boolean { | |
| 50 | + for (const [index, row] of getData().entries()) { | |
| 51 | + if ( | |
| 52 | + row.name === null || | |
| 53 | + row.name === undefined || | |
| 54 | + (typeof row.name === 'string' && String(row.name).trim() === '') || | |
| 55 | + (Array.isArray(row.name) && row.name.length === 0) | |
| 56 | + ) { | |
| 57 | + message.error(`第 ${index + 1} 行:名字不能为空`); | |
| 58 | + return false; | |
| 59 | + } | |
| 60 | + if ( | |
| 61 | + row.description === null || | |
| 62 | + row.description === undefined || | |
| 63 | + (typeof row.description === 'string' && String(row.description).trim() === '') || | |
| 64 | + (Array.isArray(row.description) && row.description.length === 0) | |
| 65 | + ) { | |
| 66 | + message.error(`第 ${index + 1} 行:简介不能为空`); | |
| 67 | + return false; | |
| 68 | + } | |
| 69 | + if ( | |
| 70 | + row.birthday === null || | |
| 71 | + row.birthday === undefined || | |
| 72 | + (typeof row.birthday === 'string' && String(row.birthday).trim() === '') || | |
| 73 | + (Array.isArray(row.birthday) && row.birthday.length === 0) | |
| 74 | + ) { | |
| 75 | + message.error(`第 ${index + 1} 行:出生日期不能为空`); | |
| 76 | + return false; | |
| 77 | + } | |
| 78 | + if ( | |
| 79 | + row.sex === null || | |
| 80 | + row.sex === undefined || | |
| 81 | + (typeof row.sex === 'string' && String(row.sex).trim() === '') || | |
| 82 | + (Array.isArray(row.sex) && row.sex.length === 0) | |
| 83 | + ) { | |
| 84 | + message.error(`第 ${index + 1} 行:性别不能为空`); | |
| 85 | + return false; | |
| 86 | + } | |
| 87 | + if ( | |
| 88 | + row.enabled === null || | |
| 89 | + row.enabled === undefined || | |
| 90 | + (typeof row.enabled === 'string' && String(row.enabled).trim() === '') || | |
| 91 | + (Array.isArray(row.enabled) && row.enabled.length === 0) | |
| 92 | + ) { | |
| 93 | + message.error(`第 ${index + 1} 行:是否有效不能为空`); | |
| 94 | + return false; | |
| 95 | + } | |
| 96 | + if ( | |
| 97 | + row.avatar === null || | |
| 98 | + row.avatar === undefined || | |
| 99 | + (typeof row.avatar === 'string' && String(row.avatar).trim() === '') || | |
| 100 | + (Array.isArray(row.avatar) && row.avatar.length === 0) | |
| 101 | + ) { | |
| 102 | + message.error(`第 ${index + 1} 行:头像不能为空`); | |
| 103 | + return false; | |
| 104 | + } | |
| 105 | + if ( | |
| 106 | + row.memo === null || | |
| 107 | + row.memo === undefined || | |
| 108 | + (typeof row.memo === 'string' && String(row.memo).trim() === '') || | |
| 109 | + (Array.isArray(row.memo) && row.memo.length === 0) | |
| 110 | + ) { | |
| 111 | + message.error(`第 ${index + 1} 行:备注不能为空`); | |
| 112 | + return false; | |
| 113 | + } | |
| 114 | + } | |
| 115 | + return true; | |
| 116 | +} | |
| 117 | + | |
| 118 | +defineExpose({ getData, validate }); | |
| 49 | 119 | |
| 50 | 120 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 51 | 121 | watch( |
| 52 | 122 | () => props.studentId, |
| 53 | 123 | async (val) => { |
| 124 | + list.value = []; | |
| 54 | 125 | if (!val) { |
| 55 | 126 | return; |
| 56 | 127 | } |
| ... | ... | @@ -86,7 +157,7 @@ watch( |
| 86 | 157 | <template #default="{ row }"> |
| 87 | 158 | <Select v-model:value="row.sex" placeholder="请选择性别"> |
| 88 | 159 | <Select.Option |
| 89 | - v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')" | |
| 160 | + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" | |
| 90 | 161 | :key="dict.value" |
| 91 | 162 | :value="dict.value" |
| 92 | 163 | > |
| ... | ... | @@ -99,7 +170,7 @@ watch( |
| 99 | 170 | <template #default="{ row }"> |
| 100 | 171 | <RadioGroup v-model:value="row.enabled"> |
| 101 | 172 | <Radio |
| 102 | - v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'boolean')" | |
| 173 | + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" | |
| 103 | 174 | :key="dict.value" |
| 104 | 175 | :value="dict.value" |
| 105 | 176 | > | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_inner/vue/student-teacher-form
| ... | ... | @@ -51,6 +51,18 @@ defineExpose({ |
| 51 | 51 | watch( |
| 52 | 52 | () => props.studentId, |
| 53 | 53 | async (val) => { |
| 54 | + formData.value = { | |
| 55 | + id: undefined, | |
| 56 | + studentId: undefined, | |
| 57 | + name: undefined, | |
| 58 | + description: undefined, | |
| 59 | + birthday: undefined, | |
| 60 | + sex: undefined, | |
| 61 | + enabled: undefined, | |
| 62 | + avatar: undefined, | |
| 63 | + video: undefined, | |
| 64 | + memo: undefined, | |
| 65 | + }; | |
| 54 | 66 | if (!val) { |
| 55 | 67 | return; |
| 56 | 68 | } | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/vue/form
| ... | ... | @@ -72,7 +72,11 @@ const [Modal, modalApi] = useVbenModal({ |
| 72 | 72 | async onConfirm() { |
| 73 | 73 | await formRef.value?.validate(); |
| 74 | 74 | // 校验子表单 |
| 75 | - try { | |
| 75 | + if (!studentContactFormRef.value?.validate()) { | |
| 76 | + subTabsName.value = 'studentContact'; | |
| 77 | + return; | |
| 78 | + } | |
| 79 | + try { | |
| 76 | 80 | await studentTeacherFormRef.value?.validate() |
| 77 | 81 | } catch (e) { |
| 78 | 82 | subTabsName.value = 'studentTeacher' | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/vue/index
| ... | ... | @@ -27,12 +27,11 @@ const total = ref(0) // 列表的总页数 |
| 27 | 27 | const queryParams = reactive({ |
| 28 | 28 | pageNo: 1, |
| 29 | 29 | pageSize: 10, |
| 30 | - name: undefined, | |
| 31 | - birthday: undefined, | |
| 32 | - birthday: undefined, | |
| 33 | - sex: undefined, | |
| 34 | - enabled: undefined, | |
| 35 | - createTime: undefined, | |
| 30 | + name: undefined, | |
| 31 | + birthday: undefined, | |
| 32 | + sex: undefined, | |
| 33 | + enabled: undefined, | |
| 34 | + createTime: undefined, | |
| 36 | 35 | }) |
| 37 | 36 | const queryFormRef = ref() // 搜索的表单 |
| 38 | 37 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -128,7 +127,14 @@ function handleRowCheckboxChange({ |
| 128 | 127 | async function handleExport() { |
| 129 | 128 | try { |
| 130 | 129 | exportLoading.value = true; |
| 131 | - const data = await exportStudent(queryParams); | |
| 130 | + const params = cloneDeep(queryParams) as any; | |
| 131 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 132 | + params.birthday = (params.birthday as string[]).join(','); | |
| 133 | + } | |
| 134 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 135 | + params.createTime = (params.createTime as string[]).join(','); | |
| 136 | + } | |
| 137 | + const data = await exportStudent(params); | |
| 132 | 138 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 133 | 139 | }finally { |
| 134 | 140 | exportLoading.value = false; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/vue/student-contact-form
| ... | ... | @@ -32,25 +32,96 @@ async function handleDelete(row: StudentApi.StudentContact) { |
| 32 | 32 | await tableRef.value?.remove(row); |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 36 | -defineExpose({ | |
| 37 | - getData: (): StudentApi.StudentContact[] => { | |
| 38 | - const data = list.value as StudentApi.StudentContact[]; | |
| 39 | - const removeRecords = tableRef.value?.getRemoveRecords() as StudentApi.StudentContact[]; | |
| 40 | - const insertRecords = tableRef.value?.getInsertRecords() as StudentApi.StudentContact[]; | |
| 41 | - return [ | |
| 42 | - ...data.filter( | |
| 43 | - (row) => !removeRecords.some((removed) => removed.id === row.id), | |
| 44 | - ), | |
| 45 | - ...insertRecords.map((row: any) => ({ ...row, id: undefined })), | |
| 46 | - ]; | |
| 47 | - }, | |
| 48 | -}); | |
| 35 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 36 | +function getData(): StudentApi.StudentContact[] { | |
| 37 | + const table = tableRef.value; | |
| 38 | + if (!table) { | |
| 39 | + return []; | |
| 40 | + } | |
| 41 | + const { fullData } = table.getTableData(); | |
| 42 | + const inserted = new Set(table.getInsertRecords()); | |
| 43 | + return fullData.map((row) => | |
| 44 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 45 | + ); | |
| 46 | +} | |
| 47 | + | |
| 48 | +/** 校验子表必填字段 */ | |
| 49 | +function validate(): boolean { | |
| 50 | + for (const [index, row] of getData().entries()) { | |
| 51 | + if ( | |
| 52 | + row.name === null || | |
| 53 | + row.name === undefined || | |
| 54 | + (typeof row.name === 'string' && String(row.name).trim() === '') || | |
| 55 | + (Array.isArray(row.name) && row.name.length === 0) | |
| 56 | + ) { | |
| 57 | + message.error(`第 ${index + 1} 行:名字不能为空`); | |
| 58 | + return false; | |
| 59 | + } | |
| 60 | + if ( | |
| 61 | + row.description === null || | |
| 62 | + row.description === undefined || | |
| 63 | + (typeof row.description === 'string' && String(row.description).trim() === '') || | |
| 64 | + (Array.isArray(row.description) && row.description.length === 0) | |
| 65 | + ) { | |
| 66 | + message.error(`第 ${index + 1} 行:简介不能为空`); | |
| 67 | + return false; | |
| 68 | + } | |
| 69 | + if ( | |
| 70 | + row.birthday === null || | |
| 71 | + row.birthday === undefined || | |
| 72 | + (typeof row.birthday === 'string' && String(row.birthday).trim() === '') || | |
| 73 | + (Array.isArray(row.birthday) && row.birthday.length === 0) | |
| 74 | + ) { | |
| 75 | + message.error(`第 ${index + 1} 行:出生日期不能为空`); | |
| 76 | + return false; | |
| 77 | + } | |
| 78 | + if ( | |
| 79 | + row.sex === null || | |
| 80 | + row.sex === undefined || | |
| 81 | + (typeof row.sex === 'string' && String(row.sex).trim() === '') || | |
| 82 | + (Array.isArray(row.sex) && row.sex.length === 0) | |
| 83 | + ) { | |
| 84 | + message.error(`第 ${index + 1} 行:性别不能为空`); | |
| 85 | + return false; | |
| 86 | + } | |
| 87 | + if ( | |
| 88 | + row.enabled === null || | |
| 89 | + row.enabled === undefined || | |
| 90 | + (typeof row.enabled === 'string' && String(row.enabled).trim() === '') || | |
| 91 | + (Array.isArray(row.enabled) && row.enabled.length === 0) | |
| 92 | + ) { | |
| 93 | + message.error(`第 ${index + 1} 行:是否有效不能为空`); | |
| 94 | + return false; | |
| 95 | + } | |
| 96 | + if ( | |
| 97 | + row.avatar === null || | |
| 98 | + row.avatar === undefined || | |
| 99 | + (typeof row.avatar === 'string' && String(row.avatar).trim() === '') || | |
| 100 | + (Array.isArray(row.avatar) && row.avatar.length === 0) | |
| 101 | + ) { | |
| 102 | + message.error(`第 ${index + 1} 行:头像不能为空`); | |
| 103 | + return false; | |
| 104 | + } | |
| 105 | + if ( | |
| 106 | + row.memo === null || | |
| 107 | + row.memo === undefined || | |
| 108 | + (typeof row.memo === 'string' && String(row.memo).trim() === '') || | |
| 109 | + (Array.isArray(row.memo) && row.memo.length === 0) | |
| 110 | + ) { | |
| 111 | + message.error(`第 ${index + 1} 行:备注不能为空`); | |
| 112 | + return false; | |
| 113 | + } | |
| 114 | + } | |
| 115 | + return true; | |
| 116 | +} | |
| 117 | + | |
| 118 | +defineExpose({ getData, validate }); | |
| 49 | 119 | |
| 50 | 120 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 51 | 121 | watch( |
| 52 | 122 | () => props.studentId, |
| 53 | 123 | async (val) => { |
| 124 | + list.value = []; | |
| 54 | 125 | if (!val) { |
| 55 | 126 | return; |
| 56 | 127 | } |
| ... | ... | @@ -86,7 +157,7 @@ watch( |
| 86 | 157 | <template #default="{ row }"> |
| 87 | 158 | <Select v-model:value="row.sex" placeholder="请选择性别"> |
| 88 | 159 | <Select.Option |
| 89 | - v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')" | |
| 160 | + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" | |
| 90 | 161 | :key="dict.value" |
| 91 | 162 | :value="dict.value" |
| 92 | 163 | > |
| ... | ... | @@ -99,7 +170,7 @@ watch( |
| 99 | 170 | <template #default="{ row }"> |
| 100 | 171 | <RadioGroup v-model:value="row.enabled"> |
| 101 | 172 | <Radio |
| 102 | - v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'boolean')" | |
| 173 | + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" | |
| 103 | 174 | :key="dict.value" |
| 104 | 175 | :value="dict.value" |
| 105 | 176 | > | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_master_normal/vue/student-teacher-form
| ... | ... | @@ -51,6 +51,18 @@ defineExpose({ |
| 51 | 51 | watch( |
| 52 | 52 | () => props.studentId, |
| 53 | 53 | async (val) => { |
| 54 | + formData.value = { | |
| 55 | + id: undefined, | |
| 56 | + studentId: undefined, | |
| 57 | + name: undefined, | |
| 58 | + description: undefined, | |
| 59 | + birthday: undefined, | |
| 60 | + sex: undefined, | |
| 61 | + enabled: undefined, | |
| 62 | + avatar: undefined, | |
| 63 | + video: undefined, | |
| 64 | + memo: undefined, | |
| 65 | + }; | |
| 54 | 66 | if (!val) { |
| 55 | 67 | return; |
| 56 | 68 | } | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one/vue/index
| ... | ... | @@ -27,12 +27,11 @@ const total = ref(0) // 列表的总页数 |
| 27 | 27 | const queryParams = reactive({ |
| 28 | 28 | pageNo: 1, |
| 29 | 29 | pageSize: 10, |
| 30 | - name: undefined, | |
| 31 | - birthday: undefined, | |
| 32 | - birthday: undefined, | |
| 33 | - sex: undefined, | |
| 34 | - enabled: undefined, | |
| 35 | - createTime: undefined, | |
| 30 | + name: undefined, | |
| 31 | + birthday: undefined, | |
| 32 | + sex: undefined, | |
| 33 | + enabled: undefined, | |
| 34 | + createTime: undefined, | |
| 36 | 35 | }) |
| 37 | 36 | const queryFormRef = ref() // 搜索的表单 |
| 38 | 37 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -128,7 +127,14 @@ function handleRowCheckboxChange({ |
| 128 | 127 | async function handleExport() { |
| 129 | 128 | try { |
| 130 | 129 | exportLoading.value = true; |
| 131 | - const data = await exportStudent(queryParams); | |
| 130 | + const params = cloneDeep(queryParams) as any; | |
| 131 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 132 | + params.birthday = (params.birthday as string[]).join(','); | |
| 133 | + } | |
| 134 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 135 | + params.createTime = (params.createTime as string[]).join(','); | |
| 136 | + } | |
| 137 | + const data = await exportStudent(params); | |
| 132 | 138 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 133 | 139 | }finally { |
| 134 | 140 | exportLoading.value = false; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/vue/import-form
| ... | ... | @@ -48,6 +48,11 @@ function beforeUpload(file: FileType) { |
| 48 | 48 | return false; |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | +/** 移除文件 */ | |
| 52 | +function handleRemove() { | |
| 53 | + fileRef.value = null; | |
| 54 | +} | |
| 55 | + | |
| 51 | 56 | /** 下载导入模板 */ |
| 52 | 57 | async function handleDownload() { |
| 53 | 58 | const data = await importStudentTemplate(); |
| ... | ... | @@ -58,7 +63,12 @@ async function handleDownload() { |
| 58 | 63 | <template> |
| 59 | 64 | <Modal title="导入学生" class="w-1/3"> |
| 60 | 65 | <div class="mx-4"> |
| 61 | - <Upload :max-count="1" accept=".xls,.xlsx" :before-upload="beforeUpload"> | |
| 66 | + <Upload | |
| 67 | + :max-count="1" | |
| 68 | + accept=".xls,.xlsx" | |
| 69 | + :before-upload="beforeUpload" | |
| 70 | + :on-remove="handleRemove" | |
| 71 | + > | |
| 62 | 72 | <Button type="primary"> 选择 Excel 文件 </Button> |
| 63 | 73 | </Upload> |
| 64 | 74 | </div> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_one_importEnable/vue/index
| ... | ... | @@ -28,12 +28,11 @@ const total = ref(0) // 列表的总页数 |
| 28 | 28 | const queryParams = reactive({ |
| 29 | 29 | pageNo: 1, |
| 30 | 30 | pageSize: 10, |
| 31 | - name: undefined, | |
| 32 | - birthday: undefined, | |
| 33 | - birthday: undefined, | |
| 34 | - sex: undefined, | |
| 35 | - enabled: undefined, | |
| 36 | - createTime: undefined, | |
| 31 | + name: undefined, | |
| 32 | + birthday: undefined, | |
| 33 | + sex: undefined, | |
| 34 | + enabled: undefined, | |
| 35 | + createTime: undefined, | |
| 37 | 36 | }) |
| 38 | 37 | const queryFormRef = ref() // 搜索的表单 |
| 39 | 38 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -138,7 +137,14 @@ function handleRowCheckboxChange({ |
| 138 | 137 | async function handleExport() { |
| 139 | 138 | try { |
| 140 | 139 | exportLoading.value = true; |
| 141 | - const data = await exportStudent(queryParams); | |
| 140 | + const params = cloneDeep(queryParams) as any; | |
| 141 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 142 | + params.birthday = (params.birthday as string[]).join(','); | |
| 143 | + } | |
| 144 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 145 | + params.createTime = (params.createTime as string[]).join(','); | |
| 146 | + } | |
| 147 | + const data = await exportStudent(params); | |
| 142 | 148 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 143 | 149 | }finally { |
| 144 | 150 | exportLoading.value = false; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_general_tree/vue/index
| ... | ... | @@ -24,7 +24,7 @@ const loading = ref(true) // 列表的加载中 |
| 24 | 24 | const list = ref<any[]>([]) // 树列表的数据 |
| 25 | 25 | |
| 26 | 26 | const queryParams = reactive({ |
| 27 | - name: undefined, | |
| 27 | + name: undefined, | |
| 28 | 28 | }) |
| 29 | 29 | const queryFormRef = ref() // 搜索的表单 |
| 30 | 30 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -91,7 +91,8 @@ async function handleDelete(row: CategoryApi.Category) { |
| 91 | 91 | async function handleExport() { |
| 92 | 92 | try { |
| 93 | 93 | exportLoading.value = true; |
| 94 | - const data = await exportCategory(queryParams); | |
| 94 | + const params = cloneDeep(queryParams) as any; | |
| 95 | + const data = await exportCategory(params); | |
| 95 | 96 | downloadFileFromBlobPart({ fileName: '分类.xls', source: data }); |
| 96 | 97 | }finally { |
| 97 | 98 | exportLoading.value = false; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_erp/vue/form
| ... | ... | @@ -5,7 +5,7 @@ import { computed, ref } from 'vue'; |
| 5 | 5 | |
| 6 | 6 | import { useVbenModal } from '@vben/common-ui'; |
| 7 | 7 | |
| 8 | -import { message, Tabs } from 'ant-design-vue'; | |
| 8 | +import { message } from 'ant-design-vue'; | |
| 9 | 9 | |
| 10 | 10 | import { useVbenForm } from '#/adapter/form'; |
| 11 | 11 | import { createStudent, getStudent, updateStudent } from '#/api/infra/demo'; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/ts/data
| ... | ... | @@ -269,7 +269,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 269 | 269 | minWidth: 120, |
| 270 | 270 | slots: { default: 'sex' }, |
| 271 | 271 | params: { |
| 272 | - options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'boolean'), | |
| 272 | + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), | |
| 273 | 273 | }, |
| 274 | 274 | }, |
| 275 | 275 | { |
| ... | ... | @@ -309,7 +309,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 309 | 309 | } |
| 310 | 310 | |
| 311 | 311 | /** 列表的字段 */ |
| 312 | - export function useStudentContactGridColumns(): VxeTableGridOptions<StudentApi.StudentContact>['columns'] { | |
| 312 | + export function useStudentContactGridColumns(): VxeTableGridOptions<InfraStudentApi.StudentContact>['columns'] { | |
| 313 | 313 | return [ |
| 314 | 314 | { |
| 315 | 315 | field: 'id', |
| ... | ... | @@ -490,7 +490,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 490 | 490 | } |
| 491 | 491 | |
| 492 | 492 | /** 列表的字段 */ |
| 493 | - export function useStudentTeacherGridColumns(): VxeTableGridOptions<StudentApi.StudentTeacher>['columns'] { | |
| 493 | + export function useStudentTeacherGridColumns(): VxeTableGridOptions<InfraStudentApi.StudentTeacher>['columns'] { | |
| 494 | 494 | return [ |
| 495 | 495 | { |
| 496 | 496 | field: 'id', | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/vue/form
| ... | ... | @@ -5,7 +5,7 @@ import { computed, ref } from 'vue'; |
| 5 | 5 | |
| 6 | 6 | import { useVbenModal } from '@vben/common-ui'; |
| 7 | 7 | |
| 8 | -import { message } from 'ant-design-vue'; | |
| 8 | +import { message, Tabs } from 'ant-design-vue'; | |
| 9 | 9 | |
| 10 | 10 | import { useVbenForm } from '#/adapter/form'; |
| 11 | 11 | import { createStudent, getStudent, updateStudent } from '#/api/infra/demo'; |
| ... | ... | @@ -48,7 +48,12 @@ const [Modal, modalApi] = useVbenModal({ |
| 48 | 48 | return; |
| 49 | 49 | } |
| 50 | 50 | // 校验子表单 |
| 51 | - const studentTeacherValid = await studentTeacherFormRef.value?.validate(); | |
| 51 | + const studentContactValid = await studentContactFormRef.value?.validate(); | |
| 52 | + if (!studentContactValid) { | |
| 53 | + subTabsName.value = 'studentContact'; | |
| 54 | + return; | |
| 55 | + } | |
| 56 | + const studentTeacherValid = await studentTeacherFormRef.value?.validate(); | |
| 52 | 57 | if (!studentTeacherValid) { |
| 53 | 58 | subTabsName.value = 'studentTeacher'; |
| 54 | 59 | return; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/vue/student-contact-form
| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | import { $t } from '#/locales'; |
| 7 | 7 | |
| 8 | 8 | import { Plus } from "@vben/icons"; |
| 9 | -import { Button, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue'; | |
| 9 | +import { Button, Checkbox, CheckboxGroup, DatePicker, Input, message, RadioGroup, Select, Tabs, Textarea } from 'ant-design-vue'; | |
| 10 | 10 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 11 | 11 | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| 12 | 12 | import { useStudentContactGridEditColumns } from '../data'; |
| ... | ... | @@ -45,26 +45,96 @@ const handleDelete = async (row: InfraStudentApi.StudentContact) => { |
| 45 | 45 | await gridApi.grid.remove(row); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 49 | -defineExpose({ | |
| 50 | - getData: (): InfraStudentApi.StudentContact[] => { | |
| 51 | - const data = gridApi.grid.getData() as InfraStudentApi.StudentContact[]; | |
| 52 | - const removeRecords = gridApi.grid.getRemoveRecords() as InfraStudentApi.StudentContact[]; | |
| 53 | - const insertRecords = gridApi.grid.getInsertRecords() as InfraStudentApi.StudentContact[]; | |
| 54 | - return data | |
| 55 | - .filter((row) => !removeRecords.some((removed) => removed.id === row.id)) | |
| 56 | - .concat(insertRecords.map((row: any) => ({ ...row, id: undefined }))); | |
| 57 | - }, | |
| 58 | -}); | |
| 48 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 49 | +function getData(): InfraStudentApi.StudentContact[] { | |
| 50 | + const { fullData } = gridApi.grid.getTableData(); | |
| 51 | + const inserted = new Set(gridApi.grid.getInsertRecords()); | |
| 52 | + return fullData.map((row) => | |
| 53 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 54 | + ); | |
| 55 | +} | |
| 56 | + | |
| 57 | +/** 校验子表必填字段 */ | |
| 58 | +function validate(): boolean { | |
| 59 | + for (const [index, row] of getData().entries()) { | |
| 60 | + if ( | |
| 61 | + row.name === null || | |
| 62 | + row.name === undefined || | |
| 63 | + (typeof row.name === 'string' && String(row.name).trim() === '') || | |
| 64 | + (Array.isArray(row.name) && row.name.length === 0) | |
| 65 | + ) { | |
| 66 | + message.error(`第 ${index + 1} 行:名字不能为空`); | |
| 67 | + return false; | |
| 68 | + } | |
| 69 | + if ( | |
| 70 | + row.description === null || | |
| 71 | + row.description === undefined || | |
| 72 | + (typeof row.description === 'string' && String(row.description).trim() === '') || | |
| 73 | + (Array.isArray(row.description) && row.description.length === 0) | |
| 74 | + ) { | |
| 75 | + message.error(`第 ${index + 1} 行:简介不能为空`); | |
| 76 | + return false; | |
| 77 | + } | |
| 78 | + if ( | |
| 79 | + row.birthday === null || | |
| 80 | + row.birthday === undefined || | |
| 81 | + (typeof row.birthday === 'string' && String(row.birthday).trim() === '') || | |
| 82 | + (Array.isArray(row.birthday) && row.birthday.length === 0) | |
| 83 | + ) { | |
| 84 | + message.error(`第 ${index + 1} 行:出生日期不能为空`); | |
| 85 | + return false; | |
| 86 | + } | |
| 87 | + if ( | |
| 88 | + row.sex === null || | |
| 89 | + row.sex === undefined || | |
| 90 | + (typeof row.sex === 'string' && String(row.sex).trim() === '') || | |
| 91 | + (Array.isArray(row.sex) && row.sex.length === 0) | |
| 92 | + ) { | |
| 93 | + message.error(`第 ${index + 1} 行:性别不能为空`); | |
| 94 | + return false; | |
| 95 | + } | |
| 96 | + if ( | |
| 97 | + row.enabled === null || | |
| 98 | + row.enabled === undefined || | |
| 99 | + (typeof row.enabled === 'string' && String(row.enabled).trim() === '') || | |
| 100 | + (Array.isArray(row.enabled) && row.enabled.length === 0) | |
| 101 | + ) { | |
| 102 | + message.error(`第 ${index + 1} 行:是否有效不能为空`); | |
| 103 | + return false; | |
| 104 | + } | |
| 105 | + if ( | |
| 106 | + row.avatar === null || | |
| 107 | + row.avatar === undefined || | |
| 108 | + (typeof row.avatar === 'string' && String(row.avatar).trim() === '') || | |
| 109 | + (Array.isArray(row.avatar) && row.avatar.length === 0) | |
| 110 | + ) { | |
| 111 | + message.error(`第 ${index + 1} 行:头像不能为空`); | |
| 112 | + return false; | |
| 113 | + } | |
| 114 | + if ( | |
| 115 | + row.memo === null || | |
| 116 | + row.memo === undefined || | |
| 117 | + (typeof row.memo === 'string' && String(row.memo).trim() === '') || | |
| 118 | + (Array.isArray(row.memo) && row.memo.length === 0) | |
| 119 | + ) { | |
| 120 | + message.error(`第 ${index + 1} 行:备注不能为空`); | |
| 121 | + return false; | |
| 122 | + } | |
| 123 | + } | |
| 124 | + return true; | |
| 125 | +} | |
| 126 | + | |
| 127 | +defineExpose({ getData, validate }); | |
| 59 | 128 | |
| 60 | 129 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 61 | 130 | watch( |
| 62 | 131 | () => props.studentId, |
| 63 | 132 | async (val) => { |
| 133 | + await nextTick(); | |
| 64 | 134 | if (!val) { |
| 135 | + await gridApi.grid.loadData([]); | |
| 65 | 136 | return; |
| 66 | 137 | } |
| 67 | - await nextTick(); | |
| 68 | 138 | await gridApi.grid.loadData(await getStudentContactListByStudentId(props.studentId!)); |
| 69 | 139 | }, |
| 70 | 140 | { immediate: true }, | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_inner/vue/student-teacher-form
| ... | ... | @@ -39,10 +39,11 @@ defineExpose({ |
| 39 | 39 | watch( |
| 40 | 40 | () => props.studentId, |
| 41 | 41 | async (val) => { |
| 42 | + await nextTick(); | |
| 43 | + await formApi.resetForm(); | |
| 42 | 44 | if (!val) { |
| 43 | 45 | return; |
| 44 | 46 | } |
| 45 | - await nextTick(); | |
| 46 | 47 | await formApi.setValues(await getStudentTeacherByStudentId(props.studentId!)); |
| 47 | 48 | }, |
| 48 | 49 | { immediate: true }, | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/ts/data
| ... | ... | @@ -268,7 +268,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 268 | 268 | minWidth: 120, |
| 269 | 269 | slots: { default: 'sex' }, |
| 270 | 270 | params: { |
| 271 | - options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'boolean'), | |
| 271 | + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), | |
| 272 | 272 | }, |
| 273 | 273 | }, |
| 274 | 274 | { | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/vue/form
| ... | ... | @@ -5,7 +5,7 @@ import { computed, ref } from 'vue'; |
| 5 | 5 | |
| 6 | 6 | import { useVbenModal } from '@vben/common-ui'; |
| 7 | 7 | |
| 8 | -import { message } from 'ant-design-vue'; | |
| 8 | +import { message, Tabs } from 'ant-design-vue'; | |
| 9 | 9 | |
| 10 | 10 | import { useVbenForm } from '#/adapter/form'; |
| 11 | 11 | import { createStudent, getStudent, updateStudent } from '#/api/infra/demo'; |
| ... | ... | @@ -48,7 +48,12 @@ const [Modal, modalApi] = useVbenModal({ |
| 48 | 48 | return; |
| 49 | 49 | } |
| 50 | 50 | // 校验子表单 |
| 51 | - const studentTeacherValid = await studentTeacherFormRef.value?.validate(); | |
| 51 | + const studentContactValid = await studentContactFormRef.value?.validate(); | |
| 52 | + if (!studentContactValid) { | |
| 53 | + subTabsName.value = 'studentContact'; | |
| 54 | + return; | |
| 55 | + } | |
| 56 | + const studentTeacherValid = await studentTeacherFormRef.value?.validate(); | |
| 52 | 57 | if (!studentTeacherValid) { |
| 53 | 58 | subTabsName.value = 'studentTeacher'; |
| 54 | 59 | return; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/vue/student-contact-form
| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | import { $t } from '#/locales'; |
| 7 | 7 | |
| 8 | 8 | import { Plus } from "@vben/icons"; |
| 9 | -import { Button, Tabs, Checkbox, Input, Textarea, Select,RadioGroup,CheckboxGroup, DatePicker } from 'ant-design-vue'; | |
| 9 | +import { Button, Checkbox, CheckboxGroup, DatePicker, Input, message, RadioGroup, Select, Tabs, Textarea } from 'ant-design-vue'; | |
| 10 | 10 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 11 | 11 | import { useVbenVxeGrid } from '#/adapter/vxe-table'; |
| 12 | 12 | import { useStudentContactGridEditColumns } from '../data'; |
| ... | ... | @@ -45,26 +45,96 @@ const handleDelete = async (row: InfraStudentApi.StudentContact) => { |
| 45 | 45 | await gridApi.grid.remove(row); |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 49 | -defineExpose({ | |
| 50 | - getData: (): InfraStudentApi.StudentContact[] => { | |
| 51 | - const data = gridApi.grid.getData() as InfraStudentApi.StudentContact[]; | |
| 52 | - const removeRecords = gridApi.grid.getRemoveRecords() as InfraStudentApi.StudentContact[]; | |
| 53 | - const insertRecords = gridApi.grid.getInsertRecords() as InfraStudentApi.StudentContact[]; | |
| 54 | - return data | |
| 55 | - .filter((row) => !removeRecords.some((removed) => removed.id === row.id)) | |
| 56 | - .concat(insertRecords.map((row: any) => ({ ...row, id: undefined }))); | |
| 57 | - }, | |
| 58 | -}); | |
| 48 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 49 | +function getData(): InfraStudentApi.StudentContact[] { | |
| 50 | + const { fullData } = gridApi.grid.getTableData(); | |
| 51 | + const inserted = new Set(gridApi.grid.getInsertRecords()); | |
| 52 | + return fullData.map((row) => | |
| 53 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 54 | + ); | |
| 55 | +} | |
| 56 | + | |
| 57 | +/** 校验子表必填字段 */ | |
| 58 | +function validate(): boolean { | |
| 59 | + for (const [index, row] of getData().entries()) { | |
| 60 | + if ( | |
| 61 | + row.name === null || | |
| 62 | + row.name === undefined || | |
| 63 | + (typeof row.name === 'string' && String(row.name).trim() === '') || | |
| 64 | + (Array.isArray(row.name) && row.name.length === 0) | |
| 65 | + ) { | |
| 66 | + message.error(`第 ${index + 1} 行:名字不能为空`); | |
| 67 | + return false; | |
| 68 | + } | |
| 69 | + if ( | |
| 70 | + row.description === null || | |
| 71 | + row.description === undefined || | |
| 72 | + (typeof row.description === 'string' && String(row.description).trim() === '') || | |
| 73 | + (Array.isArray(row.description) && row.description.length === 0) | |
| 74 | + ) { | |
| 75 | + message.error(`第 ${index + 1} 行:简介不能为空`); | |
| 76 | + return false; | |
| 77 | + } | |
| 78 | + if ( | |
| 79 | + row.birthday === null || | |
| 80 | + row.birthday === undefined || | |
| 81 | + (typeof row.birthday === 'string' && String(row.birthday).trim() === '') || | |
| 82 | + (Array.isArray(row.birthday) && row.birthday.length === 0) | |
| 83 | + ) { | |
| 84 | + message.error(`第 ${index + 1} 行:出生日期不能为空`); | |
| 85 | + return false; | |
| 86 | + } | |
| 87 | + if ( | |
| 88 | + row.sex === null || | |
| 89 | + row.sex === undefined || | |
| 90 | + (typeof row.sex === 'string' && String(row.sex).trim() === '') || | |
| 91 | + (Array.isArray(row.sex) && row.sex.length === 0) | |
| 92 | + ) { | |
| 93 | + message.error(`第 ${index + 1} 行:性别不能为空`); | |
| 94 | + return false; | |
| 95 | + } | |
| 96 | + if ( | |
| 97 | + row.enabled === null || | |
| 98 | + row.enabled === undefined || | |
| 99 | + (typeof row.enabled === 'string' && String(row.enabled).trim() === '') || | |
| 100 | + (Array.isArray(row.enabled) && row.enabled.length === 0) | |
| 101 | + ) { | |
| 102 | + message.error(`第 ${index + 1} 行:是否有效不能为空`); | |
| 103 | + return false; | |
| 104 | + } | |
| 105 | + if ( | |
| 106 | + row.avatar === null || | |
| 107 | + row.avatar === undefined || | |
| 108 | + (typeof row.avatar === 'string' && String(row.avatar).trim() === '') || | |
| 109 | + (Array.isArray(row.avatar) && row.avatar.length === 0) | |
| 110 | + ) { | |
| 111 | + message.error(`第 ${index + 1} 行:头像不能为空`); | |
| 112 | + return false; | |
| 113 | + } | |
| 114 | + if ( | |
| 115 | + row.memo === null || | |
| 116 | + row.memo === undefined || | |
| 117 | + (typeof row.memo === 'string' && String(row.memo).trim() === '') || | |
| 118 | + (Array.isArray(row.memo) && row.memo.length === 0) | |
| 119 | + ) { | |
| 120 | + message.error(`第 ${index + 1} 行:备注不能为空`); | |
| 121 | + return false; | |
| 122 | + } | |
| 123 | + } | |
| 124 | + return true; | |
| 125 | +} | |
| 126 | + | |
| 127 | +defineExpose({ getData, validate }); | |
| 59 | 128 | |
| 60 | 129 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 61 | 130 | watch( |
| 62 | 131 | () => props.studentId, |
| 63 | 132 | async (val) => { |
| 133 | + await nextTick(); | |
| 64 | 134 | if (!val) { |
| 135 | + await gridApi.grid.loadData([]); | |
| 65 | 136 | return; |
| 66 | 137 | } |
| 67 | - await nextTick(); | |
| 68 | 138 | await gridApi.grid.loadData(await getStudentContactListByStudentId(props.studentId!)); |
| 69 | 139 | }, |
| 70 | 140 | { immediate: true }, | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_master_normal/vue/student-teacher-form
| ... | ... | @@ -39,10 +39,11 @@ defineExpose({ |
| 39 | 39 | watch( |
| 40 | 40 | () => props.studentId, |
| 41 | 41 | async (val) => { |
| 42 | + await nextTick(); | |
| 43 | + await formApi.resetForm(); | |
| 42 | 44 | if (!val) { |
| 43 | 45 | return; |
| 44 | 46 | } |
| 45 | - await nextTick(); | |
| 46 | 47 | await formApi.setValues(await getStudentTeacherByStudentId(props.studentId!)); |
| 47 | 48 | }, |
| 48 | 49 | { immediate: true }, | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_one_importEnable/vue/import-form
| ... | ... | @@ -51,6 +51,11 @@ function beforeUpload(file: FileType) { |
| 51 | 51 | return false; |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | +/** 移除文件 */ | |
| 55 | +function handleRemove() { | |
| 56 | + formApi.setFieldValue('file', undefined); | |
| 57 | +} | |
| 58 | + | |
| 54 | 59 | /** 下载模板 */ |
| 55 | 60 | async function handleDownload() { |
| 56 | 61 | const data = await importStudentTemplate(); |
| ... | ... | @@ -67,6 +72,7 @@ async function handleDownload() { |
| 67 | 72 | :max-count="1" |
| 68 | 73 | accept=".xls,.xlsx" |
| 69 | 74 | :before-upload="beforeUpload" |
| 75 | + :on-remove="handleRemove" | |
| 70 | 76 | > |
| 71 | 77 | <Button type="primary"> 选择 Excel 文件 </Button> |
| 72 | 78 | </Upload> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_antd_schema_tree/ts/data
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_erp/vue/form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { useVbenModal } from '@vben/common-ui'; |
| ... | ... | @@ -11,7 +11,7 @@ import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElSelect, El |
| 11 | 11 | |
| 12 | 12 | import { computed, ref, reactive } from 'vue'; |
| 13 | 13 | import { $t } from '#/locales'; |
| 14 | -import { getStudent, createStudent, updateStudent } from '#/api/infra/student'; | |
| 14 | +import { getStudent, createStudent, updateStudent } from '#/api/infra/demo'; | |
| 15 | 15 | |
| 16 | 16 | const emit = defineEmits(['success']); |
| 17 | 17 | |
| ... | ... | @@ -102,56 +102,56 @@ const [Modal, modalApi] = useVbenModal({ |
| 102 | 102 | |
| 103 | 103 | <template> |
| 104 | 104 | <Modal :title="getTitle"> |
| 105 | - <el-form | |
| 105 | + <ElForm | |
| 106 | 106 | ref="formRef" |
| 107 | 107 | :model="formData" |
| 108 | 108 | :rules="rules" |
| 109 | 109 | label-width="120px" |
| 110 | 110 | label-position="right" |
| 111 | 111 | > |
| 112 | - <el-form-item label="名字" prop="name"> | |
| 113 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 114 | - </el-form-item> | |
| 115 | - <el-form-item label="简介" prop="description"> | |
| 116 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 117 | - </el-form-item> | |
| 118 | - <el-form-item label="出生日期" prop="birthday"> | |
| 119 | - <el-date-picker | |
| 112 | + <ElFormItem label="名字" prop="name"> | |
| 113 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 114 | + </ElFormItem> | |
| 115 | + <ElFormItem label="简介" prop="description"> | |
| 116 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 117 | + </ElFormItem> | |
| 118 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 119 | + <ElDatePicker | |
| 120 | 120 | v-model="formData.birthday" |
| 121 | 121 | value-format="x" |
| 122 | 122 | placeholder="选择出生日期" |
| 123 | 123 | /> |
| 124 | - </el-form-item> | |
| 125 | - <el-form-item label="性别" prop="sex"> | |
| 126 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 127 | - <el-option | |
| 124 | + </ElFormItem> | |
| 125 | + <ElFormItem label="性别" prop="sex"> | |
| 126 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 127 | + <ElOption | |
| 128 | 128 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 129 | 129 | :key="dict.value" |
| 130 | 130 | :value="dict.value" |
| 131 | 131 | :label="dict.label" |
| 132 | 132 | /> |
| 133 | - </el-select> | |
| 134 | - </el-form-item> | |
| 135 | - <el-form-item label="是否有效" prop="enabled"> | |
| 136 | - <el-radio-group v-model="formData.enabled"> | |
| 137 | - <el-radio | |
| 133 | + </ElSelect> | |
| 134 | + </ElFormItem> | |
| 135 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 136 | + <ElRadioGroup v-model="formData.enabled"> | |
| 137 | + <ElRadio | |
| 138 | 138 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 139 | 139 | :key="dict.value" |
| 140 | - :label="dict.value" | |
| 140 | + :value="dict.value" | |
| 141 | 141 | > |
| 142 | 142 | {{ dict.label }} |
| 143 | - </el-radio> | |
| 144 | - </el-radio-group> | |
| 145 | - </el-form-item> | |
| 146 | - <el-form-item label="头像" prop="avatar"> | |
| 143 | + </ElRadio> | |
| 144 | + </ElRadioGroup> | |
| 145 | + </ElFormItem> | |
| 146 | + <ElFormItem label="头像" prop="avatar"> | |
| 147 | 147 | <ImageUpload v-model="formData.avatar" /> |
| 148 | - </el-form-item> | |
| 149 | - <el-form-item label="附件" prop="video"> | |
| 148 | + </ElFormItem> | |
| 149 | + <ElFormItem label="附件" prop="video"> | |
| 150 | 150 | <FileUpload v-model="formData.video" /> |
| 151 | - </el-form-item> | |
| 152 | - <el-form-item label="备注" prop="memo"> | |
| 151 | + </ElFormItem> | |
| 152 | + <ElFormItem label="备注" prop="memo"> | |
| 153 | 153 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 154 | - </el-form-item> | |
| 155 | - </el-form> | |
| 154 | + </ElFormItem> | |
| 155 | + </ElForm> | |
| 156 | 156 | </Modal> |
| 157 | 157 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_erp/vue/index
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | |
| 4 | 4 | import { ref, h, reactive, onMounted, nextTick } from 'vue'; |
| 5 | 5 | |
| ... | ... | @@ -19,7 +19,7 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 19 | 19 | |
| 20 | 20 | import { $t } from '#/locales'; |
| 21 | 21 | import { isEmpty } from '@vben/utils'; |
| 22 | -import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/student'; | |
| 22 | +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/demo'; | |
| 23 | 23 | |
| 24 | 24 | /** 子表的列表 */ |
| 25 | 25 | const subTabsName = ref('studentContact') |
| ... | ... | @@ -35,12 +35,11 @@ const total = ref(0) // 列表的总页数 |
| 35 | 35 | const queryParams = reactive({ |
| 36 | 36 | pageNo: 1, |
| 37 | 37 | pageSize: 10, |
| 38 | - name: undefined, | |
| 39 | - birthday: undefined, | |
| 40 | - birthday: undefined, | |
| 41 | - sex: undefined, | |
| 42 | - enabled: undefined, | |
| 43 | - createTime: undefined, | |
| 38 | + name: undefined, | |
| 39 | + birthday: undefined, | |
| 40 | + sex: undefined, | |
| 41 | + enabled: undefined, | |
| 42 | + createTime: undefined, | |
| 44 | 43 | }) |
| 45 | 44 | const queryFormRef = ref() // 搜索的表单 |
| 46 | 45 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -134,7 +133,14 @@ function handleRowCheckboxChange({ |
| 134 | 133 | async function handleExport() { |
| 135 | 134 | try { |
| 136 | 135 | exportLoading.value = true; |
| 137 | - const data = await exportStudent(queryParams); | |
| 136 | + const params = cloneDeep(queryParams) as any; | |
| 137 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 138 | + params.birthday = (params.birthday as string[]).join(','); | |
| 139 | + } | |
| 140 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 141 | + params.createTime = (params.createTime as string[]).join(','); | |
| 142 | + } | |
| 143 | + const data = await exportStudent(params); | |
| 138 | 144 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 139 | 145 | }finally { |
| 140 | 146 | exportLoading.value = false; |
| ... | ... | @@ -156,61 +162,61 @@ onMounted(() => { |
| 156 | 162 | |
| 157 | 163 | <ContentWrap v-if="!hiddenSearchBar"> |
| 158 | 164 | <!-- 搜索工作栏 --> |
| 159 | - <el-form | |
| 165 | + <ElForm | |
| 160 | 166 | :model="queryParams" |
| 161 | 167 | ref="queryFormRef" |
| 162 | 168 | inline |
| 163 | 169 | > |
| 164 | - <el-form-item label="名字"> | |
| 165 | - <el-input | |
| 170 | + <ElFormItem label="名字"> | |
| 171 | + <ElInput | |
| 166 | 172 | v-model="queryParams.name" |
| 167 | 173 | placeholder="请输入名字" |
| 168 | 174 | clearable |
| 169 | 175 | @keyup.enter="handleQuery" |
| 170 | 176 | class="!w-[240px]" |
| 171 | 177 | /> |
| 172 | - </el-form-item> | |
| 173 | - <el-form-item label="出生日期"> | |
| 174 | - <el-date-picker | |
| 178 | + </ElFormItem> | |
| 179 | + <ElFormItem label="出生日期"> | |
| 180 | + <ElDatePicker | |
| 175 | 181 | v-model="queryParams.birthday" |
| 176 | 182 | value-format="YYYY-MM-DD" |
| 177 | 183 | placeholder="选择出生日期" |
| 178 | 184 | clearable |
| 179 | 185 | class="!w-[240px]" |
| 180 | 186 | /> |
| 181 | - </el-form-item> | |
| 182 | - <el-form-item label="性别"> | |
| 183 | - <el-select | |
| 187 | + </ElFormItem> | |
| 188 | + <ElFormItem label="性别"> | |
| 189 | + <ElSelect | |
| 184 | 190 | v-model="queryParams.sex" |
| 185 | 191 | placeholder="请选择性别" |
| 186 | 192 | clearable |
| 187 | 193 | class="!w-[240px]" |
| 188 | 194 | > |
| 189 | - <el-option | |
| 195 | + <ElOption | |
| 190 | 196 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 191 | 197 | :key="dict.value" |
| 192 | 198 | :value="dict.value" |
| 193 | 199 | :label="dict.label" |
| 194 | 200 | /> |
| 195 | - </el-select> | |
| 196 | - </el-form-item> | |
| 197 | - <el-form-item label="是否有效"> | |
| 198 | - <el-select | |
| 201 | + </ElSelect> | |
| 202 | + </ElFormItem> | |
| 203 | + <ElFormItem label="是否有效"> | |
| 204 | + <ElSelect | |
| 199 | 205 | v-model="queryParams.enabled" |
| 200 | 206 | placeholder="请选择是否有效" |
| 201 | 207 | clearable |
| 202 | 208 | class="!w-[240px]" |
| 203 | 209 | > |
| 204 | - <el-option | |
| 210 | + <ElOption | |
| 205 | 211 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 206 | 212 | :key="dict.value" |
| 207 | 213 | :value="dict.value" |
| 208 | 214 | :label="dict.label" |
| 209 | 215 | /> |
| 210 | - </el-select> | |
| 211 | - </el-form-item> | |
| 212 | - <el-form-item label="创建时间"> | |
| 213 | - <el-date-picker | |
| 216 | + </ElSelect> | |
| 217 | + </ElFormItem> | |
| 218 | + <ElFormItem label="创建时间"> | |
| 219 | + <ElDatePicker | |
| 214 | 220 | v-model="queryParams.createTime" |
| 215 | 221 | type="daterange" |
| 216 | 222 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -219,24 +225,24 @@ onMounted(() => { |
| 219 | 225 | end-placeholder="结束日期" |
| 220 | 226 | class="!w-[240px]" |
| 221 | 227 | /> |
| 222 | - </el-form-item> | |
| 223 | - <el-form-item> | |
| 224 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 225 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 228 | + </ElFormItem> | |
| 229 | + <ElFormItem> | |
| 230 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 231 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 226 | 232 | 搜索 |
| 227 | - </el-button> | |
| 228 | - </el-form-item> | |
| 229 | - </el-form> | |
| 233 | + </ElButton> | |
| 234 | + </ElFormItem> | |
| 235 | + </ElForm> | |
| 230 | 236 | </ContentWrap> |
| 231 | 237 | |
| 232 | 238 | <!-- 列表 --> |
| 233 | 239 | <ContentWrap title="学生"> |
| 234 | 240 | <template #extra> |
| 235 | - <TableToolbar | |
| 241 | + <VbenVxeTableToolbar | |
| 236 | 242 | ref="tableToolbarRef" |
| 237 | 243 | v-model:hidden-search="hiddenSearchBar" |
| 238 | 244 | > |
| 239 | - <el-button | |
| 245 | + <ElButton | |
| 240 | 246 | class="ml-2" |
| 241 | 247 | :icon="h(Plus)" |
| 242 | 248 | type="primary" |
| ... | ... | @@ -244,8 +250,8 @@ onMounted(() => { |
| 244 | 250 | v-access:code="['infra:student:create']" |
| 245 | 251 | > |
| 246 | 252 | {{ $t('ui.actionTitle.create', ['学生']) }} |
| 247 | - </el-button> | |
| 248 | - <el-button | |
| 253 | + </ElButton> | |
| 254 | + <ElButton | |
| 249 | 255 | :icon="h(Download)" |
| 250 | 256 | type="primary" |
| 251 | 257 | class="ml-2" |
| ... | ... | @@ -254,8 +260,8 @@ onMounted(() => { |
| 254 | 260 | v-access:code="['infra:student:export']" |
| 255 | 261 | > |
| 256 | 262 | {{ $t('ui.actionTitle.export') }} |
| 257 | - </el-button> | |
| 258 | - <el-button | |
| 263 | + </ElButton> | |
| 264 | + <ElButton | |
| 259 | 265 | :icon="h(Trash2)" |
| 260 | 266 | type="danger" |
| 261 | 267 | class="ml-2" |
| ... | ... | @@ -264,10 +270,10 @@ onMounted(() => { |
| 264 | 270 | v-access:code="['infra:student:delete']" |
| 265 | 271 | > |
| 266 | 272 | 批量删除 |
| 267 | - </el-button> | |
| 268 | - </TableToolbar> | |
| 273 | + </ElButton> | |
| 274 | + </VbenVxeTableToolbar> | |
| 269 | 275 | </template> |
| 270 | - <vxe-table | |
| 276 | + <VxeTable | |
| 271 | 277 | ref="tableRef" |
| 272 | 278 | :data="list" |
| 273 | 279 | @cell-click="onCellClick" |
| ... | ... | @@ -281,36 +287,36 @@ onMounted(() => { |
| 281 | 287 | @checkboxAll="handleRowCheckboxChange" |
| 282 | 288 | @checkboxChange="handleRowCheckboxChange" |
| 283 | 289 | > |
| 284 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 285 | - <vxe-column field="id" title="编号" align="center" /> | |
| 286 | - <vxe-column field="name" title="名字" align="center" /> | |
| 287 | - <vxe-column field="description" title="简介" align="center" /> | |
| 288 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 290 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 291 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 292 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 293 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 294 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 289 | 295 | <template #default="{row}"> |
| 290 | 296 | {{formatDateTime(row.birthday)}} |
| 291 | 297 | </template> |
| 292 | - </vxe-column> | |
| 293 | - <vxe-column field="sex" title="性别" align="center"> | |
| 298 | + </VxeColumn> | |
| 299 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 294 | 300 | <template #default="{row}"> |
| 295 | 301 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 296 | 302 | </template> |
| 297 | - </vxe-column> | |
| 298 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 303 | + </VxeColumn> | |
| 304 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 299 | 305 | <template #default="{row}"> |
| 300 | 306 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 301 | 307 | </template> |
| 302 | - </vxe-column> | |
| 303 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 304 | - <vxe-column field="video" title="附件" align="center" /> | |
| 305 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 306 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 308 | + </VxeColumn> | |
| 309 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 310 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 311 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 312 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 307 | 313 | <template #default="{row}"> |
| 308 | 314 | {{formatDateTime(row.createTime)}} |
| 309 | 315 | </template> |
| 310 | - </vxe-column> | |
| 311 | - <vxe-column field="operation" title="操作" align="center"> | |
| 316 | + </VxeColumn> | |
| 317 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 312 | 318 | <template #default="{row}"> |
| 313 | - <el-button | |
| 319 | + <ElButton | |
| 314 | 320 | size="small" |
| 315 | 321 | type="primary" |
| 316 | 322 | link |
| ... | ... | @@ -318,8 +324,8 @@ onMounted(() => { |
| 318 | 324 | v-access:code="['infra:student:update']" |
| 319 | 325 | > |
| 320 | 326 | {{ $t('ui.actionTitle.edit') }} |
| 321 | - </el-button> | |
| 322 | - <el-button | |
| 327 | + </ElButton> | |
| 328 | + <ElButton | |
| 323 | 329 | size="small" |
| 324 | 330 | type="danger" |
| 325 | 331 | link |
| ... | ... | @@ -328,13 +334,13 @@ onMounted(() => { |
| 328 | 334 | v-access:code="['infra:student:delete']" |
| 329 | 335 | > |
| 330 | 336 | {{ $t('ui.actionTitle.delete') }} |
| 331 | - </el-button> | |
| 337 | + </ElButton> | |
| 332 | 338 | </template> |
| 333 | - </vxe-column> | |
| 334 | - </vxe-table> | |
| 339 | + </VxeColumn> | |
| 340 | + </VxeTable> | |
| 335 | 341 | <!-- 分页 --> |
| 336 | 342 | <div class="mt-2 flex justify-end"> |
| 337 | - <el-pagination | |
| 343 | + <ElPagination | |
| 338 | 344 | :total="total" |
| 339 | 345 | v-model:current-page="queryParams.pageNo" |
| 340 | 346 | v-model:page-size="queryParams.pageSize" |
| ... | ... | @@ -347,14 +353,14 @@ onMounted(() => { |
| 347 | 353 | </ContentWrap> |
| 348 | 354 | <ContentWrap> |
| 349 | 355 | <!-- 子表的表单 --> |
| 350 | - <el-tabs v-model="subTabsName"> | |
| 351 | - <el-tab-pane name="studentContact" label="学生联系人"> | |
| 356 | + <ElTabs v-model="subTabsName"> | |
| 357 | + <ElTabPane name="studentContact" label="学生联系人"> | |
| 352 | 358 | <StudentContactList :student-id="selectStudent?.id" /> |
| 353 | - </el-tab-pane> | |
| 354 | - <el-tab-pane name="studentTeacher" label="学生班主任"> | |
| 359 | + </ElTabPane> | |
| 360 | + <ElTabPane name="studentTeacher" label="学生班主任"> | |
| 355 | 361 | <StudentTeacherList :student-id="selectStudent?.id" /> |
| 356 | - </el-tab-pane> | |
| 357 | - </el-tabs> | |
| 362 | + </ElTabPane> | |
| 363 | + </ElTabs> | |
| 358 | 364 | </ContentWrap> |
| 359 | 365 | </Page> |
| 360 | 366 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_erp/vue/student-contact-form
| 1 | 1 | <script lang="ts" setup> |
| 2 | - import type { StudentApi } from '#/api/infra/student'; | |
| 2 | + import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { computed, ref, reactive } from 'vue'; |
| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | |
| 14 | 14 | import { $t } from '#/locales'; |
| 15 | 15 | |
| 16 | - import { getStudentContact, createStudentContact, updateStudentContact } from '#/api/infra/student'; | |
| 16 | + import { getStudentContact, createStudentContact, updateStudentContact } from '#/api/infra/demo'; | |
| 17 | 17 | |
| 18 | 18 | const emit = defineEmits(['success']); |
| 19 | 19 | const getTitle = computed(() => { |
| ... | ... | @@ -107,56 +107,56 @@ |
| 107 | 107 | |
| 108 | 108 | <template> |
| 109 | 109 | <Modal :title="getTitle"> |
| 110 | - <el-form | |
| 110 | + <ElForm | |
| 111 | 111 | ref="formRef" |
| 112 | 112 | :model="formData" |
| 113 | 113 | :rules="rules" |
| 114 | 114 | label-width="120px" |
| 115 | 115 | label-position="right" |
| 116 | 116 | > |
| 117 | - <el-form-item label="名字" prop="name"> | |
| 118 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 119 | - </el-form-item> | |
| 120 | - <el-form-item label="简介" prop="description"> | |
| 121 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 122 | - </el-form-item> | |
| 123 | - <el-form-item label="出生日期" prop="birthday"> | |
| 124 | - <el-date-picker | |
| 117 | + <ElFormItem label="名字" prop="name"> | |
| 118 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 119 | + </ElFormItem> | |
| 120 | + <ElFormItem label="简介" prop="description"> | |
| 121 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 122 | + </ElFormItem> | |
| 123 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 124 | + <ElDatePicker | |
| 125 | 125 | v-model="formData.birthday" |
| 126 | 126 | value-format="x" |
| 127 | 127 | placeholder="选择出生日期" |
| 128 | 128 | /> |
| 129 | - </el-form-item> | |
| 130 | - <el-form-item label="性别" prop="sex"> | |
| 131 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 132 | - <el-option | |
| 129 | + </ElFormItem> | |
| 130 | + <ElFormItem label="性别" prop="sex"> | |
| 131 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 132 | + <ElOption | |
| 133 | 133 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 134 | 134 | :key="dict.value" |
| 135 | 135 | :value="dict.value" |
| 136 | 136 | :label="dict.label" |
| 137 | 137 | /> |
| 138 | - </el-select> | |
| 139 | - </el-form-item> | |
| 140 | - <el-form-item label="是否有效" prop="enabled"> | |
| 141 | - <el-radio-group v-model="formData.enabled"> | |
| 142 | - <el-radio | |
| 138 | + </ElSelect> | |
| 139 | + </ElFormItem> | |
| 140 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 141 | + <ElRadioGroup v-model="formData.enabled"> | |
| 142 | + <ElRadio | |
| 143 | 143 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 144 | 144 | :key="dict.value" |
| 145 | - :label="dict.value" | |
| 145 | + :value="dict.value" | |
| 146 | 146 | > |
| 147 | 147 | {{ dict.label }} |
| 148 | - </el-radio> | |
| 149 | - </el-radio-group> | |
| 150 | - </el-form-item> | |
| 151 | - <el-form-item label="头像" prop="avatar"> | |
| 148 | + </ElRadio> | |
| 149 | + </ElRadioGroup> | |
| 150 | + </ElFormItem> | |
| 151 | + <ElFormItem label="头像" prop="avatar"> | |
| 152 | 152 | <ImageUpload v-model="formData.avatar" /> |
| 153 | - </el-form-item> | |
| 154 | - <el-form-item label="附件" prop="video"> | |
| 153 | + </ElFormItem> | |
| 154 | + <ElFormItem label="附件" prop="video"> | |
| 155 | 155 | <FileUpload v-model="formData.video" /> |
| 156 | - </el-form-item> | |
| 157 | - <el-form-item label="备注" prop="memo"> | |
| 156 | + </ElFormItem> | |
| 157 | + <ElFormItem label="备注" prop="memo"> | |
| 158 | 158 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 159 | - </el-form-item> | |
| 160 | - </el-form> | |
| 159 | + </ElFormItem> | |
| 160 | + </ElForm> | |
| 161 | 161 | </Modal> |
| 162 | 162 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_erp/vue/student-contact-list
| 1 | 1 | <script lang="ts" setup> |
| 2 | - import type { StudentApi } from '#/api/infra/student'; | |
| 2 | + import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { VxeTableInstance } from '#/adapter/vxe-table'; |
| 4 | 4 | |
| 5 | 5 | import { reactive,ref, h, nextTick,watch,onMounted } from 'vue'; |
| 6 | 6 | |
| 7 | 7 | import { DICT_TYPE } from '@vben/constants'; |
| 8 | 8 | import { getDictOptions } from '@vben/hooks'; |
| 9 | +import { formatDateTime } from '@vben/utils'; | |
| 9 | 10 | |
| 10 | 11 | import { DictTag } from '#/components/dict-tag'; |
| 11 | 12 | import { getRangePickerDefaultProps } from '#/utils'; |
| ... | ... | @@ -21,8 +22,8 @@ |
| 21 | 22 | import { Plus, Trash2 } from '@vben/icons'; |
| 22 | 23 | import { $t } from '#/locales'; |
| 23 | 24 | |
| 24 | - import { deleteStudentContact, deleteStudentContactList, getStudentContactPage } from '#/api/infra/student'; | |
| 25 | - import { isEmpty } from '@vben/utils'; | |
| 25 | + import { deleteStudentContact, deleteStudentContactList, getStudentContactPage } from '#/api/infra/demo'; | |
| 26 | + import { cloneDeep, isEmpty } from '@vben/utils'; | |
| 26 | 27 | |
| 27 | 28 | const props = defineProps<{ |
| 28 | 29 | studentId?: number // 学生编号(主表的关联字段) |
| ... | ... | @@ -159,61 +160,61 @@ onMounted(() => { |
| 159 | 160 | <div class="h-[600px]"> |
| 160 | 161 | <ContentWrap v-if="!hiddenSearchBar"> |
| 161 | 162 | <!-- 搜索工作栏 --> |
| 162 | - <el-form | |
| 163 | + <ElForm | |
| 163 | 164 | :model="queryParams" |
| 164 | 165 | ref="queryFormRef" |
| 165 | 166 | inline |
| 166 | 167 | > |
| 167 | - <el-form-item label="名字"> | |
| 168 | - <el-input | |
| 168 | + <ElFormItem label="名字"> | |
| 169 | + <ElInput | |
| 169 | 170 | v-model="queryParams.name" |
| 170 | 171 | placeholder="请输入名字" |
| 171 | 172 | clearable |
| 172 | 173 | @keyup.enter="handleQuery" |
| 173 | 174 | class="!w-[240px]" |
| 174 | 175 | /> |
| 175 | - </el-form-item> | |
| 176 | - <el-form-item label="出生日期"> | |
| 177 | - <el-date-picker | |
| 176 | + </ElFormItem> | |
| 177 | + <ElFormItem label="出生日期"> | |
| 178 | + <ElDatePicker | |
| 178 | 179 | v-model="queryParams.birthday" |
| 179 | 180 | value-format="YYYY-MM-DD" |
| 180 | 181 | placeholder="选择出生日期" |
| 181 | 182 | clearable |
| 182 | 183 | class="!w-[240px]" |
| 183 | 184 | /> |
| 184 | - </el-form-item> | |
| 185 | - <el-form-item label="性别"> | |
| 186 | - <el-select | |
| 185 | + </ElFormItem> | |
| 186 | + <ElFormItem label="性别"> | |
| 187 | + <ElSelect | |
| 187 | 188 | v-model="queryParams.sex" |
| 188 | 189 | placeholder="请选择性别" |
| 189 | 190 | clearable |
| 190 | 191 | class="!w-[240px]" |
| 191 | 192 | > |
| 192 | - <el-option | |
| 193 | + <ElOption | |
| 193 | 194 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 194 | 195 | :key="dict.value" |
| 195 | 196 | :value="dict.value" |
| 196 | 197 | :label="dict.label" |
| 197 | 198 | /> |
| 198 | - </el-select> | |
| 199 | - </el-form-item> | |
| 200 | - <el-form-item label="是否有效"> | |
| 201 | - <el-select | |
| 199 | + </ElSelect> | |
| 200 | + </ElFormItem> | |
| 201 | + <ElFormItem label="是否有效"> | |
| 202 | + <ElSelect | |
| 202 | 203 | v-model="queryParams.enabled" |
| 203 | 204 | placeholder="请选择是否有效" |
| 204 | 205 | clearable |
| 205 | 206 | class="!w-[240px]" |
| 206 | 207 | > |
| 207 | - <el-option | |
| 208 | + <ElOption | |
| 208 | 209 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 209 | 210 | :key="dict.value" |
| 210 | 211 | :value="dict.value" |
| 211 | 212 | :label="dict.label" |
| 212 | 213 | /> |
| 213 | - </el-select> | |
| 214 | - </el-form-item> | |
| 215 | - <el-form-item label="创建时间"> | |
| 216 | - <el-date-picker | |
| 214 | + </ElSelect> | |
| 215 | + </ElFormItem> | |
| 216 | + <ElFormItem label="创建时间"> | |
| 217 | + <ElDatePicker | |
| 217 | 218 | v-model="queryParams.createTime" |
| 218 | 219 | type="daterange" |
| 219 | 220 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -222,14 +223,14 @@ onMounted(() => { |
| 222 | 223 | end-placeholder="结束日期" |
| 223 | 224 | class="!w-[240px]" |
| 224 | 225 | /> |
| 225 | - </el-form-item> | |
| 226 | - <el-form-item> | |
| 227 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 228 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 226 | + </ElFormItem> | |
| 227 | + <ElFormItem> | |
| 228 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 229 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 229 | 230 | 搜索 |
| 230 | - </el-button> | |
| 231 | - </el-form-item> | |
| 232 | - </el-form> | |
| 231 | + </ElButton> | |
| 232 | + </ElFormItem> | |
| 233 | + </ElForm> | |
| 233 | 234 | </ContentWrap> |
| 234 | 235 | |
| 235 | 236 | <!-- 列表 --> |
| ... | ... | @@ -239,7 +240,7 @@ onMounted(() => { |
| 239 | 240 | ref="tableToolbarRef" |
| 240 | 241 | v-model:hidden-search="hiddenSearchBar" |
| 241 | 242 | > |
| 242 | - <el-button | |
| 243 | + <ElButton | |
| 243 | 244 | class="ml-2" |
| 244 | 245 | :icon="h(Plus)" |
| 245 | 246 | type="primary" |
| ... | ... | @@ -247,8 +248,8 @@ onMounted(() => { |
| 247 | 248 | v-access:code="['infra:student:create']" |
| 248 | 249 | > |
| 249 | 250 | {{ $t('ui.actionTitle.create', ['学生']) }} |
| 250 | - </el-button> | |
| 251 | - <el-button | |
| 251 | + </ElButton> | |
| 252 | + <ElButton | |
| 252 | 253 | :icon="h(Trash2)" |
| 253 | 254 | type="danger" |
| 254 | 255 | class="ml-2" |
| ... | ... | @@ -257,10 +258,10 @@ onMounted(() => { |
| 257 | 258 | v-access:code="['infra:student:delete']" |
| 258 | 259 | > |
| 259 | 260 | 批量删除 |
| 260 | - </el-button> | |
| 261 | - </TableToolbar> | |
| 261 | + </ElButton> | |
| 262 | + </VbenVxeTableToolbar> | |
| 262 | 263 | </template> |
| 263 | - <vxe-table | |
| 264 | + <VxeTable | |
| 264 | 265 | ref="tableRef" |
| 265 | 266 | :data="list" |
| 266 | 267 | show-overflow |
| ... | ... | @@ -268,37 +269,37 @@ onMounted(() => { |
| 268 | 269 | @checkboxAll="handleRowCheckboxChange" |
| 269 | 270 | @checkboxChange="handleRowCheckboxChange" |
| 270 | 271 | > |
| 271 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 272 | - <vxe-column field="id" title="编号" align="center" /> | |
| 273 | - <vxe-column field="studentId" title="学生编号" align="center" /> | |
| 274 | - <vxe-column field="name" title="名字" align="center" /> | |
| 275 | - <vxe-column field="description" title="简介" align="center" /> | |
| 276 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 272 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 273 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 274 | + <VxeColumn field="studentId" title="学生编号" align="center" /> | |
| 275 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 276 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 277 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 277 | 278 | <template #default="{row}"> |
| 278 | 279 | {{formatDateTime(row.birthday)}} |
| 279 | 280 | </template> |
| 280 | - </vxe-column> | |
| 281 | - <vxe-column field="sex" title="性别" align="center"> | |
| 281 | + </VxeColumn> | |
| 282 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 282 | 283 | <template #default="{row}"> |
| 283 | 284 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 284 | 285 | </template> |
| 285 | - </vxe-column> | |
| 286 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 286 | + </VxeColumn> | |
| 287 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 287 | 288 | <template #default="{row}"> |
| 288 | 289 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 289 | 290 | </template> |
| 290 | - </vxe-column> | |
| 291 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 292 | - <vxe-column field="video" title="附件" align="center" /> | |
| 293 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 294 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 291 | + </VxeColumn> | |
| 292 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 293 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 294 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 295 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 295 | 296 | <template #default="{row}"> |
| 296 | 297 | {{formatDateTime(row.createTime)}} |
| 297 | 298 | </template> |
| 298 | - </vxe-column> | |
| 299 | - <vxe-column field="operation" title="操作" align="center"> | |
| 299 | + </VxeColumn> | |
| 300 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 300 | 301 | <template #default="{row}"> |
| 301 | - <el-button | |
| 302 | + <ElButton | |
| 302 | 303 | size="small" |
| 303 | 304 | type="primary" |
| 304 | 305 | link |
| ... | ... | @@ -306,8 +307,8 @@ onMounted(() => { |
| 306 | 307 | v-access:code="['infra:student:update']" |
| 307 | 308 | > |
| 308 | 309 | {{ $t('ui.actionTitle.edit') }} |
| 309 | - </el-button> | |
| 310 | - <el-button | |
| 310 | + </ElButton> | |
| 311 | + <ElButton | |
| 311 | 312 | size="small" |
| 312 | 313 | type="danger" |
| 313 | 314 | link |
| ... | ... | @@ -316,13 +317,13 @@ onMounted(() => { |
| 316 | 317 | v-access:code="['infra:student:delete']" |
| 317 | 318 | > |
| 318 | 319 | {{ $t('ui.actionTitle.delete') }} |
| 319 | - </el-button> | |
| 320 | + </ElButton> | |
| 320 | 321 | </template> |
| 321 | - </vxe-column> | |
| 322 | - </vxe-table> | |
| 322 | + </VxeColumn> | |
| 323 | + </VxeTable> | |
| 323 | 324 | <!-- 分页 --> |
| 324 | 325 | <div class="mt-2 flex justify-end"> |
| 325 | - <el-pagination | |
| 326 | + <ElPagination | |
| 326 | 327 | :total="total" |
| 327 | 328 | v-model:current-page="queryParams.pageNo" |
| 328 | 329 | v-model:page-size="queryParams.pageSize" | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_erp/vue/student-teacher-form
| 1 | 1 | <script lang="ts" setup> |
| 2 | - import type { StudentApi } from '#/api/infra/student'; | |
| 2 | + import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { computed, ref, reactive } from 'vue'; |
| ... | ... | @@ -13,7 +13,7 @@ |
| 13 | 13 | |
| 14 | 14 | import { $t } from '#/locales'; |
| 15 | 15 | |
| 16 | - import { getStudentTeacher, createStudentTeacher, updateStudentTeacher } from '#/api/infra/student'; | |
| 16 | + import { getStudentTeacher, createStudentTeacher, updateStudentTeacher } from '#/api/infra/demo'; | |
| 17 | 17 | |
| 18 | 18 | const emit = defineEmits(['success']); |
| 19 | 19 | const getTitle = computed(() => { |
| ... | ... | @@ -107,56 +107,56 @@ |
| 107 | 107 | |
| 108 | 108 | <template> |
| 109 | 109 | <Modal :title="getTitle"> |
| 110 | - <el-form | |
| 110 | + <ElForm | |
| 111 | 111 | ref="formRef" |
| 112 | 112 | :model="formData" |
| 113 | 113 | :rules="rules" |
| 114 | 114 | label-width="120px" |
| 115 | 115 | label-position="right" |
| 116 | 116 | > |
| 117 | - <el-form-item label="名字" prop="name"> | |
| 118 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 119 | - </el-form-item> | |
| 120 | - <el-form-item label="简介" prop="description"> | |
| 121 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 122 | - </el-form-item> | |
| 123 | - <el-form-item label="出生日期" prop="birthday"> | |
| 124 | - <el-date-picker | |
| 117 | + <ElFormItem label="名字" prop="name"> | |
| 118 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 119 | + </ElFormItem> | |
| 120 | + <ElFormItem label="简介" prop="description"> | |
| 121 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 122 | + </ElFormItem> | |
| 123 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 124 | + <ElDatePicker | |
| 125 | 125 | v-model="formData.birthday" |
| 126 | 126 | value-format="x" |
| 127 | 127 | placeholder="选择出生日期" |
| 128 | 128 | /> |
| 129 | - </el-form-item> | |
| 130 | - <el-form-item label="性别" prop="sex"> | |
| 131 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 132 | - <el-option | |
| 129 | + </ElFormItem> | |
| 130 | + <ElFormItem label="性别" prop="sex"> | |
| 131 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 132 | + <ElOption | |
| 133 | 133 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 134 | 134 | :key="dict.value" |
| 135 | 135 | :value="dict.value" |
| 136 | 136 | :label="dict.label" |
| 137 | 137 | /> |
| 138 | - </el-select> | |
| 139 | - </el-form-item> | |
| 140 | - <el-form-item label="是否有效" prop="enabled"> | |
| 141 | - <el-radio-group v-model="formData.enabled"> | |
| 142 | - <el-radio | |
| 138 | + </ElSelect> | |
| 139 | + </ElFormItem> | |
| 140 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 141 | + <ElRadioGroup v-model="formData.enabled"> | |
| 142 | + <ElRadio | |
| 143 | 143 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 144 | 144 | :key="dict.value" |
| 145 | - :label="dict.value" | |
| 145 | + :value="dict.value" | |
| 146 | 146 | > |
| 147 | 147 | {{ dict.label }} |
| 148 | - </el-radio> | |
| 149 | - </el-radio-group> | |
| 150 | - </el-form-item> | |
| 151 | - <el-form-item label="头像" prop="avatar"> | |
| 148 | + </ElRadio> | |
| 149 | + </ElRadioGroup> | |
| 150 | + </ElFormItem> | |
| 151 | + <ElFormItem label="头像" prop="avatar"> | |
| 152 | 152 | <ImageUpload v-model="formData.avatar" /> |
| 153 | - </el-form-item> | |
| 154 | - <el-form-item label="附件" prop="video"> | |
| 153 | + </ElFormItem> | |
| 154 | + <ElFormItem label="附件" prop="video"> | |
| 155 | 155 | <FileUpload v-model="formData.video" /> |
| 156 | - </el-form-item> | |
| 157 | - <el-form-item label="备注" prop="memo"> | |
| 156 | + </ElFormItem> | |
| 157 | + <ElFormItem label="备注" prop="memo"> | |
| 158 | 158 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 159 | - </el-form-item> | |
| 160 | - </el-form> | |
| 159 | + </ElFormItem> | |
| 160 | + </ElForm> | |
| 161 | 161 | </Modal> |
| 162 | 162 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_erp/vue/student-teacher-list
| 1 | 1 | <script lang="ts" setup> |
| 2 | - import type { StudentApi } from '#/api/infra/student'; | |
| 2 | + import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { VxeTableInstance } from '#/adapter/vxe-table'; |
| 4 | 4 | |
| 5 | 5 | import { reactive,ref, h, nextTick,watch,onMounted } from 'vue'; |
| 6 | 6 | |
| 7 | 7 | import { DICT_TYPE } from '@vben/constants'; |
| 8 | 8 | import { getDictOptions } from '@vben/hooks'; |
| 9 | +import { formatDateTime } from '@vben/utils'; | |
| 9 | 10 | |
| 10 | 11 | import { DictTag } from '#/components/dict-tag'; |
| 11 | 12 | import { getRangePickerDefaultProps } from '#/utils'; |
| ... | ... | @@ -21,8 +22,8 @@ |
| 21 | 22 | import { Plus, Trash2 } from '@vben/icons'; |
| 22 | 23 | import { $t } from '#/locales'; |
| 23 | 24 | |
| 24 | - import { deleteStudentTeacher, deleteStudentTeacherList, getStudentTeacherPage } from '#/api/infra/student'; | |
| 25 | - import { isEmpty } from '@vben/utils'; | |
| 25 | + import { deleteStudentTeacher, deleteStudentTeacherList, getStudentTeacherPage } from '#/api/infra/demo'; | |
| 26 | + import { cloneDeep, isEmpty } from '@vben/utils'; | |
| 26 | 27 | |
| 27 | 28 | const props = defineProps<{ |
| 28 | 29 | studentId?: number // 学生编号(主表的关联字段) |
| ... | ... | @@ -159,61 +160,61 @@ onMounted(() => { |
| 159 | 160 | <div class="h-[600px]"> |
| 160 | 161 | <ContentWrap v-if="!hiddenSearchBar"> |
| 161 | 162 | <!-- 搜索工作栏 --> |
| 162 | - <el-form | |
| 163 | + <ElForm | |
| 163 | 164 | :model="queryParams" |
| 164 | 165 | ref="queryFormRef" |
| 165 | 166 | inline |
| 166 | 167 | > |
| 167 | - <el-form-item label="名字"> | |
| 168 | - <el-input | |
| 168 | + <ElFormItem label="名字"> | |
| 169 | + <ElInput | |
| 169 | 170 | v-model="queryParams.name" |
| 170 | 171 | placeholder="请输入名字" |
| 171 | 172 | clearable |
| 172 | 173 | @keyup.enter="handleQuery" |
| 173 | 174 | class="!w-[240px]" |
| 174 | 175 | /> |
| 175 | - </el-form-item> | |
| 176 | - <el-form-item label="出生日期"> | |
| 177 | - <el-date-picker | |
| 176 | + </ElFormItem> | |
| 177 | + <ElFormItem label="出生日期"> | |
| 178 | + <ElDatePicker | |
| 178 | 179 | v-model="queryParams.birthday" |
| 179 | 180 | value-format="YYYY-MM-DD" |
| 180 | 181 | placeholder="选择出生日期" |
| 181 | 182 | clearable |
| 182 | 183 | class="!w-[240px]" |
| 183 | 184 | /> |
| 184 | - </el-form-item> | |
| 185 | - <el-form-item label="性别"> | |
| 186 | - <el-select | |
| 185 | + </ElFormItem> | |
| 186 | + <ElFormItem label="性别"> | |
| 187 | + <ElSelect | |
| 187 | 188 | v-model="queryParams.sex" |
| 188 | 189 | placeholder="请选择性别" |
| 189 | 190 | clearable |
| 190 | 191 | class="!w-[240px]" |
| 191 | 192 | > |
| 192 | - <el-option | |
| 193 | + <ElOption | |
| 193 | 194 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 194 | 195 | :key="dict.value" |
| 195 | 196 | :value="dict.value" |
| 196 | 197 | :label="dict.label" |
| 197 | 198 | /> |
| 198 | - </el-select> | |
| 199 | - </el-form-item> | |
| 200 | - <el-form-item label="是否有效"> | |
| 201 | - <el-select | |
| 199 | + </ElSelect> | |
| 200 | + </ElFormItem> | |
| 201 | + <ElFormItem label="是否有效"> | |
| 202 | + <ElSelect | |
| 202 | 203 | v-model="queryParams.enabled" |
| 203 | 204 | placeholder="请选择是否有效" |
| 204 | 205 | clearable |
| 205 | 206 | class="!w-[240px]" |
| 206 | 207 | > |
| 207 | - <el-option | |
| 208 | + <ElOption | |
| 208 | 209 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 209 | 210 | :key="dict.value" |
| 210 | 211 | :value="dict.value" |
| 211 | 212 | :label="dict.label" |
| 212 | 213 | /> |
| 213 | - </el-select> | |
| 214 | - </el-form-item> | |
| 215 | - <el-form-item label="创建时间"> | |
| 216 | - <el-date-picker | |
| 214 | + </ElSelect> | |
| 215 | + </ElFormItem> | |
| 216 | + <ElFormItem label="创建时间"> | |
| 217 | + <ElDatePicker | |
| 217 | 218 | v-model="queryParams.createTime" |
| 218 | 219 | type="daterange" |
| 219 | 220 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -222,14 +223,14 @@ onMounted(() => { |
| 222 | 223 | end-placeholder="结束日期" |
| 223 | 224 | class="!w-[240px]" |
| 224 | 225 | /> |
| 225 | - </el-form-item> | |
| 226 | - <el-form-item> | |
| 227 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 228 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 226 | + </ElFormItem> | |
| 227 | + <ElFormItem> | |
| 228 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 229 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 229 | 230 | 搜索 |
| 230 | - </el-button> | |
| 231 | - </el-form-item> | |
| 232 | - </el-form> | |
| 231 | + </ElButton> | |
| 232 | + </ElFormItem> | |
| 233 | + </ElForm> | |
| 233 | 234 | </ContentWrap> |
| 234 | 235 | |
| 235 | 236 | <!-- 列表 --> |
| ... | ... | @@ -239,7 +240,7 @@ onMounted(() => { |
| 239 | 240 | ref="tableToolbarRef" |
| 240 | 241 | v-model:hidden-search="hiddenSearchBar" |
| 241 | 242 | > |
| 242 | - <el-button | |
| 243 | + <ElButton | |
| 243 | 244 | class="ml-2" |
| 244 | 245 | :icon="h(Plus)" |
| 245 | 246 | type="primary" |
| ... | ... | @@ -247,8 +248,8 @@ onMounted(() => { |
| 247 | 248 | v-access:code="['infra:student:create']" |
| 248 | 249 | > |
| 249 | 250 | {{ $t('ui.actionTitle.create', ['学生']) }} |
| 250 | - </el-button> | |
| 251 | - <el-button | |
| 251 | + </ElButton> | |
| 252 | + <ElButton | |
| 252 | 253 | :icon="h(Trash2)" |
| 253 | 254 | type="danger" |
| 254 | 255 | class="ml-2" |
| ... | ... | @@ -257,10 +258,10 @@ onMounted(() => { |
| 257 | 258 | v-access:code="['infra:student:delete']" |
| 258 | 259 | > |
| 259 | 260 | 批量删除 |
| 260 | - </el-button> | |
| 261 | - </TableToolbar> | |
| 261 | + </ElButton> | |
| 262 | + </VbenVxeTableToolbar> | |
| 262 | 263 | </template> |
| 263 | - <vxe-table | |
| 264 | + <VxeTable | |
| 264 | 265 | ref="tableRef" |
| 265 | 266 | :data="list" |
| 266 | 267 | show-overflow |
| ... | ... | @@ -268,37 +269,37 @@ onMounted(() => { |
| 268 | 269 | @checkboxAll="handleRowCheckboxChange" |
| 269 | 270 | @checkboxChange="handleRowCheckboxChange" |
| 270 | 271 | > |
| 271 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 272 | - <vxe-column field="id" title="编号" align="center" /> | |
| 273 | - <vxe-column field="studentId" title="学生编号" align="center" /> | |
| 274 | - <vxe-column field="name" title="名字" align="center" /> | |
| 275 | - <vxe-column field="description" title="简介" align="center" /> | |
| 276 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 272 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 273 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 274 | + <VxeColumn field="studentId" title="学生编号" align="center" /> | |
| 275 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 276 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 277 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 277 | 278 | <template #default="{row}"> |
| 278 | 279 | {{formatDateTime(row.birthday)}} |
| 279 | 280 | </template> |
| 280 | - </vxe-column> | |
| 281 | - <vxe-column field="sex" title="性别" align="center"> | |
| 281 | + </VxeColumn> | |
| 282 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 282 | 283 | <template #default="{row}"> |
| 283 | 284 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 284 | 285 | </template> |
| 285 | - </vxe-column> | |
| 286 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 286 | + </VxeColumn> | |
| 287 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 287 | 288 | <template #default="{row}"> |
| 288 | 289 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 289 | 290 | </template> |
| 290 | - </vxe-column> | |
| 291 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 292 | - <vxe-column field="video" title="附件" align="center" /> | |
| 293 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 294 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 291 | + </VxeColumn> | |
| 292 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 293 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 294 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 295 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 295 | 296 | <template #default="{row}"> |
| 296 | 297 | {{formatDateTime(row.createTime)}} |
| 297 | 298 | </template> |
| 298 | - </vxe-column> | |
| 299 | - <vxe-column field="operation" title="操作" align="center"> | |
| 299 | + </VxeColumn> | |
| 300 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 300 | 301 | <template #default="{row}"> |
| 301 | - <el-button | |
| 302 | + <ElButton | |
| 302 | 303 | size="small" |
| 303 | 304 | type="primary" |
| 304 | 305 | link |
| ... | ... | @@ -306,8 +307,8 @@ onMounted(() => { |
| 306 | 307 | v-access:code="['infra:student:update']" |
| 307 | 308 | > |
| 308 | 309 | {{ $t('ui.actionTitle.edit') }} |
| 309 | - </el-button> | |
| 310 | - <el-button | |
| 310 | + </ElButton> | |
| 311 | + <ElButton | |
| 311 | 312 | size="small" |
| 312 | 313 | type="danger" |
| 313 | 314 | link |
| ... | ... | @@ -316,13 +317,13 @@ onMounted(() => { |
| 316 | 317 | v-access:code="['infra:student:delete']" |
| 317 | 318 | > |
| 318 | 319 | {{ $t('ui.actionTitle.delete') }} |
| 319 | - </el-button> | |
| 320 | + </ElButton> | |
| 320 | 321 | </template> |
| 321 | - </vxe-column> | |
| 322 | - </vxe-table> | |
| 322 | + </VxeColumn> | |
| 323 | + </VxeTable> | |
| 323 | 324 | <!-- 分页 --> |
| 324 | 325 | <div class="mt-2 flex justify-end"> |
| 325 | - <el-pagination | |
| 326 | + <ElPagination | |
| 326 | 327 | :total="total" |
| 327 | 328 | v-model:current-page="queryParams.pageNo" |
| 328 | 329 | v-model:page-size="queryParams.pageSize" | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/vue/form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { useVbenModal } from '@vben/common-ui'; |
| ... | ... | @@ -13,7 +13,7 @@ import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElSelect, El |
| 13 | 13 | |
| 14 | 14 | import { computed, ref, reactive } from 'vue'; |
| 15 | 15 | import { $t } from '#/locales'; |
| 16 | -import { getStudent, createStudent, updateStudent } from '#/api/infra/student'; | |
| 16 | +import { getStudent, createStudent, updateStudent } from '#/api/infra/demo'; | |
| 17 | 17 | |
| 18 | 18 | const emit = defineEmits(['success']); |
| 19 | 19 | |
| ... | ... | @@ -71,7 +71,11 @@ const [Modal, modalApi] = useVbenModal({ |
| 71 | 71 | async onConfirm() { |
| 72 | 72 | await formRef.value?.validate(); |
| 73 | 73 | // 校验子表单 |
| 74 | - try { | |
| 74 | + if (!studentContactFormRef.value?.validate()) { | |
| 75 | + subTabsName.value = 'studentContact'; | |
| 76 | + return; | |
| 77 | + } | |
| 78 | + try { | |
| 75 | 79 | await studentTeacherFormRef.value?.validate() |
| 76 | 80 | } catch (e) { |
| 77 | 81 | subTabsName.value = 'studentTeacher' |
| ... | ... | @@ -118,65 +122,65 @@ const [Modal, modalApi] = useVbenModal({ |
| 118 | 122 | |
| 119 | 123 | <template> |
| 120 | 124 | <Modal :title="getTitle"> |
| 121 | - <el-form | |
| 125 | + <ElForm | |
| 122 | 126 | ref="formRef" |
| 123 | 127 | :model="formData" |
| 124 | 128 | :rules="rules" |
| 125 | 129 | label-width="120px" |
| 126 | 130 | label-position="right" |
| 127 | 131 | > |
| 128 | - <el-form-item label="名字" prop="name"> | |
| 129 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 130 | - </el-form-item> | |
| 131 | - <el-form-item label="简介" prop="description"> | |
| 132 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 133 | - </el-form-item> | |
| 134 | - <el-form-item label="出生日期" prop="birthday"> | |
| 135 | - <el-date-picker | |
| 132 | + <ElFormItem label="名字" prop="name"> | |
| 133 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 134 | + </ElFormItem> | |
| 135 | + <ElFormItem label="简介" prop="description"> | |
| 136 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 137 | + </ElFormItem> | |
| 138 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 139 | + <ElDatePicker | |
| 136 | 140 | v-model="formData.birthday" |
| 137 | 141 | value-format="x" |
| 138 | 142 | placeholder="选择出生日期" |
| 139 | 143 | /> |
| 140 | - </el-form-item> | |
| 141 | - <el-form-item label="性别" prop="sex"> | |
| 142 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 143 | - <el-option | |
| 144 | + </ElFormItem> | |
| 145 | + <ElFormItem label="性别" prop="sex"> | |
| 146 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 147 | + <ElOption | |
| 144 | 148 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 145 | 149 | :key="dict.value" |
| 146 | 150 | :value="dict.value" |
| 147 | 151 | :label="dict.label" |
| 148 | 152 | /> |
| 149 | - </el-select> | |
| 150 | - </el-form-item> | |
| 151 | - <el-form-item label="是否有效" prop="enabled"> | |
| 152 | - <el-radio-group v-model="formData.enabled"> | |
| 153 | - <el-radio | |
| 153 | + </ElSelect> | |
| 154 | + </ElFormItem> | |
| 155 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 156 | + <ElRadioGroup v-model="formData.enabled"> | |
| 157 | + <ElRadio | |
| 154 | 158 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 155 | 159 | :key="dict.value" |
| 156 | - :label="dict.value" | |
| 160 | + :value="dict.value" | |
| 157 | 161 | > |
| 158 | 162 | {{ dict.label }} |
| 159 | - </el-radio> | |
| 160 | - </el-radio-group> | |
| 161 | - </el-form-item> | |
| 162 | - <el-form-item label="头像" prop="avatar"> | |
| 163 | + </ElRadio> | |
| 164 | + </ElRadioGroup> | |
| 165 | + </ElFormItem> | |
| 166 | + <ElFormItem label="头像" prop="avatar"> | |
| 163 | 167 | <ImageUpload v-model="formData.avatar" /> |
| 164 | - </el-form-item> | |
| 165 | - <el-form-item label="附件" prop="video"> | |
| 168 | + </ElFormItem> | |
| 169 | + <ElFormItem label="附件" prop="video"> | |
| 166 | 170 | <FileUpload v-model="formData.video" /> |
| 167 | - </el-form-item> | |
| 168 | - <el-form-item label="备注" prop="memo"> | |
| 171 | + </ElFormItem> | |
| 172 | + <ElFormItem label="备注" prop="memo"> | |
| 169 | 173 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 170 | - </el-form-item> | |
| 171 | - </el-form> | |
| 174 | + </ElFormItem> | |
| 175 | + </ElForm> | |
| 172 | 176 | <!-- 子表的表单 --> |
| 173 | - <el-tabs v-model="subTabsName"> | |
| 174 | - <el-tab-pane name="studentContact" label="学生联系人"> | |
| 177 | + <ElTabs v-model="subTabsName"> | |
| 178 | + <ElTabPane name="studentContact" label="学生联系人"> | |
| 175 | 179 | <StudentContactForm ref="studentContactFormRef" :student-id="formData?.id" /> |
| 176 | - </el-tab-pane> | |
| 177 | - <el-tab-pane name="studentTeacher" label="学生班主任"> | |
| 180 | + </ElTabPane> | |
| 181 | + <ElTabPane name="studentTeacher" label="学生班主任"> | |
| 178 | 182 | <StudentTeacherForm ref="studentTeacherFormRef" :student-id="formData?.id" /> |
| 179 | - </el-tab-pane> | |
| 180 | - </el-tabs> | |
| 183 | + </ElTabPane> | |
| 184 | + </ElTabs> | |
| 181 | 185 | </Modal> |
| 182 | 186 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/vue/index
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | |
| 4 | 4 | import { ref, h, reactive, onMounted, nextTick } from 'vue'; |
| 5 | 5 | |
| ... | ... | @@ -19,7 +19,7 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 19 | 19 | |
| 20 | 20 | import { $t } from '#/locales'; |
| 21 | 21 | import { isEmpty } from '@vben/utils'; |
| 22 | -import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/student'; | |
| 22 | +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/demo'; | |
| 23 | 23 | |
| 24 | 24 | /** 子表的列表 */ |
| 25 | 25 | const subTabsName = ref('studentContact') |
| ... | ... | @@ -31,12 +31,11 @@ const total = ref(0) // 列表的总页数 |
| 31 | 31 | const queryParams = reactive({ |
| 32 | 32 | pageNo: 1, |
| 33 | 33 | pageSize: 10, |
| 34 | - name: undefined, | |
| 35 | - birthday: undefined, | |
| 36 | - birthday: undefined, | |
| 37 | - sex: undefined, | |
| 38 | - enabled: undefined, | |
| 39 | - createTime: undefined, | |
| 34 | + name: undefined, | |
| 35 | + birthday: undefined, | |
| 36 | + sex: undefined, | |
| 37 | + enabled: undefined, | |
| 38 | + createTime: undefined, | |
| 40 | 39 | }) |
| 41 | 40 | const queryFormRef = ref() // 搜索的表单 |
| 42 | 41 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -130,7 +129,14 @@ function handleRowCheckboxChange({ |
| 130 | 129 | async function handleExport() { |
| 131 | 130 | try { |
| 132 | 131 | exportLoading.value = true; |
| 133 | - const data = await exportStudent(queryParams); | |
| 132 | + const params = cloneDeep(queryParams) as any; | |
| 133 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 134 | + params.birthday = (params.birthday as string[]).join(','); | |
| 135 | + } | |
| 136 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 137 | + params.createTime = (params.createTime as string[]).join(','); | |
| 138 | + } | |
| 139 | + const data = await exportStudent(params); | |
| 134 | 140 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 135 | 141 | }finally { |
| 136 | 142 | exportLoading.value = false; |
| ... | ... | @@ -152,61 +158,61 @@ onMounted(() => { |
| 152 | 158 | |
| 153 | 159 | <ContentWrap v-if="!hiddenSearchBar"> |
| 154 | 160 | <!-- 搜索工作栏 --> |
| 155 | - <el-form | |
| 161 | + <ElForm | |
| 156 | 162 | :model="queryParams" |
| 157 | 163 | ref="queryFormRef" |
| 158 | 164 | inline |
| 159 | 165 | > |
| 160 | - <el-form-item label="名字"> | |
| 161 | - <el-input | |
| 166 | + <ElFormItem label="名字"> | |
| 167 | + <ElInput | |
| 162 | 168 | v-model="queryParams.name" |
| 163 | 169 | placeholder="请输入名字" |
| 164 | 170 | clearable |
| 165 | 171 | @keyup.enter="handleQuery" |
| 166 | 172 | class="!w-[240px]" |
| 167 | 173 | /> |
| 168 | - </el-form-item> | |
| 169 | - <el-form-item label="出生日期"> | |
| 170 | - <el-date-picker | |
| 174 | + </ElFormItem> | |
| 175 | + <ElFormItem label="出生日期"> | |
| 176 | + <ElDatePicker | |
| 171 | 177 | v-model="queryParams.birthday" |
| 172 | 178 | value-format="YYYY-MM-DD" |
| 173 | 179 | placeholder="选择出生日期" |
| 174 | 180 | clearable |
| 175 | 181 | class="!w-[240px]" |
| 176 | 182 | /> |
| 177 | - </el-form-item> | |
| 178 | - <el-form-item label="性别"> | |
| 179 | - <el-select | |
| 183 | + </ElFormItem> | |
| 184 | + <ElFormItem label="性别"> | |
| 185 | + <ElSelect | |
| 180 | 186 | v-model="queryParams.sex" |
| 181 | 187 | placeholder="请选择性别" |
| 182 | 188 | clearable |
| 183 | 189 | class="!w-[240px]" |
| 184 | 190 | > |
| 185 | - <el-option | |
| 191 | + <ElOption | |
| 186 | 192 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 187 | 193 | :key="dict.value" |
| 188 | 194 | :value="dict.value" |
| 189 | 195 | :label="dict.label" |
| 190 | 196 | /> |
| 191 | - </el-select> | |
| 192 | - </el-form-item> | |
| 193 | - <el-form-item label="是否有效"> | |
| 194 | - <el-select | |
| 197 | + </ElSelect> | |
| 198 | + </ElFormItem> | |
| 199 | + <ElFormItem label="是否有效"> | |
| 200 | + <ElSelect | |
| 195 | 201 | v-model="queryParams.enabled" |
| 196 | 202 | placeholder="请选择是否有效" |
| 197 | 203 | clearable |
| 198 | 204 | class="!w-[240px]" |
| 199 | 205 | > |
| 200 | - <el-option | |
| 206 | + <ElOption | |
| 201 | 207 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 202 | 208 | :key="dict.value" |
| 203 | 209 | :value="dict.value" |
| 204 | 210 | :label="dict.label" |
| 205 | 211 | /> |
| 206 | - </el-select> | |
| 207 | - </el-form-item> | |
| 208 | - <el-form-item label="创建时间"> | |
| 209 | - <el-date-picker | |
| 212 | + </ElSelect> | |
| 213 | + </ElFormItem> | |
| 214 | + <ElFormItem label="创建时间"> | |
| 215 | + <ElDatePicker | |
| 210 | 216 | v-model="queryParams.createTime" |
| 211 | 217 | type="daterange" |
| 212 | 218 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -215,24 +221,24 @@ onMounted(() => { |
| 215 | 221 | end-placeholder="结束日期" |
| 216 | 222 | class="!w-[240px]" |
| 217 | 223 | /> |
| 218 | - </el-form-item> | |
| 219 | - <el-form-item> | |
| 220 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 221 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 224 | + </ElFormItem> | |
| 225 | + <ElFormItem> | |
| 226 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 227 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 222 | 228 | 搜索 |
| 223 | - </el-button> | |
| 224 | - </el-form-item> | |
| 225 | - </el-form> | |
| 229 | + </ElButton> | |
| 230 | + </ElFormItem> | |
| 231 | + </ElForm> | |
| 226 | 232 | </ContentWrap> |
| 227 | 233 | |
| 228 | 234 | <!-- 列表 --> |
| 229 | 235 | <ContentWrap title="学生"> |
| 230 | 236 | <template #extra> |
| 231 | - <TableToolbar | |
| 237 | + <VbenVxeTableToolbar | |
| 232 | 238 | ref="tableToolbarRef" |
| 233 | 239 | v-model:hidden-search="hiddenSearchBar" |
| 234 | 240 | > |
| 235 | - <el-button | |
| 241 | + <ElButton | |
| 236 | 242 | class="ml-2" |
| 237 | 243 | :icon="h(Plus)" |
| 238 | 244 | type="primary" |
| ... | ... | @@ -240,8 +246,8 @@ onMounted(() => { |
| 240 | 246 | v-access:code="['infra:student:create']" |
| 241 | 247 | > |
| 242 | 248 | {{ $t('ui.actionTitle.create', ['学生']) }} |
| 243 | - </el-button> | |
| 244 | - <el-button | |
| 249 | + </ElButton> | |
| 250 | + <ElButton | |
| 245 | 251 | :icon="h(Download)" |
| 246 | 252 | type="primary" |
| 247 | 253 | class="ml-2" |
| ... | ... | @@ -250,8 +256,8 @@ onMounted(() => { |
| 250 | 256 | v-access:code="['infra:student:export']" |
| 251 | 257 | > |
| 252 | 258 | {{ $t('ui.actionTitle.export') }} |
| 253 | - </el-button> | |
| 254 | - <el-button | |
| 259 | + </ElButton> | |
| 260 | + <ElButton | |
| 255 | 261 | :icon="h(Trash2)" |
| 256 | 262 | type="danger" |
| 257 | 263 | class="ml-2" |
| ... | ... | @@ -260,10 +266,10 @@ onMounted(() => { |
| 260 | 266 | v-access:code="['infra:student:delete']" |
| 261 | 267 | > |
| 262 | 268 | 批量删除 |
| 263 | - </el-button> | |
| 264 | - </TableToolbar> | |
| 269 | + </ElButton> | |
| 270 | + </VbenVxeTableToolbar> | |
| 265 | 271 | </template> |
| 266 | - <vxe-table | |
| 272 | + <VxeTable | |
| 267 | 273 | ref="tableRef" |
| 268 | 274 | :data="list" |
| 269 | 275 | show-overflow |
| ... | ... | @@ -271,50 +277,50 @@ onMounted(() => { |
| 271 | 277 | @checkboxAll="handleRowCheckboxChange" |
| 272 | 278 | @checkboxChange="handleRowCheckboxChange" |
| 273 | 279 | > |
| 274 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 280 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 275 | 281 | <!-- 子表的列表 --> |
| 276 | - <vxe-column type="expand" width="60"> | |
| 282 | + <VxeColumn type="expand" width="60"> | |
| 277 | 283 | <template #content="{ row }"> |
| 278 | 284 | <!-- 子表的表单 --> |
| 279 | - <el-tabs v-model="subTabsName" class="mx-8"> | |
| 280 | - <el-tab-pane name="studentContact" label="学生联系人"> | |
| 285 | + <ElTabs v-model="subTabsName" class="mx-8"> | |
| 286 | + <ElTabPane name="studentContact" label="学生联系人"> | |
| 281 | 287 | <StudentContactList :student-id="row?.id" /> |
| 282 | - </el-tab-pane> | |
| 283 | - <el-tab-pane name="studentTeacher" label="学生班主任"> | |
| 288 | + </ElTabPane> | |
| 289 | + <ElTabPane name="studentTeacher" label="学生班主任"> | |
| 284 | 290 | <StudentTeacherList :student-id="row?.id" /> |
| 285 | - </el-tab-pane> | |
| 286 | - </el-tabs> | |
| 291 | + </ElTabPane> | |
| 292 | + </ElTabs> | |
| 287 | 293 | </template> |
| 288 | - </vxe-column> | |
| 289 | - <vxe-column field="id" title="编号" align="center" /> | |
| 290 | - <vxe-column field="name" title="名字" align="center" /> | |
| 291 | - <vxe-column field="description" title="简介" align="center" /> | |
| 292 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 294 | + </VxeColumn> | |
| 295 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 296 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 297 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 298 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 293 | 299 | <template #default="{row}"> |
| 294 | 300 | {{formatDateTime(row.birthday)}} |
| 295 | 301 | </template> |
| 296 | - </vxe-column> | |
| 297 | - <vxe-column field="sex" title="性别" align="center"> | |
| 302 | + </VxeColumn> | |
| 303 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 298 | 304 | <template #default="{row}"> |
| 299 | 305 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 300 | 306 | </template> |
| 301 | - </vxe-column> | |
| 302 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 307 | + </VxeColumn> | |
| 308 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 303 | 309 | <template #default="{row}"> |
| 304 | 310 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 305 | 311 | </template> |
| 306 | - </vxe-column> | |
| 307 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 308 | - <vxe-column field="video" title="附件" align="center" /> | |
| 309 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 310 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 312 | + </VxeColumn> | |
| 313 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 314 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 315 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 316 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 311 | 317 | <template #default="{row}"> |
| 312 | 318 | {{formatDateTime(row.createTime)}} |
| 313 | 319 | </template> |
| 314 | - </vxe-column> | |
| 315 | - <vxe-column field="operation" title="操作" align="center"> | |
| 320 | + </VxeColumn> | |
| 321 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 316 | 322 | <template #default="{row}"> |
| 317 | - <el-button | |
| 323 | + <ElButton | |
| 318 | 324 | size="small" |
| 319 | 325 | type="primary" |
| 320 | 326 | link |
| ... | ... | @@ -322,8 +328,8 @@ onMounted(() => { |
| 322 | 328 | v-access:code="['infra:student:update']" |
| 323 | 329 | > |
| 324 | 330 | {{ $t('ui.actionTitle.edit') }} |
| 325 | - </el-button> | |
| 326 | - <el-button | |
| 331 | + </ElButton> | |
| 332 | + <ElButton | |
| 327 | 333 | size="small" |
| 328 | 334 | type="danger" |
| 329 | 335 | link |
| ... | ... | @@ -332,13 +338,13 @@ onMounted(() => { |
| 332 | 338 | v-access:code="['infra:student:delete']" |
| 333 | 339 | > |
| 334 | 340 | {{ $t('ui.actionTitle.delete') }} |
| 335 | - </el-button> | |
| 341 | + </ElButton> | |
| 336 | 342 | </template> |
| 337 | - </vxe-column> | |
| 338 | - </vxe-table> | |
| 343 | + </VxeColumn> | |
| 344 | + </VxeTable> | |
| 339 | 345 | <!-- 分页 --> |
| 340 | 346 | <div class="mt-2 flex justify-end"> |
| 341 | - <el-pagination | |
| 347 | + <ElPagination | |
| 342 | 348 | :total="total" |
| 343 | 349 | v-model:current-page="queryParams.pageNo" |
| 344 | 350 | v-model:page-size="queryParams.pageSize" | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/vue/student-contact-form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { VxeTableInstance } from '#/adapter/vxe-table'; | |
| 3 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 4 | |
| 4 | -import { computed, ref, reactive, h, onMounted,watch,nextTick } from 'vue'; | |
| 5 | +import { ref, watch } from 'vue'; | |
| 5 | 6 | |
| 6 | 7 | import { DICT_TYPE } from '@vben/constants'; |
| 7 | 8 | import { getDictOptions } from '@vben/hooks'; |
| 9 | +import { Plus } from '@vben/icons'; | |
| 8 | 10 | |
| 9 | -import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElButton, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCheckboxGroup, ElCheckbox, ElDatePicker } from 'element-plus'; | |
| 10 | -import { $t } from '#/locales'; | |
| 11 | +import { | |
| 12 | + ElButton, | |
| 13 | + ElDatePicker, | |
| 14 | + ElInput, | |
| 15 | + ElMessage, | |
| 16 | + ElOption, | |
| 17 | + ElRadio, | |
| 18 | + ElRadioGroup, | |
| 19 | + ElSelect, | |
| 20 | +} from 'element-plus'; | |
| 11 | 21 | |
| 12 | - import type { VxeTableInstance } from '#/adapter/vxe-table'; | |
| 13 | -import { Plus } from "@vben/icons"; | |
| 14 | -import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; | |
| 15 | -import { getStudentContactListByStudentId } from '#/api/infra/student'; | |
| 22 | + import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; | |
| 23 | +import { getStudentContactListByStudentId } from '#/api/infra/demo'; | |
| 24 | +import { $t } from '#/locales'; | |
| 16 | 25 | |
| 17 | 26 | const props = defineProps<{ |
| 18 | 27 | studentId?: number // 学生编号(主表的关联字段) |
| ... | ... | @@ -30,24 +39,96 @@ async function onDelete(row: StudentApi.StudentContact) { |
| 30 | 39 | await tableRef.value?.remove(row); |
| 31 | 40 | } |
| 32 | 41 | |
| 33 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 34 | -defineExpose({ | |
| 35 | - getData: (): StudentApi.StudentContact[] => { | |
| 36 | - const data = list.value as StudentApi.StudentContact[]; | |
| 37 | - const removeRecords = tableRef.value?.getRemoveRecords() as StudentApi.StudentContact[]; | |
| 38 | - const insertRecords = tableRef.value?.getInsertRecords() as StudentApi.StudentContact[]; | |
| 39 | - return [ | |
| 40 | - ...data.filter( | |
| 41 | - (row) => !removeRecords.some((removed) => removed.id === row.id), | |
| 42 | - ), | |
| 43 | - ...insertRecords.map((row: any) => ({ ...row, id: undefined })), | |
| 44 | - }, | |
| 45 | -}); | |
| 42 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 43 | +function getData(): StudentApi.StudentContact[] { | |
| 44 | + const table = tableRef.value; | |
| 45 | + if (!table) { | |
| 46 | + return []; | |
| 47 | + } | |
| 48 | + const { fullData } = table.getTableData(); | |
| 49 | + const inserted = new Set(table.getInsertRecords()); | |
| 50 | + return fullData.map((row) => | |
| 51 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 52 | + ); | |
| 53 | +} | |
| 54 | + | |
| 55 | +/** 校验子表必填字段 */ | |
| 56 | +function validate(): boolean { | |
| 57 | + for (const [index, row] of getData().entries()) { | |
| 58 | + if ( | |
| 59 | + row.name === null || | |
| 60 | + row.name === undefined || | |
| 61 | + (typeof row.name === 'string' && String(row.name).trim() === '') || | |
| 62 | + (Array.isArray(row.name) && row.name.length === 0) | |
| 63 | + ) { | |
| 64 | + ElMessage.error(`第 ${index + 1} 行:名字不能为空`); | |
| 65 | + return false; | |
| 66 | + } | |
| 67 | + if ( | |
| 68 | + row.description === null || | |
| 69 | + row.description === undefined || | |
| 70 | + (typeof row.description === 'string' && String(row.description).trim() === '') || | |
| 71 | + (Array.isArray(row.description) && row.description.length === 0) | |
| 72 | + ) { | |
| 73 | + ElMessage.error(`第 ${index + 1} 行:简介不能为空`); | |
| 74 | + return false; | |
| 75 | + } | |
| 76 | + if ( | |
| 77 | + row.birthday === null || | |
| 78 | + row.birthday === undefined || | |
| 79 | + (typeof row.birthday === 'string' && String(row.birthday).trim() === '') || | |
| 80 | + (Array.isArray(row.birthday) && row.birthday.length === 0) | |
| 81 | + ) { | |
| 82 | + ElMessage.error(`第 ${index + 1} 行:出生日期不能为空`); | |
| 83 | + return false; | |
| 84 | + } | |
| 85 | + if ( | |
| 86 | + row.sex === null || | |
| 87 | + row.sex === undefined || | |
| 88 | + (typeof row.sex === 'string' && String(row.sex).trim() === '') || | |
| 89 | + (Array.isArray(row.sex) && row.sex.length === 0) | |
| 90 | + ) { | |
| 91 | + ElMessage.error(`第 ${index + 1} 行:性别不能为空`); | |
| 92 | + return false; | |
| 93 | + } | |
| 94 | + if ( | |
| 95 | + row.enabled === null || | |
| 96 | + row.enabled === undefined || | |
| 97 | + (typeof row.enabled === 'string' && String(row.enabled).trim() === '') || | |
| 98 | + (Array.isArray(row.enabled) && row.enabled.length === 0) | |
| 99 | + ) { | |
| 100 | + ElMessage.error(`第 ${index + 1} 行:是否有效不能为空`); | |
| 101 | + return false; | |
| 102 | + } | |
| 103 | + if ( | |
| 104 | + row.avatar === null || | |
| 105 | + row.avatar === undefined || | |
| 106 | + (typeof row.avatar === 'string' && String(row.avatar).trim() === '') || | |
| 107 | + (Array.isArray(row.avatar) && row.avatar.length === 0) | |
| 108 | + ) { | |
| 109 | + ElMessage.error(`第 ${index + 1} 行:头像不能为空`); | |
| 110 | + return false; | |
| 111 | + } | |
| 112 | + if ( | |
| 113 | + row.memo === null || | |
| 114 | + row.memo === undefined || | |
| 115 | + (typeof row.memo === 'string' && String(row.memo).trim() === '') || | |
| 116 | + (Array.isArray(row.memo) && row.memo.length === 0) | |
| 117 | + ) { | |
| 118 | + ElMessage.error(`第 ${index + 1} 行:备注不能为空`); | |
| 119 | + return false; | |
| 120 | + } | |
| 121 | + } | |
| 122 | + return true; | |
| 123 | +} | |
| 124 | + | |
| 125 | +defineExpose({ getData, validate }); | |
| 46 | 126 | |
| 47 | 127 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 48 | 128 | watch( |
| 49 | 129 | () => props.studentId, |
| 50 | 130 | async (val) => { |
| 131 | + list.value = []; | |
| 51 | 132 | if (!val) { |
| 52 | 133 | return; |
| 53 | 134 | } |
| ... | ... | @@ -58,70 +139,70 @@ watch( |
| 58 | 139 | </script> |
| 59 | 140 | |
| 60 | 141 | <template> |
| 61 | - <vxe-table ref="tableRef" :data="list" show-overflow class="mx-4"> | |
| 62 | - <vxe-column field="name" title="名字" align="center"> | |
| 142 | + <VxeTable ref="tableRef" :data="list" show-overflow class="mx-4"> | |
| 143 | + <VxeColumn field="name" title="名字" align="center"> | |
| 63 | 144 | <template #default="{row}"> |
| 64 | - <el-input v-model="row.name" /> | |
| 145 | + <ElInput v-model="row.name" /> | |
| 65 | 146 | </template> |
| 66 | - </vxe-column> | |
| 67 | - <vxe-column field="description" title="简介" align="center"> | |
| 147 | + </VxeColumn> | |
| 148 | + <VxeColumn field="description" title="简介" align="center"> | |
| 68 | 149 | <template #default="{row}"> |
| 69 | - <el-input v-model="row.description" type="textarea" /> | |
| 150 | + <ElInput v-model="row.description" type="textarea" /> | |
| 70 | 151 | </template> |
| 71 | - </vxe-column> | |
| 72 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 152 | + </VxeColumn> | |
| 153 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 73 | 154 | <template #default="{row}"> |
| 74 | - <el-date-picker | |
| 155 | + <ElDatePicker | |
| 75 | 156 | v-model="row.birthday" |
| 76 | 157 | type="datetime" |
| 77 | 158 | value-format="x" |
| 78 | 159 | format="YYYY-MM-DD HH:mm:ss" |
| 79 | 160 | /> |
| 80 | 161 | </template> |
| 81 | - </vxe-column> | |
| 82 | - <vxe-column field="sex" title="性别" align="center"> | |
| 162 | + </VxeColumn> | |
| 163 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 83 | 164 | <template #default="{row}"> |
| 84 | - <el-select v-model="row.sex" placeholder="请选择性别"> | |
| 85 | - <el-option | |
| 86 | - v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')" | |
| 165 | + <ElSelect v-model="row.sex" placeholder="请选择性别"> | |
| 166 | + <ElOption | |
| 167 | + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" | |
| 87 | 168 | :key="dict.value" |
| 88 | 169 | :value="dict.value" |
| 89 | 170 | :label="dict.label" |
| 90 | 171 | /> |
| 91 | - </el-select> | |
| 172 | + </ElSelect> | |
| 92 | 173 | </template> |
| 93 | - </vxe-column> | |
| 94 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 174 | + </VxeColumn> | |
| 175 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 95 | 176 | <template #default="{row}"> |
| 96 | - <el-radio-group v-model="row.enabled"> | |
| 97 | - <el-radio | |
| 98 | - v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'boolean')" | |
| 177 | + <ElRadioGroup v-model="row.enabled"> | |
| 178 | + <ElRadio | |
| 179 | + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" | |
| 99 | 180 | :key="dict.value" |
| 100 | - :label="dict.value" | |
| 181 | + :value="dict.value" | |
| 101 | 182 | > |
| 102 | 183 | {{ dict.label }} |
| 103 | - </el-radio> | |
| 104 | - </el-radio-group> | |
| 184 | + </ElRadio> | |
| 185 | + </ElRadioGroup> | |
| 105 | 186 | </template> |
| 106 | - </vxe-column> | |
| 107 | - <vxe-column field="avatar" title="头像" align="center"> | |
| 187 | + </VxeColumn> | |
| 188 | + <VxeColumn field="avatar" title="头像" align="center"> | |
| 108 | 189 | <template #default="{row}"> |
| 109 | 190 | <ImageUpload v-model="row.avatar" /> |
| 110 | 191 | </template> |
| 111 | - </vxe-column> | |
| 112 | - <vxe-column field="video" title="附件" align="center"> | |
| 192 | + </VxeColumn> | |
| 193 | + <VxeColumn field="video" title="附件" align="center"> | |
| 113 | 194 | <template #default="{row}"> |
| 114 | 195 | <FileUpload v-model="row.video" /> |
| 115 | 196 | </template> |
| 116 | - </vxe-column> | |
| 117 | - <vxe-column field="memo" title="备注" align="center"> | |
| 197 | + </VxeColumn> | |
| 198 | + <VxeColumn field="memo" title="备注" align="center"> | |
| 118 | 199 | <template #default="{row}"> |
| 119 | - <el-input v-model="row.memo" type="textarea" /> | |
| 200 | + <ElInput v-model="row.memo" type="textarea" /> | |
| 120 | 201 | </template> |
| 121 | - </vxe-column> | |
| 122 | - <vxe-column field="operation" title="操作" align="center"> | |
| 202 | + </VxeColumn> | |
| 203 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 123 | 204 | <template #default="{row}"> |
| 124 | - <el-button | |
| 205 | + <ElButton | |
| 125 | 206 | size="small" |
| 126 | 207 | type="danger" |
| 127 | 208 | link |
| ... | ... | @@ -129,13 +210,13 @@ watch( |
| 129 | 210 | v-access:code="['infra:student:delete']" |
| 130 | 211 | > |
| 131 | 212 | {{ $t('ui.actionTitle.delete') }} |
| 132 | - </el-button> | |
| 213 | + </ElButton> | |
| 133 | 214 | </template> |
| 134 | - </vxe-column> | |
| 135 | - </vxe-table> | |
| 215 | + </VxeColumn> | |
| 216 | + </VxeTable> | |
| 136 | 217 | <div class="flex justify-center mt-4"> |
| 137 | - <el-button :icon="h(Plus)" type="primary" plain @click="handleAdd" v-access:code="['infra:student:create']"> | |
| 218 | + <ElButton :icon="Plus" type="primary" plain @click="handleAdd" v-access:code="['infra:student:create']"> | |
| 138 | 219 | {{ $t('ui.actionTitle.create', ['学生联系人']) }} |
| 139 | - </el-button> | |
| 220 | + </ElButton> | |
| 140 | 221 | </div> |
| 141 | 222 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/vue/student-contact-list
| 1 | 1 | <script lang="ts" setup> |
| 2 | - import type { StudentApi } from '#/api/infra/student'; | |
| 2 | + import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { VxeTableInstance } from '#/adapter/vxe-table'; |
| 4 | 4 | |
| 5 | 5 | import { reactive,ref, h, nextTick,watch,onMounted } from 'vue'; |
| 6 | 6 | |
| 7 | 7 | import { DICT_TYPE } from '@vben/constants'; |
| 8 | 8 | import { getDictOptions } from '@vben/hooks'; |
| 9 | +import { formatDateTime } from '@vben/utils'; | |
| 9 | 10 | |
| 10 | 11 | import { DictTag } from '#/components/dict-tag'; |
| 11 | 12 | import { getRangePickerDefaultProps } from '#/utils'; |
| ... | ... | @@ -13,7 +14,7 @@ |
| 13 | 14 | import { ContentWrap } from '#/components/content-wrap'; |
| 14 | 15 | |
| 15 | 16 | |
| 16 | - import { getStudentContactListByStudentId } from '#/api/infra/student'; | |
| 17 | + import { getStudentContactListByStudentId } from '#/api/infra/demo'; | |
| 17 | 18 | |
| 18 | 19 | const props = defineProps<{ |
| 19 | 20 | studentId?: number // 学生编号(主表的关联字段) |
| ... | ... | @@ -52,38 +53,38 @@ watch( |
| 52 | 53 | |
| 53 | 54 | <template> |
| 54 | 55 | <ContentWrap title="学生联系人列表"> |
| 55 | - <vxe-table | |
| 56 | + <VxeTable | |
| 56 | 57 | :data="list" |
| 57 | 58 | show-overflow |
| 58 | 59 | :loading="loading" |
| 59 | 60 | > |
| 60 | - <vxe-column field="id" title="编号" align="center" /> | |
| 61 | - <vxe-column field="studentId" title="学生编号" align="center" /> | |
| 62 | - <vxe-column field="name" title="名字" align="center" /> | |
| 63 | - <vxe-column field="description" title="简介" align="center" /> | |
| 64 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 61 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 62 | + <VxeColumn field="studentId" title="学生编号" align="center" /> | |
| 63 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 64 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 65 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 65 | 66 | <template #default="{row}"> |
| 66 | 67 | {{formatDateTime(row.birthday)}} |
| 67 | 68 | </template> |
| 68 | - </vxe-column> | |
| 69 | - <vxe-column field="sex" title="性别" align="center"> | |
| 69 | + </VxeColumn> | |
| 70 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 70 | 71 | <template #default="{row}"> |
| 71 | 72 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 72 | 73 | </template> |
| 73 | - </vxe-column> | |
| 74 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 74 | + </VxeColumn> | |
| 75 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 75 | 76 | <template #default="{row}"> |
| 76 | 77 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 77 | 78 | </template> |
| 78 | - </vxe-column> | |
| 79 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 80 | - <vxe-column field="video" title="附件" align="center" /> | |
| 81 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 82 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 79 | + </VxeColumn> | |
| 80 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 81 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 82 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 83 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 83 | 84 | <template #default="{row}"> |
| 84 | 85 | {{formatDateTime(row.createTime)}} |
| 85 | 86 | </template> |
| 86 | - </vxe-column> | |
| 87 | - </vxe-table> | |
| 87 | + </VxeColumn> | |
| 88 | + </VxeTable> | |
| 88 | 89 | </ContentWrap> |
| 89 | 90 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/vue/student-teacher-form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { FormRules } from 'element-plus'; | |
| 3 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 4 | |
| 4 | -import { computed, ref, reactive, h, onMounted,watch,nextTick } from 'vue'; | |
| 5 | +import { nextTick, reactive, ref, watch } from 'vue'; | |
| 5 | 6 | |
| 6 | 7 | import { DICT_TYPE } from '@vben/constants'; |
| 7 | 8 | import { getDictOptions } from '@vben/hooks'; |
| 8 | 9 | |
| 9 | -import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElButton, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCheckboxGroup, ElCheckbox, ElDatePicker } from 'element-plus'; | |
| 10 | -import { $t } from '#/locales'; | |
| 10 | +import { | |
| 11 | + ElForm, | |
| 12 | + ElFormItem, | |
| 13 | + ElDatePicker, | |
| 14 | + ElInput, | |
| 15 | + ElOption, | |
| 16 | + ElRadio, | |
| 17 | + ElRadioGroup, | |
| 18 | + ElSelect, | |
| 19 | +} from 'element-plus'; | |
| 11 | 20 | |
| 12 | -import type { FormRules } from 'element-plus'; | |
| 13 | 21 | import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 14 | -import { getStudentTeacherByStudentId } from '#/api/infra/student'; | |
| 22 | +import { getStudentTeacherByStudentId } from '#/api/infra/demo'; | |
| 23 | +import { $t } from '#/locales'; | |
| 15 | 24 | |
| 16 | 25 | const props = defineProps<{ |
| 17 | 26 | studentId?: number // 学生编号(主表的关联字段) |
| ... | ... | @@ -50,6 +59,18 @@ defineExpose({ |
| 50 | 59 | watch( |
| 51 | 60 | () => props.studentId, |
| 52 | 61 | async (val) => { |
| 62 | + formData.value = { | |
| 63 | + id: undefined, | |
| 64 | + studentId: undefined, | |
| 65 | + name: undefined, | |
| 66 | + description: undefined, | |
| 67 | + birthday: undefined, | |
| 68 | + sex: undefined, | |
| 69 | + enabled: undefined, | |
| 70 | + avatar: undefined, | |
| 71 | + video: undefined, | |
| 72 | + memo: undefined, | |
| 73 | + }; | |
| 53 | 74 | if (!val) { |
| 54 | 75 | return; |
| 55 | 76 | } |
| ... | ... | @@ -61,7 +82,7 @@ watch( |
| 61 | 82 | </script> |
| 62 | 83 | |
| 63 | 84 | <template> |
| 64 | - <el-form | |
| 85 | + <ElForm | |
| 65 | 86 | ref="formRef" |
| 66 | 87 | class="mx-4" |
| 67 | 88 | :model="formData" |
| ... | ... | @@ -69,48 +90,48 @@ watch( |
| 69 | 90 | label-width="120px" |
| 70 | 91 | label-position="right" |
| 71 | 92 | > |
| 72 | - <el-form-item label="名字" prop="name"> | |
| 73 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 74 | - </el-form-item> | |
| 75 | - <el-form-item label="简介" prop="description"> | |
| 76 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 77 | - </el-form-item> | |
| 78 | - <el-form-item label="出生日期" prop="birthday"> | |
| 79 | - <el-date-picker | |
| 93 | + <ElFormItem label="名字" prop="name"> | |
| 94 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 95 | + </ElFormItem> | |
| 96 | + <ElFormItem label="简介" prop="description"> | |
| 97 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 98 | + </ElFormItem> | |
| 99 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 100 | + <ElDatePicker | |
| 80 | 101 | v-model="formData.birthday" |
| 81 | 102 | value-format="x" |
| 82 | 103 | placeholder="选择出生日期" |
| 83 | 104 | /> |
| 84 | - </el-form-item> | |
| 85 | - <el-form-item label="性别" prop="sex"> | |
| 86 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 87 | - <el-option | |
| 105 | + </ElFormItem> | |
| 106 | + <ElFormItem label="性别" prop="sex"> | |
| 107 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 108 | + <ElOption | |
| 88 | 109 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 89 | 110 | :key="dict.value" |
| 90 | 111 | :value="dict.value" |
| 91 | 112 | :label="dict.label" |
| 92 | 113 | /> |
| 93 | - </el-select> | |
| 94 | - </el-form-item> | |
| 95 | - <el-form-item label="是否有效" prop="enabled"> | |
| 96 | - <el-radio-group v-model="formData.enabled"> | |
| 97 | - <el-radio | |
| 114 | + </ElSelect> | |
| 115 | + </ElFormItem> | |
| 116 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 117 | + <ElRadioGroup v-model="formData.enabled"> | |
| 118 | + <ElRadio | |
| 98 | 119 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 99 | 120 | :key="dict.value" |
| 100 | - :label="dict.value" | |
| 121 | + :value="dict.value" | |
| 101 | 122 | > |
| 102 | 123 | {{ dict.label }} |
| 103 | - </el-radio> | |
| 104 | - </el-radio-group> | |
| 105 | - </el-form-item> | |
| 106 | - <el-form-item label="头像" prop="avatar"> | |
| 124 | + </ElRadio> | |
| 125 | + </ElRadioGroup> | |
| 126 | + </ElFormItem> | |
| 127 | + <ElFormItem label="头像" prop="avatar"> | |
| 107 | 128 | <ImageUpload v-model="formData.avatar" /> |
| 108 | - </el-form-item> | |
| 109 | - <el-form-item label="附件" prop="video"> | |
| 129 | + </ElFormItem> | |
| 130 | + <ElFormItem label="附件" prop="video"> | |
| 110 | 131 | <FileUpload v-model="formData.video" /> |
| 111 | - </el-form-item> | |
| 112 | - <el-form-item label="备注" prop="memo"> | |
| 132 | + </ElFormItem> | |
| 133 | + <ElFormItem label="备注" prop="memo"> | |
| 113 | 134 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 114 | - </el-form-item> | |
| 115 | - </el-form> | |
| 135 | + </ElFormItem> | |
| 136 | + </ElForm> | |
| 116 | 137 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_inner/vue/student-teacher-list
| 1 | 1 | <script lang="ts" setup> |
| 2 | - import type { StudentApi } from '#/api/infra/student'; | |
| 2 | + import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { VxeTableInstance } from '#/adapter/vxe-table'; |
| 4 | 4 | |
| 5 | 5 | import { reactive,ref, h, nextTick,watch,onMounted } from 'vue'; |
| 6 | 6 | |
| 7 | 7 | import { DICT_TYPE } from '@vben/constants'; |
| 8 | 8 | import { getDictOptions } from '@vben/hooks'; |
| 9 | +import { formatDateTime } from '@vben/utils'; | |
| 9 | 10 | |
| 10 | 11 | import { DictTag } from '#/components/dict-tag'; |
| 11 | 12 | import { getRangePickerDefaultProps } from '#/utils'; |
| ... | ... | @@ -13,7 +14,7 @@ |
| 13 | 14 | import { ContentWrap } from '#/components/content-wrap'; |
| 14 | 15 | |
| 15 | 16 | |
| 16 | - import { getStudentTeacherByStudentId } from '#/api/infra/student'; | |
| 17 | + import { getStudentTeacherByStudentId } from '#/api/infra/demo'; | |
| 17 | 18 | |
| 18 | 19 | const props = defineProps<{ |
| 19 | 20 | studentId?: number // 学生编号(主表的关联字段) |
| ... | ... | @@ -52,38 +53,38 @@ watch( |
| 52 | 53 | |
| 53 | 54 | <template> |
| 54 | 55 | <ContentWrap title="学生班主任列表"> |
| 55 | - <vxe-table | |
| 56 | + <VxeTable | |
| 56 | 57 | :data="list" |
| 57 | 58 | show-overflow |
| 58 | 59 | :loading="loading" |
| 59 | 60 | > |
| 60 | - <vxe-column field="id" title="编号" align="center" /> | |
| 61 | - <vxe-column field="studentId" title="学生编号" align="center" /> | |
| 62 | - <vxe-column field="name" title="名字" align="center" /> | |
| 63 | - <vxe-column field="description" title="简介" align="center" /> | |
| 64 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 61 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 62 | + <VxeColumn field="studentId" title="学生编号" align="center" /> | |
| 63 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 64 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 65 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 65 | 66 | <template #default="{row}"> |
| 66 | 67 | {{formatDateTime(row.birthday)}} |
| 67 | 68 | </template> |
| 68 | - </vxe-column> | |
| 69 | - <vxe-column field="sex" title="性别" align="center"> | |
| 69 | + </VxeColumn> | |
| 70 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 70 | 71 | <template #default="{row}"> |
| 71 | 72 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 72 | 73 | </template> |
| 73 | - </vxe-column> | |
| 74 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 74 | + </VxeColumn> | |
| 75 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 75 | 76 | <template #default="{row}"> |
| 76 | 77 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 77 | 78 | </template> |
| 78 | - </vxe-column> | |
| 79 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 80 | - <vxe-column field="video" title="附件" align="center" /> | |
| 81 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 82 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 79 | + </VxeColumn> | |
| 80 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 81 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 82 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 83 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 83 | 84 | <template #default="{row}"> |
| 84 | 85 | {{formatDateTime(row.createTime)}} |
| 85 | 86 | </template> |
| 86 | - </vxe-column> | |
| 87 | - </vxe-table> | |
| 87 | + </VxeColumn> | |
| 88 | + </VxeTable> | |
| 88 | 89 | </ContentWrap> |
| 89 | 90 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/vue/form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { useVbenModal } from '@vben/common-ui'; |
| ... | ... | @@ -13,7 +13,7 @@ import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElSelect, El |
| 13 | 13 | |
| 14 | 14 | import { computed, ref, reactive } from 'vue'; |
| 15 | 15 | import { $t } from '#/locales'; |
| 16 | -import { getStudent, createStudent, updateStudent } from '#/api/infra/student'; | |
| 16 | +import { getStudent, createStudent, updateStudent } from '#/api/infra/demo'; | |
| 17 | 17 | |
| 18 | 18 | const emit = defineEmits(['success']); |
| 19 | 19 | |
| ... | ... | @@ -71,7 +71,11 @@ const [Modal, modalApi] = useVbenModal({ |
| 71 | 71 | async onConfirm() { |
| 72 | 72 | await formRef.value?.validate(); |
| 73 | 73 | // 校验子表单 |
| 74 | - try { | |
| 74 | + if (!studentContactFormRef.value?.validate()) { | |
| 75 | + subTabsName.value = 'studentContact'; | |
| 76 | + return; | |
| 77 | + } | |
| 78 | + try { | |
| 75 | 79 | await studentTeacherFormRef.value?.validate() |
| 76 | 80 | } catch (e) { |
| 77 | 81 | subTabsName.value = 'studentTeacher' |
| ... | ... | @@ -118,65 +122,65 @@ const [Modal, modalApi] = useVbenModal({ |
| 118 | 122 | |
| 119 | 123 | <template> |
| 120 | 124 | <Modal :title="getTitle"> |
| 121 | - <el-form | |
| 125 | + <ElForm | |
| 122 | 126 | ref="formRef" |
| 123 | 127 | :model="formData" |
| 124 | 128 | :rules="rules" |
| 125 | 129 | label-width="120px" |
| 126 | 130 | label-position="right" |
| 127 | 131 | > |
| 128 | - <el-form-item label="名字" prop="name"> | |
| 129 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 130 | - </el-form-item> | |
| 131 | - <el-form-item label="简介" prop="description"> | |
| 132 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 133 | - </el-form-item> | |
| 134 | - <el-form-item label="出生日期" prop="birthday"> | |
| 135 | - <el-date-picker | |
| 132 | + <ElFormItem label="名字" prop="name"> | |
| 133 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 134 | + </ElFormItem> | |
| 135 | + <ElFormItem label="简介" prop="description"> | |
| 136 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 137 | + </ElFormItem> | |
| 138 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 139 | + <ElDatePicker | |
| 136 | 140 | v-model="formData.birthday" |
| 137 | 141 | value-format="x" |
| 138 | 142 | placeholder="选择出生日期" |
| 139 | 143 | /> |
| 140 | - </el-form-item> | |
| 141 | - <el-form-item label="性别" prop="sex"> | |
| 142 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 143 | - <el-option | |
| 144 | + </ElFormItem> | |
| 145 | + <ElFormItem label="性别" prop="sex"> | |
| 146 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 147 | + <ElOption | |
| 144 | 148 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 145 | 149 | :key="dict.value" |
| 146 | 150 | :value="dict.value" |
| 147 | 151 | :label="dict.label" |
| 148 | 152 | /> |
| 149 | - </el-select> | |
| 150 | - </el-form-item> | |
| 151 | - <el-form-item label="是否有效" prop="enabled"> | |
| 152 | - <el-radio-group v-model="formData.enabled"> | |
| 153 | - <el-radio | |
| 153 | + </ElSelect> | |
| 154 | + </ElFormItem> | |
| 155 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 156 | + <ElRadioGroup v-model="formData.enabled"> | |
| 157 | + <ElRadio | |
| 154 | 158 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 155 | 159 | :key="dict.value" |
| 156 | - :label="dict.value" | |
| 160 | + :value="dict.value" | |
| 157 | 161 | > |
| 158 | 162 | {{ dict.label }} |
| 159 | - </el-radio> | |
| 160 | - </el-radio-group> | |
| 161 | - </el-form-item> | |
| 162 | - <el-form-item label="头像" prop="avatar"> | |
| 163 | + </ElRadio> | |
| 164 | + </ElRadioGroup> | |
| 165 | + </ElFormItem> | |
| 166 | + <ElFormItem label="头像" prop="avatar"> | |
| 163 | 167 | <ImageUpload v-model="formData.avatar" /> |
| 164 | - </el-form-item> | |
| 165 | - <el-form-item label="附件" prop="video"> | |
| 168 | + </ElFormItem> | |
| 169 | + <ElFormItem label="附件" prop="video"> | |
| 166 | 170 | <FileUpload v-model="formData.video" /> |
| 167 | - </el-form-item> | |
| 168 | - <el-form-item label="备注" prop="memo"> | |
| 171 | + </ElFormItem> | |
| 172 | + <ElFormItem label="备注" prop="memo"> | |
| 169 | 173 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 170 | - </el-form-item> | |
| 171 | - </el-form> | |
| 174 | + </ElFormItem> | |
| 175 | + </ElForm> | |
| 172 | 176 | <!-- 子表的表单 --> |
| 173 | - <el-tabs v-model="subTabsName"> | |
| 174 | - <el-tab-pane name="studentContact" label="学生联系人"> | |
| 177 | + <ElTabs v-model="subTabsName"> | |
| 178 | + <ElTabPane name="studentContact" label="学生联系人"> | |
| 175 | 179 | <StudentContactForm ref="studentContactFormRef" :student-id="formData?.id" /> |
| 176 | - </el-tab-pane> | |
| 177 | - <el-tab-pane name="studentTeacher" label="学生班主任"> | |
| 180 | + </ElTabPane> | |
| 181 | + <ElTabPane name="studentTeacher" label="学生班主任"> | |
| 178 | 182 | <StudentTeacherForm ref="studentTeacherFormRef" :student-id="formData?.id" /> |
| 179 | - </el-tab-pane> | |
| 180 | - </el-tabs> | |
| 183 | + </ElTabPane> | |
| 184 | + </ElTabs> | |
| 181 | 185 | </Modal> |
| 182 | 186 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/vue/index
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | |
| 4 | 4 | import { ref, h, reactive, onMounted, nextTick } from 'vue'; |
| 5 | 5 | |
| ... | ... | @@ -17,7 +17,7 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 17 | 17 | |
| 18 | 18 | import { $t } from '#/locales'; |
| 19 | 19 | import { isEmpty } from '@vben/utils'; |
| 20 | -import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/student'; | |
| 20 | +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/demo'; | |
| 21 | 21 | |
| 22 | 22 | |
| 23 | 23 | const loading = ref(true) // 列表的加载中 |
| ... | ... | @@ -27,12 +27,11 @@ const total = ref(0) // 列表的总页数 |
| 27 | 27 | const queryParams = reactive({ |
| 28 | 28 | pageNo: 1, |
| 29 | 29 | pageSize: 10, |
| 30 | - name: undefined, | |
| 31 | - birthday: undefined, | |
| 32 | - birthday: undefined, | |
| 33 | - sex: undefined, | |
| 34 | - enabled: undefined, | |
| 35 | - createTime: undefined, | |
| 30 | + name: undefined, | |
| 31 | + birthday: undefined, | |
| 32 | + sex: undefined, | |
| 33 | + enabled: undefined, | |
| 34 | + createTime: undefined, | |
| 36 | 35 | }) |
| 37 | 36 | const queryFormRef = ref() // 搜索的表单 |
| 38 | 37 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -126,7 +125,14 @@ function handleRowCheckboxChange({ |
| 126 | 125 | async function handleExport() { |
| 127 | 126 | try { |
| 128 | 127 | exportLoading.value = true; |
| 129 | - const data = await exportStudent(queryParams); | |
| 128 | + const params = cloneDeep(queryParams) as any; | |
| 129 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 130 | + params.birthday = (params.birthday as string[]).join(','); | |
| 131 | + } | |
| 132 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 133 | + params.createTime = (params.createTime as string[]).join(','); | |
| 134 | + } | |
| 135 | + const data = await exportStudent(params); | |
| 130 | 136 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 131 | 137 | }finally { |
| 132 | 138 | exportLoading.value = false; |
| ... | ... | @@ -148,61 +154,61 @@ onMounted(() => { |
| 148 | 154 | |
| 149 | 155 | <ContentWrap v-if="!hiddenSearchBar"> |
| 150 | 156 | <!-- 搜索工作栏 --> |
| 151 | - <el-form | |
| 157 | + <ElForm | |
| 152 | 158 | :model="queryParams" |
| 153 | 159 | ref="queryFormRef" |
| 154 | 160 | inline |
| 155 | 161 | > |
| 156 | - <el-form-item label="名字"> | |
| 157 | - <el-input | |
| 162 | + <ElFormItem label="名字"> | |
| 163 | + <ElInput | |
| 158 | 164 | v-model="queryParams.name" |
| 159 | 165 | placeholder="请输入名字" |
| 160 | 166 | clearable |
| 161 | 167 | @keyup.enter="handleQuery" |
| 162 | 168 | class="!w-[240px]" |
| 163 | 169 | /> |
| 164 | - </el-form-item> | |
| 165 | - <el-form-item label="出生日期"> | |
| 166 | - <el-date-picker | |
| 170 | + </ElFormItem> | |
| 171 | + <ElFormItem label="出生日期"> | |
| 172 | + <ElDatePicker | |
| 167 | 173 | v-model="queryParams.birthday" |
| 168 | 174 | value-format="YYYY-MM-DD" |
| 169 | 175 | placeholder="选择出生日期" |
| 170 | 176 | clearable |
| 171 | 177 | class="!w-[240px]" |
| 172 | 178 | /> |
| 173 | - </el-form-item> | |
| 174 | - <el-form-item label="性别"> | |
| 175 | - <el-select | |
| 179 | + </ElFormItem> | |
| 180 | + <ElFormItem label="性别"> | |
| 181 | + <ElSelect | |
| 176 | 182 | v-model="queryParams.sex" |
| 177 | 183 | placeholder="请选择性别" |
| 178 | 184 | clearable |
| 179 | 185 | class="!w-[240px]" |
| 180 | 186 | > |
| 181 | - <el-option | |
| 187 | + <ElOption | |
| 182 | 188 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 183 | 189 | :key="dict.value" |
| 184 | 190 | :value="dict.value" |
| 185 | 191 | :label="dict.label" |
| 186 | 192 | /> |
| 187 | - </el-select> | |
| 188 | - </el-form-item> | |
| 189 | - <el-form-item label="是否有效"> | |
| 190 | - <el-select | |
| 193 | + </ElSelect> | |
| 194 | + </ElFormItem> | |
| 195 | + <ElFormItem label="是否有效"> | |
| 196 | + <ElSelect | |
| 191 | 197 | v-model="queryParams.enabled" |
| 192 | 198 | placeholder="请选择是否有效" |
| 193 | 199 | clearable |
| 194 | 200 | class="!w-[240px]" |
| 195 | 201 | > |
| 196 | - <el-option | |
| 202 | + <ElOption | |
| 197 | 203 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 198 | 204 | :key="dict.value" |
| 199 | 205 | :value="dict.value" |
| 200 | 206 | :label="dict.label" |
| 201 | 207 | /> |
| 202 | - </el-select> | |
| 203 | - </el-form-item> | |
| 204 | - <el-form-item label="创建时间"> | |
| 205 | - <el-date-picker | |
| 208 | + </ElSelect> | |
| 209 | + </ElFormItem> | |
| 210 | + <ElFormItem label="创建时间"> | |
| 211 | + <ElDatePicker | |
| 206 | 212 | v-model="queryParams.createTime" |
| 207 | 213 | type="daterange" |
| 208 | 214 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -211,24 +217,24 @@ onMounted(() => { |
| 211 | 217 | end-placeholder="结束日期" |
| 212 | 218 | class="!w-[240px]" |
| 213 | 219 | /> |
| 214 | - </el-form-item> | |
| 215 | - <el-form-item> | |
| 216 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 217 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 220 | + </ElFormItem> | |
| 221 | + <ElFormItem> | |
| 222 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 223 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 218 | 224 | 搜索 |
| 219 | - </el-button> | |
| 220 | - </el-form-item> | |
| 221 | - </el-form> | |
| 225 | + </ElButton> | |
| 226 | + </ElFormItem> | |
| 227 | + </ElForm> | |
| 222 | 228 | </ContentWrap> |
| 223 | 229 | |
| 224 | 230 | <!-- 列表 --> |
| 225 | 231 | <ContentWrap title="学生"> |
| 226 | 232 | <template #extra> |
| 227 | - <TableToolbar | |
| 233 | + <VbenVxeTableToolbar | |
| 228 | 234 | ref="tableToolbarRef" |
| 229 | 235 | v-model:hidden-search="hiddenSearchBar" |
| 230 | 236 | > |
| 231 | - <el-button | |
| 237 | + <ElButton | |
| 232 | 238 | class="ml-2" |
| 233 | 239 | :icon="h(Plus)" |
| 234 | 240 | type="primary" |
| ... | ... | @@ -236,8 +242,8 @@ onMounted(() => { |
| 236 | 242 | v-access:code="['infra:student:create']" |
| 237 | 243 | > |
| 238 | 244 | {{ $t('ui.actionTitle.create', ['学生']) }} |
| 239 | - </el-button> | |
| 240 | - <el-button | |
| 245 | + </ElButton> | |
| 246 | + <ElButton | |
| 241 | 247 | :icon="h(Download)" |
| 242 | 248 | type="primary" |
| 243 | 249 | class="ml-2" |
| ... | ... | @@ -246,8 +252,8 @@ onMounted(() => { |
| 246 | 252 | v-access:code="['infra:student:export']" |
| 247 | 253 | > |
| 248 | 254 | {{ $t('ui.actionTitle.export') }} |
| 249 | - </el-button> | |
| 250 | - <el-button | |
| 255 | + </ElButton> | |
| 256 | + <ElButton | |
| 251 | 257 | :icon="h(Trash2)" |
| 252 | 258 | type="danger" |
| 253 | 259 | class="ml-2" |
| ... | ... | @@ -256,10 +262,10 @@ onMounted(() => { |
| 256 | 262 | v-access:code="['infra:student:delete']" |
| 257 | 263 | > |
| 258 | 264 | 批量删除 |
| 259 | - </el-button> | |
| 260 | - </TableToolbar> | |
| 265 | + </ElButton> | |
| 266 | + </VbenVxeTableToolbar> | |
| 261 | 267 | </template> |
| 262 | - <vxe-table | |
| 268 | + <VxeTable | |
| 263 | 269 | ref="tableRef" |
| 264 | 270 | :data="list" |
| 265 | 271 | show-overflow |
| ... | ... | @@ -267,36 +273,36 @@ onMounted(() => { |
| 267 | 273 | @checkboxAll="handleRowCheckboxChange" |
| 268 | 274 | @checkboxChange="handleRowCheckboxChange" |
| 269 | 275 | > |
| 270 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 271 | - <vxe-column field="id" title="编号" align="center" /> | |
| 272 | - <vxe-column field="name" title="名字" align="center" /> | |
| 273 | - <vxe-column field="description" title="简介" align="center" /> | |
| 274 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 276 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 277 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 278 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 279 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 280 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 275 | 281 | <template #default="{row}"> |
| 276 | 282 | {{formatDateTime(row.birthday)}} |
| 277 | 283 | </template> |
| 278 | - </vxe-column> | |
| 279 | - <vxe-column field="sex" title="性别" align="center"> | |
| 284 | + </VxeColumn> | |
| 285 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 280 | 286 | <template #default="{row}"> |
| 281 | 287 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 282 | 288 | </template> |
| 283 | - </vxe-column> | |
| 284 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 289 | + </VxeColumn> | |
| 290 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 285 | 291 | <template #default="{row}"> |
| 286 | 292 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 287 | 293 | </template> |
| 288 | - </vxe-column> | |
| 289 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 290 | - <vxe-column field="video" title="附件" align="center" /> | |
| 291 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 292 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 294 | + </VxeColumn> | |
| 295 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 296 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 297 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 298 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 293 | 299 | <template #default="{row}"> |
| 294 | 300 | {{formatDateTime(row.createTime)}} |
| 295 | 301 | </template> |
| 296 | - </vxe-column> | |
| 297 | - <vxe-column field="operation" title="操作" align="center"> | |
| 302 | + </VxeColumn> | |
| 303 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 298 | 304 | <template #default="{row}"> |
| 299 | - <el-button | |
| 305 | + <ElButton | |
| 300 | 306 | size="small" |
| 301 | 307 | type="primary" |
| 302 | 308 | link |
| ... | ... | @@ -304,8 +310,8 @@ onMounted(() => { |
| 304 | 310 | v-access:code="['infra:student:update']" |
| 305 | 311 | > |
| 306 | 312 | {{ $t('ui.actionTitle.edit') }} |
| 307 | - </el-button> | |
| 308 | - <el-button | |
| 313 | + </ElButton> | |
| 314 | + <ElButton | |
| 309 | 315 | size="small" |
| 310 | 316 | type="danger" |
| 311 | 317 | link |
| ... | ... | @@ -314,13 +320,13 @@ onMounted(() => { |
| 314 | 320 | v-access:code="['infra:student:delete']" |
| 315 | 321 | > |
| 316 | 322 | {{ $t('ui.actionTitle.delete') }} |
| 317 | - </el-button> | |
| 323 | + </ElButton> | |
| 318 | 324 | </template> |
| 319 | - </vxe-column> | |
| 320 | - </vxe-table> | |
| 325 | + </VxeColumn> | |
| 326 | + </VxeTable> | |
| 321 | 327 | <!-- 分页 --> |
| 322 | 328 | <div class="mt-2 flex justify-end"> |
| 323 | - <el-pagination | |
| 329 | + <ElPagination | |
| 324 | 330 | :total="total" |
| 325 | 331 | v-model:current-page="queryParams.pageNo" |
| 326 | 332 | v-model:page-size="queryParams.pageSize" | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/vue/student-contact-form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { VxeTableInstance } from '#/adapter/vxe-table'; | |
| 3 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 4 | |
| 4 | -import { computed, ref, reactive, h, onMounted,watch,nextTick } from 'vue'; | |
| 5 | +import { ref, watch } from 'vue'; | |
| 5 | 6 | |
| 6 | 7 | import { DICT_TYPE } from '@vben/constants'; |
| 7 | 8 | import { getDictOptions } from '@vben/hooks'; |
| 9 | +import { Plus } from '@vben/icons'; | |
| 8 | 10 | |
| 9 | -import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElButton, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCheckboxGroup, ElCheckbox, ElDatePicker } from 'element-plus'; | |
| 10 | -import { $t } from '#/locales'; | |
| 11 | +import { | |
| 12 | + ElButton, | |
| 13 | + ElDatePicker, | |
| 14 | + ElInput, | |
| 15 | + ElMessage, | |
| 16 | + ElOption, | |
| 17 | + ElRadio, | |
| 18 | + ElRadioGroup, | |
| 19 | + ElSelect, | |
| 20 | +} from 'element-plus'; | |
| 11 | 21 | |
| 12 | - import type { VxeTableInstance } from '#/adapter/vxe-table'; | |
| 13 | -import { Plus } from "@vben/icons"; | |
| 14 | -import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; | |
| 15 | -import { getStudentContactListByStudentId } from '#/api/infra/student'; | |
| 22 | + import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; | |
| 23 | +import { getStudentContactListByStudentId } from '#/api/infra/demo'; | |
| 24 | +import { $t } from '#/locales'; | |
| 16 | 25 | |
| 17 | 26 | const props = defineProps<{ |
| 18 | 27 | studentId?: number // 学生编号(主表的关联字段) |
| ... | ... | @@ -30,24 +39,96 @@ async function onDelete(row: StudentApi.StudentContact) { |
| 30 | 39 | await tableRef.value?.remove(row); |
| 31 | 40 | } |
| 32 | 41 | |
| 33 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 34 | -defineExpose({ | |
| 35 | - getData: (): StudentApi.StudentContact[] => { | |
| 36 | - const data = list.value as StudentApi.StudentContact[]; | |
| 37 | - const removeRecords = tableRef.value?.getRemoveRecords() as StudentApi.StudentContact[]; | |
| 38 | - const insertRecords = tableRef.value?.getInsertRecords() as StudentApi.StudentContact[]; | |
| 39 | - return [ | |
| 40 | - ...data.filter( | |
| 41 | - (row) => !removeRecords.some((removed) => removed.id === row.id), | |
| 42 | - ), | |
| 43 | - ...insertRecords.map((row: any) => ({ ...row, id: undefined })), | |
| 44 | - }, | |
| 45 | -}); | |
| 42 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 43 | +function getData(): StudentApi.StudentContact[] { | |
| 44 | + const table = tableRef.value; | |
| 45 | + if (!table) { | |
| 46 | + return []; | |
| 47 | + } | |
| 48 | + const { fullData } = table.getTableData(); | |
| 49 | + const inserted = new Set(table.getInsertRecords()); | |
| 50 | + return fullData.map((row) => | |
| 51 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 52 | + ); | |
| 53 | +} | |
| 54 | + | |
| 55 | +/** 校验子表必填字段 */ | |
| 56 | +function validate(): boolean { | |
| 57 | + for (const [index, row] of getData().entries()) { | |
| 58 | + if ( | |
| 59 | + row.name === null || | |
| 60 | + row.name === undefined || | |
| 61 | + (typeof row.name === 'string' && String(row.name).trim() === '') || | |
| 62 | + (Array.isArray(row.name) && row.name.length === 0) | |
| 63 | + ) { | |
| 64 | + ElMessage.error(`第 ${index + 1} 行:名字不能为空`); | |
| 65 | + return false; | |
| 66 | + } | |
| 67 | + if ( | |
| 68 | + row.description === null || | |
| 69 | + row.description === undefined || | |
| 70 | + (typeof row.description === 'string' && String(row.description).trim() === '') || | |
| 71 | + (Array.isArray(row.description) && row.description.length === 0) | |
| 72 | + ) { | |
| 73 | + ElMessage.error(`第 ${index + 1} 行:简介不能为空`); | |
| 74 | + return false; | |
| 75 | + } | |
| 76 | + if ( | |
| 77 | + row.birthday === null || | |
| 78 | + row.birthday === undefined || | |
| 79 | + (typeof row.birthday === 'string' && String(row.birthday).trim() === '') || | |
| 80 | + (Array.isArray(row.birthday) && row.birthday.length === 0) | |
| 81 | + ) { | |
| 82 | + ElMessage.error(`第 ${index + 1} 行:出生日期不能为空`); | |
| 83 | + return false; | |
| 84 | + } | |
| 85 | + if ( | |
| 86 | + row.sex === null || | |
| 87 | + row.sex === undefined || | |
| 88 | + (typeof row.sex === 'string' && String(row.sex).trim() === '') || | |
| 89 | + (Array.isArray(row.sex) && row.sex.length === 0) | |
| 90 | + ) { | |
| 91 | + ElMessage.error(`第 ${index + 1} 行:性别不能为空`); | |
| 92 | + return false; | |
| 93 | + } | |
| 94 | + if ( | |
| 95 | + row.enabled === null || | |
| 96 | + row.enabled === undefined || | |
| 97 | + (typeof row.enabled === 'string' && String(row.enabled).trim() === '') || | |
| 98 | + (Array.isArray(row.enabled) && row.enabled.length === 0) | |
| 99 | + ) { | |
| 100 | + ElMessage.error(`第 ${index + 1} 行:是否有效不能为空`); | |
| 101 | + return false; | |
| 102 | + } | |
| 103 | + if ( | |
| 104 | + row.avatar === null || | |
| 105 | + row.avatar === undefined || | |
| 106 | + (typeof row.avatar === 'string' && String(row.avatar).trim() === '') || | |
| 107 | + (Array.isArray(row.avatar) && row.avatar.length === 0) | |
| 108 | + ) { | |
| 109 | + ElMessage.error(`第 ${index + 1} 行:头像不能为空`); | |
| 110 | + return false; | |
| 111 | + } | |
| 112 | + if ( | |
| 113 | + row.memo === null || | |
| 114 | + row.memo === undefined || | |
| 115 | + (typeof row.memo === 'string' && String(row.memo).trim() === '') || | |
| 116 | + (Array.isArray(row.memo) && row.memo.length === 0) | |
| 117 | + ) { | |
| 118 | + ElMessage.error(`第 ${index + 1} 行:备注不能为空`); | |
| 119 | + return false; | |
| 120 | + } | |
| 121 | + } | |
| 122 | + return true; | |
| 123 | +} | |
| 124 | + | |
| 125 | +defineExpose({ getData, validate }); | |
| 46 | 126 | |
| 47 | 127 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 48 | 128 | watch( |
| 49 | 129 | () => props.studentId, |
| 50 | 130 | async (val) => { |
| 131 | + list.value = []; | |
| 51 | 132 | if (!val) { |
| 52 | 133 | return; |
| 53 | 134 | } |
| ... | ... | @@ -58,70 +139,70 @@ watch( |
| 58 | 139 | </script> |
| 59 | 140 | |
| 60 | 141 | <template> |
| 61 | - <vxe-table ref="tableRef" :data="list" show-overflow class="mx-4"> | |
| 62 | - <vxe-column field="name" title="名字" align="center"> | |
| 142 | + <VxeTable ref="tableRef" :data="list" show-overflow class="mx-4"> | |
| 143 | + <VxeColumn field="name" title="名字" align="center"> | |
| 63 | 144 | <template #default="{row}"> |
| 64 | - <el-input v-model="row.name" /> | |
| 145 | + <ElInput v-model="row.name" /> | |
| 65 | 146 | </template> |
| 66 | - </vxe-column> | |
| 67 | - <vxe-column field="description" title="简介" align="center"> | |
| 147 | + </VxeColumn> | |
| 148 | + <VxeColumn field="description" title="简介" align="center"> | |
| 68 | 149 | <template #default="{row}"> |
| 69 | - <el-input v-model="row.description" type="textarea" /> | |
| 150 | + <ElInput v-model="row.description" type="textarea" /> | |
| 70 | 151 | </template> |
| 71 | - </vxe-column> | |
| 72 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 152 | + </VxeColumn> | |
| 153 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 73 | 154 | <template #default="{row}"> |
| 74 | - <el-date-picker | |
| 155 | + <ElDatePicker | |
| 75 | 156 | v-model="row.birthday" |
| 76 | 157 | type="datetime" |
| 77 | 158 | value-format="x" |
| 78 | 159 | format="YYYY-MM-DD HH:mm:ss" |
| 79 | 160 | /> |
| 80 | 161 | </template> |
| 81 | - </vxe-column> | |
| 82 | - <vxe-column field="sex" title="性别" align="center"> | |
| 162 | + </VxeColumn> | |
| 163 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 83 | 164 | <template #default="{row}"> |
| 84 | - <el-select v-model="row.sex" placeholder="请选择性别"> | |
| 85 | - <el-option | |
| 86 | - v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'number')" | |
| 165 | + <ElSelect v-model="row.sex" placeholder="请选择性别"> | |
| 166 | + <ElOption | |
| 167 | + v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" | |
| 87 | 168 | :key="dict.value" |
| 88 | 169 | :value="dict.value" |
| 89 | 170 | :label="dict.label" |
| 90 | 171 | /> |
| 91 | - </el-select> | |
| 172 | + </ElSelect> | |
| 92 | 173 | </template> |
| 93 | - </vxe-column> | |
| 94 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 174 | + </VxeColumn> | |
| 175 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 95 | 176 | <template #default="{row}"> |
| 96 | - <el-radio-group v-model="row.enabled"> | |
| 97 | - <el-radio | |
| 98 | - v-for="dict in getDictOptions(DICT_TYPE.$dictType.toUpperCase(), 'boolean')" | |
| 177 | + <ElRadioGroup v-model="row.enabled"> | |
| 178 | + <ElRadio | |
| 179 | + v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" | |
| 99 | 180 | :key="dict.value" |
| 100 | - :label="dict.value" | |
| 181 | + :value="dict.value" | |
| 101 | 182 | > |
| 102 | 183 | {{ dict.label }} |
| 103 | - </el-radio> | |
| 104 | - </el-radio-group> | |
| 184 | + </ElRadio> | |
| 185 | + </ElRadioGroup> | |
| 105 | 186 | </template> |
| 106 | - </vxe-column> | |
| 107 | - <vxe-column field="avatar" title="头像" align="center"> | |
| 187 | + </VxeColumn> | |
| 188 | + <VxeColumn field="avatar" title="头像" align="center"> | |
| 108 | 189 | <template #default="{row}"> |
| 109 | 190 | <ImageUpload v-model="row.avatar" /> |
| 110 | 191 | </template> |
| 111 | - </vxe-column> | |
| 112 | - <vxe-column field="video" title="附件" align="center"> | |
| 192 | + </VxeColumn> | |
| 193 | + <VxeColumn field="video" title="附件" align="center"> | |
| 113 | 194 | <template #default="{row}"> |
| 114 | 195 | <FileUpload v-model="row.video" /> |
| 115 | 196 | </template> |
| 116 | - </vxe-column> | |
| 117 | - <vxe-column field="memo" title="备注" align="center"> | |
| 197 | + </VxeColumn> | |
| 198 | + <VxeColumn field="memo" title="备注" align="center"> | |
| 118 | 199 | <template #default="{row}"> |
| 119 | - <el-input v-model="row.memo" type="textarea" /> | |
| 200 | + <ElInput v-model="row.memo" type="textarea" /> | |
| 120 | 201 | </template> |
| 121 | - </vxe-column> | |
| 122 | - <vxe-column field="operation" title="操作" align="center"> | |
| 202 | + </VxeColumn> | |
| 203 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 123 | 204 | <template #default="{row}"> |
| 124 | - <el-button | |
| 205 | + <ElButton | |
| 125 | 206 | size="small" |
| 126 | 207 | type="danger" |
| 127 | 208 | link |
| ... | ... | @@ -129,13 +210,13 @@ watch( |
| 129 | 210 | v-access:code="['infra:student:delete']" |
| 130 | 211 | > |
| 131 | 212 | {{ $t('ui.actionTitle.delete') }} |
| 132 | - </el-button> | |
| 213 | + </ElButton> | |
| 133 | 214 | </template> |
| 134 | - </vxe-column> | |
| 135 | - </vxe-table> | |
| 215 | + </VxeColumn> | |
| 216 | + </VxeTable> | |
| 136 | 217 | <div class="flex justify-center mt-4"> |
| 137 | - <el-button :icon="h(Plus)" type="primary" plain @click="handleAdd" v-access:code="['infra:student:create']"> | |
| 218 | + <ElButton :icon="Plus" type="primary" plain @click="handleAdd" v-access:code="['infra:student:create']"> | |
| 138 | 219 | {{ $t('ui.actionTitle.create', ['学生联系人']) }} |
| 139 | - </el-button> | |
| 220 | + </ElButton> | |
| 140 | 221 | </div> |
| 141 | 222 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_master_normal/vue/student-teacher-form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { FormRules } from 'element-plus'; | |
| 3 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 4 | |
| 4 | -import { computed, ref, reactive, h, onMounted,watch,nextTick } from 'vue'; | |
| 5 | +import { nextTick, reactive, ref, watch } from 'vue'; | |
| 5 | 6 | |
| 6 | 7 | import { DICT_TYPE } from '@vben/constants'; |
| 7 | 8 | import { getDictOptions } from '@vben/hooks'; |
| 8 | 9 | |
| 9 | -import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElButton, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCheckboxGroup, ElCheckbox, ElDatePicker } from 'element-plus'; | |
| 10 | -import { $t } from '#/locales'; | |
| 10 | +import { | |
| 11 | + ElForm, | |
| 12 | + ElFormItem, | |
| 13 | + ElDatePicker, | |
| 14 | + ElInput, | |
| 15 | + ElOption, | |
| 16 | + ElRadio, | |
| 17 | + ElRadioGroup, | |
| 18 | + ElSelect, | |
| 19 | +} from 'element-plus'; | |
| 11 | 20 | |
| 12 | -import type { FormRules } from 'element-plus'; | |
| 13 | 21 | import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 14 | -import { getStudentTeacherByStudentId } from '#/api/infra/student'; | |
| 22 | +import { getStudentTeacherByStudentId } from '#/api/infra/demo'; | |
| 23 | +import { $t } from '#/locales'; | |
| 15 | 24 | |
| 16 | 25 | const props = defineProps<{ |
| 17 | 26 | studentId?: number // 学生编号(主表的关联字段) |
| ... | ... | @@ -50,6 +59,18 @@ defineExpose({ |
| 50 | 59 | watch( |
| 51 | 60 | () => props.studentId, |
| 52 | 61 | async (val) => { |
| 62 | + formData.value = { | |
| 63 | + id: undefined, | |
| 64 | + studentId: undefined, | |
| 65 | + name: undefined, | |
| 66 | + description: undefined, | |
| 67 | + birthday: undefined, | |
| 68 | + sex: undefined, | |
| 69 | + enabled: undefined, | |
| 70 | + avatar: undefined, | |
| 71 | + video: undefined, | |
| 72 | + memo: undefined, | |
| 73 | + }; | |
| 53 | 74 | if (!val) { |
| 54 | 75 | return; |
| 55 | 76 | } |
| ... | ... | @@ -61,7 +82,7 @@ watch( |
| 61 | 82 | </script> |
| 62 | 83 | |
| 63 | 84 | <template> |
| 64 | - <el-form | |
| 85 | + <ElForm | |
| 65 | 86 | ref="formRef" |
| 66 | 87 | class="mx-4" |
| 67 | 88 | :model="formData" |
| ... | ... | @@ -69,48 +90,48 @@ watch( |
| 69 | 90 | label-width="120px" |
| 70 | 91 | label-position="right" |
| 71 | 92 | > |
| 72 | - <el-form-item label="名字" prop="name"> | |
| 73 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 74 | - </el-form-item> | |
| 75 | - <el-form-item label="简介" prop="description"> | |
| 76 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 77 | - </el-form-item> | |
| 78 | - <el-form-item label="出生日期" prop="birthday"> | |
| 79 | - <el-date-picker | |
| 93 | + <ElFormItem label="名字" prop="name"> | |
| 94 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 95 | + </ElFormItem> | |
| 96 | + <ElFormItem label="简介" prop="description"> | |
| 97 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 98 | + </ElFormItem> | |
| 99 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 100 | + <ElDatePicker | |
| 80 | 101 | v-model="formData.birthday" |
| 81 | 102 | value-format="x" |
| 82 | 103 | placeholder="选择出生日期" |
| 83 | 104 | /> |
| 84 | - </el-form-item> | |
| 85 | - <el-form-item label="性别" prop="sex"> | |
| 86 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 87 | - <el-option | |
| 105 | + </ElFormItem> | |
| 106 | + <ElFormItem label="性别" prop="sex"> | |
| 107 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 108 | + <ElOption | |
| 88 | 109 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 89 | 110 | :key="dict.value" |
| 90 | 111 | :value="dict.value" |
| 91 | 112 | :label="dict.label" |
| 92 | 113 | /> |
| 93 | - </el-select> | |
| 94 | - </el-form-item> | |
| 95 | - <el-form-item label="是否有效" prop="enabled"> | |
| 96 | - <el-radio-group v-model="formData.enabled"> | |
| 97 | - <el-radio | |
| 114 | + </ElSelect> | |
| 115 | + </ElFormItem> | |
| 116 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 117 | + <ElRadioGroup v-model="formData.enabled"> | |
| 118 | + <ElRadio | |
| 98 | 119 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 99 | 120 | :key="dict.value" |
| 100 | - :label="dict.value" | |
| 121 | + :value="dict.value" | |
| 101 | 122 | > |
| 102 | 123 | {{ dict.label }} |
| 103 | - </el-radio> | |
| 104 | - </el-radio-group> | |
| 105 | - </el-form-item> | |
| 106 | - <el-form-item label="头像" prop="avatar"> | |
| 124 | + </ElRadio> | |
| 125 | + </ElRadioGroup> | |
| 126 | + </ElFormItem> | |
| 127 | + <ElFormItem label="头像" prop="avatar"> | |
| 107 | 128 | <ImageUpload v-model="formData.avatar" /> |
| 108 | - </el-form-item> | |
| 109 | - <el-form-item label="附件" prop="video"> | |
| 129 | + </ElFormItem> | |
| 130 | + <ElFormItem label="附件" prop="video"> | |
| 110 | 131 | <FileUpload v-model="formData.video" /> |
| 111 | - </el-form-item> | |
| 112 | - <el-form-item label="备注" prop="memo"> | |
| 132 | + </ElFormItem> | |
| 133 | + <ElFormItem label="备注" prop="memo"> | |
| 113 | 134 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 114 | - </el-form-item> | |
| 115 | - </el-form> | |
| 135 | + </ElFormItem> | |
| 136 | + </ElForm> | |
| 116 | 137 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one/vue/form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { useVbenModal } from '@vben/common-ui'; |
| ... | ... | @@ -11,7 +11,7 @@ import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElSelect, El |
| 11 | 11 | |
| 12 | 12 | import { computed, ref, reactive } from 'vue'; |
| 13 | 13 | import { $t } from '#/locales'; |
| 14 | -import { getStudent, createStudent, updateStudent } from '#/api/infra/student'; | |
| 14 | +import { getStudent, createStudent, updateStudent } from '#/api/infra/demo'; | |
| 15 | 15 | |
| 16 | 16 | const emit = defineEmits(['success']); |
| 17 | 17 | |
| ... | ... | @@ -102,56 +102,56 @@ const [Modal, modalApi] = useVbenModal({ |
| 102 | 102 | |
| 103 | 103 | <template> |
| 104 | 104 | <Modal :title="getTitle"> |
| 105 | - <el-form | |
| 105 | + <ElForm | |
| 106 | 106 | ref="formRef" |
| 107 | 107 | :model="formData" |
| 108 | 108 | :rules="rules" |
| 109 | 109 | label-width="120px" |
| 110 | 110 | label-position="right" |
| 111 | 111 | > |
| 112 | - <el-form-item label="名字" prop="name"> | |
| 113 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 114 | - </el-form-item> | |
| 115 | - <el-form-item label="简介" prop="description"> | |
| 116 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 117 | - </el-form-item> | |
| 118 | - <el-form-item label="出生日期" prop="birthday"> | |
| 119 | - <el-date-picker | |
| 112 | + <ElFormItem label="名字" prop="name"> | |
| 113 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 114 | + </ElFormItem> | |
| 115 | + <ElFormItem label="简介" prop="description"> | |
| 116 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 117 | + </ElFormItem> | |
| 118 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 119 | + <ElDatePicker | |
| 120 | 120 | v-model="formData.birthday" |
| 121 | 121 | value-format="x" |
| 122 | 122 | placeholder="选择出生日期" |
| 123 | 123 | /> |
| 124 | - </el-form-item> | |
| 125 | - <el-form-item label="性别" prop="sex"> | |
| 126 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 127 | - <el-option | |
| 124 | + </ElFormItem> | |
| 125 | + <ElFormItem label="性别" prop="sex"> | |
| 126 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 127 | + <ElOption | |
| 128 | 128 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 129 | 129 | :key="dict.value" |
| 130 | 130 | :value="dict.value" |
| 131 | 131 | :label="dict.label" |
| 132 | 132 | /> |
| 133 | - </el-select> | |
| 134 | - </el-form-item> | |
| 135 | - <el-form-item label="是否有效" prop="enabled"> | |
| 136 | - <el-radio-group v-model="formData.enabled"> | |
| 137 | - <el-radio | |
| 133 | + </ElSelect> | |
| 134 | + </ElFormItem> | |
| 135 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 136 | + <ElRadioGroup v-model="formData.enabled"> | |
| 137 | + <ElRadio | |
| 138 | 138 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 139 | 139 | :key="dict.value" |
| 140 | - :label="dict.value" | |
| 140 | + :value="dict.value" | |
| 141 | 141 | > |
| 142 | 142 | {{ dict.label }} |
| 143 | - </el-radio> | |
| 144 | - </el-radio-group> | |
| 145 | - </el-form-item> | |
| 146 | - <el-form-item label="头像" prop="avatar"> | |
| 143 | + </ElRadio> | |
| 144 | + </ElRadioGroup> | |
| 145 | + </ElFormItem> | |
| 146 | + <ElFormItem label="头像" prop="avatar"> | |
| 147 | 147 | <ImageUpload v-model="formData.avatar" /> |
| 148 | - </el-form-item> | |
| 149 | - <el-form-item label="附件" prop="video"> | |
| 148 | + </ElFormItem> | |
| 149 | + <ElFormItem label="附件" prop="video"> | |
| 150 | 150 | <FileUpload v-model="formData.video" /> |
| 151 | - </el-form-item> | |
| 152 | - <el-form-item label="备注" prop="memo"> | |
| 151 | + </ElFormItem> | |
| 152 | + <ElFormItem label="备注" prop="memo"> | |
| 153 | 153 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 154 | - </el-form-item> | |
| 155 | - </el-form> | |
| 154 | + </ElFormItem> | |
| 155 | + </ElForm> | |
| 156 | 156 | </Modal> |
| 157 | 157 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one/vue/index
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | |
| 4 | 4 | import { ref, h, reactive, onMounted, nextTick } from 'vue'; |
| 5 | 5 | |
| ... | ... | @@ -17,7 +17,7 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 17 | 17 | |
| 18 | 18 | import { $t } from '#/locales'; |
| 19 | 19 | import { isEmpty } from '@vben/utils'; |
| 20 | -import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/student'; | |
| 20 | +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/demo'; | |
| 21 | 21 | |
| 22 | 22 | |
| 23 | 23 | const loading = ref(true) // 列表的加载中 |
| ... | ... | @@ -27,12 +27,11 @@ const total = ref(0) // 列表的总页数 |
| 27 | 27 | const queryParams = reactive({ |
| 28 | 28 | pageNo: 1, |
| 29 | 29 | pageSize: 10, |
| 30 | - name: undefined, | |
| 31 | - birthday: undefined, | |
| 32 | - birthday: undefined, | |
| 33 | - sex: undefined, | |
| 34 | - enabled: undefined, | |
| 35 | - createTime: undefined, | |
| 30 | + name: undefined, | |
| 31 | + birthday: undefined, | |
| 32 | + sex: undefined, | |
| 33 | + enabled: undefined, | |
| 34 | + createTime: undefined, | |
| 36 | 35 | }) |
| 37 | 36 | const queryFormRef = ref() // 搜索的表单 |
| 38 | 37 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -126,7 +125,14 @@ function handleRowCheckboxChange({ |
| 126 | 125 | async function handleExport() { |
| 127 | 126 | try { |
| 128 | 127 | exportLoading.value = true; |
| 129 | - const data = await exportStudent(queryParams); | |
| 128 | + const params = cloneDeep(queryParams) as any; | |
| 129 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 130 | + params.birthday = (params.birthday as string[]).join(','); | |
| 131 | + } | |
| 132 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 133 | + params.createTime = (params.createTime as string[]).join(','); | |
| 134 | + } | |
| 135 | + const data = await exportStudent(params); | |
| 130 | 136 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 131 | 137 | }finally { |
| 132 | 138 | exportLoading.value = false; |
| ... | ... | @@ -148,61 +154,61 @@ onMounted(() => { |
| 148 | 154 | |
| 149 | 155 | <ContentWrap v-if="!hiddenSearchBar"> |
| 150 | 156 | <!-- 搜索工作栏 --> |
| 151 | - <el-form | |
| 157 | + <ElForm | |
| 152 | 158 | :model="queryParams" |
| 153 | 159 | ref="queryFormRef" |
| 154 | 160 | inline |
| 155 | 161 | > |
| 156 | - <el-form-item label="名字"> | |
| 157 | - <el-input | |
| 162 | + <ElFormItem label="名字"> | |
| 163 | + <ElInput | |
| 158 | 164 | v-model="queryParams.name" |
| 159 | 165 | placeholder="请输入名字" |
| 160 | 166 | clearable |
| 161 | 167 | @keyup.enter="handleQuery" |
| 162 | 168 | class="!w-[240px]" |
| 163 | 169 | /> |
| 164 | - </el-form-item> | |
| 165 | - <el-form-item label="出生日期"> | |
| 166 | - <el-date-picker | |
| 170 | + </ElFormItem> | |
| 171 | + <ElFormItem label="出生日期"> | |
| 172 | + <ElDatePicker | |
| 167 | 173 | v-model="queryParams.birthday" |
| 168 | 174 | value-format="YYYY-MM-DD" |
| 169 | 175 | placeholder="选择出生日期" |
| 170 | 176 | clearable |
| 171 | 177 | class="!w-[240px]" |
| 172 | 178 | /> |
| 173 | - </el-form-item> | |
| 174 | - <el-form-item label="性别"> | |
| 175 | - <el-select | |
| 179 | + </ElFormItem> | |
| 180 | + <ElFormItem label="性别"> | |
| 181 | + <ElSelect | |
| 176 | 182 | v-model="queryParams.sex" |
| 177 | 183 | placeholder="请选择性别" |
| 178 | 184 | clearable |
| 179 | 185 | class="!w-[240px]" |
| 180 | 186 | > |
| 181 | - <el-option | |
| 187 | + <ElOption | |
| 182 | 188 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 183 | 189 | :key="dict.value" |
| 184 | 190 | :value="dict.value" |
| 185 | 191 | :label="dict.label" |
| 186 | 192 | /> |
| 187 | - </el-select> | |
| 188 | - </el-form-item> | |
| 189 | - <el-form-item label="是否有效"> | |
| 190 | - <el-select | |
| 193 | + </ElSelect> | |
| 194 | + </ElFormItem> | |
| 195 | + <ElFormItem label="是否有效"> | |
| 196 | + <ElSelect | |
| 191 | 197 | v-model="queryParams.enabled" |
| 192 | 198 | placeholder="请选择是否有效" |
| 193 | 199 | clearable |
| 194 | 200 | class="!w-[240px]" |
| 195 | 201 | > |
| 196 | - <el-option | |
| 202 | + <ElOption | |
| 197 | 203 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 198 | 204 | :key="dict.value" |
| 199 | 205 | :value="dict.value" |
| 200 | 206 | :label="dict.label" |
| 201 | 207 | /> |
| 202 | - </el-select> | |
| 203 | - </el-form-item> | |
| 204 | - <el-form-item label="创建时间"> | |
| 205 | - <el-date-picker | |
| 208 | + </ElSelect> | |
| 209 | + </ElFormItem> | |
| 210 | + <ElFormItem label="创建时间"> | |
| 211 | + <ElDatePicker | |
| 206 | 212 | v-model="queryParams.createTime" |
| 207 | 213 | type="daterange" |
| 208 | 214 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -211,24 +217,24 @@ onMounted(() => { |
| 211 | 217 | end-placeholder="结束日期" |
| 212 | 218 | class="!w-[240px]" |
| 213 | 219 | /> |
| 214 | - </el-form-item> | |
| 215 | - <el-form-item> | |
| 216 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 217 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 220 | + </ElFormItem> | |
| 221 | + <ElFormItem> | |
| 222 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 223 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 218 | 224 | 搜索 |
| 219 | - </el-button> | |
| 220 | - </el-form-item> | |
| 221 | - </el-form> | |
| 225 | + </ElButton> | |
| 226 | + </ElFormItem> | |
| 227 | + </ElForm> | |
| 222 | 228 | </ContentWrap> |
| 223 | 229 | |
| 224 | 230 | <!-- 列表 --> |
| 225 | 231 | <ContentWrap title="学生"> |
| 226 | 232 | <template #extra> |
| 227 | - <TableToolbar | |
| 233 | + <VbenVxeTableToolbar | |
| 228 | 234 | ref="tableToolbarRef" |
| 229 | 235 | v-model:hidden-search="hiddenSearchBar" |
| 230 | 236 | > |
| 231 | - <el-button | |
| 237 | + <ElButton | |
| 232 | 238 | class="ml-2" |
| 233 | 239 | :icon="h(Plus)" |
| 234 | 240 | type="primary" |
| ... | ... | @@ -236,8 +242,8 @@ onMounted(() => { |
| 236 | 242 | v-access:code="['infra:student:create']" |
| 237 | 243 | > |
| 238 | 244 | {{ $t('ui.actionTitle.create', ['学生']) }} |
| 239 | - </el-button> | |
| 240 | - <el-button | |
| 245 | + </ElButton> | |
| 246 | + <ElButton | |
| 241 | 247 | :icon="h(Download)" |
| 242 | 248 | type="primary" |
| 243 | 249 | class="ml-2" |
| ... | ... | @@ -246,8 +252,8 @@ onMounted(() => { |
| 246 | 252 | v-access:code="['infra:student:export']" |
| 247 | 253 | > |
| 248 | 254 | {{ $t('ui.actionTitle.export') }} |
| 249 | - </el-button> | |
| 250 | - <el-button | |
| 255 | + </ElButton> | |
| 256 | + <ElButton | |
| 251 | 257 | :icon="h(Trash2)" |
| 252 | 258 | type="danger" |
| 253 | 259 | class="ml-2" |
| ... | ... | @@ -256,10 +262,10 @@ onMounted(() => { |
| 256 | 262 | v-access:code="['infra:student:delete']" |
| 257 | 263 | > |
| 258 | 264 | 批量删除 |
| 259 | - </el-button> | |
| 260 | - </TableToolbar> | |
| 265 | + </ElButton> | |
| 266 | + </VbenVxeTableToolbar> | |
| 261 | 267 | </template> |
| 262 | - <vxe-table | |
| 268 | + <VxeTable | |
| 263 | 269 | ref="tableRef" |
| 264 | 270 | :data="list" |
| 265 | 271 | show-overflow |
| ... | ... | @@ -267,36 +273,36 @@ onMounted(() => { |
| 267 | 273 | @checkboxAll="handleRowCheckboxChange" |
| 268 | 274 | @checkboxChange="handleRowCheckboxChange" |
| 269 | 275 | > |
| 270 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 271 | - <vxe-column field="id" title="编号" align="center" /> | |
| 272 | - <vxe-column field="name" title="名字" align="center" /> | |
| 273 | - <vxe-column field="description" title="简介" align="center" /> | |
| 274 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 276 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 277 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 278 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 279 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 280 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 275 | 281 | <template #default="{row}"> |
| 276 | 282 | {{formatDateTime(row.birthday)}} |
| 277 | 283 | </template> |
| 278 | - </vxe-column> | |
| 279 | - <vxe-column field="sex" title="性别" align="center"> | |
| 284 | + </VxeColumn> | |
| 285 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 280 | 286 | <template #default="{row}"> |
| 281 | 287 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 282 | 288 | </template> |
| 283 | - </vxe-column> | |
| 284 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 289 | + </VxeColumn> | |
| 290 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 285 | 291 | <template #default="{row}"> |
| 286 | 292 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 287 | 293 | </template> |
| 288 | - </vxe-column> | |
| 289 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 290 | - <vxe-column field="video" title="附件" align="center" /> | |
| 291 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 292 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 294 | + </VxeColumn> | |
| 295 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 296 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 297 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 298 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 293 | 299 | <template #default="{row}"> |
| 294 | 300 | {{formatDateTime(row.createTime)}} |
| 295 | 301 | </template> |
| 296 | - </vxe-column> | |
| 297 | - <vxe-column field="operation" title="操作" align="center"> | |
| 302 | + </VxeColumn> | |
| 303 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 298 | 304 | <template #default="{row}"> |
| 299 | - <el-button | |
| 305 | + <ElButton | |
| 300 | 306 | size="small" |
| 301 | 307 | type="primary" |
| 302 | 308 | link |
| ... | ... | @@ -304,8 +310,8 @@ onMounted(() => { |
| 304 | 310 | v-access:code="['infra:student:update']" |
| 305 | 311 | > |
| 306 | 312 | {{ $t('ui.actionTitle.edit') }} |
| 307 | - </el-button> | |
| 308 | - <el-button | |
| 313 | + </ElButton> | |
| 314 | + <ElButton | |
| 309 | 315 | size="small" |
| 310 | 316 | type="danger" |
| 311 | 317 | link |
| ... | ... | @@ -314,13 +320,13 @@ onMounted(() => { |
| 314 | 320 | v-access:code="['infra:student:delete']" |
| 315 | 321 | > |
| 316 | 322 | {{ $t('ui.actionTitle.delete') }} |
| 317 | - </el-button> | |
| 323 | + </ElButton> | |
| 318 | 324 | </template> |
| 319 | - </vxe-column> | |
| 320 | - </vxe-table> | |
| 325 | + </VxeColumn> | |
| 326 | + </VxeTable> | |
| 321 | 327 | <!-- 分页 --> |
| 322 | 328 | <div class="mt-2 flex justify-end"> |
| 323 | - <el-pagination | |
| 329 | + <ElPagination | |
| 324 | 330 | :total="total" |
| 325 | 331 | v-model:current-page="queryParams.pageNo" |
| 326 | 332 | v-model:page-size="queryParams.pageSize" | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/vue/form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { useVbenModal } from '@vben/common-ui'; |
| ... | ... | @@ -11,7 +11,7 @@ import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElSelect, El |
| 11 | 11 | |
| 12 | 12 | import { computed, ref, reactive } from 'vue'; |
| 13 | 13 | import { $t } from '#/locales'; |
| 14 | -import { getStudent, createStudent, updateStudent } from '#/api/infra/student'; | |
| 14 | +import { getStudent, createStudent, updateStudent } from '#/api/infra/demo'; | |
| 15 | 15 | |
| 16 | 16 | const emit = defineEmits(['success']); |
| 17 | 17 | |
| ... | ... | @@ -102,56 +102,56 @@ const [Modal, modalApi] = useVbenModal({ |
| 102 | 102 | |
| 103 | 103 | <template> |
| 104 | 104 | <Modal :title="getTitle"> |
| 105 | - <el-form | |
| 105 | + <ElForm | |
| 106 | 106 | ref="formRef" |
| 107 | 107 | :model="formData" |
| 108 | 108 | :rules="rules" |
| 109 | 109 | label-width="120px" |
| 110 | 110 | label-position="right" |
| 111 | 111 | > |
| 112 | - <el-form-item label="名字" prop="name"> | |
| 113 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 114 | - </el-form-item> | |
| 115 | - <el-form-item label="简介" prop="description"> | |
| 116 | - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 117 | - </el-form-item> | |
| 118 | - <el-form-item label="出生日期" prop="birthday"> | |
| 119 | - <el-date-picker | |
| 112 | + <ElFormItem label="名字" prop="name"> | |
| 113 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 114 | + </ElFormItem> | |
| 115 | + <ElFormItem label="简介" prop="description"> | |
| 116 | + <ElInput v-model="formData.description" type="textarea" placeholder="请输入简介" /> | |
| 117 | + </ElFormItem> | |
| 118 | + <ElFormItem label="出生日期" prop="birthday"> | |
| 119 | + <ElDatePicker | |
| 120 | 120 | v-model="formData.birthday" |
| 121 | 121 | value-format="x" |
| 122 | 122 | placeholder="选择出生日期" |
| 123 | 123 | /> |
| 124 | - </el-form-item> | |
| 125 | - <el-form-item label="性别" prop="sex"> | |
| 126 | - <el-select v-model="formData.sex" placeholder="请选择性别"> | |
| 127 | - <el-option | |
| 124 | + </ElFormItem> | |
| 125 | + <ElFormItem label="性别" prop="sex"> | |
| 126 | + <ElSelect v-model="formData.sex" placeholder="请选择性别"> | |
| 127 | + <ElOption | |
| 128 | 128 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 129 | 129 | :key="dict.value" |
| 130 | 130 | :value="dict.value" |
| 131 | 131 | :label="dict.label" |
| 132 | 132 | /> |
| 133 | - </el-select> | |
| 134 | - </el-form-item> | |
| 135 | - <el-form-item label="是否有效" prop="enabled"> | |
| 136 | - <el-radio-group v-model="formData.enabled"> | |
| 137 | - <el-radio | |
| 133 | + </ElSelect> | |
| 134 | + </ElFormItem> | |
| 135 | + <ElFormItem label="是否有效" prop="enabled"> | |
| 136 | + <ElRadioGroup v-model="formData.enabled"> | |
| 137 | + <ElRadio | |
| 138 | 138 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 139 | 139 | :key="dict.value" |
| 140 | - :label="dict.value" | |
| 140 | + :value="dict.value" | |
| 141 | 141 | > |
| 142 | 142 | {{ dict.label }} |
| 143 | - </el-radio> | |
| 144 | - </el-radio-group> | |
| 145 | - </el-form-item> | |
| 146 | - <el-form-item label="头像" prop="avatar"> | |
| 143 | + </ElRadio> | |
| 144 | + </ElRadioGroup> | |
| 145 | + </ElFormItem> | |
| 146 | + <ElFormItem label="头像" prop="avatar"> | |
| 147 | 147 | <ImageUpload v-model="formData.avatar" /> |
| 148 | - </el-form-item> | |
| 149 | - <el-form-item label="附件" prop="video"> | |
| 148 | + </ElFormItem> | |
| 149 | + <ElFormItem label="附件" prop="video"> | |
| 150 | 150 | <FileUpload v-model="formData.video" /> |
| 151 | - </el-form-item> | |
| 152 | - <el-form-item label="备注" prop="memo"> | |
| 151 | + </ElFormItem> | |
| 152 | + <ElFormItem label="备注" prop="memo"> | |
| 153 | 153 | <RichTextarea v-model="formData.memo" height="500px" /> |
| 154 | - </el-form-item> | |
| 155 | - </el-form> | |
| 154 | + </ElFormItem> | |
| 155 | + </ElForm> | |
| 156 | 156 | </Modal> |
| 157 | 157 | </template> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/vue/import-form
| ... | ... | @@ -47,6 +47,16 @@ function handleChange(file: any) { |
| 47 | 47 | } |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | +/** 移除文件 */ | |
| 51 | +function handleRemove() { | |
| 52 | + fileRef.value = null; | |
| 53 | +} | |
| 54 | + | |
| 55 | +/** 超出文件数量 */ | |
| 56 | +function handleExceed() { | |
| 57 | + ElMessage.warning('只能选择一个文件,请先移除已选文件'); | |
| 58 | +} | |
| 59 | + | |
| 50 | 60 | /** 下载导入模板 */ |
| 51 | 61 | async function handleDownload() { |
| 52 | 62 | const data = await importStudentTemplate(); |
| ... | ... | @@ -61,6 +71,8 @@ async function handleDownload() { |
| 61 | 71 | :limit="1" |
| 62 | 72 | accept=".xls,.xlsx" |
| 63 | 73 | :on-change="handleChange" |
| 74 | + :on-remove="handleRemove" | |
| 75 | + :on-exceed="handleExceed" | |
| 64 | 76 | :auto-upload="false" |
| 65 | 77 | > |
| 66 | 78 | <ElButton type="primary"> 选择 Excel 文件 </ElButton> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_one_importEnable/vue/index
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { StudentApi } from '#/api/infra/student'; | |
| 2 | +import type { StudentApi } from '#/api/infra/demo'; | |
| 3 | 3 | |
| 4 | 4 | import { ref, h, reactive, onMounted, nextTick } from 'vue'; |
| 5 | 5 | |
| ... | ... | @@ -17,7 +17,7 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 17 | 17 | |
| 18 | 18 | import { $t } from '#/locales'; |
| 19 | 19 | import { isEmpty } from '@vben/utils'; |
| 20 | -import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/student'; | |
| 20 | +import { getStudentPage, deleteStudent, deleteStudentList, exportStudent } from '#/api/infra/demo'; | |
| 21 | 21 | import StudentImport from './modules/import-form.vue'; |
| 22 | 22 | |
| 23 | 23 | |
| ... | ... | @@ -28,12 +28,11 @@ const total = ref(0) // 列表的总页数 |
| 28 | 28 | const queryParams = reactive({ |
| 29 | 29 | pageNo: 1, |
| 30 | 30 | pageSize: 10, |
| 31 | - name: undefined, | |
| 32 | - birthday: undefined, | |
| 33 | - birthday: undefined, | |
| 34 | - sex: undefined, | |
| 35 | - enabled: undefined, | |
| 36 | - createTime: undefined, | |
| 31 | + name: undefined, | |
| 32 | + birthday: undefined, | |
| 33 | + sex: undefined, | |
| 34 | + enabled: undefined, | |
| 35 | + createTime: undefined, | |
| 37 | 36 | }) |
| 38 | 37 | const queryFormRef = ref() // 搜索的表单 |
| 39 | 38 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -136,7 +135,14 @@ function handleRowCheckboxChange({ |
| 136 | 135 | async function handleExport() { |
| 137 | 136 | try { |
| 138 | 137 | exportLoading.value = true; |
| 139 | - const data = await exportStudent(queryParams); | |
| 138 | + const params = cloneDeep(queryParams) as any; | |
| 139 | + if (params.birthday && Array.isArray(params.birthday)) { | |
| 140 | + params.birthday = (params.birthday as string[]).join(','); | |
| 141 | + } | |
| 142 | + if (params.createTime && Array.isArray(params.createTime)) { | |
| 143 | + params.createTime = (params.createTime as string[]).join(','); | |
| 144 | + } | |
| 145 | + const data = await exportStudent(params); | |
| 140 | 146 | downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); |
| 141 | 147 | }finally { |
| 142 | 148 | exportLoading.value = false; |
| ... | ... | @@ -159,61 +165,61 @@ onMounted(() => { |
| 159 | 165 | |
| 160 | 166 | <ContentWrap v-if="!hiddenSearchBar"> |
| 161 | 167 | <!-- 搜索工作栏 --> |
| 162 | - <el-form | |
| 168 | + <ElForm | |
| 163 | 169 | :model="queryParams" |
| 164 | 170 | ref="queryFormRef" |
| 165 | 171 | inline |
| 166 | 172 | > |
| 167 | - <el-form-item label="名字"> | |
| 168 | - <el-input | |
| 173 | + <ElFormItem label="名字"> | |
| 174 | + <ElInput | |
| 169 | 175 | v-model="queryParams.name" |
| 170 | 176 | placeholder="请输入名字" |
| 171 | 177 | clearable |
| 172 | 178 | @keyup.enter="handleQuery" |
| 173 | 179 | class="!w-[240px]" |
| 174 | 180 | /> |
| 175 | - </el-form-item> | |
| 176 | - <el-form-item label="出生日期"> | |
| 177 | - <el-date-picker | |
| 181 | + </ElFormItem> | |
| 182 | + <ElFormItem label="出生日期"> | |
| 183 | + <ElDatePicker | |
| 178 | 184 | v-model="queryParams.birthday" |
| 179 | 185 | value-format="YYYY-MM-DD" |
| 180 | 186 | placeholder="选择出生日期" |
| 181 | 187 | clearable |
| 182 | 188 | class="!w-[240px]" |
| 183 | 189 | /> |
| 184 | - </el-form-item> | |
| 185 | - <el-form-item label="性别"> | |
| 186 | - <el-select | |
| 190 | + </ElFormItem> | |
| 191 | + <ElFormItem label="性别"> | |
| 192 | + <ElSelect | |
| 187 | 193 | v-model="queryParams.sex" |
| 188 | 194 | placeholder="请选择性别" |
| 189 | 195 | clearable |
| 190 | 196 | class="!w-[240px]" |
| 191 | 197 | > |
| 192 | - <el-option | |
| 198 | + <ElOption | |
| 193 | 199 | v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" |
| 194 | 200 | :key="dict.value" |
| 195 | 201 | :value="dict.value" |
| 196 | 202 | :label="dict.label" |
| 197 | 203 | /> |
| 198 | - </el-select> | |
| 199 | - </el-form-item> | |
| 200 | - <el-form-item label="是否有效"> | |
| 201 | - <el-select | |
| 204 | + </ElSelect> | |
| 205 | + </ElFormItem> | |
| 206 | + <ElFormItem label="是否有效"> | |
| 207 | + <ElSelect | |
| 202 | 208 | v-model="queryParams.enabled" |
| 203 | 209 | placeholder="请选择是否有效" |
| 204 | 210 | clearable |
| 205 | 211 | class="!w-[240px]" |
| 206 | 212 | > |
| 207 | - <el-option | |
| 213 | + <ElOption | |
| 208 | 214 | v-for="dict in getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean')" |
| 209 | 215 | :key="dict.value" |
| 210 | 216 | :value="dict.value" |
| 211 | 217 | :label="dict.label" |
| 212 | 218 | /> |
| 213 | - </el-select> | |
| 214 | - </el-form-item> | |
| 215 | - <el-form-item label="创建时间"> | |
| 216 | - <el-date-picker | |
| 219 | + </ElSelect> | |
| 220 | + </ElFormItem> | |
| 221 | + <ElFormItem label="创建时间"> | |
| 222 | + <ElDatePicker | |
| 217 | 223 | v-model="queryParams.createTime" |
| 218 | 224 | type="daterange" |
| 219 | 225 | value-format="YYYY-MM-DD" |
| ... | ... | @@ -222,24 +228,24 @@ onMounted(() => { |
| 222 | 228 | end-placeholder="结束日期" |
| 223 | 229 | class="!w-[240px]" |
| 224 | 230 | /> |
| 225 | - </el-form-item> | |
| 226 | - <el-form-item> | |
| 227 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 228 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 231 | + </ElFormItem> | |
| 232 | + <ElFormItem> | |
| 233 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 234 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 229 | 235 | 搜索 |
| 230 | - </el-button> | |
| 231 | - </el-form-item> | |
| 232 | - </el-form> | |
| 236 | + </ElButton> | |
| 237 | + </ElFormItem> | |
| 238 | + </ElForm> | |
| 233 | 239 | </ContentWrap> |
| 234 | 240 | |
| 235 | 241 | <!-- 列表 --> |
| 236 | 242 | <ContentWrap title="学生"> |
| 237 | 243 | <template #extra> |
| 238 | - <TableToolbar | |
| 244 | + <VbenVxeTableToolbar | |
| 239 | 245 | ref="tableToolbarRef" |
| 240 | 246 | v-model:hidden-search="hiddenSearchBar" |
| 241 | 247 | > |
| 242 | - <el-button | |
| 248 | + <ElButton | |
| 243 | 249 | class="ml-2" |
| 244 | 250 | :icon="h(Plus)" |
| 245 | 251 | type="primary" |
| ... | ... | @@ -247,16 +253,16 @@ onMounted(() => { |
| 247 | 253 | v-access:code="['infra:student:create']" |
| 248 | 254 | > |
| 249 | 255 | {{ $t('ui.actionTitle.create', ['学生']) }} |
| 250 | - </el-button> | |
| 251 | - <el-button | |
| 256 | + </ElButton> | |
| 257 | + <ElButton | |
| 252 | 258 | class="ml-2" |
| 253 | 259 | type="primary" |
| 254 | 260 | @click="handleImport" |
| 255 | 261 | v-access:code="['infra:student:import']" |
| 256 | 262 | > |
| 257 | 263 | 导入 |
| 258 | - </el-button> | |
| 259 | - <el-button | |
| 264 | + </ElButton> | |
| 265 | + <ElButton | |
| 260 | 266 | :icon="h(Download)" |
| 261 | 267 | type="primary" |
| 262 | 268 | class="ml-2" |
| ... | ... | @@ -265,8 +271,8 @@ onMounted(() => { |
| 265 | 271 | v-access:code="['infra:student:export']" |
| 266 | 272 | > |
| 267 | 273 | {{ $t('ui.actionTitle.export') }} |
| 268 | - </el-button> | |
| 269 | - <el-button | |
| 274 | + </ElButton> | |
| 275 | + <ElButton | |
| 270 | 276 | :icon="h(Trash2)" |
| 271 | 277 | type="danger" |
| 272 | 278 | class="ml-2" |
| ... | ... | @@ -275,10 +281,10 @@ onMounted(() => { |
| 275 | 281 | v-access:code="['infra:student:delete']" |
| 276 | 282 | > |
| 277 | 283 | 批量删除 |
| 278 | - </el-button> | |
| 279 | - </TableToolbar> | |
| 284 | + </ElButton> | |
| 285 | + </VbenVxeTableToolbar> | |
| 280 | 286 | </template> |
| 281 | - <vxe-table | |
| 287 | + <VxeTable | |
| 282 | 288 | ref="tableRef" |
| 283 | 289 | :data="list" |
| 284 | 290 | show-overflow |
| ... | ... | @@ -286,36 +292,36 @@ onMounted(() => { |
| 286 | 292 | @checkboxAll="handleRowCheckboxChange" |
| 287 | 293 | @checkboxChange="handleRowCheckboxChange" |
| 288 | 294 | > |
| 289 | - <vxe-column type="checkbox" width="40"></vxe-column> | |
| 290 | - <vxe-column field="id" title="编号" align="center" /> | |
| 291 | - <vxe-column field="name" title="名字" align="center" /> | |
| 292 | - <vxe-column field="description" title="简介" align="center" /> | |
| 293 | - <vxe-column field="birthday" title="出生日期" align="center"> | |
| 295 | + <VxeColumn type="checkbox" width="40"></VxeColumn> | |
| 296 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 297 | + <VxeColumn field="name" title="名字" align="center" /> | |
| 298 | + <VxeColumn field="description" title="简介" align="center" /> | |
| 299 | + <VxeColumn field="birthday" title="出生日期" align="center"> | |
| 294 | 300 | <template #default="{row}"> |
| 295 | 301 | {{formatDateTime(row.birthday)}} |
| 296 | 302 | </template> |
| 297 | - </vxe-column> | |
| 298 | - <vxe-column field="sex" title="性别" align="center"> | |
| 303 | + </VxeColumn> | |
| 304 | + <VxeColumn field="sex" title="性别" align="center"> | |
| 299 | 305 | <template #default="{row}"> |
| 300 | 306 | <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> |
| 301 | 307 | </template> |
| 302 | - </vxe-column> | |
| 303 | - <vxe-column field="enabled" title="是否有效" align="center"> | |
| 308 | + </VxeColumn> | |
| 309 | + <VxeColumn field="enabled" title="是否有效" align="center"> | |
| 304 | 310 | <template #default="{row}"> |
| 305 | 311 | <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="row.enabled" /> |
| 306 | 312 | </template> |
| 307 | - </vxe-column> | |
| 308 | - <vxe-column field="avatar" title="头像" align="center" /> | |
| 309 | - <vxe-column field="video" title="附件" align="center" /> | |
| 310 | - <vxe-column field="memo" title="备注" align="center" /> | |
| 311 | - <vxe-column field="createTime" title="创建时间" align="center"> | |
| 313 | + </VxeColumn> | |
| 314 | + <VxeColumn field="avatar" title="头像" align="center" /> | |
| 315 | + <VxeColumn field="video" title="附件" align="center" /> | |
| 316 | + <VxeColumn field="memo" title="备注" align="center" /> | |
| 317 | + <VxeColumn field="createTime" title="创建时间" align="center"> | |
| 312 | 318 | <template #default="{row}"> |
| 313 | 319 | {{formatDateTime(row.createTime)}} |
| 314 | 320 | </template> |
| 315 | - </vxe-column> | |
| 316 | - <vxe-column field="operation" title="操作" align="center"> | |
| 321 | + </VxeColumn> | |
| 322 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 317 | 323 | <template #default="{row}"> |
| 318 | - <el-button | |
| 324 | + <ElButton | |
| 319 | 325 | size="small" |
| 320 | 326 | type="primary" |
| 321 | 327 | link |
| ... | ... | @@ -323,8 +329,8 @@ onMounted(() => { |
| 323 | 329 | v-access:code="['infra:student:update']" |
| 324 | 330 | > |
| 325 | 331 | {{ $t('ui.actionTitle.edit') }} |
| 326 | - </el-button> | |
| 327 | - <el-button | |
| 332 | + </ElButton> | |
| 333 | + <ElButton | |
| 328 | 334 | size="small" |
| 329 | 335 | type="danger" |
| 330 | 336 | link |
| ... | ... | @@ -333,13 +339,13 @@ onMounted(() => { |
| 333 | 339 | v-access:code="['infra:student:delete']" |
| 334 | 340 | > |
| 335 | 341 | {{ $t('ui.actionTitle.delete') }} |
| 336 | - </el-button> | |
| 342 | + </ElButton> | |
| 337 | 343 | </template> |
| 338 | - </vxe-column> | |
| 339 | - </vxe-table> | |
| 344 | + </VxeColumn> | |
| 345 | + </VxeTable> | |
| 340 | 346 | <!-- 分页 --> |
| 341 | 347 | <div class="mt-2 flex justify-end"> |
| 342 | - <el-pagination | |
| 348 | + <ElPagination | |
| 343 | 349 | :total="total" |
| 344 | 350 | v-model:current-page="queryParams.pageNo" |
| 345 | 351 | v-model:page-size="queryParams.pageSize" | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_tree/vue/form
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { CategoryApi } from '#/api/infra/category'; | |
| 2 | +import type { CategoryApi } from '#/api/infra/demo'; | |
| 3 | 3 | import type { FormRules } from 'element-plus'; |
| 4 | 4 | |
| 5 | 5 | import { useVbenModal } from '@vben/common-ui'; |
| ... | ... | @@ -7,12 +7,12 @@ import { getDictOptions } from '@vben/hooks'; |
| 7 | 7 | import { Tinymce as RichTextarea } from '#/components/tinymce'; |
| 8 | 8 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 9 | 9 | import { ElMessage, ElTabs, ElTabPane, ElForm, ElFormItem, ElInput, ElSelect, ElOption, ElRadioGroup, ElRadio, ElCheckboxGroup, ElCheckbox, ElDatePicker, ElTreeSelect } from 'element-plus'; |
| 10 | -import { getCategoryList } from '#/api/infra/category'; | |
| 10 | +import { getCategoryList } from '#/api/infra/demo'; | |
| 11 | 11 | import { handleTree } from '@vben/utils' |
| 12 | 12 | |
| 13 | 13 | import { computed, ref, reactive } from 'vue'; |
| 14 | 14 | import { $t } from '#/locales'; |
| 15 | -import { getCategory, createCategory, updateCategory } from '#/api/infra/category'; | |
| 15 | +import { getCategory, createCategory, updateCategory } from '#/api/infra/demo'; | |
| 16 | 16 | |
| 17 | 17 | const emit = defineEmits(['success']); |
| 18 | 18 | |
| ... | ... | @@ -98,18 +98,18 @@ const [Modal, modalApi] = useVbenModal({ |
| 98 | 98 | |
| 99 | 99 | <template> |
| 100 | 100 | <Modal :title="getTitle"> |
| 101 | - <el-form | |
| 101 | + <ElForm | |
| 102 | 102 | ref="formRef" |
| 103 | 103 | :model="formData" |
| 104 | 104 | :rules="rules" |
| 105 | 105 | label-width="120px" |
| 106 | 106 | label-position="right" |
| 107 | 107 | > |
| 108 | - <el-form-item label="名字" prop="name"> | |
| 109 | - <el-input v-model="formData.name" placeholder="请输入名字" /> | |
| 110 | - </el-form-item> | |
| 111 | - <el-form-item label="父编号" prop="parentId"> | |
| 112 | - <el-tree-select | |
| 108 | + <ElFormItem label="名字" prop="name"> | |
| 109 | + <ElInput v-model="formData.name" placeholder="请输入名字" /> | |
| 110 | + </ElFormItem> | |
| 111 | + <ElFormItem label="父编号" prop="parentId"> | |
| 112 | + <ElTreeSelect | |
| 113 | 113 | v-model="formData.parentId" |
| 114 | 114 | :data="categoryTree" |
| 115 | 115 | :props="{ |
| ... | ... | @@ -121,7 +121,7 @@ const [Modal, modalApi] = useVbenModal({ |
| 121 | 121 | default-expand-all |
| 122 | 122 | placeholder="请选择父编号" |
| 123 | 123 | /> |
| 124 | - </el-form-item> | |
| 125 | - </el-form> | |
| 124 | + </ElFormItem> | |
| 125 | + </ElForm> | |
| 126 | 126 | </Modal> |
| 127 | 127 | </template> |
| 128 | 128 | \ No newline at end of file | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_general_tree/vue/index
| 1 | 1 | <script lang="ts" setup> |
| 2 | -import type { CategoryApi } from '#/api/infra/category'; | |
| 2 | +import type { CategoryApi } from '#/api/infra/demo'; | |
| 3 | 3 | |
| 4 | 4 | import { ref, h, reactive, onMounted, nextTick } from 'vue'; |
| 5 | 5 | |
| ... | ... | @@ -16,14 +16,14 @@ import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; |
| 16 | 16 | |
| 17 | 17 | import { $t } from '#/locales'; |
| 18 | 18 | import { handleTree,isEmpty } from '@vben/utils' |
| 19 | -import { getCategoryList, deleteCategory, exportCategory } from '#/api/infra/category'; | |
| 19 | +import { getCategoryList, deleteCategory, exportCategory } from '#/api/infra/demo'; | |
| 20 | 20 | |
| 21 | 21 | |
| 22 | 22 | const loading = ref(true) // 列表的加载中 |
| 23 | 23 | const list = ref<any[]>([]) // 树列表的数据 |
| 24 | 24 | |
| 25 | 25 | const queryParams = reactive({ |
| 26 | - name: undefined, | |
| 26 | + name: undefined, | |
| 27 | 27 | }) |
| 28 | 28 | const queryFormRef = ref() // 搜索的表单 |
| 29 | 29 | const exportLoading = ref(false) // 导出的加载中 |
| ... | ... | @@ -89,7 +89,8 @@ async function handleDelete(row: CategoryApi.Category) { |
| 89 | 89 | async function handleExport() { |
| 90 | 90 | try { |
| 91 | 91 | exportLoading.value = true; |
| 92 | - const data = await exportCategory(queryParams); | |
| 92 | + const params = cloneDeep(queryParams) as any; | |
| 93 | + const data = await exportCategory(params); | |
| 93 | 94 | downloadFileFromBlobPart({ fileName: '分类.xls', source: data }); |
| 94 | 95 | }finally { |
| 95 | 96 | exportLoading.value = false; |
| ... | ... | @@ -117,40 +118,40 @@ onMounted(() => { |
| 117 | 118 | |
| 118 | 119 | <ContentWrap v-if="!hiddenSearchBar"> |
| 119 | 120 | <!-- 搜索工作栏 --> |
| 120 | - <el-form | |
| 121 | + <ElForm | |
| 121 | 122 | :model="queryParams" |
| 122 | 123 | ref="queryFormRef" |
| 123 | 124 | inline |
| 124 | 125 | > |
| 125 | - <el-form-item label="名字"> | |
| 126 | - <el-input | |
| 126 | + <ElFormItem label="名字"> | |
| 127 | + <ElInput | |
| 127 | 128 | v-model="queryParams.name" |
| 128 | 129 | placeholder="请输入名字" |
| 129 | 130 | clearable |
| 130 | 131 | @keyup.enter="handleQuery" |
| 131 | 132 | class="!w-[240px]" |
| 132 | 133 | /> |
| 133 | - </el-form-item> | |
| 134 | - <el-form-item> | |
| 135 | - <el-button class="ml-2" @click="resetQuery"> 重置 </el-button> | |
| 136 | - <el-button class="ml-2" @click="handleQuery" type="primary"> | |
| 134 | + </ElFormItem> | |
| 135 | + <ElFormItem> | |
| 136 | + <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | |
| 137 | + <ElButton class="ml-2" @click="handleQuery" type="primary"> | |
| 137 | 138 | 搜索 |
| 138 | - </el-button> | |
| 139 | - </el-form-item> | |
| 140 | - </el-form> | |
| 139 | + </ElButton> | |
| 140 | + </ElFormItem> | |
| 141 | + </ElForm> | |
| 141 | 142 | </ContentWrap> |
| 142 | 143 | |
| 143 | 144 | <!-- 列表 --> |
| 144 | 145 | <ContentWrap title="分类"> |
| 145 | 146 | <template #extra> |
| 146 | - <TableToolbar | |
| 147 | + <VbenVxeTableToolbar | |
| 147 | 148 | ref="tableToolbarRef" |
| 148 | 149 | v-model:hidden-search="hiddenSearchBar" |
| 149 | 150 | > |
| 150 | - <el-button @click="handleExpand" class="mr-2"> | |
| 151 | + <ElButton @click="handleExpand" class="mr-2"> | |
| 151 | 152 | {{ isExpanded ? '收缩' : '展开' }} |
| 152 | - </el-button> | |
| 153 | - <el-button | |
| 153 | + </ElButton> | |
| 154 | + <ElButton | |
| 154 | 155 | class="ml-2" |
| 155 | 156 | :icon="h(Plus)" |
| 156 | 157 | type="primary" |
| ... | ... | @@ -158,8 +159,8 @@ onMounted(() => { |
| 158 | 159 | v-access:code="['infra:category:create']" |
| 159 | 160 | > |
| 160 | 161 | {{ $t('ui.actionTitle.create', ['分类']) }} |
| 161 | - </el-button> | |
| 162 | - <el-button | |
| 162 | + </ElButton> | |
| 163 | + <ElButton | |
| 163 | 164 | :icon="h(Download)" |
| 164 | 165 | type="primary" |
| 165 | 166 | class="ml-2" |
| ... | ... | @@ -168,10 +169,10 @@ onMounted(() => { |
| 168 | 169 | v-access:code="['infra:category:export']" |
| 169 | 170 | > |
| 170 | 171 | {{ $t('ui.actionTitle.export') }} |
| 171 | - </el-button> | |
| 172 | - </TableToolbar> | |
| 172 | + </ElButton> | |
| 173 | + </VbenVxeTableToolbar> | |
| 173 | 174 | </template> |
| 174 | - <vxe-table | |
| 175 | + <VxeTable | |
| 175 | 176 | ref="tableRef" |
| 176 | 177 | :data="list" |
| 177 | 178 | :tree-config="{ |
| ... | ... | @@ -184,12 +185,12 @@ onMounted(() => { |
| 184 | 185 | show-overflow |
| 185 | 186 | :loading="loading" |
| 186 | 187 | > |
| 187 | - <vxe-column field="id" title="编号" align="center" /> | |
| 188 | - <vxe-column field="name" title="名字" align="center" tree-node/> | |
| 189 | - <vxe-column field="parentId" title="父编号" align="center" /> | |
| 190 | - <vxe-column field="operation" title="操作" align="center"> | |
| 188 | + <VxeColumn field="id" title="编号" align="center" /> | |
| 189 | + <VxeColumn field="name" title="名字" align="center" tree-node/> | |
| 190 | + <VxeColumn field="parentId" title="父编号" align="center" /> | |
| 191 | + <VxeColumn field="operation" title="操作" align="center"> | |
| 191 | 192 | <template #default="{row}"> |
| 192 | - <el-button | |
| 193 | + <ElButton | |
| 193 | 194 | size="small" |
| 194 | 195 | type="primary" |
| 195 | 196 | link |
| ... | ... | @@ -197,8 +198,8 @@ onMounted(() => { |
| 197 | 198 | v-access:code="['infra:category:create']" |
| 198 | 199 | > |
| 199 | 200 | 新增下级 |
| 200 | - </el-button> | |
| 201 | - <el-button | |
| 201 | + </ElButton> | |
| 202 | + <ElButton | |
| 202 | 203 | size="small" |
| 203 | 204 | type="primary" |
| 204 | 205 | link |
| ... | ... | @@ -206,8 +207,8 @@ onMounted(() => { |
| 206 | 207 | v-access:code="['infra:category:update']" |
| 207 | 208 | > |
| 208 | 209 | {{ $t('ui.actionTitle.edit') }} |
| 209 | - </el-button> | |
| 210 | - <el-button | |
| 210 | + </ElButton> | |
| 211 | + <ElButton | |
| 211 | 212 | size="small" |
| 212 | 213 | type="danger" |
| 213 | 214 | link |
| ... | ... | @@ -217,10 +218,10 @@ onMounted(() => { |
| 217 | 218 | v-access:code="['infra:category:delete']" |
| 218 | 219 | > |
| 219 | 220 | {{ $t('ui.actionTitle.delete') }} |
| 220 | - </el-button> | |
| 221 | + </ElButton> | |
| 221 | 222 | </template> |
| 222 | - </vxe-column> | |
| 223 | - </vxe-table> | |
| 223 | + </VxeColumn> | |
| 224 | + </VxeTable> | |
| 224 | 225 | </ContentWrap> |
| 225 | 226 | </Page> |
| 226 | 227 | </template> |
| 227 | 228 | \ No newline at end of file | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_erp/ts/data
| ... | ... | @@ -42,7 +42,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 42 | 42 | rules: 'required', |
| 43 | 43 | component: 'DatePicker', |
| 44 | 44 | componentProps: { |
| 45 | - showTime: true, | |
| 45 | + type: 'datetime', | |
| 46 | 46 | format: 'YYYY-MM-DD HH:mm:ss', |
| 47 | 47 | valueFormat: 'x', |
| 48 | 48 | class: '!w-full', |
| ... | ... | @@ -65,8 +65,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 65 | 65 | component: 'RadioGroup', |
| 66 | 66 | componentProps: { |
| 67 | 67 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 68 | - buttonStyle: 'solid', | |
| 69 | - optionType: 'button', | |
| 68 | + isButton: true, | |
| 70 | 69 | }, |
| 71 | 70 | }, |
| 72 | 71 | { |
| ... | ... | @@ -277,7 +276,7 @@ export function useStudentContactFormSchema(): VbenFormSchema[] { |
| 277 | 276 | rules: 'required', |
| 278 | 277 | component: 'DatePicker', |
| 279 | 278 | componentProps: { |
| 280 | - showTime: true, | |
| 279 | + type: 'datetime', | |
| 281 | 280 | format: 'YYYY-MM-DD HH:mm:ss', |
| 282 | 281 | valueFormat: 'x', |
| 283 | 282 | class: '!w-full', |
| ... | ... | @@ -300,8 +299,7 @@ export function useStudentContactFormSchema(): VbenFormSchema[] { |
| 300 | 299 | component: 'RadioGroup', |
| 301 | 300 | componentProps: { |
| 302 | 301 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 303 | - buttonStyle: 'solid', | |
| 304 | - optionType: 'button', | |
| 302 | + isButton: true, | |
| 305 | 303 | }, |
| 306 | 304 | }, |
| 307 | 305 | { |
| ... | ... | @@ -520,7 +518,7 @@ export function useStudentTeacherFormSchema(): VbenFormSchema[] { |
| 520 | 518 | rules: 'required', |
| 521 | 519 | component: 'DatePicker', |
| 522 | 520 | componentProps: { |
| 523 | - showTime: true, | |
| 521 | + type: 'datetime', | |
| 524 | 522 | format: 'YYYY-MM-DD HH:mm:ss', |
| 525 | 523 | valueFormat: 'x', |
| 526 | 524 | class: '!w-full', |
| ... | ... | @@ -543,8 +541,7 @@ export function useStudentTeacherFormSchema(): VbenFormSchema[] { |
| 543 | 541 | component: 'RadioGroup', |
| 544 | 542 | componentProps: { |
| 545 | 543 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 546 | - buttonStyle: 'solid', | |
| 547 | - optionType: 'button', | |
| 544 | + isButton: true, | |
| 548 | 545 | }, |
| 549 | 546 | }, |
| 550 | 547 | { | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_erp/vue/form
| ... | ... | @@ -5,7 +5,7 @@ import { computed, ref } from 'vue'; |
| 5 | 5 | |
| 6 | 6 | import { useVbenModal } from '@vben/common-ui'; |
| 7 | 7 | |
| 8 | -import { ElMessage, ElTabs, ElTabPane } from 'element-plus'; | |
| 8 | +import { ElMessage } from 'element-plus'; | |
| 9 | 9 | |
| 10 | 10 | import { useVbenForm } from '#/adapter/form'; |
| 11 | 11 | import { createStudent, getStudent, updateStudent } from '#/api/infra/demo'; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/ts/data
| ... | ... | @@ -42,7 +42,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 42 | 42 | rules: 'required', |
| 43 | 43 | component: 'DatePicker', |
| 44 | 44 | componentProps: { |
| 45 | - showTime: true, | |
| 45 | + type: 'datetime', | |
| 46 | 46 | format: 'YYYY-MM-DD HH:mm:ss', |
| 47 | 47 | valueFormat: 'x', |
| 48 | 48 | class: '!w-full', |
| ... | ... | @@ -65,8 +65,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 65 | 65 | component: 'RadioGroup', |
| 66 | 66 | componentProps: { |
| 67 | 67 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 68 | - buttonStyle: 'solid', | |
| 69 | - optionType: 'button', | |
| 68 | + isButton: true, | |
| 70 | 69 | }, |
| 71 | 70 | }, |
| 72 | 71 | { |
| ... | ... | @@ -270,7 +269,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 270 | 269 | minWidth: 120, |
| 271 | 270 | slots: { default: 'sex' }, |
| 272 | 271 | params: { |
| 273 | - options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'boolean'), | |
| 272 | + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), | |
| 274 | 273 | }, |
| 275 | 274 | }, |
| 276 | 275 | { |
| ... | ... | @@ -310,7 +309,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 310 | 309 | } |
| 311 | 310 | |
| 312 | 311 | /** 列表的字段 */ |
| 313 | - export function useStudentContactGridColumns(): VxeTableGridOptions<StudentApi.StudentContact>['columns'] { | |
| 312 | + export function useStudentContactGridColumns(): VxeTableGridOptions<InfraStudentApi.StudentContact>['columns'] { | |
| 314 | 313 | return [ |
| 315 | 314 | { |
| 316 | 315 | field: 'id', |
| ... | ... | @@ -444,7 +443,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 444 | 443 | rules: 'required', |
| 445 | 444 | component: 'DatePicker', |
| 446 | 445 | componentProps: { |
| 447 | - showTime: true, | |
| 446 | + type: 'datetime', | |
| 448 | 447 | format: 'YYYY-MM-DD HH:mm:ss', |
| 449 | 448 | valueFormat: 'x', |
| 450 | 449 | class: '!w-full', |
| ... | ... | @@ -467,8 +466,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 467 | 466 | component: 'RadioGroup', |
| 468 | 467 | componentProps: { |
| 469 | 468 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 470 | - buttonStyle: 'solid', | |
| 471 | - optionType: 'button', | |
| 469 | + isButton: true, | |
| 472 | 470 | }, |
| 473 | 471 | }, |
| 474 | 472 | { |
| ... | ... | @@ -492,7 +490,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 492 | 490 | } |
| 493 | 491 | |
| 494 | 492 | /** 列表的字段 */ |
| 495 | - export function useStudentTeacherGridColumns(): VxeTableGridOptions<StudentApi.StudentTeacher>['columns'] { | |
| 493 | + export function useStudentTeacherGridColumns(): VxeTableGridOptions<InfraStudentApi.StudentTeacher>['columns'] { | |
| 496 | 494 | return [ |
| 497 | 495 | { |
| 498 | 496 | field: 'id', | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/vue/form
| ... | ... | @@ -5,7 +5,7 @@ import { computed, ref } from 'vue'; |
| 5 | 5 | |
| 6 | 6 | import { useVbenModal } from '@vben/common-ui'; |
| 7 | 7 | |
| 8 | -import { ElMessage } from 'element-plus'; | |
| 8 | +import { ElMessage, ElTabPane, ElTabs } from 'element-plus'; | |
| 9 | 9 | |
| 10 | 10 | import { useVbenForm } from '#/adapter/form'; |
| 11 | 11 | import { createStudent, getStudent, updateStudent } from '#/api/infra/demo'; |
| ... | ... | @@ -48,7 +48,12 @@ const [Modal, modalApi] = useVbenModal({ |
| 48 | 48 | return; |
| 49 | 49 | } |
| 50 | 50 | // 校验子表单 |
| 51 | - const studentTeacherValid = await studentTeacherFormRef.value?.validate(); | |
| 51 | + const studentContactValid = await studentContactFormRef.value?.validate(); | |
| 52 | + if (!studentContactValid) { | |
| 53 | + subTabsName.value = 'studentContact'; | |
| 54 | + return; | |
| 55 | + } | |
| 56 | + const studentTeacherValid = await studentTeacherFormRef.value?.validate(); | |
| 52 | 57 | if (!studentTeacherValid) { |
| 53 | 58 | subTabsName.value = 'studentTeacher'; |
| 54 | 59 | return; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/vue/student-contact-form
| ... | ... | @@ -6,10 +6,9 @@ |
| 6 | 6 | import { $t } from '#/locales'; |
| 7 | 7 | |
| 8 | 8 | import { Plus } from "@vben/icons"; |
| 9 | -import { ElButton, ElTabs, ElTabPane, ElCheckbox, ElInput, ElSelect, ElOption, ElRadioGroup, ElCheckboxGroup, ElDatePicker } from 'element-plus'; | |
| 9 | +import { ElButton, ElCheckbox, ElCheckboxGroup, ElDatePicker, ElInput, ElMessage, ElOption, ElRadio, ElRadioGroup, ElSelect, ElTabPane, ElTabs } from 'element-plus'; | |
| 10 | 10 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 11 | -import type { OnActionClickParams } from '#/adapter/vxe-table'; | |
| 12 | -import { useVbenVxeGrid } from '#/adapter/vxe-table'; | |
| 11 | +import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; | |
| 13 | 12 | import { useStudentContactGridEditColumns } from '../data'; |
| 14 | 13 | import { getStudentContactListByStudentId } from '#/api/infra/demo'; |
| 15 | 14 | |
| ... | ... | @@ -17,22 +16,9 @@ const props = defineProps<{ |
| 17 | 16 | studentId?: number // 学生编号(主表的关联字段) |
| 18 | 17 | }>() |
| 19 | 18 | |
| 20 | - /** 表格操作按钮的回调函数 */ | |
| 21 | -function onActionClick({ | |
| 22 | - code, | |
| 23 | - row, | |
| 24 | -}: OnActionClickParams<InfraStudentApi.StudentContact>) { | |
| 25 | - switch (code) { | |
| 26 | - case 'delete': { | |
| 27 | - onDelete(row); | |
| 28 | - break; | |
| 29 | - } | |
| 30 | - } | |
| 31 | -} | |
| 32 | - | |
| 33 | -const [Grid, gridApi] = useVbenVxeGrid({ | |
| 19 | + const [Grid, gridApi] = useVbenVxeGrid({ | |
| 34 | 20 | gridOptions: { |
| 35 | - columns: useStudentContactGridEditColumns(onActionClick), | |
| 21 | + columns: useStudentContactGridEditColumns(), | |
| 36 | 22 | border: true, |
| 37 | 23 | showOverflow: true, |
| 38 | 24 | autoResize: true, |
| ... | ... | @@ -51,7 +37,7 @@ gridOptions: { |
| 51 | 37 | |
| 52 | 38 | /** 添加学生联系人 */ |
| 53 | 39 | const onAdd = async () => { |
| 54 | - await gridApi.grid.insertAt({} as StudentApi.StudentContact, -1); | |
| 40 | + await gridApi.grid.insertAt({} as InfraStudentApi.StudentContact, -1); | |
| 55 | 41 | } |
| 56 | 42 | |
| 57 | 43 | /** 删除学生联系人 */ |
| ... | ... | @@ -59,26 +45,96 @@ const onDelete = async (row: InfraStudentApi.StudentContact) => { |
| 59 | 45 | await gridApi.grid.remove(row); |
| 60 | 46 | } |
| 61 | 47 | |
| 62 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 63 | -defineExpose({ | |
| 64 | - getData: (): InfraStudentApi.StudentContact[] => { | |
| 65 | - const data = gridApi.grid.getData() as InfraStudentApi.StudentContact[]; | |
| 66 | - const removeRecords = gridApi.grid.getRemoveRecords() as InfraStudentApi.StudentContact[]; | |
| 67 | - const insertRecords = gridApi.grid.getInsertRecords() as InfraStudentApi.StudentContact[]; | |
| 68 | - return data | |
| 69 | - .filter((row) => !removeRecords.some((removed) => removed.id === row.id)) | |
| 70 | - .concat(insertRecords.map((row: any) => ({ ...row, id: undefined }))); | |
| 71 | - }, | |
| 72 | -}); | |
| 48 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 49 | +function getData(): InfraStudentApi.StudentContact[] { | |
| 50 | + const { fullData } = gridApi.grid.getTableData(); | |
| 51 | + const inserted = new Set(gridApi.grid.getInsertRecords()); | |
| 52 | + return fullData.map((row) => | |
| 53 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 54 | + ); | |
| 55 | +} | |
| 56 | + | |
| 57 | +/** 校验子表必填字段 */ | |
| 58 | +function validate(): boolean { | |
| 59 | + for (const [index, row] of getData().entries()) { | |
| 60 | + if ( | |
| 61 | + row.name === null || | |
| 62 | + row.name === undefined || | |
| 63 | + (typeof row.name === 'string' && String(row.name).trim() === '') || | |
| 64 | + (Array.isArray(row.name) && row.name.length === 0) | |
| 65 | + ) { | |
| 66 | + ElMessage.error(`第 ${index + 1} 行:名字不能为空`); | |
| 67 | + return false; | |
| 68 | + } | |
| 69 | + if ( | |
| 70 | + row.description === null || | |
| 71 | + row.description === undefined || | |
| 72 | + (typeof row.description === 'string' && String(row.description).trim() === '') || | |
| 73 | + (Array.isArray(row.description) && row.description.length === 0) | |
| 74 | + ) { | |
| 75 | + ElMessage.error(`第 ${index + 1} 行:简介不能为空`); | |
| 76 | + return false; | |
| 77 | + } | |
| 78 | + if ( | |
| 79 | + row.birthday === null || | |
| 80 | + row.birthday === undefined || | |
| 81 | + (typeof row.birthday === 'string' && String(row.birthday).trim() === '') || | |
| 82 | + (Array.isArray(row.birthday) && row.birthday.length === 0) | |
| 83 | + ) { | |
| 84 | + ElMessage.error(`第 ${index + 1} 行:出生日期不能为空`); | |
| 85 | + return false; | |
| 86 | + } | |
| 87 | + if ( | |
| 88 | + row.sex === null || | |
| 89 | + row.sex === undefined || | |
| 90 | + (typeof row.sex === 'string' && String(row.sex).trim() === '') || | |
| 91 | + (Array.isArray(row.sex) && row.sex.length === 0) | |
| 92 | + ) { | |
| 93 | + ElMessage.error(`第 ${index + 1} 行:性别不能为空`); | |
| 94 | + return false; | |
| 95 | + } | |
| 96 | + if ( | |
| 97 | + row.enabled === null || | |
| 98 | + row.enabled === undefined || | |
| 99 | + (typeof row.enabled === 'string' && String(row.enabled).trim() === '') || | |
| 100 | + (Array.isArray(row.enabled) && row.enabled.length === 0) | |
| 101 | + ) { | |
| 102 | + ElMessage.error(`第 ${index + 1} 行:是否有效不能为空`); | |
| 103 | + return false; | |
| 104 | + } | |
| 105 | + if ( | |
| 106 | + row.avatar === null || | |
| 107 | + row.avatar === undefined || | |
| 108 | + (typeof row.avatar === 'string' && String(row.avatar).trim() === '') || | |
| 109 | + (Array.isArray(row.avatar) && row.avatar.length === 0) | |
| 110 | + ) { | |
| 111 | + ElMessage.error(`第 ${index + 1} 行:头像不能为空`); | |
| 112 | + return false; | |
| 113 | + } | |
| 114 | + if ( | |
| 115 | + row.memo === null || | |
| 116 | + row.memo === undefined || | |
| 117 | + (typeof row.memo === 'string' && String(row.memo).trim() === '') || | |
| 118 | + (Array.isArray(row.memo) && row.memo.length === 0) | |
| 119 | + ) { | |
| 120 | + ElMessage.error(`第 ${index + 1} 行:备注不能为空`); | |
| 121 | + return false; | |
| 122 | + } | |
| 123 | + } | |
| 124 | + return true; | |
| 125 | +} | |
| 126 | + | |
| 127 | +defineExpose({ getData, validate }); | |
| 73 | 128 | |
| 74 | 129 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 75 | 130 | watch( |
| 76 | 131 | () => props.studentId, |
| 77 | 132 | async (val) => { |
| 133 | + await nextTick(); | |
| 78 | 134 | if (!val) { |
| 135 | + await gridApi.grid.loadData([]); | |
| 79 | 136 | return; |
| 80 | 137 | } |
| 81 | - await nextTick(); | |
| 82 | 138 | await gridApi.grid.loadData(await getStudentContactListByStudentId(props.studentId!)); |
| 83 | 139 | }, |
| 84 | 140 | { immediate: true }, |
| ... | ... | @@ -88,13 +144,13 @@ watch( |
| 88 | 144 | <template> |
| 89 | 145 | <Grid class="mx-4"> |
| 90 | 146 | <template #name="{ row }"> |
| 91 | - <el-input v-model="row.name" /> | |
| 147 | + <ElInput v-model="row.name" /> | |
| 92 | 148 | </template> |
| 93 | 149 | <template #description="{ row }"> |
| 94 | - <el-input v-model="row.description" type="textarea" /> | |
| 150 | + <ElInput v-model="row.description" type="textarea" /> | |
| 95 | 151 | </template> |
| 96 | 152 | <template #birthday="{ row }"> |
| 97 | - <el-date-picker | |
| 153 | + <ElDatePicker | |
| 98 | 154 | v-model="row.birthday" |
| 99 | 155 | type="datetime" |
| 100 | 156 | value-format="x" |
| ... | ... | @@ -102,16 +158,16 @@ watch( |
| 102 | 158 | /> |
| 103 | 159 | </template> |
| 104 | 160 | <template #sex="{ row, column }"> |
| 105 | - <el-select v-model="row.sex" class="w-full"> | |
| 106 | - <el-option v-for="option in column.params.options" :key="option.value" :value="option.value" :label="option.label" /> | |
| 107 | - </el-select> | |
| 161 | + <ElSelect v-model="row.sex" class="w-full"> | |
| 162 | + <ElOption v-for="option in column.params.options" :key="option.value" :value="option.value" :label="option.label" /> | |
| 163 | + </ElSelect> | |
| 108 | 164 | </template> |
| 109 | 165 | <template #enabled="{ row, column }"> |
| 110 | - <el-radio-group v-model="row.enabled"> | |
| 111 | - <el-radio v-for="option in column.params.options" :key="option.value" :label="option.value"> | |
| 166 | + <ElRadioGroup v-model="row.enabled"> | |
| 167 | + <ElRadio v-for="option in column.params.options" :key="option.value" :value="option.value"> | |
| 112 | 168 | {{ option.label }} |
| 113 | - </el-radio> | |
| 114 | - </el-radio-group> | |
| 169 | + </ElRadio> | |
| 170 | + </ElRadioGroup> | |
| 115 | 171 | </template> |
| 116 | 172 | <template #avatar="{ row }"> |
| 117 | 173 | <ImageUpload v-model="row.avatar" /> |
| ... | ... | @@ -120,12 +176,25 @@ watch( |
| 120 | 176 | <FileUpload v-model="row.video" /> |
| 121 | 177 | </template> |
| 122 | 178 | <template #memo="{ row }"> |
| 123 | - <el-input v-model="row.memo" type="textarea" /> | |
| 179 | + <ElInput v-model="row.memo" type="textarea" /> | |
| 124 | 180 | </template> |
| 181 | + <template #actions="{ row }"> | |
| 182 | + <TableAction | |
| 183 | + :actions="[ | |
| 184 | + { | |
| 185 | + label: $t('common.delete'), | |
| 186 | + type: 'danger', link: true, | |
| 187 | + icon: ACTION_ICON.DELETE, | |
| 188 | + auth: ['infra:student:delete'], | |
| 189 | + onClick: onDelete.bind(null, row), | |
| 190 | + }, | |
| 191 | + ]" | |
| 192 | + /> | |
| 193 | + </template> | |
| 125 | 194 | </Grid> |
| 126 | 195 | <div class="flex justify-center -mt-4"> |
| 127 | - <el-button :icon="Plus" type="primary" plain @click="onAdd" v-access:code="['infra:student:create']"> | |
| 196 | + <ElButton :icon="Plus" type="primary" plain @click="onAdd" v-access:code="['infra:student:create']"> | |
| 128 | 197 | {{ $t('ui.actionTitle.create', ['学生联系人']) }} |
| 129 | - </el-button> | |
| 198 | + </ElButton> | |
| 130 | 199 | </div> |
| 131 | 200 | </template> |
| 132 | 201 | \ No newline at end of file | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_inner/vue/student-teacher-form
| ... | ... | @@ -39,10 +39,11 @@ defineExpose({ |
| 39 | 39 | watch( |
| 40 | 40 | () => props.studentId, |
| 41 | 41 | async (val) => { |
| 42 | + await nextTick(); | |
| 43 | + await formApi.resetForm(); | |
| 42 | 44 | if (!val) { |
| 43 | 45 | return; |
| 44 | 46 | } |
| 45 | - await nextTick(); | |
| 46 | 47 | await formApi.setValues(await getStudentTeacherByStudentId(props.studentId!)); |
| 47 | 48 | }, |
| 48 | 49 | { immediate: true }, | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/ts/data
| ... | ... | @@ -42,7 +42,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 42 | 42 | rules: 'required', |
| 43 | 43 | component: 'DatePicker', |
| 44 | 44 | componentProps: { |
| 45 | - showTime: true, | |
| 45 | + type: 'datetime', | |
| 46 | 46 | format: 'YYYY-MM-DD HH:mm:ss', |
| 47 | 47 | valueFormat: 'x', |
| 48 | 48 | class: '!w-full', |
| ... | ... | @@ -65,8 +65,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 65 | 65 | component: 'RadioGroup', |
| 66 | 66 | componentProps: { |
| 67 | 67 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 68 | - buttonStyle: 'solid', | |
| 69 | - optionType: 'button', | |
| 68 | + isButton: true, | |
| 70 | 69 | }, |
| 71 | 70 | }, |
| 72 | 71 | { |
| ... | ... | @@ -269,7 +268,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 269 | 268 | minWidth: 120, |
| 270 | 269 | slots: { default: 'sex' }, |
| 271 | 270 | params: { |
| 272 | - options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'boolean'), | |
| 271 | + options: getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number'), | |
| 273 | 272 | }, |
| 274 | 273 | }, |
| 275 | 274 | { |
| ... | ... | @@ -345,7 +344,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 345 | 344 | rules: 'required', |
| 346 | 345 | component: 'DatePicker', |
| 347 | 346 | componentProps: { |
| 348 | - showTime: true, | |
| 347 | + type: 'datetime', | |
| 349 | 348 | format: 'YYYY-MM-DD HH:mm:ss', |
| 350 | 349 | valueFormat: 'x', |
| 351 | 350 | class: '!w-full', |
| ... | ... | @@ -368,8 +367,7 @@ export function useGridColumns(): VxeTableGridOptions<InfraStudentApi.Student>[' |
| 368 | 367 | component: 'RadioGroup', |
| 369 | 368 | componentProps: { |
| 370 | 369 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 371 | - buttonStyle: 'solid', | |
| 372 | - optionType: 'button', | |
| 370 | + isButton: true, | |
| 373 | 371 | }, |
| 374 | 372 | }, |
| 375 | 373 | { | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/vue/form
| ... | ... | @@ -5,7 +5,7 @@ import { computed, ref } from 'vue'; |
| 5 | 5 | |
| 6 | 6 | import { useVbenModal } from '@vben/common-ui'; |
| 7 | 7 | |
| 8 | -import { ElMessage } from 'element-plus'; | |
| 8 | +import { ElMessage, ElTabPane, ElTabs } from 'element-plus'; | |
| 9 | 9 | |
| 10 | 10 | import { useVbenForm } from '#/adapter/form'; |
| 11 | 11 | import { createStudent, getStudent, updateStudent } from '#/api/infra/demo'; |
| ... | ... | @@ -48,7 +48,12 @@ const [Modal, modalApi] = useVbenModal({ |
| 48 | 48 | return; |
| 49 | 49 | } |
| 50 | 50 | // 校验子表单 |
| 51 | - const studentTeacherValid = await studentTeacherFormRef.value?.validate(); | |
| 51 | + const studentContactValid = await studentContactFormRef.value?.validate(); | |
| 52 | + if (!studentContactValid) { | |
| 53 | + subTabsName.value = 'studentContact'; | |
| 54 | + return; | |
| 55 | + } | |
| 56 | + const studentTeacherValid = await studentTeacherFormRef.value?.validate(); | |
| 52 | 57 | if (!studentTeacherValid) { |
| 53 | 58 | subTabsName.value = 'studentTeacher'; |
| 54 | 59 | return; | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/vue/student-contact-form
| ... | ... | @@ -6,10 +6,9 @@ |
| 6 | 6 | import { $t } from '#/locales'; |
| 7 | 7 | |
| 8 | 8 | import { Plus } from "@vben/icons"; |
| 9 | -import { ElButton, ElTabs, ElTabPane, ElCheckbox, ElInput, ElSelect, ElOption, ElRadioGroup, ElCheckboxGroup, ElDatePicker } from 'element-plus'; | |
| 9 | +import { ElButton, ElCheckbox, ElCheckboxGroup, ElDatePicker, ElInput, ElMessage, ElOption, ElRadio, ElRadioGroup, ElSelect, ElTabPane, ElTabs } from 'element-plus'; | |
| 10 | 10 | import { ImageUpload, FileUpload } from "#/components/upload"; |
| 11 | -import type { OnActionClickParams } from '#/adapter/vxe-table'; | |
| 12 | -import { useVbenVxeGrid } from '#/adapter/vxe-table'; | |
| 11 | +import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; | |
| 13 | 12 | import { useStudentContactGridEditColumns } from '../data'; |
| 14 | 13 | import { getStudentContactListByStudentId } from '#/api/infra/demo'; |
| 15 | 14 | |
| ... | ... | @@ -17,22 +16,9 @@ const props = defineProps<{ |
| 17 | 16 | studentId?: number // 学生编号(主表的关联字段) |
| 18 | 17 | }>() |
| 19 | 18 | |
| 20 | - /** 表格操作按钮的回调函数 */ | |
| 21 | -function onActionClick({ | |
| 22 | - code, | |
| 23 | - row, | |
| 24 | -}: OnActionClickParams<InfraStudentApi.StudentContact>) { | |
| 25 | - switch (code) { | |
| 26 | - case 'delete': { | |
| 27 | - onDelete(row); | |
| 28 | - break; | |
| 29 | - } | |
| 30 | - } | |
| 31 | -} | |
| 32 | - | |
| 33 | -const [Grid, gridApi] = useVbenVxeGrid({ | |
| 19 | + const [Grid, gridApi] = useVbenVxeGrid({ | |
| 34 | 20 | gridOptions: { |
| 35 | - columns: useStudentContactGridEditColumns(onActionClick), | |
| 21 | + columns: useStudentContactGridEditColumns(), | |
| 36 | 22 | border: true, |
| 37 | 23 | showOverflow: true, |
| 38 | 24 | autoResize: true, |
| ... | ... | @@ -51,7 +37,7 @@ gridOptions: { |
| 51 | 37 | |
| 52 | 38 | /** 添加学生联系人 */ |
| 53 | 39 | const onAdd = async () => { |
| 54 | - await gridApi.grid.insertAt({} as StudentApi.StudentContact, -1); | |
| 40 | + await gridApi.grid.insertAt({} as InfraStudentApi.StudentContact, -1); | |
| 55 | 41 | } |
| 56 | 42 | |
| 57 | 43 | /** 删除学生联系人 */ |
| ... | ... | @@ -59,26 +45,96 @@ const onDelete = async (row: InfraStudentApi.StudentContact) => { |
| 59 | 45 | await gridApi.grid.remove(row); |
| 60 | 46 | } |
| 61 | 47 | |
| 62 | -/** 提供获取表格数据的方法供父组件调用 */ | |
| 63 | -defineExpose({ | |
| 64 | - getData: (): InfraStudentApi.StudentContact[] => { | |
| 65 | - const data = gridApi.grid.getData() as InfraStudentApi.StudentContact[]; | |
| 66 | - const removeRecords = gridApi.grid.getRemoveRecords() as InfraStudentApi.StudentContact[]; | |
| 67 | - const insertRecords = gridApi.grid.getInsertRecords() as InfraStudentApi.StudentContact[]; | |
| 68 | - return data | |
| 69 | - .filter((row) => !removeRecords.some((removed) => removed.id === row.id)) | |
| 70 | - .concat(insertRecords.map((row: any) => ({ ...row, id: undefined }))); | |
| 71 | - }, | |
| 72 | -}); | |
| 48 | +/** 获取当前子表数据,新增行不提交表格生成的临时编号 */ | |
| 49 | +function getData(): InfraStudentApi.StudentContact[] { | |
| 50 | + const { fullData } = gridApi.grid.getTableData(); | |
| 51 | + const inserted = new Set(gridApi.grid.getInsertRecords()); | |
| 52 | + return fullData.map((row) => | |
| 53 | + inserted.has(row) ? { ...row, id: undefined } : { ...row }, | |
| 54 | + ); | |
| 55 | +} | |
| 56 | + | |
| 57 | +/** 校验子表必填字段 */ | |
| 58 | +function validate(): boolean { | |
| 59 | + for (const [index, row] of getData().entries()) { | |
| 60 | + if ( | |
| 61 | + row.name === null || | |
| 62 | + row.name === undefined || | |
| 63 | + (typeof row.name === 'string' && String(row.name).trim() === '') || | |
| 64 | + (Array.isArray(row.name) && row.name.length === 0) | |
| 65 | + ) { | |
| 66 | + ElMessage.error(`第 ${index + 1} 行:名字不能为空`); | |
| 67 | + return false; | |
| 68 | + } | |
| 69 | + if ( | |
| 70 | + row.description === null || | |
| 71 | + row.description === undefined || | |
| 72 | + (typeof row.description === 'string' && String(row.description).trim() === '') || | |
| 73 | + (Array.isArray(row.description) && row.description.length === 0) | |
| 74 | + ) { | |
| 75 | + ElMessage.error(`第 ${index + 1} 行:简介不能为空`); | |
| 76 | + return false; | |
| 77 | + } | |
| 78 | + if ( | |
| 79 | + row.birthday === null || | |
| 80 | + row.birthday === undefined || | |
| 81 | + (typeof row.birthday === 'string' && String(row.birthday).trim() === '') || | |
| 82 | + (Array.isArray(row.birthday) && row.birthday.length === 0) | |
| 83 | + ) { | |
| 84 | + ElMessage.error(`第 ${index + 1} 行:出生日期不能为空`); | |
| 85 | + return false; | |
| 86 | + } | |
| 87 | + if ( | |
| 88 | + row.sex === null || | |
| 89 | + row.sex === undefined || | |
| 90 | + (typeof row.sex === 'string' && String(row.sex).trim() === '') || | |
| 91 | + (Array.isArray(row.sex) && row.sex.length === 0) | |
| 92 | + ) { | |
| 93 | + ElMessage.error(`第 ${index + 1} 行:性别不能为空`); | |
| 94 | + return false; | |
| 95 | + } | |
| 96 | + if ( | |
| 97 | + row.enabled === null || | |
| 98 | + row.enabled === undefined || | |
| 99 | + (typeof row.enabled === 'string' && String(row.enabled).trim() === '') || | |
| 100 | + (Array.isArray(row.enabled) && row.enabled.length === 0) | |
| 101 | + ) { | |
| 102 | + ElMessage.error(`第 ${index + 1} 行:是否有效不能为空`); | |
| 103 | + return false; | |
| 104 | + } | |
| 105 | + if ( | |
| 106 | + row.avatar === null || | |
| 107 | + row.avatar === undefined || | |
| 108 | + (typeof row.avatar === 'string' && String(row.avatar).trim() === '') || | |
| 109 | + (Array.isArray(row.avatar) && row.avatar.length === 0) | |
| 110 | + ) { | |
| 111 | + ElMessage.error(`第 ${index + 1} 行:头像不能为空`); | |
| 112 | + return false; | |
| 113 | + } | |
| 114 | + if ( | |
| 115 | + row.memo === null || | |
| 116 | + row.memo === undefined || | |
| 117 | + (typeof row.memo === 'string' && String(row.memo).trim() === '') || | |
| 118 | + (Array.isArray(row.memo) && row.memo.length === 0) | |
| 119 | + ) { | |
| 120 | + ElMessage.error(`第 ${index + 1} 行:备注不能为空`); | |
| 121 | + return false; | |
| 122 | + } | |
| 123 | + } | |
| 124 | + return true; | |
| 125 | +} | |
| 126 | + | |
| 127 | +defineExpose({ getData, validate }); | |
| 73 | 128 | |
| 74 | 129 | /** 监听主表的关联字段的变化,加载对应的子表数据 */ |
| 75 | 130 | watch( |
| 76 | 131 | () => props.studentId, |
| 77 | 132 | async (val) => { |
| 133 | + await nextTick(); | |
| 78 | 134 | if (!val) { |
| 135 | + await gridApi.grid.loadData([]); | |
| 79 | 136 | return; |
| 80 | 137 | } |
| 81 | - await nextTick(); | |
| 82 | 138 | await gridApi.grid.loadData(await getStudentContactListByStudentId(props.studentId!)); |
| 83 | 139 | }, |
| 84 | 140 | { immediate: true }, |
| ... | ... | @@ -88,13 +144,13 @@ watch( |
| 88 | 144 | <template> |
| 89 | 145 | <Grid class="mx-4"> |
| 90 | 146 | <template #name="{ row }"> |
| 91 | - <el-input v-model="row.name" /> | |
| 147 | + <ElInput v-model="row.name" /> | |
| 92 | 148 | </template> |
| 93 | 149 | <template #description="{ row }"> |
| 94 | - <el-input v-model="row.description" type="textarea" /> | |
| 150 | + <ElInput v-model="row.description" type="textarea" /> | |
| 95 | 151 | </template> |
| 96 | 152 | <template #birthday="{ row }"> |
| 97 | - <el-date-picker | |
| 153 | + <ElDatePicker | |
| 98 | 154 | v-model="row.birthday" |
| 99 | 155 | type="datetime" |
| 100 | 156 | value-format="x" |
| ... | ... | @@ -102,16 +158,16 @@ watch( |
| 102 | 158 | /> |
| 103 | 159 | </template> |
| 104 | 160 | <template #sex="{ row, column }"> |
| 105 | - <el-select v-model="row.sex" class="w-full"> | |
| 106 | - <el-option v-for="option in column.params.options" :key="option.value" :value="option.value" :label="option.label" /> | |
| 107 | - </el-select> | |
| 161 | + <ElSelect v-model="row.sex" class="w-full"> | |
| 162 | + <ElOption v-for="option in column.params.options" :key="option.value" :value="option.value" :label="option.label" /> | |
| 163 | + </ElSelect> | |
| 108 | 164 | </template> |
| 109 | 165 | <template #enabled="{ row, column }"> |
| 110 | - <el-radio-group v-model="row.enabled"> | |
| 111 | - <el-radio v-for="option in column.params.options" :key="option.value" :label="option.value"> | |
| 166 | + <ElRadioGroup v-model="row.enabled"> | |
| 167 | + <ElRadio v-for="option in column.params.options" :key="option.value" :value="option.value"> | |
| 112 | 168 | {{ option.label }} |
| 113 | - </el-radio> | |
| 114 | - </el-radio-group> | |
| 169 | + </ElRadio> | |
| 170 | + </ElRadioGroup> | |
| 115 | 171 | </template> |
| 116 | 172 | <template #avatar="{ row }"> |
| 117 | 173 | <ImageUpload v-model="row.avatar" /> |
| ... | ... | @@ -120,12 +176,25 @@ watch( |
| 120 | 176 | <FileUpload v-model="row.video" /> |
| 121 | 177 | </template> |
| 122 | 178 | <template #memo="{ row }"> |
| 123 | - <el-input v-model="row.memo" type="textarea" /> | |
| 179 | + <ElInput v-model="row.memo" type="textarea" /> | |
| 124 | 180 | </template> |
| 181 | + <template #actions="{ row }"> | |
| 182 | + <TableAction | |
| 183 | + :actions="[ | |
| 184 | + { | |
| 185 | + label: $t('common.delete'), | |
| 186 | + type: 'danger', link: true, | |
| 187 | + icon: ACTION_ICON.DELETE, | |
| 188 | + auth: ['infra:student:delete'], | |
| 189 | + onClick: onDelete.bind(null, row), | |
| 190 | + }, | |
| 191 | + ]" | |
| 192 | + /> | |
| 193 | + </template> | |
| 125 | 194 | </Grid> |
| 126 | 195 | <div class="flex justify-center -mt-4"> |
| 127 | - <el-button :icon="Plus" type="primary" plain @click="onAdd" v-access:code="['infra:student:create']"> | |
| 196 | + <ElButton :icon="Plus" type="primary" plain @click="onAdd" v-access:code="['infra:student:create']"> | |
| 128 | 197 | {{ $t('ui.actionTitle.create', ['学生联系人']) }} |
| 129 | - </el-button> | |
| 198 | + </ElButton> | |
| 130 | 199 | </div> |
| 131 | 200 | </template> |
| 132 | 201 | \ No newline at end of file | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_master_normal/vue/student-teacher-form
| ... | ... | @@ -39,10 +39,11 @@ defineExpose({ |
| 39 | 39 | watch( |
| 40 | 40 | () => props.studentId, |
| 41 | 41 | async (val) => { |
| 42 | + await nextTick(); | |
| 43 | + await formApi.resetForm(); | |
| 42 | 44 | if (!val) { |
| 43 | 45 | return; |
| 44 | 46 | } |
| 45 | - await nextTick(); | |
| 46 | 47 | await formApi.setValues(await getStudentTeacherByStudentId(props.studentId!)); |
| 47 | 48 | }, |
| 48 | 49 | { immediate: true }, | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one/ts/data
| ... | ... | @@ -42,7 +42,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 42 | 42 | rules: 'required', |
| 43 | 43 | component: 'DatePicker', |
| 44 | 44 | componentProps: { |
| 45 | - showTime: true, | |
| 45 | + type: 'datetime', | |
| 46 | 46 | format: 'YYYY-MM-DD HH:mm:ss', |
| 47 | 47 | valueFormat: 'x', |
| 48 | 48 | class: '!w-full', |
| ... | ... | @@ -65,8 +65,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 65 | 65 | component: 'RadioGroup', |
| 66 | 66 | componentProps: { |
| 67 | 67 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 68 | - buttonStyle: 'solid', | |
| 69 | - optionType: 'button', | |
| 68 | + isButton: true, | |
| 70 | 69 | }, |
| 71 | 70 | }, |
| 72 | 71 | { | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/ts/data
| ... | ... | @@ -42,7 +42,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 42 | 42 | rules: 'required', |
| 43 | 43 | component: 'DatePicker', |
| 44 | 44 | componentProps: { |
| 45 | - showTime: true, | |
| 45 | + type: 'datetime', | |
| 46 | 46 | format: 'YYYY-MM-DD HH:mm:ss', |
| 47 | 47 | valueFormat: 'x', |
| 48 | 48 | class: '!w-full', |
| ... | ... | @@ -65,8 +65,7 @@ export function useFormSchema(): VbenFormSchema[] { |
| 65 | 65 | component: 'RadioGroup', |
| 66 | 66 | componentProps: { |
| 67 | 67 | options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), |
| 68 | - buttonStyle: 'solid', | |
| 69 | - optionType: 'button', | |
| 68 | + isButton: true, | |
| 70 | 69 | }, |
| 71 | 70 | }, |
| 72 | 71 | { | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_one_importEnable/vue/import-form
| ... | ... | @@ -50,6 +50,16 @@ function handleChange(file: any) { |
| 50 | 50 | } |
| 51 | 51 | } |
| 52 | 52 | |
| 53 | +/** 移除文件 */ | |
| 54 | +function handleRemove() { | |
| 55 | + formApi.setFieldValue('file', undefined); | |
| 56 | +} | |
| 57 | + | |
| 58 | +/** 超出文件数量 */ | |
| 59 | +function handleExceed() { | |
| 60 | + ElMessage.warning('只能选择一个文件,请先移除已选文件'); | |
| 61 | +} | |
| 62 | + | |
| 53 | 63 | /** 下载模板 */ |
| 54 | 64 | async function handleDownload() { |
| 55 | 65 | const data = await importStudentTemplate(); |
| ... | ... | @@ -66,6 +76,8 @@ async function handleDownload() { |
| 66 | 76 | :limit="1" |
| 67 | 77 | accept=".xls,.xlsx" |
| 68 | 78 | :on-change="handleChange" |
| 79 | + :on-remove="handleRemove" | |
| 80 | + :on-exceed="handleExceed" | |
| 69 | 81 | :auto-upload="false" |
| 70 | 82 | > |
| 71 | 83 | <ElButton type="primary"> 选择 Excel 文件 </ElButton> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vben5_ele_schema_tree/ts/data
| ... | ... | @@ -32,13 +32,14 @@ export function useFormSchema(): VbenFormSchema[] { |
| 32 | 32 | id: 0, |
| 33 | 33 | name: '顶级分类', |
| 34 | 34 | }); |
| 35 | - return handleTree(data); | |
| 35 | + return handleTree(data, 'id', 'parentId'); | |
| 36 | 36 | }, |
| 37 | 37 | labelField: 'name', |
| 38 | 38 | valueField: 'id', |
| 39 | 39 | childrenField: 'children', |
| 40 | 40 | placeholder: '请选择上级分类', |
| 41 | - treeDefaultExpandAll: true, | |
| 41 | + defaultExpandAll: true, | |
| 42 | + checkStrictly: true, | |
| 42 | 43 | }, |
| 43 | 44 | rules: 'selectRequired', |
| 44 | 45 | }, | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_erp/vue/StudentContactList
| ... | ... | @@ -64,7 +64,7 @@ |
| 64 | 64 | </el-table-column> |
| 65 | 65 | </el-table> |
| 66 | 66 | <!-- 分页组件 --> |
| 67 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 67 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 68 | 68 | @pagination="getList"/> |
| 69 | 69 | <!-- 对话框(添加 / 修改) --> |
| 70 | 70 | <StudentContactForm ref="formRef" @success="getList" /> |
| ... | ... | @@ -79,9 +79,13 @@ |
| 79 | 79 | components: { |
| 80 | 80 | StudentContactForm |
| 81 | 81 | }, |
| 82 | - props:[ | |
| 83 | - 'studentId' | |
| 84 | - ],// 学生编号(主表的关联字段) | |
| 82 | + props: { | |
| 83 | + // 学生编号(主表的关联字段) | |
| 84 | + studentId: { | |
| 85 | + type: Number, | |
| 86 | + default: undefined | |
| 87 | + } | |
| 88 | + }, | |
| 85 | 89 | data() { |
| 86 | 90 | return { |
| 87 | 91 | // 遮罩层 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_erp/vue/StudentTeacherList
| ... | ... | @@ -64,7 +64,7 @@ |
| 64 | 64 | </el-table-column> |
| 65 | 65 | </el-table> |
| 66 | 66 | <!-- 分页组件 --> |
| 67 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 67 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 68 | 68 | @pagination="getList"/> |
| 69 | 69 | <!-- 对话框(添加 / 修改) --> |
| 70 | 70 | <StudentTeacherForm ref="formRef" @success="getList" /> |
| ... | ... | @@ -79,9 +79,13 @@ |
| 79 | 79 | components: { |
| 80 | 80 | StudentTeacherForm |
| 81 | 81 | }, |
| 82 | - props:[ | |
| 83 | - 'studentId' | |
| 84 | - ],// 学生编号(主表的关联字段) | |
| 82 | + props: { | |
| 83 | + // 学生编号(主表的关联字段) | |
| 84 | + studentId: { | |
| 85 | + type: Number, | |
| 86 | + default: undefined | |
| 87 | + } | |
| 88 | + }, | |
| 85 | 89 | data() { |
| 86 | 90 | return { |
| 87 | 91 | // 遮罩层 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_erp/vue/index
| ... | ... | @@ -53,7 +53,7 @@ |
| 53 | 53 | 批量删除 |
| 54 | 54 | </el-button> |
| 55 | 55 | </el-col> |
| 56 | - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | |
| 56 | + <RightToolbar :showSearch.sync="showSearch" @queryTable="getList"></RightToolbar> | |
| 57 | 57 | </el-row> |
| 58 | 58 | |
| 59 | 59 | <el-table |
| ... | ... | @@ -127,7 +127,7 @@ |
| 127 | 127 | </el-table-column> |
| 128 | 128 | </el-table> |
| 129 | 129 | <!-- 分页组件 --> |
| 130 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 130 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 131 | 131 | @pagination="getList"/> |
| 132 | 132 | <!-- 对话框(添加 / 修改) --> |
| 133 | 133 | <StudentForm ref="formRef" @success="getList" /> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_inner/vue/StudentContactForm
| ... | ... | @@ -97,9 +97,13 @@ |
| 97 | 97 | FileUpload, |
| 98 | 98 | Editor, |
| 99 | 99 | }, |
| 100 | - props:[ | |
| 101 | - 'studentId' | |
| 102 | - ],// 学生编号(主表的关联字段) | |
| 100 | + props: { | |
| 101 | + // 学生编号(主表的关联字段) | |
| 102 | + studentId: { | |
| 103 | + type: Number, | |
| 104 | + default: undefined | |
| 105 | + } | |
| 106 | + }, | |
| 103 | 107 | data() { |
| 104 | 108 | return { |
| 105 | 109 | // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_inner/vue/StudentContactList
| ... | ... | @@ -48,9 +48,13 @@ |
| 48 | 48 | import * as StudentApi from '@/api/infra/demo'; |
| 49 | 49 | export default { |
| 50 | 50 | name: "StudentContactList", |
| 51 | - props:[ | |
| 52 | - 'studentId' | |
| 53 | - ],// 学生编号(主表的关联字段) | |
| 51 | + props: { | |
| 52 | + // 学生编号(主表的关联字段) | |
| 53 | + studentId: { | |
| 54 | + type: Number, | |
| 55 | + default: undefined | |
| 56 | + } | |
| 57 | + }, | |
| 54 | 58 | data() { |
| 55 | 59 | return { |
| 56 | 60 | // 遮罩层 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_inner/vue/StudentTeacherForm
| ... | ... | @@ -53,9 +53,13 @@ |
| 53 | 53 | FileUpload, |
| 54 | 54 | Editor, |
| 55 | 55 | }, |
| 56 | - props:[ | |
| 57 | - 'studentId' | |
| 58 | - ],// 学生编号(主表的关联字段) | |
| 56 | + props: { | |
| 57 | + // 学生编号(主表的关联字段) | |
| 58 | + studentId: { | |
| 59 | + type: Number, | |
| 60 | + default: undefined | |
| 61 | + } | |
| 62 | + }, | |
| 59 | 63 | data() { |
| 60 | 64 | return { |
| 61 | 65 | // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_inner/vue/StudentTeacherList
| ... | ... | @@ -48,9 +48,13 @@ |
| 48 | 48 | import * as StudentApi from '@/api/infra/demo'; |
| 49 | 49 | export default { |
| 50 | 50 | name: "StudentTeacherList", |
| 51 | - props:[ | |
| 52 | - 'studentId' | |
| 53 | - ],// 学生编号(主表的关联字段) | |
| 51 | + props: { | |
| 52 | + // 学生编号(主表的关联字段) | |
| 53 | + studentId: { | |
| 54 | + type: Number, | |
| 55 | + default: undefined | |
| 56 | + } | |
| 57 | + }, | |
| 54 | 58 | data() { |
| 55 | 59 | return { |
| 56 | 60 | // 遮罩层 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_inner/vue/index
| ... | ... | @@ -53,7 +53,7 @@ |
| 53 | 53 | 批量删除 |
| 54 | 54 | </el-button> |
| 55 | 55 | </el-col> |
| 56 | - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | |
| 56 | + <RightToolbar :showSearch.sync="showSearch" @queryTable="getList"></RightToolbar> | |
| 57 | 57 | </el-row> |
| 58 | 58 | |
| 59 | 59 | <el-table |
| ... | ... | @@ -137,7 +137,7 @@ |
| 137 | 137 | </el-table-column> |
| 138 | 138 | </el-table> |
| 139 | 139 | <!-- 分页组件 --> |
| 140 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 140 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 141 | 141 | @pagination="getList"/> |
| 142 | 142 | <!-- 对话框(添加 / 修改) --> |
| 143 | 143 | <StudentForm ref="formRef" @success="getList" /> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_normal/vue/StudentContactForm
| ... | ... | @@ -97,9 +97,13 @@ |
| 97 | 97 | FileUpload, |
| 98 | 98 | Editor, |
| 99 | 99 | }, |
| 100 | - props:[ | |
| 101 | - 'studentId' | |
| 102 | - ],// 学生编号(主表的关联字段) | |
| 100 | + props: { | |
| 101 | + // 学生编号(主表的关联字段) | |
| 102 | + studentId: { | |
| 103 | + type: Number, | |
| 104 | + default: undefined | |
| 105 | + } | |
| 106 | + }, | |
| 103 | 107 | data() { |
| 104 | 108 | return { |
| 105 | 109 | // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_normal/vue/StudentTeacherForm
| ... | ... | @@ -53,9 +53,13 @@ |
| 53 | 53 | FileUpload, |
| 54 | 54 | Editor, |
| 55 | 55 | }, |
| 56 | - props:[ | |
| 57 | - 'studentId' | |
| 58 | - ],// 学生编号(主表的关联字段) | |
| 56 | + props: { | |
| 57 | + // 学生编号(主表的关联字段) | |
| 58 | + studentId: { | |
| 59 | + type: Number, | |
| 60 | + default: undefined | |
| 61 | + } | |
| 62 | + }, | |
| 59 | 63 | data() { |
| 60 | 64 | return { |
| 61 | 65 | // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_master_normal/vue/index
| ... | ... | @@ -53,7 +53,7 @@ |
| 53 | 53 | 批量删除 |
| 54 | 54 | </el-button> |
| 55 | 55 | </el-col> |
| 56 | - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | |
| 56 | + <RightToolbar :showSearch.sync="showSearch" @queryTable="getList"></RightToolbar> | |
| 57 | 57 | </el-row> |
| 58 | 58 | |
| 59 | 59 | <el-table |
| ... | ... | @@ -124,7 +124,7 @@ |
| 124 | 124 | </el-table-column> |
| 125 | 125 | </el-table> |
| 126 | 126 | <!-- 分页组件 --> |
| 127 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 127 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 128 | 128 | @pagination="getList"/> |
| 129 | 129 | <!-- 对话框(添加 / 修改) --> |
| 130 | 130 | <StudentForm ref="formRef" @success="getList" /> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_one/vue/index
| ... | ... | @@ -53,7 +53,7 @@ |
| 53 | 53 | 批量删除 |
| 54 | 54 | </el-button> |
| 55 | 55 | </el-col> |
| 56 | - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | |
| 56 | + <RightToolbar :showSearch.sync="showSearch" @queryTable="getList"></RightToolbar> | |
| 57 | 57 | </el-row> |
| 58 | 58 | |
| 59 | 59 | <el-table |
| ... | ... | @@ -124,7 +124,7 @@ |
| 124 | 124 | </el-table-column> |
| 125 | 125 | </el-table> |
| 126 | 126 | <!-- 分页组件 --> |
| 127 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 127 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 128 | 128 | @pagination="getList"/> |
| 129 | 129 | <!-- 对话框(添加 / 修改) --> |
| 130 | 130 | <StudentForm ref="formRef" @success="getList" /> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_one_importEnable/vue/index
| ... | ... | @@ -61,7 +61,7 @@ |
| 61 | 61 | 批量删除 |
| 62 | 62 | </el-button> |
| 63 | 63 | </el-col> |
| 64 | - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | |
| 64 | + <RightToolbar :showSearch.sync="showSearch" @queryTable="getList"></RightToolbar> | |
| 65 | 65 | </el-row> |
| 66 | 66 | <input ref="importFileRef" type="file" style="display: none" accept=".xls,.xlsx" @change="handleImportFileChange" /> |
| 67 | 67 | |
| ... | ... | @@ -133,7 +133,7 @@ |
| 133 | 133 | </el-table-column> |
| 134 | 134 | </el-table> |
| 135 | 135 | <!-- 分页组件 --> |
| 136 | - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 136 | + <Pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" | |
| 137 | 137 | @pagination="getList"/> |
| 138 | 138 | <!-- 对话框(添加 / 修改) --> |
| 139 | 139 | <StudentForm ref="formRef" @success="getList" /> | ... | ... |
yudao-module-infra/src/test/resources/codegen/vue2_tree/vue/index
yudao-module-infra/src/test/resources/codegen/vue3_master_erp/vue/StudentContactForm
yudao-module-infra/src/test/resources/codegen/vue3_master_erp/vue/StudentForm
yudao-module-infra/src/test/resources/codegen/vue3_master_erp/vue/StudentTeacherForm
yudao-module-infra/src/test/resources/codegen/vue3_master_inner/vue/StudentContactForm
yudao-module-infra/src/test/resources/codegen/vue3_master_inner/vue/StudentForm
yudao-module-infra/src/test/resources/codegen/vue3_master_inner/vue/StudentTeacherForm
yudao-module-infra/src/test/resources/codegen/vue3_master_normal/vue/StudentContactForm
yudao-module-infra/src/test/resources/codegen/vue3_master_normal/vue/StudentForm
yudao-module-infra/src/test/resources/codegen/vue3_master_normal/vue/StudentTeacherForm
yudao-module-infra/src/test/resources/codegen/vue3_one/vue/StudentForm
yudao-module-infra/src/test/resources/codegen/vue3_one_importEnable/vue/StudentForm