Commit cb6b7a754e8631703c1fad6ebe2d17c983410e3a
1 parent
9d272e79
Vue3 CRUD Schema 模版,index 和 form 完善
Showing
3 changed files
with
135 additions
and
141 deletions
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/codegen/inner/CodegenEngine.java
| @@ -112,6 +112,10 @@ public class CodegenEngine { | @@ -112,6 +112,10 @@ public class CodegenEngine { | ||
| 112 | // Vue3 Schema 模版 | 112 | // Vue3 Schema 模版 |
| 113 | .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/data.ts"), | 113 | .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/data.ts"), |
| 114 | vue3FilePath("views/${table.moduleName}/${classNameVar}/${classNameVar}.data.ts")) | 114 | vue3FilePath("views/${table.moduleName}/${classNameVar}/${classNameVar}.data.ts")) |
| 115 | + .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/index.vue"), | ||
| 116 | + vue3FilePath("views/${table.moduleName}/${classNameVar}/index.vue")) | ||
| 117 | + .put(CodegenFrontTypeEnum.VUE3_SCHEMA.getType(), vue3SchemaTemplatePath("views/form.vue"), | ||
| 118 | + vue3FilePath("views/${table.moduleName}/${classNameVar}/${simpleClassName}Form.vue")) | ||
| 115 | .build(); | 119 | .build(); |
| 116 | 120 | ||
| 117 | @Resource | 121 | @Resource |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/form.vue.vm
0 → 100644
| 1 | +<template> | ||
| 2 | + <Dialog :title="dialogTitle" v-model="dialogVisible"> | ||
| 3 | + <Form ref="formRef" :schema="allSchemas.formSchema" :rules="rules" v-loading="formLoading" /> | ||
| 4 | + <template #footer> | ||
| 5 | + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> | ||
| 6 | + <el-button @click="dialogVisible = false">取 消</el-button> | ||
| 7 | + </template> | ||
| 8 | + </Dialog> | ||
| 9 | +</template> | ||
| 10 | +<script setup lang="ts"> | ||
| 11 | + import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}' | ||
| 12 | +import { rules, allSchemas } from './${classNameVar}.data' | ||
| 13 | +const { t } = useI18n() // 国际化 | ||
| 14 | +const message = useMessage() // 消息弹窗 | ||
| 15 | + | ||
| 16 | +const dialogVisible = ref(false) // 弹窗的是否展示 | ||
| 17 | +const dialogTitle = ref('') // 弹窗的标题 | ||
| 18 | +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 | ||
| 19 | +const formType = ref('') // 表单的类型:create - 新增;update - 修改 | ||
| 20 | +const formRef = ref() // 表单 Ref | ||
| 21 | + | ||
| 22 | +/** 打开弹窗 */ | ||
| 23 | +const open = async (type: string, id?: number) => { | ||
| 24 | + dialogVisible.value = true | ||
| 25 | + dialogTitle.value = t('action.' + type) | ||
| 26 | + formType.value = type | ||
| 27 | + // 修改时,设置数据 | ||
| 28 | + if (id) { | ||
| 29 | + formLoading.value = true | ||
| 30 | + try { | ||
| 31 | + const data = await ${simpleClassName}Api.get${simpleClassName}(id) | ||
| 32 | + formRef.value.setValues(data) | ||
| 33 | + } finally { | ||
| 34 | + formLoading.value = false | ||
| 35 | + } | ||
| 36 | + } | ||
| 37 | +} | ||
| 38 | +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 | ||
| 39 | + | ||
| 40 | +/** 提交表单 */ | ||
| 41 | +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 | ||
| 42 | +const submitForm = async () => { | ||
| 43 | + // 校验表单 | ||
| 44 | + if (!formRef) return | ||
| 45 | + const valid = await formRef.value.getElFormRef().validate() | ||
| 46 | + if (!valid) return | ||
| 47 | + // 提交请求 | ||
| 48 | + formLoading.value = true | ||
| 49 | + try { | ||
| 50 | + const data = formRef.value.formModel as ${simpleClassName}Api.${simpleClassName}VO | ||
| 51 | + if (formType.value === 'create') { | ||
| 52 | + await ${simpleClassName}Api.create${simpleClassName}(data) | ||
| 53 | + message.success(t('common.createSuccess')) | ||
| 54 | + } else { | ||
| 55 | + await ${simpleClassName}Api.update${simpleClassName}(data) | ||
| 56 | + message.success(t('common.updateSuccess')) | ||
| 57 | + } | ||
| 58 | + dialogVisible.value = false | ||
| 59 | + // 发送操作成功的事件 | ||
| 60 | + emit('success') | ||
| 61 | + } finally { | ||
| 62 | + formLoading.value = false | ||
| 63 | + } | ||
| 64 | +} | ||
| 65 | +</script> |
yudao-module-infra/yudao-module-infra-biz/src/main/resources/codegen/vue3_schema/views/index.vue.vm
| 1 | <template> | 1 | <template> |
| 2 | + <!-- 搜索工作栏 --> | ||
| 2 | <ContentWrap> | 3 | <ContentWrap> |
| 3 | - <!-- 列表 --> | ||
| 4 | - <XTable @register="registerTable"> | ||
| 5 | - <template #toolbar_buttons> | ||
| 6 | - <!-- 操作:新增 --> | ||
| 7 | - <XButton | 4 | + <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams"> |
| 5 | + <!-- 新增等操作按钮 --> | ||
| 6 | + <template #actionMore> | ||
| 7 | + <el-button | ||
| 8 | type="primary" | 8 | type="primary" |
| 9 | - preIcon="ep:zoom-in" | ||
| 10 | - :title="t('action.add')" | 9 | + plain |
| 10 | + @click="openForm('create')" | ||
| 11 | v-hasPermi="['${permissionPrefix}:create']" | 11 | v-hasPermi="['${permissionPrefix}:create']" |
| 12 | - @click="handleCreate()" | ||
| 13 | - /> | ||
| 14 | - <!-- 操作:导出 --> | ||
| 15 | - <XButton | ||
| 16 | - type="warning" | ||
| 17 | - preIcon="ep:download" | ||
| 18 | - :title="t('action.export')" | ||
| 19 | - v-hasPermi="['${permissionPrefix}:export']" | ||
| 20 | - @click="exportList('${table.classComment}.xls')" | ||
| 21 | - /> | 12 | + > |
| 13 | + <Icon icon="ep:plus" class="mr-5px" /> 新增 | ||
| 14 | + </el-button> | ||
| 22 | </template> | 15 | </template> |
| 23 | - <template #actionbtns_default="{ row }"> | ||
| 24 | - <!-- 操作:修改 --> | ||
| 25 | - <XTextButton | ||
| 26 | - preIcon="ep:edit" | ||
| 27 | - :title="t('action.edit')" | 16 | + </Search> |
| 17 | + </ContentWrap> | ||
| 18 | + | ||
| 19 | + <!-- 列表 --> | ||
| 20 | + <ContentWrap> | ||
| 21 | + <Table | ||
| 22 | + :columns="allSchemas.tableColumns" | ||
| 23 | + :data="tableObject.tableList" | ||
| 24 | + :loading="tableObject.loading" | ||
| 25 | + :pagination="{ | ||
| 26 | + total: tableObject.total | ||
| 27 | + }" | ||
| 28 | + v-model:pageSize="tableObject.pageSize" | ||
| 29 | + v-model:currentPage="tableObject.currentPage" | ||
| 30 | + > | ||
| 31 | + <template #action="{ row }"> | ||
| 32 | + <el-button | ||
| 33 | + link | ||
| 34 | + type="primary" | ||
| 35 | + @click="openForm('update', row.id)" | ||
| 28 | v-hasPermi="['${permissionPrefix}:update']" | 36 | v-hasPermi="['${permissionPrefix}:update']" |
| 29 | - @click="handleUpdate(row.id)" | ||
| 30 | - /> | ||
| 31 | - <!-- 操作:详情 --> | ||
| 32 | - <XTextButton | ||
| 33 | - preIcon="ep:view" | ||
| 34 | - :title="t('action.detail')" | ||
| 35 | - v-hasPermi="['${permissionPrefix}:query']" | ||
| 36 | - @click="handleDetail(row.id)" | ||
| 37 | - /> | ||
| 38 | - <!-- 操作:删除 --> | ||
| 39 | - <XTextButton | ||
| 40 | - preIcon="ep:delete" | ||
| 41 | - :title="t('action.del')" | 37 | + > |
| 38 | + 编辑 | ||
| 39 | + </el-button> | ||
| 40 | + <el-button | ||
| 41 | + link | ||
| 42 | + type="danger" | ||
| 42 | v-hasPermi="['${permissionPrefix}:delete']" | 43 | v-hasPermi="['${permissionPrefix}:delete']" |
| 43 | - @click="deleteData(row.id)" | ||
| 44 | - /> | 44 | + @click="handleDelete(row.id)" |
| 45 | + > | ||
| 46 | + 删除 | ||
| 47 | + </el-button> | ||
| 45 | </template> | 48 | </template> |
| 46 | - </XTable> | 49 | + </Table> |
| 47 | </ContentWrap> | 50 | </ContentWrap> |
| 48 | - <!-- 弹窗 --> | ||
| 49 | - <XModal id="${classNameVar}Model" :loading="modelLoading" v-model="modelVisible" :title="modelTitle"> | ||
| 50 | - <!-- 表单:添加/修改 --> | ||
| 51 | - <Form | ||
| 52 | - ref="formRef" | ||
| 53 | - v-if="['create', 'update'].includes(actionType)" | ||
| 54 | - :schema="allSchemas.formSchema" | ||
| 55 | - :rules="rules" | ||
| 56 | - /> | ||
| 57 | - <!-- 表单:详情 --> | ||
| 58 | - <Descriptions | ||
| 59 | - v-if="actionType === 'detail'" | ||
| 60 | - :schema="allSchemas.detailSchema" | ||
| 61 | - :data="detailData" | ||
| 62 | - /> | ||
| 63 | - <template #footer> | ||
| 64 | - <!-- 按钮:保存 --> | ||
| 65 | - <XButton | ||
| 66 | - v-if="['create', 'update'].includes(actionType)" | ||
| 67 | - type="primary" | ||
| 68 | - :title="t('action.save')" | ||
| 69 | - :loading="actionLoading" | ||
| 70 | - @click="submitForm()" | ||
| 71 | - /> | ||
| 72 | - <!-- 按钮:关闭 --> | ||
| 73 | - <XButton :loading="actionLoading" :title="t('dialog.close')" @click="modelVisible = false" /> | ||
| 74 | - </template> | ||
| 75 | - </XModal> | 51 | + |
| 52 | + <!-- 表单弹窗:添加/修改 --> | ||
| 53 | + <${simpleClassName}Form ref="formRef" @success="getList" /> | ||
| 76 | </template> | 54 | </template> |
| 77 | -<script setup lang="ts" name="${simpleClassName}"> | ||
| 78 | -import { FormExpose } from '@/components/Form' | ||
| 79 | -// 业务相关的 import | ||
| 80 | -import { rules, allSchemas } from './${classNameVar}.data' | 55 | +<script setup lang="ts" name="${table.className}"> |
| 56 | +import { allSchemas } from './${classNameVar}.data' | ||
| 81 | import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}' | 57 | import * as ${simpleClassName}Api from '@/api/${table.moduleName}/${classNameVar}' |
| 58 | +import ${simpleClassName}Form from './${simpleClassName}Form.vue' | ||
| 82 | 59 | ||
| 83 | -const { t } = useI18n() // 国际化 | ||
| 84 | -const message = useMessage() // 消息弹窗 | ||
| 85 | - | ||
| 86 | -// 列表相关的变量 | ||
| 87 | -const [registerTable, { reload, deleteData, exportList }] = useXTable({ | ||
| 88 | - allSchemas: allSchemas, | ||
| 89 | - getListApi: ${simpleClassName}Api.get${simpleClassName}PageApi, | ||
| 90 | - deleteApi: ${simpleClassName}Api.delete${simpleClassName}Api, | ||
| 91 | - exportListApi: ${simpleClassName}Api.export${simpleClassName}Api | 60 | +// tableObject:表格的属性对象,可获得分页大小、条数等属性 |
| 61 | +// tableMethods:表格的操作对象,可进行获得分页、删除记录等操作 | ||
| 62 | +// 详细可见:https://kailong110120130.gitee.io/vue-element-plus-admin-doc/components/table.html#usetable | ||
| 63 | +const { tableObject, tableMethods } = useTable({ | ||
| 64 | + getListApi: ${simpleClassName}Api.get${simpleClassName}Page, // 分页接口 | ||
| 65 | + delListApi: ${simpleClassName}Api.delete${simpleClassName} // 删除接口 | ||
| 92 | }) | 66 | }) |
| 67 | +// 获得表格的各种操作 | ||
| 68 | +const { getList, setSearchParams } = tableMethods | ||
| 93 | 69 | ||
| 94 | -// 弹窗相关的变量 | ||
| 95 | -const modelVisible = ref(false) // 是否显示弹出层 | ||
| 96 | -const modelTitle = ref('edit') // 弹出层标题 | ||
| 97 | -const modelLoading = ref(false) // 弹出层loading | ||
| 98 | -const actionType = ref('') // 操作按钮的类型 | ||
| 99 | -const actionLoading = ref(false) // 按钮 Loading | ||
| 100 | -const formRef = ref<FormExpose>() // 表单 Ref | ||
| 101 | -const detailData = ref() // 详情 Ref | ||
| 102 | - | ||
| 103 | -// 设置标题 | ||
| 104 | -const setDialogTile = (type: string) => { | ||
| 105 | - modelLoading.value = true | ||
| 106 | - modelTitle.value = t('action.' + type) | ||
| 107 | - actionType.value = type | ||
| 108 | - modelVisible.value = true | 70 | +/** 添加/修改操作 */ |
| 71 | +const formRef = ref() | ||
| 72 | +const openForm = (type: string, id?: number) => { | ||
| 73 | + formRef.value.open(type, id) | ||
| 109 | } | 74 | } |
| 110 | 75 | ||
| 111 | -// 新增操作 | ||
| 112 | -const handleCreate = () => { | ||
| 113 | - setDialogTile('create') | ||
| 114 | - modelLoading.value = false | 76 | +/** 删除按钮操作 */ |
| 77 | +const handleDelete = (id: number) => { | ||
| 78 | + tableMethods.delList(id, false) | ||
| 115 | } | 79 | } |
| 116 | 80 | ||
| 117 | -// 修改操作 | ||
| 118 | -const handleUpdate = async (rowId: number) => { | ||
| 119 | - setDialogTile('update') | ||
| 120 | - // 设置数据 | ||
| 121 | - const res = await ${simpleClassName}Api.get${simpleClassName}Api(rowId) | ||
| 122 | - unref(formRef)?.setValues(res) | ||
| 123 | - modelLoading.value = false | ||
| 124 | -} | ||
| 125 | - | ||
| 126 | -// 详情操作 | ||
| 127 | -const handleDetail = async (rowId: number) => { | ||
| 128 | - setDialogTile('detail') | ||
| 129 | - const res = await ${simpleClassName}Api.get${simpleClassName}Api(rowId) | ||
| 130 | - detailData.value = res | ||
| 131 | - modelLoading.value = false | ||
| 132 | -} | ||
| 133 | - | ||
| 134 | -// 提交按钮 | ||
| 135 | -const submitForm = async () => { | ||
| 136 | - const elForm = unref(formRef)?.getElFormRef() | ||
| 137 | - if (!elForm) return | ||
| 138 | - elForm.validate(async (valid) => { | ||
| 139 | - if (valid) { | ||
| 140 | - actionLoading.value = true | ||
| 141 | - // 提交请求 | ||
| 142 | - try { | ||
| 143 | - const data = unref(formRef)?.formModel as ${simpleClassName}Api.${simpleClassName}VO | ||
| 144 | - if (actionType.value === 'create') { | ||
| 145 | - await ${simpleClassName}Api.create${simpleClassName}Api(data) | ||
| 146 | - message.success(t('common.createSuccess')) | ||
| 147 | - } else { | ||
| 148 | - await ${simpleClassName}Api.update${simpleClassName}Api(data) | ||
| 149 | - message.success(t('common.updateSuccess')) | ||
| 150 | - } | ||
| 151 | - modelVisible.value = false | ||
| 152 | - } finally { | ||
| 153 | - actionLoading.value = false | ||
| 154 | - // 刷新列表 | ||
| 155 | - await reload() | ||
| 156 | - } | ||
| 157 | - } | ||
| 158 | - }) | ||
| 159 | -} | 81 | +/** 初始化 **/ |
| 82 | +onMounted(() => { | ||
| 83 | + getList() | ||
| 84 | +}) | ||
| 160 | </script> | 85 | </script> |