feat: 【ele】新增 general 主子表 normal 模式代码生成示例
							parent
							
								
									836d6ab3f3
								
							
						
					
					
						commit
						fe8c7b67f7
					
				|  | @ -0,0 +1,316 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal'; | ||||||
|  | 
 | ||||||
|  | import { h, onMounted, reactive, ref } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { Page, useVbenModal } from '@vben/common-ui'; | ||||||
|  | import { Download, Plus, Trash2 } from '@vben/icons'; | ||||||
|  | import { | ||||||
|  |   cloneDeep, | ||||||
|  |   downloadFileFromBlobPart, | ||||||
|  |   formatDateTime, | ||||||
|  |   isEmpty, | ||||||
|  | } from '@vben/utils'; | ||||||
|  | 
 | ||||||
|  | import { | ||||||
|  |   ElButton, | ||||||
|  |   ElDatePicker, | ||||||
|  |   ElForm, | ||||||
|  |   ElFormItem, | ||||||
|  |   ElInput, | ||||||
|  |   ElLoading, | ||||||
|  |   ElMessage, | ||||||
|  |   ElOption, | ||||||
|  |   ElPagination, | ||||||
|  |   ElSelect, | ||||||
|  | } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; | ||||||
|  | import { | ||||||
|  |   deleteDemo03Student, | ||||||
|  |   deleteDemo03StudentList, | ||||||
|  |   exportDemo03Student, | ||||||
|  |   getDemo03StudentPage, | ||||||
|  | } from '#/api/infra/demo/demo03/normal'; | ||||||
|  | import { ContentWrap } from '#/components/content-wrap'; | ||||||
|  | import { DictTag } from '#/components/dict-tag'; | ||||||
|  | import { TableToolbar } from '#/components/table-toolbar'; | ||||||
|  | import { useTableToolbar } from '#/hooks'; | ||||||
|  | import { $t } from '#/locales'; | ||||||
|  | import { DICT_TYPE, getDictOptions } from '#/utils'; | ||||||
|  | 
 | ||||||
|  | import Demo03StudentForm from './modules/form.vue'; | ||||||
|  | 
 | ||||||
|  | const loading = ref(true); // 列表的加载中 | ||||||
|  | const list = ref<Demo03StudentApi.Demo03Student[]>([]); // 列表的数据 | ||||||
|  | 
 | ||||||
|  | const total = ref(0); // 列表的总页数 | ||||||
|  | const queryParams = reactive({ | ||||||
|  |   pageNo: 1, | ||||||
|  |   pageSize: 10, | ||||||
|  |   name: undefined, | ||||||
|  |   sex: undefined, | ||||||
|  |   description: undefined, | ||||||
|  |   createTime: undefined, | ||||||
|  | }); | ||||||
|  | const queryFormRef = ref(); // 搜索的表单 | ||||||
|  | const exportLoading = ref(false); // 导出的加载中 | ||||||
|  | 
 | ||||||
|  | /** 查询列表 */ | ||||||
|  | const getList = async () => { | ||||||
|  |   loading.value = true; | ||||||
|  |   try { | ||||||
|  |     const params = cloneDeep(queryParams) as any; | ||||||
|  |     if (params.createTime && Array.isArray(params.createTime)) { | ||||||
|  |       params.createTime = (params.createTime as string[]).join(','); | ||||||
|  |     } | ||||||
|  |     const data = await getDemo03StudentPage(params); | ||||||
|  |     list.value = data.list; | ||||||
|  |     total.value = data.total; | ||||||
|  |   } finally { | ||||||
|  |     loading.value = false; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** 搜索按钮操作 */ | ||||||
|  | const handleQuery = () => { | ||||||
|  |   queryParams.pageNo = 1; | ||||||
|  |   getList(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** 重置按钮操作 */ | ||||||
|  | const resetQuery = () => { | ||||||
|  |   queryFormRef.value.resetFields(); | ||||||
|  |   handleQuery(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const [FormModal, formModalApi] = useVbenModal({ | ||||||
|  |   connectedComponent: Demo03StudentForm, | ||||||
|  |   destroyOnClose: true, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** 创建学生 */ | ||||||
|  | function handleCreate() { | ||||||
|  |   formModalApi.setData({}).open(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 编辑学生 */ | ||||||
|  | function handleEdit(row: Demo03StudentApi.Demo03Student) { | ||||||
|  |   formModalApi.setData(row).open(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 删除学生 */ | ||||||
|  | async function handleDelete(row: Demo03StudentApi.Demo03Student) { | ||||||
|  |   const loadingInstance = ElLoading.service({ | ||||||
|  |     text: $t('ui.actionMessage.deleting', [row.id]), | ||||||
|  |     background: 'rgba(0, 0, 0, 0.7)', | ||||||
|  |   }); | ||||||
|  |   try { | ||||||
|  |     await deleteDemo03Student(row.id as number); | ||||||
|  |     ElMessage.success($t('ui.actionMessage.deleteSuccess', [row.id])); | ||||||
|  |     await getList(); | ||||||
|  |   } finally { | ||||||
|  |     loadingInstance.close(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 批量删除学生 */ | ||||||
|  | async function handleDeleteBatch() { | ||||||
|  |   const loadingInstance = ElLoading.service({ | ||||||
|  |     text: $t('ui.actionMessage.deleting'), | ||||||
|  |     background: 'rgba(0, 0, 0, 0.7)', | ||||||
|  |   }); | ||||||
|  |   try { | ||||||
|  |     await deleteDemo03StudentList(checkedIds.value); | ||||||
|  |     ElMessage.success($t('ui.actionMessage.deleteSuccess')); | ||||||
|  |     await getList(); | ||||||
|  |   } finally { | ||||||
|  |     loadingInstance.close(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const checkedIds = ref<number[]>([]); | ||||||
|  | function handleRowCheckboxChange({ | ||||||
|  |   records, | ||||||
|  | }: { | ||||||
|  |   records: Demo03StudentApi.Demo03Student[]; | ||||||
|  | }) { | ||||||
|  |   checkedIds.value = records.map((item) => item.id); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 导出表格 */ | ||||||
|  | async function onExport() { | ||||||
|  |   try { | ||||||
|  |     exportLoading.value = true; | ||||||
|  |     const data = await exportDemo03Student(queryParams); | ||||||
|  |     downloadFileFromBlobPart({ fileName: '学生.xls', source: data }); | ||||||
|  |   } finally { | ||||||
|  |     exportLoading.value = false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** 初始化 */ | ||||||
|  | const { hiddenSearchBar, tableToolbarRef, tableRef } = useTableToolbar(); | ||||||
|  | onMounted(() => { | ||||||
|  |   getList(); | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <Page auto-content-height> | ||||||
|  |     <FormModal @success="getList" /> | ||||||
|  | 
 | ||||||
|  |     <ContentWrap v-if="!hiddenSearchBar"> | ||||||
|  |       <!-- 搜索工作栏 --> | ||||||
|  |       <ElForm :model="queryParams" ref="queryFormRef" inline> | ||||||
|  |         <ElFormItem label="名字"> | ||||||
|  |           <ElInput | ||||||
|  |             v-model="queryParams.name" | ||||||
|  |             placeholder="请输入名字" | ||||||
|  |             clearable | ||||||
|  |             @keyup.enter="handleQuery" | ||||||
|  |             class="!w-[240px]" | ||||||
|  |           /> | ||||||
|  |         </ElFormItem> | ||||||
|  |         <ElFormItem label="性别"> | ||||||
|  |           <ElSelect | ||||||
|  |             v-model="queryParams.sex" | ||||||
|  |             placeholder="请选择性别" | ||||||
|  |             clearable | ||||||
|  |             class="!w-[240px]" | ||||||
|  |           > | ||||||
|  |             <ElOption | ||||||
|  |               v-for="dict in getDictOptions( | ||||||
|  |                 DICT_TYPE.SYSTEM_USER_SEX, | ||||||
|  |                 'number', | ||||||
|  |               )" | ||||||
|  |               :key="dict.value" | ||||||
|  |               :value="dict.value" | ||||||
|  |               :label="dict.label" | ||||||
|  |             /> | ||||||
|  |           </ElSelect> | ||||||
|  |         </ElFormItem> | ||||||
|  |         <ElFormItem label="创建时间"> | ||||||
|  |           <ElDatePicker | ||||||
|  |             v-model="queryParams.createTime" | ||||||
|  |             type="daterange" | ||||||
|  |             value-format="YYYY-MM-DD" | ||||||
|  |             range-separator="至" | ||||||
|  |             start-placeholder="开始日期" | ||||||
|  |             end-placeholder="结束日期" | ||||||
|  |             class="!w-[240px]" | ||||||
|  |           /> | ||||||
|  |         </ElFormItem> | ||||||
|  |         <ElFormItem> | ||||||
|  |           <ElButton class="ml-2" @click="resetQuery"> 重置 </ElButton> | ||||||
|  |           <ElButton class="ml-2" @click="handleQuery" type="primary"> | ||||||
|  |             搜索 | ||||||
|  |           </ElButton> | ||||||
|  |         </ElFormItem> | ||||||
|  |       </ElForm> | ||||||
|  |     </ContentWrap> | ||||||
|  | 
 | ||||||
|  |     <!-- 列表 --> | ||||||
|  |     <ContentWrap title="学生"> | ||||||
|  |       <template #extra> | ||||||
|  |         <TableToolbar | ||||||
|  |           ref="tableToolbarRef" | ||||||
|  |           v-model:hidden-search="hiddenSearchBar" | ||||||
|  |         > | ||||||
|  |           <ElButton | ||||||
|  |             class="ml-2" | ||||||
|  |             :icon="h(Plus)" | ||||||
|  |             type="primary" | ||||||
|  |             @click="handleCreate" | ||||||
|  |             v-access:code="['infra:demo03-student:create']" | ||||||
|  |           > | ||||||
|  |             {{ $t('ui.actionTitle.create', ['学生']) }} | ||||||
|  |           </ElButton> | ||||||
|  |           <ElButton | ||||||
|  |             :icon="h(Download)" | ||||||
|  |             type="primary" | ||||||
|  |             class="ml-2" | ||||||
|  |             :loading="exportLoading" | ||||||
|  |             @click="onExport" | ||||||
|  |             v-access:code="['infra:demo03-student:export']" | ||||||
|  |           > | ||||||
|  |             {{ $t('ui.actionTitle.export') }} | ||||||
|  |           </ElButton> | ||||||
|  |           <ElButton | ||||||
|  |             :icon="h(Trash2)" | ||||||
|  |             type="danger" | ||||||
|  |             class="ml-2" | ||||||
|  |             :disabled="isEmpty(checkedIds)" | ||||||
|  |             @click="handleDeleteBatch" | ||||||
|  |             v-access:code="['infra:demo03-student:delete']" | ||||||
|  |           > | ||||||
|  |             批量删除 | ||||||
|  |           </ElButton> | ||||||
|  |         </TableToolbar> | ||||||
|  |       </template> | ||||||
|  |       <VxeTable | ||||||
|  |         ref="tableRef" | ||||||
|  |         :data="list" | ||||||
|  |         show-overflow | ||||||
|  |         :loading="loading" | ||||||
|  |         @checkbox-all="handleRowCheckboxChange" | ||||||
|  |         @checkbox-change="handleRowCheckboxChange" | ||||||
|  |       > | ||||||
|  |         <VxeColumn type="checkbox" width="40" /> | ||||||
|  |         <VxeColumn field="id" title="编号" align="center" /> | ||||||
|  |         <VxeColumn field="name" title="名字" align="center" /> | ||||||
|  |         <VxeColumn field="sex" title="性别" align="center"> | ||||||
|  |           <template #default="{ row }"> | ||||||
|  |             <DictTag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="row.sex" /> | ||||||
|  |           </template> | ||||||
|  |         </VxeColumn> | ||||||
|  |         <VxeColumn field="birthday" title="出生日期" align="center"> | ||||||
|  |           <template #default="{ row }"> | ||||||
|  |             {{ formatDateTime(row.birthday) }} | ||||||
|  |           </template> | ||||||
|  |         </VxeColumn> | ||||||
|  |         <VxeColumn field="description" title="简介" align="center" /> | ||||||
|  |         <VxeColumn field="createTime" title="创建时间" align="center"> | ||||||
|  |           <template #default="{ row }"> | ||||||
|  |             {{ formatDateTime(row.createTime) }} | ||||||
|  |           </template> | ||||||
|  |         </VxeColumn> | ||||||
|  |         <VxeColumn field="operation" title="操作" align="center"> | ||||||
|  |           <template #default="{ row }"> | ||||||
|  |             <ElButton | ||||||
|  |               size="small" | ||||||
|  |               type="primary" | ||||||
|  |               link | ||||||
|  |               @click="handleEdit(row as any)" | ||||||
|  |               v-access:code="['infra:demo03-student:update']" | ||||||
|  |             > | ||||||
|  |               {{ $t('ui.actionTitle.edit') }} | ||||||
|  |             </ElButton> | ||||||
|  |             <ElButton | ||||||
|  |               size="small" | ||||||
|  |               type="danger" | ||||||
|  |               link | ||||||
|  |               class="ml-2" | ||||||
|  |               @click="handleDelete(row as any)" | ||||||
|  |               v-access:code="['infra:demo03-student:delete']" | ||||||
|  |             > | ||||||
|  |               {{ $t('ui.actionTitle.delete') }} | ||||||
|  |             </ElButton> | ||||||
|  |           </template> | ||||||
|  |         </VxeColumn> | ||||||
|  |       </VxeTable> | ||||||
|  |       <!-- 分页 --> | ||||||
|  |       <div class="mt-2 flex justify-end"> | ||||||
|  |         <ElPagination | ||||||
|  |           :total="total" | ||||||
|  |           v-model:current-page="queryParams.pageNo" | ||||||
|  |           v-model:page-size="queryParams.pageSize" | ||||||
|  |           :page-sizes="[10, 20, 50, 100]" | ||||||
|  |           layout="total, sizes, prev, pager, next, jumper" | ||||||
|  |           @size-change="getList" | ||||||
|  |           @current-change="getList" | ||||||
|  |         /> | ||||||
|  |       </div> | ||||||
|  |     </ContentWrap> | ||||||
|  |   </Page> | ||||||
|  | </template> | ||||||
|  | @ -0,0 +1,95 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { VxeTableInstance } from '#/adapter/vxe-table'; | ||||||
|  | import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal'; | ||||||
|  | 
 | ||||||
|  | import { h, ref, watch } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { Plus } from '@vben/icons'; | ||||||
|  | 
 | ||||||
|  | import { ElButton, ElInput } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import { VxeColumn, VxeTable } from '#/adapter/vxe-table'; | ||||||
|  | import { getDemo03CourseListByStudentId } from '#/api/infra/demo/demo03/normal'; | ||||||
|  | import { $t } from '#/locales'; | ||||||
|  | 
 | ||||||
|  | const props = defineProps<{ | ||||||
|  |   studentId?: number; // 学生编号(主表的关联字段) | ||||||
|  | }>(); | ||||||
|  | 
 | ||||||
|  | const list = ref<Demo03StudentApi.Demo03Course[]>([]); // 列表的数据 | ||||||
|  | const tableRef = ref<VxeTableInstance>(); | ||||||
|  | /** 添加学生课程 */ | ||||||
|  | const onAdd = async () => { | ||||||
|  |   await tableRef.value?.insertAt({} as Demo03StudentApi.Demo03Course, -1); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** 删除学生课程 */ | ||||||
|  | const onDelete = async (row: Demo03StudentApi.Demo03Course) => { | ||||||
|  |   await tableRef.value?.remove(row); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /** 提供获取表格数据的方法供父组件调用 */ | ||||||
|  | defineExpose({ | ||||||
|  |   getData: (): Demo03StudentApi.Demo03Course[] => { | ||||||
|  |     const data = list.value as Demo03StudentApi.Demo03Course[]; | ||||||
|  |     const removeRecords = | ||||||
|  |       tableRef.value?.getRemoveRecords() as Demo03StudentApi.Demo03Course[]; | ||||||
|  |     const insertRecords = | ||||||
|  |       tableRef.value?.getInsertRecords() as Demo03StudentApi.Demo03Course[]; | ||||||
|  |     return data | ||||||
|  |       .filter((row) => !removeRecords.some((removed) => removed.id === row.id)) | ||||||
|  |       ?.concat(insertRecords.map((row: any) => ({ ...row, id: undefined }))); | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** 监听主表的关联字段的变化,加载对应的子表数据 */ | ||||||
|  | watch( | ||||||
|  |   () => props.studentId, | ||||||
|  |   async (val) => { | ||||||
|  |     if (!val) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     list.value = await getDemo03CourseListByStudentId(props.studentId!); | ||||||
|  |   }, | ||||||
|  |   { immediate: true }, | ||||||
|  | ); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <VxeTable ref="tableRef" :data="list" show-overflow class="mx-4"> | ||||||
|  |     <VxeColumn field="name" title="名字" align="center"> | ||||||
|  |       <template #default="{ row }"> | ||||||
|  |         <ElInput v-model="row.name" /> | ||||||
|  |       </template> | ||||||
|  |     </VxeColumn> | ||||||
|  |     <VxeColumn field="score" title="分数" align="center"> | ||||||
|  |       <template #default="{ row }"> | ||||||
|  |         <ElInput v-model="row.score" /> | ||||||
|  |       </template> | ||||||
|  |     </VxeColumn> | ||||||
|  |     <VxeColumn field="operation" title="操作" align="center"> | ||||||
|  |       <template #default="{ row }"> | ||||||
|  |         <ElButton | ||||||
|  |           size="small" | ||||||
|  |           type="danger" | ||||||
|  |           link | ||||||
|  |           @click="onDelete(row as any)" | ||||||
|  |           v-access:code="['infra:demo03-student:delete']" | ||||||
|  |         > | ||||||
|  |           {{ $t('ui.actionTitle.delete') }} | ||||||
|  |         </ElButton> | ||||||
|  |       </template> | ||||||
|  |     </VxeColumn> | ||||||
|  |   </VxeTable> | ||||||
|  |   <div class="mt-4 flex justify-center"> | ||||||
|  |     <ElButton | ||||||
|  |       :icon="h(Plus)" | ||||||
|  |       type="primary" | ||||||
|  |       plain | ||||||
|  |       @click="onAdd" | ||||||
|  |       v-access:code="['infra:demo03-student:create']" | ||||||
|  |     > | ||||||
|  |       {{ $t('ui.actionTitle.create', ['学生课程']) }} | ||||||
|  |     </ElButton> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | @ -0,0 +1,67 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { FormRules } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal'; | ||||||
|  | 
 | ||||||
|  | import { nextTick, reactive, ref, watch } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { ElForm, ElFormItem, ElInput } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import { getDemo03GradeByStudentId } from '#/api/infra/demo/demo03/normal'; | ||||||
|  | 
 | ||||||
|  | const props = defineProps<{ | ||||||
|  |   studentId?: number; // 学生编号(主表的关联字段) | ||||||
|  | }>(); | ||||||
|  | 
 | ||||||
|  | const formRef = ref(); | ||||||
|  | const formData = ref<Partial<Demo03StudentApi.Demo03Grade>>({ | ||||||
|  |   id: undefined, | ||||||
|  |   studentId: undefined, | ||||||
|  |   name: undefined, | ||||||
|  |   teacher: undefined, | ||||||
|  | }); | ||||||
|  | const rules = reactive<FormRules>({ | ||||||
|  |   studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], | ||||||
|  |   name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], | ||||||
|  |   teacher: [{ required: true, message: '班主任不能为空', trigger: 'blur' }], | ||||||
|  | }); | ||||||
|  | /** 暴露出表单校验方法和表单值获取方法 */ | ||||||
|  | defineExpose({ | ||||||
|  |   validate: async () => await formRef.value?.validate(), | ||||||
|  |   getValues: () => formData.value, | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** 监听主表的关联字段的变化,加载对应的子表数据 */ | ||||||
|  | watch( | ||||||
|  |   () => props.studentId, | ||||||
|  |   async (val) => { | ||||||
|  |     if (!val) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     await nextTick(); | ||||||
|  |     formData.value = await getDemo03GradeByStudentId(props.studentId!); | ||||||
|  |   }, | ||||||
|  |   { immediate: true }, | ||||||
|  | ); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <ElForm | ||||||
|  |     ref="formRef" | ||||||
|  |     class="mx-4" | ||||||
|  |     :model="formData" | ||||||
|  |     :rules="rules" | ||||||
|  |     label-width="120px" | ||||||
|  |     label-position="right" | ||||||
|  |   > | ||||||
|  |     <ElFormItem label="学生编号" prop="studentId"> | ||||||
|  |       <ElInput v-model="formData.studentId" placeholder="请输入学生编号" /> | ||||||
|  |     </ElFormItem> | ||||||
|  |     <ElFormItem label="名字" prop="name"> | ||||||
|  |       <ElInput v-model="formData.name" placeholder="请输入名字" /> | ||||||
|  |     </ElFormItem> | ||||||
|  |     <ElFormItem label="班主任" prop="teacher"> | ||||||
|  |       <ElInput v-model="formData.teacher" placeholder="请输入班主任" /> | ||||||
|  |     </ElFormItem> | ||||||
|  |   </ElForm> | ||||||
|  | </template> | ||||||
|  | @ -0,0 +1,171 @@ | ||||||
|  | <script lang="ts" setup> | ||||||
|  | import type { FormRules } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import type { Demo03StudentApi } from '#/api/infra/demo/demo03/normal'; | ||||||
|  | 
 | ||||||
|  | import { computed, reactive, ref } from 'vue'; | ||||||
|  | 
 | ||||||
|  | import { useVbenModal } from '@vben/common-ui'; | ||||||
|  | 
 | ||||||
|  | import { | ||||||
|  |   ElDatePicker, | ||||||
|  |   ElForm, | ||||||
|  |   ElFormItem, | ||||||
|  |   ElInput, | ||||||
|  |   ElMessage, | ||||||
|  |   ElRadio, | ||||||
|  |   ElRadioGroup, | ||||||
|  |   ElTabPane, | ||||||
|  |   ElTabs, | ||||||
|  | } from 'element-plus'; | ||||||
|  | 
 | ||||||
|  | import { | ||||||
|  |   createDemo03Student, | ||||||
|  |   getDemo03Student, | ||||||
|  |   updateDemo03Student, | ||||||
|  | } from '#/api/infra/demo/demo03/normal'; | ||||||
|  | import { Tinymce as RichTextarea } from '#/components/tinymce'; | ||||||
|  | import { $t } from '#/locales'; | ||||||
|  | import { DICT_TYPE, getDictOptions } from '#/utils'; | ||||||
|  | 
 | ||||||
|  | import Demo03CourseForm from './demo03-course-form.vue'; | ||||||
|  | import Demo03GradeForm from './demo03-grade-form.vue'; | ||||||
|  | 
 | ||||||
|  | const emit = defineEmits(['success']); | ||||||
|  | 
 | ||||||
|  | const formRef = ref(); | ||||||
|  | const formData = ref<Partial<Demo03StudentApi.Demo03Student>>({ | ||||||
|  |   id: undefined, | ||||||
|  |   name: undefined, | ||||||
|  |   sex: undefined, | ||||||
|  |   birthday: undefined, | ||||||
|  |   description: undefined, | ||||||
|  | }); | ||||||
|  | const rules = reactive<FormRules>({ | ||||||
|  |   name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], | ||||||
|  |   sex: [{ required: true, message: '性别不能为空', trigger: 'blur' }], | ||||||
|  |   birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], | ||||||
|  |   description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], | ||||||
|  | }); | ||||||
|  | const getTitle = computed(() => { | ||||||
|  |   return formData.value?.id | ||||||
|  |     ? $t('ui.actionTitle.edit', ['学生']) | ||||||
|  |     : $t('ui.actionTitle.create', ['学生']); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** 子表的表单 */ | ||||||
|  | const subTabsName = ref('demo03Course'); | ||||||
|  | const demo03CourseFormRef = ref<InstanceType<typeof Demo03CourseForm>>(); | ||||||
|  | const demo03GradeFormRef = ref<InstanceType<typeof Demo03GradeForm>>(); | ||||||
|  | 
 | ||||||
|  | /** 重置表单 */ | ||||||
|  | const resetForm = () => { | ||||||
|  |   formData.value = { | ||||||
|  |     id: undefined, | ||||||
|  |     name: undefined, | ||||||
|  |     sex: undefined, | ||||||
|  |     birthday: undefined, | ||||||
|  |     description: undefined, | ||||||
|  |   }; | ||||||
|  |   formRef.value?.resetFields(); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const [Modal, modalApi] = useVbenModal({ | ||||||
|  |   async onConfirm() { | ||||||
|  |     await formRef.value?.validate(); | ||||||
|  |     // 校验子表单 | ||||||
|  |     try { | ||||||
|  |       await demo03GradeFormRef.value?.validate(); | ||||||
|  |     } catch { | ||||||
|  |       subTabsName.value = 'demo03Grade'; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     modalApi.lock(); | ||||||
|  |     // 提交表单 | ||||||
|  |     const data = formData.value as Demo03StudentApi.Demo03Student; | ||||||
|  |     // 拼接子表的数据 | ||||||
|  |     data.demo03Courses = demo03CourseFormRef.value?.getData(); | ||||||
|  |     data.demo03Grade = demo03GradeFormRef.value?.getValues(); | ||||||
|  |     try { | ||||||
|  |       await (formData.value?.id | ||||||
|  |         ? updateDemo03Student(data) | ||||||
|  |         : createDemo03Student(data)); | ||||||
|  |       // 关闭并提示 | ||||||
|  |       await modalApi.close(); | ||||||
|  |       emit('success'); | ||||||
|  |       ElMessage.success($t('ui.actionMessage.operationSuccess')); | ||||||
|  |     } finally { | ||||||
|  |       modalApi.unlock(); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   async onOpenChange(isOpen: boolean) { | ||||||
|  |     if (!isOpen) { | ||||||
|  |       resetForm(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     // 加载数据 | ||||||
|  |     let data = modalApi.getData<Demo03StudentApi.Demo03Student>(); | ||||||
|  |     if (!data) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if (data.id) { | ||||||
|  |       modalApi.lock(); | ||||||
|  |       try { | ||||||
|  |         data = await getDemo03Student(data.id); | ||||||
|  |       } finally { | ||||||
|  |         modalApi.unlock(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     formData.value = data; | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | <template> | ||||||
|  |   <Modal :title="getTitle"> | ||||||
|  |     <ElForm | ||||||
|  |       ref="formRef" | ||||||
|  |       :model="formData" | ||||||
|  |       :rules="rules" | ||||||
|  |       label-width="120px" | ||||||
|  |       label-position="right" | ||||||
|  |     > | ||||||
|  |       <ElFormItem label="名字" prop="name"> | ||||||
|  |         <ElInput v-model="formData.name" placeholder="请输入名字" /> | ||||||
|  |       </ElFormItem> | ||||||
|  |       <ElFormItem label="性别" prop="sex"> | ||||||
|  |         <ElRadioGroup v-model="formData.sex"> | ||||||
|  |           <ElRadio | ||||||
|  |             v-for="dict in getDictOptions(DICT_TYPE.SYSTEM_USER_SEX, 'number')" | ||||||
|  |             :key="dict.value" | ||||||
|  |             :label="dict.value" | ||||||
|  |           > | ||||||
|  |             {{ dict.label }} | ||||||
|  |           </ElRadio> | ||||||
|  |         </ElRadioGroup> | ||||||
|  |       </ElFormItem> | ||||||
|  |       <ElFormItem label="出生日期" prop="birthday"> | ||||||
|  |         <ElDatePicker | ||||||
|  |           v-model="formData.birthday" | ||||||
|  |           value-format="x" | ||||||
|  |           placeholder="选择出生日期" | ||||||
|  |         /> | ||||||
|  |       </ElFormItem> | ||||||
|  |       <ElFormItem label="简介" prop="description"> | ||||||
|  |         <RichTextarea v-model="formData.description" height="500px" /> | ||||||
|  |       </ElFormItem> | ||||||
|  |     </ElForm> | ||||||
|  |     <!-- 子表的表单 --> | ||||||
|  |     <ElTabs v-model="subTabsName"> | ||||||
|  |       <ElTabPane name="demo03Course" label="学生课程"> | ||||||
|  |         <Demo03CourseForm | ||||||
|  |           ref="demo03CourseFormRef" | ||||||
|  |           :student-id="formData?.id" | ||||||
|  |         /> | ||||||
|  |       </ElTabPane> | ||||||
|  |       <ElTabPane name="demo03Grade" label="学生班级"> | ||||||
|  |         <Demo03GradeForm ref="demo03GradeFormRef" :student-id="formData?.id" /> | ||||||
|  |       </ElTabPane> | ||||||
|  |     </ElTabs> | ||||||
|  |   </Modal> | ||||||
|  | </template> | ||||||
		Loading…
	
		Reference in New Issue
	
	 puhui999
						puhui999