From 4e413a10e621a34235a6f520f8b97cd77cc00c95 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Thu, 9 Nov 2023 23:10:54 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E4=B8=BB=E5=AD=90=E8=A1=A8=EF=BC=9A?= =?UTF-8?q?=E6=9A=82=E6=97=B6=E5=AD=98=E5=82=A8=EF=BC=8C=E5=87=86=E5=A4=87?= =?UTF-8?q?=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/demo02/index.ts | 35 ++++ .../infra/demo02/DemoStudentContactForm.vue | 71 ++++++++ src/views/infra/demo02/DemoStudentForm.vue | 97 +++++++++++ src/views/infra/demo02/index.vue | 159 ++++++++++++++++++ 4 files changed, 362 insertions(+) create mode 100644 src/api/infra/demo02/index.ts create mode 100644 src/views/infra/demo02/DemoStudentContactForm.vue create mode 100644 src/views/infra/demo02/DemoStudentForm.vue create mode 100644 src/views/infra/demo02/index.vue diff --git a/src/api/infra/demo02/index.ts b/src/api/infra/demo02/index.ts new file mode 100644 index 00000000..b575dba4 --- /dev/null +++ b/src/api/infra/demo02/index.ts @@ -0,0 +1,35 @@ +import request from '@/config/axios' + +export interface DemoStudentVO { + id: number +} + +// 查询学生列表 +export const getDemoStudentPage = async (params) => { + return await request.get({ url: `/infra/demo-student/page`, params }) +} + +// 查询学生详情 +export const getDemoStudent = async (id: number) => { + return await request.get({ url: `/infra/demo-student/get?id=` + id }) +} + +// 新增学生 +export const createDemoStudent = async (data: DemoStudentVO) => { + return await request.post({ url: `/infra/demo-student/create`, data }) +} + +// 修改学生 +export const updateDemoStudent = async (data: DemoStudentVO) => { + return await request.put({ url: `/infra/demo-student/update`, data }) +} + +// 删除学生 +export const deleteDemoStudent = async (id: number) => { + return await request.delete({ url: `/infra/demo-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemoStudent = async (params) => { + return await request.download({ url: `/infra/demo-student/export-excel`, params }) +} diff --git a/src/views/infra/demo02/DemoStudentContactForm.vue b/src/views/infra/demo02/DemoStudentContactForm.vue new file mode 100644 index 00000000..98c97fab --- /dev/null +++ b/src/views/infra/demo02/DemoStudentContactForm.vue @@ -0,0 +1,71 @@ +<template> + <!-- <el-row :gutter="10" class="mb2">--> + <!-- <el-col :span="1.5">--> + <!-- <el-button type="primary" @click="handleAdd">添加</el-button>--> + <!-- </el-col>--> + <!-- <el-col :span="1.5">--> + <!-- <el-button type="danger">删除</el-button>--> + <!-- </el-col>--> + <!-- </el-row>--> + <el-table + :data="formData" + @selection-change="handleDemoStudentContactSelectionChange" + ref="demoStudentContactRef" + :stripe="true" + > + <el-table-column label="序号" type="index" width="100" /> + <el-table-column label="名字" prop="name" width="300"> + <template #default="scope"> + <el-form-item label-width="0px" :inline-message="true"> + <el-input v-model="scope.row.name" placeholder="请输入名字" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="手机号码"> + <template #default="{ row, $index }"> + <el-form-item + label-width="0px" + :prop="`formData.${$index}.mobile`" + :rules="formRules.mobile" + :inline-message="true" + > + <el-input type="number" placeholder="输入手机号码" v-model="row.mobile" /> + </el-form-item> + </template> + </el-table-column> + </el-table> + <el-button @click="handleAdd" class="w-1/1">+ 添加客户信息</el-button> +</template> +<script setup lang="ts"> +const formData = ref([ + { + name: '芋艿' + }, + { + name: '土豆' + } +]) +const formRules = reactive({ + mobile: [required] +}) + +const handleDemoStudentContactSelectionChange = (val) => { + demoStudentContactList.value = val +} + +const demoStudentContactRef = ref() + +/** 新增按钮操作 */ +const handleAdd = () => { + formData.value.push({ + name: '测试' + }) +} + +/** 删除按钮操作 */ +const handleRemove = () => { + formData.value.push({ + name: '测试' + }) +} +</script> diff --git a/src/views/infra/demo02/DemoStudentForm.vue b/src/views/infra/demo02/DemoStudentForm.vue new file mode 100644 index 00000000..62303dc0 --- /dev/null +++ b/src/views/infra/demo02/DemoStudentForm.vue @@ -0,0 +1,97 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="表描述" prop="tableComment"> + <el-input v-model="formData.tableComment" placeholder="请输入" /> + </el-form-item> + <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> + <el-tab-pane label="User" name="first"> + <DemoStudentContactForm /> + </el-tab-pane> + <el-tab-pane label="Config" name="second">Config</el-tab-pane> + <el-tab-pane label="Role" name="third">Role</el-tab-pane> + <el-tab-pane label="Task" name="fourth">Task</el-tab-pane> + </el-tabs> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as DemoStudentApi from '@/api/infra/demo02' +import DemoStudentContactForm from './DemoStudentContactForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + demoStudentContactList: [] +}) +const formRules = reactive({}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + // resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await DemoStudentApi.getDemoStudent(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as DemoStudentApi.DemoStudentVO + if (formType.value === 'create') { + await DemoStudentApi.createDemoStudent(data) + message.success(t('common.createSuccess')) + } else { + await DemoStudentApi.updateDemoStudent(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/infra/demo02/index.vue b/src/views/infra/demo02/index.vue new file mode 100644 index 00000000..ae46f8b4 --- /dev/null +++ b/src/views/infra/demo02/index.vue @@ -0,0 +1,159 @@ +<template> + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.id" /> + </template> + </el-table-column> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <DemoStudentForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import download from '@/utils/download' +import * as DemoStudentApi from '@/api/infra/demo02' +import DemoStudentForm from './DemoStudentForm.vue' + +defineOptions({ name: 'InfraDemoStudent' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10 +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await DemoStudentApi.getDemoStudentPage(queryParams) + 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 formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await DemoStudentApi.deleteDemoStudent(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await DemoStudentApi.exportDemoStudent(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> From d45ebd4fcfb0bac96a575b5f594248e5b85f8778 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Fri, 10 Nov 2023 00:20:00 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E4=B8=BB=E5=AD=90=E8=A1=A8=EF=BC=9A?= =?UTF-8?q?=E6=9A=82=E6=97=B6=E5=AD=98=E5=82=A8=EF=BC=8C=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E8=B7=91=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/demo02/DemoStudentContactForm.vue | 54 +++++++++++-------- src/views/infra/demo02/DemoStudentForm.vue | 26 ++++++--- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/src/views/infra/demo02/DemoStudentContactForm.vue b/src/views/infra/demo02/DemoStudentContactForm.vue index 98c97fab..145b4889 100644 --- a/src/views/infra/demo02/DemoStudentContactForm.vue +++ b/src/views/infra/demo02/DemoStudentContactForm.vue @@ -1,22 +1,15 @@ <template> - <!-- <el-row :gutter="10" class="mb2">--> - <!-- <el-col :span="1.5">--> - <!-- <el-button type="primary" @click="handleAdd">添加</el-button>--> - <!-- </el-col>--> - <!-- <el-col :span="1.5">--> - <!-- <el-button type="danger">删除</el-button>--> - <!-- </el-col>--> - <!-- </el-row>--> <el-table :data="formData" @selection-change="handleDemoStudentContactSelectionChange" ref="demoStudentContactRef" :stripe="true" + class="-mt-10px" > <el-table-column label="序号" type="index" width="100" /> <el-table-column label="名字" prop="name" width="300"> <template #default="scope"> - <el-form-item label-width="0px" :inline-message="true"> + <el-form-item label-width="0px" :inline-message="true" class="mb-0px!"> <el-input v-model="scope.row.name" placeholder="请输入名字" /> </el-form-item> </template> @@ -25,26 +18,37 @@ <template #default="{ row, $index }"> <el-form-item label-width="0px" - :prop="`formData.${$index}.mobile`" + :prop="`demoStudentContactList.${$index}.mobile`" :rules="formRules.mobile" :inline-message="true" + class="mb-0px!" > <el-input type="number" placeholder="输入手机号码" v-model="row.mobile" /> </el-form-item> </template> </el-table-column> + <el-table-column align="center" fixed="right" label="操作" width="60"> + <el-button @click="handleAdd" link>—</el-button> + </el-table-column> </el-table> - <el-button @click="handleAdd" class="w-1/1">+ 添加客户信息</el-button> + <el-row justify="center" class="mt-3"> + <el-button @click="handleAdd" round>+ 添加联系人</el-button> + </el-row> </template> <script setup lang="ts"> -const formData = ref([ - { - name: '芋艿' - }, - { - name: '土豆' - } -]) +const props = defineProps<{ + formData: any[] +}>() +// const formData = ref([ +// { +// name: '芋艿', +// mobile: '15601691300' +// }, +// { +// name: '土豆', +// mobile: '15601691234' +// } +// ]) const formRules = reactive({ mobile: [required] }) @@ -56,15 +60,19 @@ const handleDemoStudentContactSelectionChange = (val) => { const demoStudentContactRef = ref() /** 新增按钮操作 */ +const emit = defineEmits(['update:formData']) const handleAdd = () => { - formData.value.push({ - name: '测试' - }) + emit('update:formData', [ + ...props.formData, + { + name: '土豆' + } + ]) } /** 删除按钮操作 */ const handleRemove = () => { - formData.value.push({ + formData.push({ name: '测试' }) } diff --git a/src/views/infra/demo02/DemoStudentForm.vue b/src/views/infra/demo02/DemoStudentForm.vue index 62303dc0..884788dc 100644 --- a/src/views/infra/demo02/DemoStudentForm.vue +++ b/src/views/infra/demo02/DemoStudentForm.vue @@ -7,16 +7,21 @@ label-width="100px" v-loading="formLoading" > - <el-form-item label="表描述" prop="tableComment"> - <el-input v-model="formData.tableComment" placeholder="请输入" /> + <el-form-item label="字段 1" prop="field1"> + <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + </el-form-item> + <el-form-item label="字段 2" prop="field2"> + <el-input v-model="formData.field2" placeholder="请输入字段 2" /> + </el-form-item> + <el-form-item label="字段 3" prop="field3"> + <el-input v-model="formData.field3" placeholder="请输入字段 3" /> </el-form-item> <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> - <el-tab-pane label="User" name="first"> - <DemoStudentContactForm /> + <el-tab-pane label="联系人信息" name="first"> + <DemoStudentContactForm v-model:form-data="formData.demoStudentContactList" /> </el-tab-pane> - <el-tab-pane label="Config" name="second">Config</el-tab-pane> - <el-tab-pane label="Role" name="third">Role</el-tab-pane> - <el-tab-pane label="Task" name="fourth">Task</el-tab-pane> + <el-tab-pane label="地址信息" name="third">地址信息</el-tab-pane> + <el-tab-pane label="其它信息" name="fourth">其它信息</el-tab-pane> </el-tabs> </el-form> <template #footer> @@ -38,7 +43,12 @@ const formLoading = ref(false) // 表单的加载中:1)修改时的数据加 const formType = ref('') // 表单的类型:create - 新增;update - 修改 const formData = ref({ id: undefined, - demoStudentContactList: [] + demoStudentContactList: [ + { + name: '芋艿', + mobile: '15601691300' + } + ] }) const formRules = reactive({}) const formRef = ref() // 表单 Ref From 86d9a97ccb08bec766ada95d5860deb28588e2b4 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Fri, 10 Nov 2023 08:51:01 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E4=B8=BB=E5=AD=90=E8=A1=A8=EF=BC=9A?= =?UTF-8?q?=E6=9A=82=E6=97=B6=E5=AD=98=E5=82=A8=EF=BC=8C=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C-=E8=A1=A8=E5=8D=95=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E8=B7=91=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/demo02/DemoStudentContactForm.vue | 27 ++++++------------- src/views/infra/demo02/DemoStudentForm.vue | 14 +++++----- 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/src/views/infra/demo02/DemoStudentContactForm.vue b/src/views/infra/demo02/DemoStudentContactForm.vue index 145b4889..0cd9d106 100644 --- a/src/views/infra/demo02/DemoStudentContactForm.vue +++ b/src/views/infra/demo02/DemoStudentContactForm.vue @@ -1,12 +1,6 @@ <template> - <el-table - :data="formData" - @selection-change="handleDemoStudentContactSelectionChange" - ref="demoStudentContactRef" - :stripe="true" - class="-mt-10px" - > - <el-table-column label="序号" type="index" width="100" /> + <el-table :data="formData" :stripe="true" class="-mt-10px"> + <el-table-column label="序号" type="index" width="60" /> <el-table-column label="名字" prop="name" width="300"> <template #default="scope"> <el-form-item label-width="0px" :inline-message="true" class="mb-0px!"> @@ -28,7 +22,9 @@ </template> </el-table-column> <el-table-column align="center" fixed="right" label="操作" width="60"> - <el-button @click="handleAdd" link>—</el-button> + <template #default="{ $index }"> + <el-button @click="handleRemove($index)" link>—</el-button> + </template> </el-table-column> </el-table> <el-row justify="center" class="mt-3"> @@ -53,12 +49,6 @@ const formRules = reactive({ mobile: [required] }) -const handleDemoStudentContactSelectionChange = (val) => { - demoStudentContactList.value = val -} - -const demoStudentContactRef = ref() - /** 新增按钮操作 */ const emit = defineEmits(['update:formData']) const handleAdd = () => { @@ -71,9 +61,8 @@ const handleAdd = () => { } /** 删除按钮操作 */ -const handleRemove = () => { - formData.push({ - name: '测试' - }) +const handleRemove = (index) => { + const formData = props.formData.filter((_, i) => i !== index) + emit('update:formData', formData) } </script> diff --git a/src/views/infra/demo02/DemoStudentForm.vue b/src/views/infra/demo02/DemoStudentForm.vue index 884788dc..1bb6d7ea 100644 --- a/src/views/infra/demo02/DemoStudentForm.vue +++ b/src/views/infra/demo02/DemoStudentForm.vue @@ -16,14 +16,14 @@ <el-form-item label="字段 3" prop="field3"> <el-input v-model="formData.field3" placeholder="请输入字段 3" /> </el-form-item> - <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> - <el-tab-pane label="联系人信息" name="first"> - <DemoStudentContactForm v-model:form-data="formData.demoStudentContactList" /> - </el-tab-pane> - <el-tab-pane label="地址信息" name="third">地址信息</el-tab-pane> - <el-tab-pane label="其它信息" name="fourth">其它信息</el-tab-pane> - </el-tabs> </el-form> + <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> + <el-tab-pane label="联系人信息" name="first"> + <DemoStudentContactForm v-model:form-data="formData.demoStudentContactList" /> + </el-tab-pane> + <el-tab-pane label="地址信息" name="third">地址信息</el-tab-pane> + <el-tab-pane label="其它信息" name="fourth">其它信息</el-tab-pane> + </el-tabs> <template #footer> <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> <el-button @click="dialogVisible = false">取 消</el-button> From 9f9e0f8bda0c19afbd6bc1d1290062d8f5ed9d3c Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Fri, 10 Nov 2023 19:54:55 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E4=B8=BB=E5=AD=90=E8=A1=A8=EF=BC=9A?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=E4=B8=89=E7=A7=8D=E6=A8=A1=E5=BC=8F=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/demo02/DemoStudentAddressForm.vue | 58 ++++++ .../infra/demo02/DemoStudentContactForm.vue | 119 ++++++----- src/views/infra/demo02/DemoStudentForm.vue | 61 ++++-- src/views/infra/demo02/index.vue | 33 ++-- .../infra/demo03/DemoStudentAddressForm.vue | 58 ++++++ .../infra/demo03/DemoStudentAddressList.vue | 38 ++++ .../infra/demo03/DemoStudentContactForm.vue | 89 +++++++++ .../infra/demo03/DemoStudentContactList.vue | 38 ++++ src/views/infra/demo03/DemoStudentForm.vue | 132 +++++++++++++ src/views/infra/demo03/index.vue | 176 +++++++++++++++++ .../infra/demo04/DemoStudentAddressForm.vue | 58 ++++++ .../infra/demo04/DemoStudentAddressList.vue | 39 ++++ .../infra/demo04/DemoStudentContactForm.vue | 96 +++++++++ .../infra/demo04/DemoStudentContactList.vue | 70 +++++++ src/views/infra/demo04/DemoStudentForm.vue | 132 +++++++++++++ src/views/infra/demo04/index.vue | 184 ++++++++++++++++++ 16 files changed, 1294 insertions(+), 87 deletions(-) create mode 100644 src/views/infra/demo02/DemoStudentAddressForm.vue create mode 100644 src/views/infra/demo03/DemoStudentAddressForm.vue create mode 100644 src/views/infra/demo03/DemoStudentAddressList.vue create mode 100644 src/views/infra/demo03/DemoStudentContactForm.vue create mode 100644 src/views/infra/demo03/DemoStudentContactList.vue create mode 100644 src/views/infra/demo03/DemoStudentForm.vue create mode 100644 src/views/infra/demo03/index.vue create mode 100644 src/views/infra/demo04/DemoStudentAddressForm.vue create mode 100644 src/views/infra/demo04/DemoStudentAddressList.vue create mode 100644 src/views/infra/demo04/DemoStudentContactForm.vue create mode 100644 src/views/infra/demo04/DemoStudentContactList.vue create mode 100644 src/views/infra/demo04/DemoStudentForm.vue create mode 100644 src/views/infra/demo04/index.vue diff --git a/src/views/infra/demo02/DemoStudentAddressForm.vue b/src/views/infra/demo02/DemoStudentAddressForm.vue new file mode 100644 index 00000000..af4cd8f1 --- /dev/null +++ b/src/views/infra/demo02/DemoStudentAddressForm.vue @@ -0,0 +1,58 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="子字段 1" prop="field1"> + <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + </el-form-item> + <el-form-item label="子字段 2" prop="field2"> + <el-input v-model="formData.field2" placeholder="请输入字段 2" /> + </el-form-item> + <el-form-item label="子字段 3" prop="field3"> + <el-input v-model="formData.field3" placeholder="请输入字段 3" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref({}) +const formRules = reactive({ + field1: [required] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + if (val) { + formData.value = { + field2: '番茄', + field3: '西瓜' + } + } else { + formData.value = {} + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 **/ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> diff --git a/src/views/infra/demo02/DemoStudentContactForm.vue b/src/views/infra/demo02/DemoStudentContactForm.vue index 0cd9d106..50c44263 100644 --- a/src/views/infra/demo02/DemoStudentContactForm.vue +++ b/src/views/infra/demo02/DemoStudentContactForm.vue @@ -1,68 +1,89 @@ <template> - <el-table :data="formData" :stripe="true" class="-mt-10px"> - <el-table-column label="序号" type="index" width="60" /> - <el-table-column label="名字" prop="name" width="300"> - <template #default="scope"> - <el-form-item label-width="0px" :inline-message="true" class="mb-0px!"> - <el-input v-model="scope.row.name" placeholder="请输入名字" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="手机号码"> - <template #default="{ row, $index }"> - <el-form-item - label-width="0px" - :prop="`demoStudentContactList.${$index}.mobile`" - :rules="formRules.mobile" - :inline-message="true" - class="mb-0px!" - > - <el-input type="number" placeholder="输入手机号码" v-model="row.mobile" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="操作" width="60"> - <template #default="{ $index }"> - <el-button @click="handleRemove($index)" link>—</el-button> - </template> - </el-table-column> - </el-table> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="0px" + v-loading="formLoading" + :inline-message="true" + > + <el-table :data="formData" class="-mt-10px"> + <el-table-column label="序号" type="index" width="100" /> + <el-table-column label="名字" prop="name" width="300"> + <template #default="row"> + <el-form-item class="mb-0px!"> + <el-input v-model="row.name" placeholder="请输入名字" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="手机号码"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.mobile`" :rules="formRules.mobile" class="mb-0px!"> + <el-input type="number" placeholder="输入手机号码" v-model="row.mobile" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column align="center" fixed="right" label="操作" width="60"> + <template #default="{ $index }"> + <el-button @click="handleDelete($index)" link>—</el-button> + </template> + </el-table-column> + </el-table> + </el-form> <el-row justify="center" class="mt-3"> <el-button @click="handleAdd" round>+ 添加联系人</el-button> </el-row> </template> <script setup lang="ts"> const props = defineProps<{ - formData: any[] + studentId: undefined // 学生编号 }>() -// const formData = ref([ -// { -// name: '芋艿', -// mobile: '15601691300' -// }, -// { -// name: '土豆', -// mobile: '15601691234' -// } -// ]) +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) const formRules = reactive({ mobile: [required] }) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + if (val) { + formData.value = [ + { + name: '芋艿', + mobile: '15601691300' + } + ] + } else { + formData.value = [] + } + }, + { immediate: true } +) /** 新增按钮操作 */ -const emit = defineEmits(['update:formData']) const handleAdd = () => { - emit('update:formData', [ - ...props.formData, - { - name: '土豆' - } - ]) + formData.value.push({ + name: '土豆' + }) } /** 删除按钮操作 */ -const handleRemove = (index) => { - const formData = props.formData.filter((_, i) => i !== index) - emit('update:formData', formData) +const handleDelete = (index) => { + formData.value.splice(index, 1) } + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 **/ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) </script> diff --git a/src/views/infra/demo02/DemoStudentForm.vue b/src/views/infra/demo02/DemoStudentForm.vue index 1bb6d7ea..fe0788c4 100644 --- a/src/views/infra/demo02/DemoStudentForm.vue +++ b/src/views/infra/demo02/DemoStudentForm.vue @@ -17,12 +17,14 @@ <el-input v-model="formData.field3" placeholder="请输入字段 3" /> </el-form-item> </el-form> - <el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleClick"> - <el-tab-pane label="联系人信息" name="first"> - <DemoStudentContactForm v-model:form-data="formData.demoStudentContactList" /> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="联系人信息" name="DemoStudentContact"> + <DemoStudentContactForm ref="demoStudentContactFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="地址信息" name="DemoStudentAddress"> + <DemoStudentAddressForm ref="demoStudentAddressFormRef" :student-id="formData.id" /> </el-tab-pane> - <el-tab-pane label="地址信息" name="third">地址信息</el-tab-pane> - <el-tab-pane label="其它信息" name="fourth">其它信息</el-tab-pane> </el-tabs> <template #footer> <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> @@ -33,6 +35,7 @@ <script setup lang="ts"> import * as DemoStudentApi from '@/api/infra/demo02' import DemoStudentContactForm from './DemoStudentContactForm.vue' +import DemoStudentAddressForm from './DemoStudentAddressForm.vue' const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 @@ -42,28 +45,36 @@ const dialogTitle = ref('') // 弹窗的标题 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 const formType = ref('') // 表单的类型:create - 新增;update - 修改 const formData = ref({ - id: undefined, - demoStudentContactList: [ - { - name: '芋艿', - mobile: '15601691300' - } - ] + id: undefined +}) +const formRules = reactive({ + field2: [required] }) -const formRules = reactive({}) const formRef = ref() // 表单 Ref +/** 子表的表单 */ +const demoStudentContactFormRef = ref() +const demoStudentAddressFormRef = ref() +const subTabsName = ref('DemoStudentContact') + /** 打开弹窗 */ const open = async (type: string, id?: number) => { dialogVisible.value = true dialogTitle.value = t('action.' + type) formType.value = type - // resetForm() + resetForm() // 修改时,设置数据 if (id) { + // debugger formLoading.value = true try { - formData.value = await DemoStudentApi.getDemoStudent(id) + // formData.value = await DemoStudentApi.getDemoStudent(id) + formData.value = { + id: id, + field1: '1', + field2: '22', + field3: '333' + } } finally { formLoading.value = false } @@ -75,13 +86,27 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗 const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 const submitForm = async () => { // 校验表单 - if (!formRef) return - const valid = await formRef.value.validate() - if (!valid) return + await formRef.value.validate() + // 校验子表单 + try { + await demoStudentContactFormRef.value.validate() + } catch (e) { + subTabsName.value = 'DemoStudentContact' + return + } + try { + await demoStudentAddressFormRef.value.validate() + } catch (e) { + subTabsName.value = 'DemoStudentAddress' + return + } // 提交请求 formLoading.value = true try { const data = formData.value as unknown as DemoStudentApi.DemoStudentVO + // 拼接子表的数据 + data.demoStudentContacts = demoStudentContactFormRef.value.getData() + data.demoStudentAddress = demoStudentAddressFormRef.value.getData() if (formType.value === 'create') { await DemoStudentApi.createDemoStudent(data) message.success(t('common.createSuccess')) diff --git a/src/views/infra/demo02/index.vue b/src/views/infra/demo02/index.vue index ae46f8b4..89fd656b 100644 --- a/src/views/infra/demo02/index.vue +++ b/src/views/infra/demo02/index.vue @@ -11,12 +11,7 @@ <el-form-item> <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['infra:demo-student:create']" - > + <el-button type="primary" plain @click="openForm('create')"> <Icon icon="ep:plus" class="mr-5px" /> 新增 </el-button> <el-button @@ -35,19 +30,10 @@ <!-- 列表 --> <ContentWrap> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="编号" align="center" prop="id"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.$dictType.toUpperCase()" :value="scope.row.id" /> - </template> - </el-table-column> + <el-table-column label="编号" align="center" prop="id" /> <el-table-column label="操作" align="center"> <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['infra:demo-student:update']" - > + <el-button link type="primary" @click="openForm('update', scope.row.id)"> 编辑 </el-button> <el-button @@ -98,9 +84,13 @@ const exportLoading = ref(false) // 导出的加载中 const getList = async () => { loading.value = true try { - const data = await DemoStudentApi.getDemoStudentPage(queryParams) - list.value = data.list - total.value = data.total + // const data = await DemoStudentApi.getDemoStudentPage(queryParams) + list.value = [ + { + id: 1 + } + ] + total.value = 10 } finally { loading.value = false } @@ -120,7 +110,10 @@ const resetQuery = () => { /** 添加/修改操作 */ const formRef = ref() +// const demoStudentContactFormRef = ref() const openForm = (type: string, id?: number) => { + // console.log(demoStudentContactFormRef, 'xx demoStudentContactFormRef xx') + // demoStudentContactFormRef.value.validate() formRef.value.open(type, id) } diff --git a/src/views/infra/demo03/DemoStudentAddressForm.vue b/src/views/infra/demo03/DemoStudentAddressForm.vue new file mode 100644 index 00000000..af4cd8f1 --- /dev/null +++ b/src/views/infra/demo03/DemoStudentAddressForm.vue @@ -0,0 +1,58 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="子字段 1" prop="field1"> + <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + </el-form-item> + <el-form-item label="子字段 2" prop="field2"> + <el-input v-model="formData.field2" placeholder="请输入字段 2" /> + </el-form-item> + <el-form-item label="子字段 3" prop="field3"> + <el-input v-model="formData.field3" placeholder="请输入字段 3" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref({}) +const formRules = reactive({ + field1: [required] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + if (val) { + formData.value = { + field2: '番茄', + field3: '西瓜' + } + } else { + formData.value = {} + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 **/ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> diff --git a/src/views/infra/demo03/DemoStudentAddressList.vue b/src/views/infra/demo03/DemoStudentAddressList.vue new file mode 100644 index 00000000..2354db56 --- /dev/null +++ b/src/views/infra/demo03/DemoStudentAddressList.vue @@ -0,0 +1,38 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="手机" align="center" prop="mobile" /> + </el-table> + </ContentWrap> +</template> + +<script setup lang="ts"> +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + // const data = await DemoStudentApi.getDemoStudentPage(queryParams) + list.value = [ + { + id: props.studentId, + mobile: '88888' + } + ] + } finally { + loading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/demo03/DemoStudentContactForm.vue b/src/views/infra/demo03/DemoStudentContactForm.vue new file mode 100644 index 00000000..50c44263 --- /dev/null +++ b/src/views/infra/demo03/DemoStudentContactForm.vue @@ -0,0 +1,89 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="0px" + v-loading="formLoading" + :inline-message="true" + > + <el-table :data="formData" class="-mt-10px"> + <el-table-column label="序号" type="index" width="100" /> + <el-table-column label="名字" prop="name" width="300"> + <template #default="row"> + <el-form-item class="mb-0px!"> + <el-input v-model="row.name" placeholder="请输入名字" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="手机号码"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.mobile`" :rules="formRules.mobile" class="mb-0px!"> + <el-input type="number" placeholder="输入手机号码" v-model="row.mobile" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column align="center" fixed="right" label="操作" width="60"> + <template #default="{ $index }"> + <el-button @click="handleDelete($index)" link>—</el-button> + </template> + </el-table-column> + </el-table> + </el-form> + <el-row justify="center" class="mt-3"> + <el-button @click="handleAdd" round>+ 添加联系人</el-button> + </el-row> +</template> +<script setup lang="ts"> +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + mobile: [required] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + if (val) { + formData.value = [ + { + name: '芋艿', + mobile: '15601691300' + } + ] + } else { + formData.value = [] + } + }, + { immediate: true } +) + +/** 新增按钮操作 */ +const handleAdd = () => { + formData.value.push({ + name: '土豆' + }) +} + +/** 删除按钮操作 */ +const handleDelete = (index) => { + formData.value.splice(index, 1) +} + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 **/ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> diff --git a/src/views/infra/demo03/DemoStudentContactList.vue b/src/views/infra/demo03/DemoStudentContactList.vue new file mode 100644 index 00000000..76d46116 --- /dev/null +++ b/src/views/infra/demo03/DemoStudentContactList.vue @@ -0,0 +1,38 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="手机" align="center" prop="mobile" /> + </el-table> + </ContentWrap> +</template> + +<script setup lang="ts"> +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + // const data = await DemoStudentApi.getDemoStudentPage(queryParams) + list.value = [ + { + id: props.studentId, + mobile: '15601691300' + } + ] + } finally { + loading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/demo03/DemoStudentForm.vue b/src/views/infra/demo03/DemoStudentForm.vue new file mode 100644 index 00000000..fe0788c4 --- /dev/null +++ b/src/views/infra/demo03/DemoStudentForm.vue @@ -0,0 +1,132 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="字段 1" prop="field1"> + <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + </el-form-item> + <el-form-item label="字段 2" prop="field2"> + <el-input v-model="formData.field2" placeholder="请输入字段 2" /> + </el-form-item> + <el-form-item label="字段 3" prop="field3"> + <el-input v-model="formData.field3" placeholder="请输入字段 3" /> + </el-form-item> + </el-form> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="联系人信息" name="DemoStudentContact"> + <DemoStudentContactForm ref="demoStudentContactFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="地址信息" name="DemoStudentAddress"> + <DemoStudentAddressForm ref="demoStudentAddressFormRef" :student-id="formData.id" /> + </el-tab-pane> + </el-tabs> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as DemoStudentApi from '@/api/infra/demo02' +import DemoStudentContactForm from './DemoStudentContactForm.vue' +import DemoStudentAddressForm from './DemoStudentAddressForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined +}) +const formRules = reactive({ + field2: [required] +}) +const formRef = ref() // 表单 Ref + +/** 子表的表单 */ +const demoStudentContactFormRef = ref() +const demoStudentAddressFormRef = ref() +const subTabsName = ref('DemoStudentContact') + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + // debugger + formLoading.value = true + try { + // formData.value = await DemoStudentApi.getDemoStudent(id) + formData.value = { + id: id, + field1: '1', + field2: '22', + field3: '333' + } + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 校验子表单 + try { + await demoStudentContactFormRef.value.validate() + } catch (e) { + subTabsName.value = 'DemoStudentContact' + return + } + try { + await demoStudentAddressFormRef.value.validate() + } catch (e) { + subTabsName.value = 'DemoStudentAddress' + return + } + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as DemoStudentApi.DemoStudentVO + // 拼接子表的数据 + data.demoStudentContacts = demoStudentContactFormRef.value.getData() + data.demoStudentAddress = demoStudentAddressFormRef.value.getData() + if (formType.value === 'create') { + await DemoStudentApi.createDemoStudent(data) + message.success(t('common.createSuccess')) + } else { + await DemoStudentApi.updateDemoStudent(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/infra/demo03/index.vue b/src/views/infra/demo03/index.vue new file mode 100644 index 00000000..afd5cbfc --- /dev/null +++ b/src/views/infra/demo03/index.vue @@ -0,0 +1,176 @@ +<template> + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button type="primary" plain @click="openForm('create')"> + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + :stripe="true" + :show-overflow-tooltip="true" + row-key="id" + > + <el-table-column type="expand"> + <template #default="scope"> + <!-- 子表的表单 --> + <el-tabs model-value="DemoStudentContact"> + <el-tab-pane label="联系人信息" name="DemoStudentContact"> + <DemoStudentContactList :student-id="scope.row.id" /> + </el-tab-pane> + <el-tab-pane label="地址信息" name="DemoStudentAddress"> + <DemoStudentAddressList :student-id="scope.row.id" /> + </el-tab-pane> + </el-tabs> + </template> + </el-table-column> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button link type="primary" @click="openForm('update', scope.row.id)"> + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <DemoStudentForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import download from '@/utils/download' +import * as DemoStudentApi from '@/api/infra/demo02' +import DemoStudentForm from './DemoStudentForm.vue' +import DemoStudentContactList from './DemoStudentContactList.vue' +import DemoStudentAddressList from './DemoStudentAddressList.vue' + +defineOptions({ name: 'InfraDemoStudent' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10 +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + // const data = await DemoStudentApi.getDemoStudentPage(queryParams) + list.value = [ + { + id: 1 + }, + { + id: 10 + } + ] + total.value = 10 + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +// const demoStudentContactFormRef = ref() +const openForm = (type: string, id?: number) => { + // console.log(demoStudentContactFormRef, 'xx demoStudentContactFormRef xx') + // demoStudentContactFormRef.value.validate() + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await DemoStudentApi.deleteDemoStudent(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await DemoStudentApi.exportDemoStudent(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/demo04/DemoStudentAddressForm.vue b/src/views/infra/demo04/DemoStudentAddressForm.vue new file mode 100644 index 00000000..af4cd8f1 --- /dev/null +++ b/src/views/infra/demo04/DemoStudentAddressForm.vue @@ -0,0 +1,58 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="子字段 1" prop="field1"> + <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + </el-form-item> + <el-form-item label="子字段 2" prop="field2"> + <el-input v-model="formData.field2" placeholder="请输入字段 2" /> + </el-form-item> + <el-form-item label="子字段 3" prop="field3"> + <el-input v-model="formData.field3" placeholder="请输入字段 3" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref({}) +const formRules = reactive({ + field1: [required] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + if (val) { + formData.value = { + field2: '番茄', + field3: '西瓜' + } + } else { + formData.value = {} + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 **/ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> diff --git a/src/views/infra/demo04/DemoStudentAddressList.vue b/src/views/infra/demo04/DemoStudentAddressList.vue new file mode 100644 index 00000000..92143456 --- /dev/null +++ b/src/views/infra/demo04/DemoStudentAddressList.vue @@ -0,0 +1,39 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="手机" align="center" prop="mobile" /> + </el-table> + </ContentWrap> +</template> + +<script setup lang="ts"> +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 + +// TODO 芋艿:暂时没改 +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + // const data = await DemoStudentApi.getDemoStudentPage(queryParams) + list.value = [ + { + id: props.studentId, + mobile: '88888' + } + ] + } finally { + loading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/demo04/DemoStudentContactForm.vue b/src/views/infra/demo04/DemoStudentContactForm.vue new file mode 100644 index 00000000..c8744eb0 --- /dev/null +++ b/src/views/infra/demo04/DemoStudentContactForm.vue @@ -0,0 +1,96 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="字段 1" prop="field1"> + <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as DemoStudentApi from '@/api/infra/demo02' +import DemoStudentContactForm from './DemoStudentContactForm.vue' +import DemoStudentAddressForm from './DemoStudentAddressForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined +}) +const formRules = reactive({ + field2: [required] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + // debugger + formLoading.value = true + try { + // formData.value = await DemoStudentApi.getDemoStudent(id) + formData.value = { + id: id, + field1: '1', + field2: '22', + field3: '333' + } + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as DemoStudentApi.DemoStudentVO + if (formType.value === 'create') { + // await DemoStudentApi.createDemoStudent(data) // TODO 芋艿:临时去掉 + message.success(t('common.createSuccess')) + } else { + await DemoStudentApi.updateDemoStudent(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/infra/demo04/DemoStudentContactList.vue b/src/views/infra/demo04/DemoStudentContactList.vue new file mode 100644 index 00000000..b944c407 --- /dev/null +++ b/src/views/infra/demo04/DemoStudentContactList.vue @@ -0,0 +1,70 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-button type="primary" plain @click="openForm('create')"> + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="手机" align="center" prop="mobile" /> + </el-table> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <DemoStudentContactForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import DemoStudentContactForm from './DemoStudentContactForm.vue' + +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const loading = ref(false) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + studentId: undefined +}) + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + queryParams.studentId = val + handleQuery() + }, + { immediate: false } +) + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + // const data = await DemoStudentApi.getDemoStudentPage(queryParams) + list.value = [ + { + id: props.studentId, + mobile: '15601691300' + } + ] + total.value = 10 + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} +</script> diff --git a/src/views/infra/demo04/DemoStudentForm.vue b/src/views/infra/demo04/DemoStudentForm.vue new file mode 100644 index 00000000..fe0788c4 --- /dev/null +++ b/src/views/infra/demo04/DemoStudentForm.vue @@ -0,0 +1,132 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="字段 1" prop="field1"> + <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + </el-form-item> + <el-form-item label="字段 2" prop="field2"> + <el-input v-model="formData.field2" placeholder="请输入字段 2" /> + </el-form-item> + <el-form-item label="字段 3" prop="field3"> + <el-input v-model="formData.field3" placeholder="请输入字段 3" /> + </el-form-item> + </el-form> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="联系人信息" name="DemoStudentContact"> + <DemoStudentContactForm ref="demoStudentContactFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="地址信息" name="DemoStudentAddress"> + <DemoStudentAddressForm ref="demoStudentAddressFormRef" :student-id="formData.id" /> + </el-tab-pane> + </el-tabs> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as DemoStudentApi from '@/api/infra/demo02' +import DemoStudentContactForm from './DemoStudentContactForm.vue' +import DemoStudentAddressForm from './DemoStudentAddressForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined +}) +const formRules = reactive({ + field2: [required] +}) +const formRef = ref() // 表单 Ref + +/** 子表的表单 */ +const demoStudentContactFormRef = ref() +const demoStudentAddressFormRef = ref() +const subTabsName = ref('DemoStudentContact') + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + // debugger + formLoading.value = true + try { + // formData.value = await DemoStudentApi.getDemoStudent(id) + formData.value = { + id: id, + field1: '1', + field2: '22', + field3: '333' + } + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 校验子表单 + try { + await demoStudentContactFormRef.value.validate() + } catch (e) { + subTabsName.value = 'DemoStudentContact' + return + } + try { + await demoStudentAddressFormRef.value.validate() + } catch (e) { + subTabsName.value = 'DemoStudentAddress' + return + } + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as DemoStudentApi.DemoStudentVO + // 拼接子表的数据 + data.demoStudentContacts = demoStudentContactFormRef.value.getData() + data.demoStudentAddress = demoStudentAddressFormRef.value.getData() + if (formType.value === 'create') { + await DemoStudentApi.createDemoStudent(data) + message.success(t('common.createSuccess')) + } else { + await DemoStudentApi.updateDemoStudent(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/infra/demo04/index.vue b/src/views/infra/demo04/index.vue new file mode 100644 index 00000000..9a6b8bfe --- /dev/null +++ b/src/views/infra/demo04/index.vue @@ -0,0 +1,184 @@ +<template> + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button type="primary" plain @click="openForm('create')"> + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + :stripe="true" + :show-overflow-tooltip="true" + highlight-current-row + @current-change="handleCurrentChange" + > + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button link type="primary" @click="openForm('update', scope.row.id)"> + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 子列表 --> + <ContentWrap> + <el-tabs model-value="DemoStudentContact"> + <el-tab-pane label="联系人信息" name="DemoStudentContact"> + <DemoStudentContactList :student-id="currentRow.id" /> + </el-tab-pane> + <el-tab-pane label="地址信息" name="DemoStudentAddress"> + <DemoStudentAddressList :student-id="currentRow.id" /> + </el-tab-pane> + </el-tabs> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <DemoStudentForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import download from '@/utils/download' +import * as DemoStudentApi from '@/api/infra/demo02' +import DemoStudentForm from './DemoStudentForm.vue' +import DemoStudentContactList from './DemoStudentContactList.vue' +import DemoStudentAddressList from './DemoStudentAddressList.vue' + +defineOptions({ name: 'InfraDemoStudent' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10 +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 +const currentRow = ref({}) // 选中行 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + // const data = await DemoStudentApi.getDemoStudentPage(queryParams) + list.value = [ + { + id: 1 + }, + { + id: 10 + } + ] + total.value = 10 + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +// const demoStudentContactFormRef = ref() +const openForm = (type: string, id?: number) => { + // console.log(demoStudentContactFormRef, 'xx demoStudentContactFormRef xx') + // demoStudentContactFormRef.value.validate() + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await DemoStudentApi.deleteDemoStudent(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await DemoStudentApi.exportDemoStudent(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 选中行操作 */ +const handleCurrentChange = (row) => { + console.log(currentRow.value, '==== currentRow.value ====') + console.log(row, '==== row ====') + currentRow.value = row +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> From 55f6e4ca25eb246d6c49327e0b23b6839d187c19 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Fri, 10 Nov 2023 23:01:36 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E4=B8=BB=E5=AD=90=E8=A1=A8=EF=BC=9A?= =?UTF-8?q?=E7=A1=AE=E8=AE=A4=E5=88=97=E8=A1=A8=E7=BC=96=E8=BE=91=E7=9A=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=BB=84=E4=BB=B6=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/UploadFile/src/UploadFile.vue | 2 + .../infra/demo02/DemoStudentContactForm.vue | 68 +++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/components/UploadFile/src/UploadFile.vue b/src/components/UploadFile/src/UploadFile.vue index 6895440b..bba466a7 100644 --- a/src/components/UploadFile/src/UploadFile.vue +++ b/src/components/UploadFile/src/UploadFile.vue @@ -144,6 +144,8 @@ watch( } else if (isArray(props.modelValue)) { // 情况2:字符串 files.concat(props.modelValue) + } else if (props.modelValue === undefined) { + // 情况3:undefined 不处理 } else { throw new Error('不支持的 modelValue 类型') } diff --git a/src/views/infra/demo02/DemoStudentContactForm.vue b/src/views/infra/demo02/DemoStudentContactForm.vue index 50c44263..694aadac 100644 --- a/src/views/infra/demo02/DemoStudentContactForm.vue +++ b/src/views/infra/demo02/DemoStudentContactForm.vue @@ -9,20 +9,73 @@ > <el-table :data="formData" class="-mt-10px"> <el-table-column label="序号" type="index" width="100" /> - <el-table-column label="名字" prop="name" width="300"> + <el-table-column label="名字" prop="name" width="50"> <template #default="row"> <el-form-item class="mb-0px!"> <el-input v-model="row.name" placeholder="请输入名字" /> </el-form-item> </template> </el-table-column> - <el-table-column label="手机号码"> + <el-table-column label="手机号码" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`${$index}.mobile`" :rules="formRules.mobile" class="mb-0px!"> <el-input type="number" placeholder="输入手机号码" v-model="row.mobile" /> </el-form-item> </template> </el-table-column> + <el-table-column label="类型" width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.javaType`" :rules="formRules.javaType" class="mb-0px!"> + <el-select v-model="row.javaType"> + <el-option label="Long" value="Long" /> + <el-option label="String" value="String" /> + <el-option label="Integer" value="Integer" /> + <el-option label="Double" value="Double" /> + <el-option label="BigDecimal" value="BigDecimal" /> + <el-option label="LocalDateTime" value="LocalDateTime" /> + <el-option label="Boolean" value="Boolean" /> + </el-select> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="多选" width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.sex`" :rules="formRules.sex" class="mb-0px!"> + <el-checkbox-group v-model="row.sex"> + <el-checkbox key="Long" label="Long">Long</el-checkbox> + <el-checkbox key="String" label="String">String</el-checkbox> + </el-checkbox-group> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="图片上传" width="200"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.pic`" :rules="formRules.pic" class="mb-0px!"> + <UploadImg v-model="row.pic" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="文件上传" width="200"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.file`" :rules="formRules.file" class="mb-0px!"> + <UploadFile v-model="row.file" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="大输入框" width="200"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.content`" :rules="formRules.content" class="mb-0px!"> + <el-input v-model="row.content" type="textarea" placeholder="请输入 content" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="HTML" width="1024"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.html`" :rules="formRules.html" class="mb-0px!"> + <Editor v-model="row.html" height="150px" /> + </el-form-item> + </template> + </el-table-column> <el-table-column align="center" fixed="right" label="操作" width="60"> <template #default="{ $index }"> <el-button @click="handleDelete($index)" link>—</el-button> @@ -41,7 +94,10 @@ const props = defineProps<{ const formLoading = ref(false) // 表单的加载中 const formData = ref([]) const formRules = reactive({ - mobile: [required] + mobile: [required], + javaType: [required], + sex: [required], + pic: [required] }) const formRef = ref() // 表单 Ref @@ -53,7 +109,11 @@ watch( formData.value = [ { name: '芋艿', - mobile: '15601691300' + mobile: '15601691300', + javaType: undefined, + sex: [], + pic: undefined, + file: undefined } ] } else { From 72c5eaae31fd37dcfcd016224351237a9e2004d7 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Sun, 12 Nov 2023 19:50:38 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=20one=20=E6=83=85=E5=86=B5=E4=B8=8B?= =?UTF-8?q?=E7=9A=84=E7=A4=BA=E4=BE=8B=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/demo01/index.ts | 43 +++ src/api/infra/demo02/index.ts | 14 + src/components/UploadFile/src/UploadFile.vue | 2 +- src/views/infra/demo01/Demo01StudentForm.vue | 150 +++++++++++ src/views/infra/demo01/index.vue | 251 ++++++++++++++++++ .../infra/demo02/DemoStudentAddressForm.vue | 100 +++++-- .../infra/demo02/DemoStudentContactForm.vue | 158 ++++++----- src/views/infra/demo02/DemoStudentForm.vue | 35 +-- .../demo02/bak/DemoStudentAddressForm.vue | 58 ++++ 9 files changed, 702 insertions(+), 109 deletions(-) create mode 100644 src/api/infra/demo01/index.ts create mode 100644 src/views/infra/demo01/Demo01StudentForm.vue create mode 100644 src/views/infra/demo01/index.vue create mode 100644 src/views/infra/demo02/bak/DemoStudentAddressForm.vue diff --git a/src/api/infra/demo01/index.ts b/src/api/infra/demo01/index.ts new file mode 100644 index 00000000..0154bc29 --- /dev/null +++ b/src/api/infra/demo01/index.ts @@ -0,0 +1,43 @@ +import request from '@/config/axios' + +export interface Demo01StudentVO { + id: number + name: string + description: string + birthday: Date + sex: number + enabled: boolean + avatar: string + video: string + memo: string +} + +// 查询学生列表 +export const getDemo01StudentPage = async (params) => { + return await request.get({ url: `/infra/demo01-student/page`, params }) +} + +// 查询学生详情 +export const getDemo01Student = async (id: number) => { + return await request.get({ url: `/infra/demo01-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo01Student = async (data: Demo01StudentVO) => { + return await request.post({ url: `/infra/demo01-student/create`, data }) +} + +// 修改学生 +export const updateDemo01Student = async (data: Demo01StudentVO) => { + return await request.put({ url: `/infra/demo01-student/update`, data }) +} + +// 删除学生 +export const deleteDemo01Student = async (id: number) => { + return await request.delete({ url: `/infra/demo01-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo01Student = async (params) => { + return await request.download({ url: `/infra/demo01-student/export-excel`, params }) +} \ No newline at end of file diff --git a/src/api/infra/demo02/index.ts b/src/api/infra/demo02/index.ts index b575dba4..500adde5 100644 --- a/src/api/infra/demo02/index.ts +++ b/src/api/infra/demo02/index.ts @@ -33,3 +33,17 @@ export const deleteDemoStudent = async (id: number) => { export const exportDemoStudent = async (params) => { return await request.download({ url: `/infra/demo-student/export-excel`, params }) } + +// 获得学生联系人列表 +export const getDemoStudentContactListByStudentId = async (studentId) => { + return await request.get({ + url: `/infra/demo-student/demo-student/list-by-student-id?studentId=` + studentId + }) +} + +// 获得学生地址 +export const getDemoStudentAddressByStudentId = async (studentId) => { + return await request.get({ + url: `/infra/demo-student/demo-student/get-by-student-id?studentId=` + studentId + }) +} diff --git a/src/components/UploadFile/src/UploadFile.vue b/src/components/UploadFile/src/UploadFile.vue index bba466a7..c1f3e4e2 100644 --- a/src/components/UploadFile/src/UploadFile.vue +++ b/src/components/UploadFile/src/UploadFile.vue @@ -144,7 +144,7 @@ watch( } else if (isArray(props.modelValue)) { // 情况2:字符串 files.concat(props.modelValue) - } else if (props.modelValue === undefined) { + } else if (props.modelValue == null) { // 情况3:undefined 不处理 } else { throw new Error('不支持的 modelValue 类型') diff --git a/src/views/infra/demo01/Demo01StudentForm.vue b/src/views/infra/demo01/Demo01StudentForm.vue new file mode 100644 index 00000000..dfc9823d --- /dev/null +++ b/src/views/infra/demo01/Demo01StudentForm.vue @@ -0,0 +1,150 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="formData.sex" placeholder="请选择性别"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-radio-group v-model="formData.enabled"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="头像"> + <UploadImg v-model="formData.avatar" /> + </el-form-item> + <el-form-item label="附件" prop="video"> + <UploadFile v-model="formData.video" /> + </el-form-item> + <el-form-item label="备注" prop="memo"> + <Editor v-model="formData.memo" height="150px" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo01StudentApi from '@/api/infra/demo01' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo01StudentApi.getDemo01Student(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo01StudentApi.Demo01StudentVO + if (formType.value === 'create') { + await Demo01StudentApi.createDemo01Student(data) + message.success(t('common.createSuccess')) + } else { + await Demo01StudentApi.updateDemo01Student(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined + } + formRef.value?.resetFields() +} +</script> diff --git a/src/views/infra/demo01/index.vue b/src/views/infra/demo01/index.vue new file mode 100644 index 00000000..fb35b561 --- /dev/null +++ b/src/views/infra/demo01/index.vue @@ -0,0 +1,251 @@ +<template> + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="queryParams.birthday" + value-format="YYYY-MM-DD" + type="date" + placeholder="选择出生日期" + clearable + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select + v-model="queryParams.sex" + placeholder="请选择性别" + clearable + class="!w-240px" + > + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-select + v-model="queryParams.enabled" + placeholder="请选择是否有效" + clearable + class="!w-240px" + > + <el-option + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo01-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo01-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column label="是否有效" align="center" prop="enabled"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> + </template> + </el-table-column> + <el-table-column label="头像" align="center" prop="avatar" /> + <el-table-column label="附件" align="center" prop="video" /> + <el-table-column label="备注" align="center" prop="memo" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo01-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo01-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo01StudentForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as Demo01StudentApi from '@/api/infra/demo01' +import Demo01StudentForm from './Demo01StudentForm.vue' + +defineOptions({ name: 'InfraDemo01Student' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + birthday: null, + birthday: [], + sex: null, + enabled: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo01StudentApi.getDemo01StudentPage(queryParams) + 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 formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo01StudentApi.deleteDemo01Student(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo01StudentApi.exportDemo01Student(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file diff --git a/src/views/infra/demo02/DemoStudentAddressForm.vue b/src/views/infra/demo02/DemoStudentAddressForm.vue index af4cd8f1..6d031406 100644 --- a/src/views/infra/demo02/DemoStudentAddressForm.vue +++ b/src/views/infra/demo02/DemoStudentAddressForm.vue @@ -6,39 +6,107 @@ label-width="100px" v-loading="formLoading" > - <el-form-item label="子字段 1" prop="field1"> - <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> </el-form-item> - <el-form-item label="子字段 2" prop="field2"> - <el-input v-model="formData.field2" placeholder="请输入字段 2" /> + <el-form-item label="个人简介"> + <Editor v-model="formData.description" height="150px" /> </el-form-item> - <el-form-item label="子字段 3" prop="field3"> - <el-input v-model="formData.field3" placeholder="请输入字段 3" /> + <el-form-item label="性别 1" prop="sex1"> + <el-select v-model="formData.sex1" placeholder="请选择性别 1"> + <el-option + v-for="dict in getStrDictOptions(DICT_TYPE.SYSTEM_SEX1)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="性别 2" prop="sex2"> + <el-checkbox-group v-model="formData.sex2"> + <el-checkbox + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_SEX2)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-checkbox> + </el-checkbox-group> + </el-form-item> + <el-form-item label="性别 3" prop="sex3"> + <el-radio-group v-model="formData.sex3"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.SYSTEM_SEX3)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="备注" prop="memo"> + <el-input v-model="formData.memo" type="textarea" placeholder="请输入备注" /> </el-form-item> </el-form> </template> <script setup lang="ts"> +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as DemoStudentApi from '@/api/infra/demo02' + const props = defineProps<{ - studentId: undefined // 学生编号 + studentId: undefined // 学生编号(主表的关联字段) }>() const formLoading = ref(false) // 表单的加载中 -const formData = ref({}) +const formData = ref([]) const formRules = reactive({ - field1: [required] + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + video: [{ required: true, message: '视频不能为空', trigger: 'blur' }], + description: [{ required: true, message: '个人简介不能为空', trigger: 'blur' }], + sex1: [{ required: true, message: '性别 1不能为空', trigger: 'change' }], + sex2: [{ required: true, message: '性别 2不能为空', trigger: 'blur' }], + sex3: [{ required: true, message: '性别 3不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] }) const formRef = ref() // 表单 Ref /** 监听主表的关联字段的变化,加载对应的子表数据 */ watch( () => props.studentId, - (val) => { - if (val) { + async (val) => { + // 情况一:val 为空,说明是新增,则置空 + if (!val) { formData.value = { - field2: '番茄', - field3: '西瓜' + id: undefined, + studentId: undefined, + name: undefined, + avatar: undefined, + video: undefined, + description: undefined, + sex1: undefined, + sex2: [], + sex3: undefined, + birthday: undefined, + memo: undefined } - } else { - formData.value = {} + return + } + // 情况二:val 非空,说明是修改,则加载数据 + try { + formLoading.value = true + formData.value = await DemoStudentApi.getDemoStudentAddressByStudentId(val) + } finally { + formLoading.value = false } }, { immediate: true } @@ -49,7 +117,7 @@ const validate = () => { return formRef.value.validate() } -/** 表单值 **/ +/** 表单值 */ const getData = () => { return formData.value } diff --git a/src/views/infra/demo02/DemoStudentContactForm.vue b/src/views/infra/demo02/DemoStudentContactForm.vue index 694aadac..5f173f14 100644 --- a/src/views/infra/demo02/DemoStudentContactForm.vue +++ b/src/views/infra/demo02/DemoStudentContactForm.vue @@ -3,84 +3,93 @@ ref="formRef" :model="formData" :rules="formRules" - label-width="0px" v-loading="formLoading" + label-width="0px" :inline-message="true" > <el-table :data="formData" class="-mt-10px"> <el-table-column label="序号" type="index" width="100" /> - <el-table-column label="名字" prop="name" width="50"> - <template #default="row"> - <el-form-item class="mb-0px!"> + <el-table-column label="名字" width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!"> <el-input v-model="row.name" placeholder="请输入名字" /> </el-form-item> </template> </el-table-column> - <el-table-column label="手机号码" width="150"> + <el-table-column label="个人简介" width="400"> <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.mobile`" :rules="formRules.mobile" class="mb-0px!"> - <el-input type="number" placeholder="输入手机号码" v-model="row.mobile" /> + <el-form-item + :prop="`${$index}.description`" + :rules="formRules.description" + class="mb-0px!" + > + <Editor v-model="row.description" height="150px" /> </el-form-item> </template> </el-table-column> - <el-table-column label="类型" width="150"> + <el-table-column label="性别 1" width="150"> <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.javaType`" :rules="formRules.javaType" class="mb-0px!"> - <el-select v-model="row.javaType"> - <el-option label="Long" value="Long" /> - <el-option label="String" value="String" /> - <el-option label="Integer" value="Integer" /> - <el-option label="Double" value="Double" /> - <el-option label="BigDecimal" value="BigDecimal" /> - <el-option label="LocalDateTime" value="LocalDateTime" /> - <el-option label="Boolean" value="Boolean" /> + <el-form-item :prop="`${$index}.sex1`" :rules="formRules.sex1" class="mb-0px!"> + <el-select v-model="row.sex1" placeholder="请选择性别 1"> + <el-option + v-for="dict in getStrDictOptions(DICT_TYPE.SYSTEM_SEX1)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> </el-select> </el-form-item> </template> </el-table-column> - <el-table-column label="多选" width="150"> + <el-table-column label="性别 2" width="150"> <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.sex`" :rules="formRules.sex" class="mb-0px!"> - <el-checkbox-group v-model="row.sex"> - <el-checkbox key="Long" label="Long">Long</el-checkbox> - <el-checkbox key="String" label="String">String</el-checkbox> + <el-form-item :prop="`${$index}.sex2`" :rules="formRules.sex2" class="mb-0px!"> + <el-checkbox-group v-model="row.sex2"> + <el-checkbox + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_SEX2)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-checkbox> </el-checkbox-group> </el-form-item> </template> </el-table-column> - <el-table-column label="图片上传" width="200"> + <el-table-column label="性别 3" width="150"> <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.pic`" :rules="formRules.pic" class="mb-0px!"> - <UploadImg v-model="row.pic" /> + <el-form-item :prop="`${$index}.sex3`" :rules="formRules.sex3" class="mb-0px!"> + <el-radio-group v-model="row.sex3"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.SYSTEM_SEX3)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> </el-form-item> </template> </el-table-column> - <el-table-column label="文件上传" width="200"> + <el-table-column label="出生日期" width="150"> <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.file`" :rules="formRules.file" class="mb-0px!"> - <UploadFile v-model="row.file" /> + <el-form-item :prop="`${$index}.birthday`" :rules="formRules.birthday" class="mb-0px!"> + <el-date-picker + v-model="row.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> </el-form-item> </template> </el-table-column> - <el-table-column label="大输入框" width="200"> + <el-table-column label="备注" width="200"> <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.content`" :rules="formRules.content" class="mb-0px!"> - <el-input v-model="row.content" type="textarea" placeholder="请输入 content" /> + <el-form-item :prop="`${$index}.memo`" :rules="formRules.memo" class="mb-0px!"> + <el-input v-model="row.memo" type="textarea" placeholder="请输入备注" /> </el-form-item> </template> </el-table-column> - <el-table-column label="HTML" width="1024"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.html`" :rules="formRules.html" class="mb-0px!"> - <Editor v-model="row.html" height="150px" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="操作" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>—</el-button> - </template> - </el-table-column> </el-table> </el-form> <el-row justify="center" class="mt-3"> @@ -88,36 +97,43 @@ </el-row> </template> <script setup lang="ts"> +import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as DemoStudentApi from '@/api/infra/demo02' + const props = defineProps<{ - studentId: undefined // 学生编号 + studentId: undefined // 学生编号(主表的关联字段) }>() const formLoading = ref(false) // 表单的加载中 const formData = ref([]) const formRules = reactive({ - mobile: [required], - javaType: [required], - sex: [required], - pic: [required] + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + video: [{ required: true, message: '视频不能为空', trigger: 'blur' }], + description: [{ required: true, message: '个人简介不能为空', trigger: 'blur' }], + sex1: [{ required: true, message: '性别 1不能为空', trigger: 'change' }], + sex2: [{ required: true, message: '性别 2不能为空', trigger: 'blur' }], + sex3: [{ required: true, message: '性别 3不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] }) const formRef = ref() // 表单 Ref /** 监听主表的关联字段的变化,加载对应的子表数据 */ watch( () => props.studentId, - (val) => { - if (val) { - formData.value = [ - { - name: '芋艿', - mobile: '15601691300', - javaType: undefined, - sex: [], - pic: undefined, - file: undefined - } - ] - } else { + async (val) => { + // 情况一:val 为空,说明是新增,则置空 + if (!val) { formData.value = [] + return + } + // 情况二:val 非空,说明是修改,则加载数据 + try { + formLoading.value = true + formData.value = await DemoStudentApi.getDemoStudentContactListByStudentId(val) + } finally { + formLoading.value = false } }, { immediate: true } @@ -125,9 +141,21 @@ watch( /** 新增按钮操作 */ const handleAdd = () => { - formData.value.push({ - name: '土豆' - }) + const row = { + id: undefined, + studentId: undefined, + name: undefined, + avatar: undefined, + video: undefined, + description: undefined, + sex1: undefined, + sex2: [], + sex3: undefined, + birthday: undefined, + memo: undefined + } + row.studentId = props.studentId + formData.value.push(row) } /** 删除按钮操作 */ @@ -140,7 +168,7 @@ const validate = () => { return formRef.value.validate() } -/** 表单值 **/ +/** 表单值 */ const getData = () => { return formData.value } diff --git a/src/views/infra/demo02/DemoStudentForm.vue b/src/views/infra/demo02/DemoStudentForm.vue index fe0788c4..e9454c0f 100644 --- a/src/views/infra/demo02/DemoStudentForm.vue +++ b/src/views/infra/demo02/DemoStudentForm.vue @@ -6,23 +6,13 @@ :rules="formRules" label-width="100px" v-loading="formLoading" - > - <el-form-item label="字段 1" prop="field1"> - <el-input v-model="formData.field1" placeholder="请输入字段 1" /> - </el-form-item> - <el-form-item label="字段 2" prop="field2"> - <el-input v-model="formData.field2" placeholder="请输入字段 2" /> - </el-form-item> - <el-form-item label="字段 3" prop="field3"> - <el-input v-model="formData.field3" placeholder="请输入字段 3" /> - </el-form-item> - </el-form> + /> <!-- 子表的表单 --> <el-tabs v-model="subTabsName"> - <el-tab-pane label="联系人信息" name="DemoStudentContact"> + <el-tab-pane label="学生联系人" name="demoStudentContact"> <DemoStudentContactForm ref="demoStudentContactFormRef" :student-id="formData.id" /> </el-tab-pane> - <el-tab-pane label="地址信息" name="DemoStudentAddress"> + <el-tab-pane label="学生地址" name="demoStudentAddress"> <DemoStudentAddressForm ref="demoStudentAddressFormRef" :student-id="formData.id" /> </el-tab-pane> </el-tabs> @@ -47,15 +37,13 @@ const formType = ref('') // 表单的类型:create - 新增;update - 修改 const formData = ref({ id: undefined }) -const formRules = reactive({ - field2: [required] -}) +const formRules = reactive({}) const formRef = ref() // 表单 Ref /** 子表的表单 */ +const subTabsName = ref('demoStudentContact') const demoStudentContactFormRef = ref() const demoStudentAddressFormRef = ref() -const subTabsName = ref('DemoStudentContact') /** 打开弹窗 */ const open = async (type: string, id?: number) => { @@ -65,16 +53,9 @@ const open = async (type: string, id?: number) => { resetForm() // 修改时,设置数据 if (id) { - // debugger formLoading.value = true try { - // formData.value = await DemoStudentApi.getDemoStudent(id) - formData.value = { - id: id, - field1: '1', - field2: '22', - field3: '333' - } + formData.value = await DemoStudentApi.getDemoStudent(id) } finally { formLoading.value = false } @@ -91,13 +72,13 @@ const submitForm = async () => { try { await demoStudentContactFormRef.value.validate() } catch (e) { - subTabsName.value = 'DemoStudentContact' + subTabsName.value = 'demoStudentContact' return } try { await demoStudentAddressFormRef.value.validate() } catch (e) { - subTabsName.value = 'DemoStudentAddress' + subTabsName.value = 'demoStudentAddress' return } // 提交请求 diff --git a/src/views/infra/demo02/bak/DemoStudentAddressForm.vue b/src/views/infra/demo02/bak/DemoStudentAddressForm.vue new file mode 100644 index 00000000..af4cd8f1 --- /dev/null +++ b/src/views/infra/demo02/bak/DemoStudentAddressForm.vue @@ -0,0 +1,58 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="子字段 1" prop="field1"> + <el-input v-model="formData.field1" placeholder="请输入字段 1" /> + </el-form-item> + <el-form-item label="子字段 2" prop="field2"> + <el-input v-model="formData.field2" placeholder="请输入字段 2" /> + </el-form-item> + <el-form-item label="子字段 3" prop="field3"> + <el-input v-model="formData.field3" placeholder="请输入字段 3" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +const props = defineProps<{ + studentId: undefined // 学生编号 +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref({}) +const formRules = reactive({ + field1: [required] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + if (val) { + formData.value = { + field2: '番茄', + field3: '西瓜' + } + } else { + formData.value = {} + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 **/ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> From f0f78860255d1b3190556cd4dbd500c69d8a4b1f Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Sun, 12 Nov 2023 22:33:38 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=E4=B8=BB=E5=AD=90=E8=A1=A8=EF=BC=88?= =?UTF-8?q?=E6=99=AE=E9=80=9A=EF=BC=89=E7=9A=84=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 5 +- src/api/infra/demo11/index.ts | 57 ++++ src/views/infra/demo11/Demo11StudentForm.vue | 183 +++++++++++++ .../components/Demo11StudentContactForm.vue | 169 ++++++++++++ .../components/Demo11StudentTeacherForm.vue | 122 +++++++++ src/views/infra/demo11/index.vue | 252 ++++++++++++++++++ 6 files changed, 786 insertions(+), 2 deletions(-) create mode 100644 src/api/infra/demo11/index.ts create mode 100644 src/views/infra/demo11/Demo11StudentForm.vue create mode 100644 src/views/infra/demo11/components/Demo11StudentContactForm.vue create mode 100644 src/views/infra/demo11/components/Demo11StudentTeacherForm.vue create mode 100644 src/views/infra/demo11/index.vue diff --git a/.eslintrc.js b/.eslintrc.js index f2977df6..70c91784 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,7 +21,7 @@ module.exports = defineConfig({ 'plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'prettier', - 'plugin:prettier/recommended', + 'plugin:prettier/recommended', '@unocss' ], rules: { @@ -67,6 +67,7 @@ module.exports = defineConfig({ } ], 'vue/multi-word-component-names': 'off', - 'vue/no-v-html': 'off' + 'vue/no-v-html': 'off', + 'prettier/prettier': 'off' // 芋艿:默认关闭 prettier 的 ESLint 校验,因为我们使用的是 IDE 的 Prettier 插件 } }) diff --git a/src/api/infra/demo11/index.ts b/src/api/infra/demo11/index.ts new file mode 100644 index 00000000..4c4c7b4e --- /dev/null +++ b/src/api/infra/demo11/index.ts @@ -0,0 +1,57 @@ +import request from '@/config/axios' + +export interface Demo11StudentVO { + id: number + name: string + description: string + birthday: Date + sex: number + enabled: boolean + avatar: string + video: string + memo: string +} + +// 查询学生列表 +export const getDemo11StudentPage = async (params) => { + return await request.get({ url: `/infra/demo11-student/page`, params }) +} + +// 查询学生详情 +export const getDemo11Student = async (id: number) => { + return await request.get({ url: `/infra/demo11-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo11Student = async (data: Demo11StudentVO) => { + return await request.post({ url: `/infra/demo11-student/create`, data }) +} + +// 修改学生 +export const updateDemo11Student = async (data: Demo11StudentVO) => { + return await request.put({ url: `/infra/demo11-student/update`, data }) +} + +// 删除学生 +export const deleteDemo11Student = async (id: number) => { + return await request.delete({ url: `/infra/demo11-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo11Student = async (params) => { + return await request.download({ url: `/infra/demo11-student/export-excel`, params }) +} + +// ==================== 子表(学生联系人) ==================== + +// 获得学生联系人列表 +export const getDemo11StudentContactListByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo11-student/demo11-student/list-by-student-id?studentId=` + studentId }) +} + +// ==================== 子表(学生班主任) ==================== + +// 获得学生班主任 +export const getDemo11StudentTeacherByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo11-student/demo11-student/get-by-student-id?studentId=` + studentId }) +} \ No newline at end of file diff --git a/src/views/infra/demo11/Demo11StudentForm.vue b/src/views/infra/demo11/Demo11StudentForm.vue new file mode 100644 index 00000000..39c21a2b --- /dev/null +++ b/src/views/infra/demo11/Demo11StudentForm.vue @@ -0,0 +1,183 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="formData.sex" placeholder="请选择性别"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-radio-group v-model="formData.enabled"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="头像"> + <UploadImg v-model="formData.avatar" /> + </el-form-item> + <el-form-item label="附件" prop="video"> + <UploadFile v-model="formData.video" /> + </el-form-item> + <el-form-item label="备注" prop="memo"> + <Editor v-model="formData.memo" height="150px" /> + </el-form-item> + </el-form> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="学生联系人" name="demo11StudentContact"> + <Demo11StudentContactForm ref="demo11StudentContactFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="学生班主任" name="demo11StudentTeacher"> + <Demo11StudentTeacherForm ref="demo11StudentTeacherFormRef" :student-id="formData.id" /> + </el-tab-pane> + </el-tabs> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo11StudentApi from '@/api/infra/demo11' +import Demo11StudentContactForm from './components/Demo11StudentContactForm.vue' +import Demo11StudentTeacherForm from './components/Demo11StudentTeacherForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 子表的表单 */ +const subTabsName = ref('demo11StudentContact') +const demo11StudentContactFormRef = ref() +const demo11StudentTeacherFormRef = ref() + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo11StudentApi.getDemo11Student(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 校验子表单 + try { + await demo11StudentContactFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo11StudentContact' + return + } + try { + await demo11StudentTeacherFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo11StudentTeacher' + return + } + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo11StudentApi.Demo11StudentVO + // 拼接子表的数据 + data.demo11StudentContacts = demo11StudentContactFormRef.value.getData() + data.demo11StudentTeacher = demo11StudentTeacherFormRef.value.getData() + if (formType.value === 'create') { + await Demo11StudentApi.createDemo11Student(data) + message.success(t('common.createSuccess')) + } else { + await Demo11StudentApi.updateDemo11Student(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo11/components/Demo11StudentContactForm.vue b/src/views/infra/demo11/components/Demo11StudentContactForm.vue new file mode 100644 index 00000000..1ab017e8 --- /dev/null +++ b/src/views/infra/demo11/components/Demo11StudentContactForm.vue @@ -0,0 +1,169 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + v-loading="formLoading" + label-width="0px" + :inline-message="true" + > + <el-table :data="formData" class="-mt-10px"> + <el-table-column label="序号" type="index" width="100" /> + <el-table-column label="名字" width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!"> + <el-input v-model="row.name" placeholder="请输入名字" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="简介" width="200"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.description`" :rules="formRules.description" class="mb-0px!"> + <el-input v-model="row.description" type="textarea" placeholder="请输入简介" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="出生日期" width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.birthday`" :rules="formRules.birthday" class="mb-0px!"> + <el-date-picker + v-model="row.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="性别" width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.sex`" :rules="formRules.sex" class="mb-0px!"> + <el-select v-model="row.sex" placeholder="请选择性别"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="是否有效" width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.enabled`" :rules="formRules.enabled" class="mb-0px!"> + <el-radio-group v-model="row.enabled"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="头像" width="200"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.avatar`" :rules="formRules.avatar" class="mb-0px!"> + <UploadImg v-model="row.avatar" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="附件" width="200"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.video`" :rules="formRules.video" class="mb-0px!"> + <UploadFile v-model="row.video" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="备注" width="400"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.memo`" :rules="formRules.memo" class="mb-0px!"> + <Editor v-model="row.memo" height="150px" /> + </el-form-item> + </template> + </el-table-column> + </el-table> + </el-form> + <el-row justify="center" class="mt-3"> + <el-button @click="handleAdd" round>+ 添加学生联系人</el-button> + </el-row> +</template> +<script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo11StudentApi from '@/api/infra/demo11' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 情况一:val 为空,说明是新增,则置空 + if (!val) { + formData.value = [] + return; + } + // 情况二:val 非空,说明是修改,则加载数据 + try { + formLoading.value = true + formData.value = await Demo11StudentApi.getDemo11StudentContactListByStudentId(val) + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 新增按钮操作 */ +const handleAdd = () => { + const row = { + id: undefined, + studentId: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined + } + row.studentId = props.studentId + formData.value.push(row) +} + +/** 删除按钮操作 */ +const handleDelete = (index) => { + formData.value.splice(index, 1) +} + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo11/components/Demo11StudentTeacherForm.vue b/src/views/infra/demo11/components/Demo11StudentTeacherForm.vue new file mode 100644 index 00000000..a8697be1 --- /dev/null +++ b/src/views/infra/demo11/components/Demo11StudentTeacherForm.vue @@ -0,0 +1,122 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="formData.sex" placeholder="请选择性别"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-radio-group v-model="formData.enabled"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="头像" prop="avatar"> + <UploadImg v-model="formData.avatar" /> + </el-form-item> + <el-form-item label="附件" prop="video"> + <UploadFile v-model="formData.video" /> + </el-form-item> + <el-form-item label="备注" prop="memo"> + <Editor v-model="formData.memo" height="150px" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo11StudentApi from '@/api/infra/demo11' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 1. 重置表单 + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined, + } + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + const data = await Demo11StudentApi.getDemo11StudentTeacherByStudentId(val) + if (!data) { + return + } + formData.value = data + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo11/index.vue b/src/views/infra/demo11/index.vue new file mode 100644 index 00000000..36529eb9 --- /dev/null +++ b/src/views/infra/demo11/index.vue @@ -0,0 +1,252 @@ +<template> + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="queryParams.birthday" + value-format="YYYY-MM-DD" + type="date" + placeholder="选择出生日期" + clearable + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select + v-model="queryParams.sex" + placeholder="请选择性别" + clearable + class="!w-240px" + > + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-select + v-model="queryParams.enabled" + placeholder="请选择是否有效" + clearable + class="!w-240px" + > + <el-option + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo11-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo11-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column label="是否有效" align="center" prop="enabled"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> + </template> + </el-table-column> + <el-table-column label="头像" align="center" prop="avatar" /> + <el-table-column label="附件" align="center" prop="video" /> + <el-table-column label="备注" align="center" prop="memo" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo11-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo11-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo11StudentForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as Demo11StudentApi from '@/api/infra/demo11' +import Demo11StudentForm from './Demo11StudentForm.vue' + +defineOptions({ name: 'InfraDemo11Student' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + birthday: null, + birthday: [], + sex: null, + enabled: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo11StudentApi.getDemo11StudentPage(queryParams) + 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 formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo11StudentApi.deleteDemo11Student(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo11StudentApi.exportDemo11Student(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file From 999d8de9e972d62ae4bf2a23bcb05d7559c8c101 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Mon, 13 Nov 2023 13:57:15 +0800 Subject: [PATCH 08/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=E4=B8=BB=E5=AD=90=E8=A1=A8=EF=BC=88?= =?UTF-8?q?=E5=86=85=E5=B5=8C=EF=BC=89=E7=9A=84=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/demo12/index.ts | 57 ++++ .../components/Demo11StudentContactForm.vue | 5 + src/views/infra/demo12/Demo12StudentForm.vue | 183 +++++++++++++ .../components/Demo12StudentContactForm.vue | 5 + .../components/Demo12StudentContactList.vue | 63 +++++ .../components/Demo12StudentTeacherForm.vue | 5 + .../components/Demo12StudentTeacherList.vue | 67 +++++ src/views/infra/demo12/index.vue | 252 ++++++++++++++++++ 8 files changed, 637 insertions(+) create mode 100644 src/api/infra/demo12/index.ts create mode 100644 src/views/infra/demo12/Demo12StudentForm.vue create mode 100644 src/views/infra/demo12/components/Demo12StudentContactForm.vue create mode 100644 src/views/infra/demo12/components/Demo12StudentContactList.vue create mode 100644 src/views/infra/demo12/components/Demo12StudentTeacherForm.vue create mode 100644 src/views/infra/demo12/components/Demo12StudentTeacherList.vue create mode 100644 src/views/infra/demo12/index.vue diff --git a/src/api/infra/demo12/index.ts b/src/api/infra/demo12/index.ts new file mode 100644 index 00000000..33c3fb4f --- /dev/null +++ b/src/api/infra/demo12/index.ts @@ -0,0 +1,57 @@ +import request from '@/config/axios' + +export interface Demo12StudentVO { + id: number + name: string + description: string + birthday: Date + sex: number + enabled: boolean + avatar: string + video: string + memo: string +} + +// 查询学生列表 +export const getDemo12StudentPage = async (params) => { + return await request.get({ url: `/infra/demo12-student/page`, params }) +} + +// 查询学生详情 +export const getDemo12Student = async (id: number) => { + return await request.get({ url: `/infra/demo12-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo12Student = async (data: Demo12StudentVO) => { + return await request.post({ url: `/infra/demo12-student/create`, data }) +} + +// 修改学生 +export const updateDemo12Student = async (data: Demo12StudentVO) => { + return await request.put({ url: `/infra/demo12-student/update`, data }) +} + +// 删除学生 +export const deleteDemo12Student = async (id: number) => { + return await request.delete({ url: `/infra/demo12-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo12Student = async (params) => { + return await request.download({ url: `/infra/demo12-student/export-excel`, params }) +} + +// ==================== 子表(学生联系人) ==================== + +// 获得学生联系人列表 +export const getDemo12StudentContactListByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo12-student/demo12-student/list-by-student-id?studentId=` + studentId }) +} + +// ==================== 子表(学生班主任) ==================== + +// 获得学生班主任 +export const getDemo12StudentTeacherByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo12-student/demo12-student/get-by-student-id?studentId=` + studentId }) +} \ No newline at end of file diff --git a/src/views/infra/demo11/components/Demo11StudentContactForm.vue b/src/views/infra/demo11/components/Demo11StudentContactForm.vue index 1ab017e8..ba900017 100644 --- a/src/views/infra/demo11/components/Demo11StudentContactForm.vue +++ b/src/views/infra/demo11/components/Demo11StudentContactForm.vue @@ -85,6 +85,11 @@ </el-form-item> </template> </el-table-column> + <el-table-column align="center" fixed="right" label="操作" width="60"> + <template #default="{ $index }"> + <el-button @click="handleDelete($index)" link>—</el-button> + </template> + </el-table-column> </el-table> </el-form> <el-row justify="center" class="mt-3"> diff --git a/src/views/infra/demo12/Demo12StudentForm.vue b/src/views/infra/demo12/Demo12StudentForm.vue new file mode 100644 index 00000000..d3cb482d --- /dev/null +++ b/src/views/infra/demo12/Demo12StudentForm.vue @@ -0,0 +1,183 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="formData.sex" placeholder="请选择性别"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-radio-group v-model="formData.enabled"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="头像"> + <UploadImg v-model="formData.avatar" /> + </el-form-item> + <el-form-item label="附件" prop="video"> + <UploadFile v-model="formData.video" /> + </el-form-item> + <el-form-item label="备注" prop="memo"> + <Editor v-model="formData.memo" height="150px" /> + </el-form-item> + </el-form> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="学生联系人" name="demo12StudentContact"> + <Demo12StudentContactForm ref="demo12StudentContactFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="学生班主任" name="demo12StudentTeacher"> + <Demo12StudentTeacherForm ref="demo12StudentTeacherFormRef" :student-id="formData.id" /> + </el-tab-pane> + </el-tabs> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo12StudentApi from '@/api/infra/demo12' +import Demo12StudentContactForm from './components/Demo12StudentContactForm.vue' +import Demo12StudentTeacherForm from './components/Demo12StudentTeacherForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 子表的表单 */ +const subTabsName = ref('demo12StudentContact') +const demo12StudentContactFormRef = ref() +const demo12StudentTeacherFormRef = ref() + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo12StudentApi.getDemo12Student(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 校验子表单 + try { + await demo12StudentContactFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo12StudentContact' + return + } + try { + await demo12StudentTeacherFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo12StudentTeacher' + return + } + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo12StudentApi.Demo12StudentVO + // 拼接子表的数据 + data.demo12StudentContacts = demo12StudentContactFormRef.value.getData() + data.demo12StudentTeacher = demo12StudentTeacherFormRef.value.getData() + if (formType.value === 'create') { + await Demo12StudentApi.createDemo12Student(data) + message.success(t('common.createSuccess')) + } else { + await Demo12StudentApi.updateDemo12Student(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentContactForm.vue b/src/views/infra/demo12/components/Demo12StudentContactForm.vue new file mode 100644 index 00000000..d71f6146 --- /dev/null +++ b/src/views/infra/demo12/components/Demo12StudentContactForm.vue @@ -0,0 +1,5 @@ +<template> + <div>123</div> +</template> +<script setup lang="ts"> +</script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentContactList.vue b/src/views/infra/demo12/components/Demo12StudentContactList.vue new file mode 100644 index 00000000..65ed9df1 --- /dev/null +++ b/src/views/infra/demo12/components/Demo12StudentContactList.vue @@ -0,0 +1,63 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="学生编号" align="center" prop="studentId" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column label="是否有效" align="center" prop="enabled"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> + </template> + </el-table-column> + <el-table-column label="头像" align="center" prop="avatar" /> + <el-table-column label="附件" align="center" prop="video" /> + <el-table-column label="备注" align="center" prop="memo" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + </el-table> + </ContentWrap> +</template> + +<script setup lang="ts"> +import { DICT_TYPE } from '@/utils/dict' +import * as Demo12StudentApi from '@/api/infra/demo12' +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + list.value = await Demo12StudentApi.getDemo12StudentContactListByStudentId(studentId.props) + } finally { + loading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue b/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue new file mode 100644 index 00000000..d71f6146 --- /dev/null +++ b/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue @@ -0,0 +1,5 @@ +<template> + <div>123</div> +</template> +<script setup lang="ts"> +</script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentTeacherList.vue b/src/views/infra/demo12/components/Demo12StudentTeacherList.vue new file mode 100644 index 00000000..55f6845b --- /dev/null +++ b/src/views/infra/demo12/components/Demo12StudentTeacherList.vue @@ -0,0 +1,67 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="学生编号" align="center" prop="studentId" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column label="是否有效" align="center" prop="enabled"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> + </template> + </el-table-column> + <el-table-column label="头像" align="center" prop="avatar" /> + <el-table-column label="附件" align="center" prop="video" /> + <el-table-column label="备注" align="center" prop="memo" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + </el-table> + </ContentWrap> +</template> + +<script setup lang="ts"> +import { DICT_TYPE } from '@/utils/dict' +import * as Demo12StudentApi from '@/api/infra/demo12' +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo12StudentApi.getDemo12StudentTeacherByStudentId(studentId.props) + if (!data) { + return + } + list.value.push(data) + } finally { + loading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file diff --git a/src/views/infra/demo12/index.vue b/src/views/infra/demo12/index.vue new file mode 100644 index 00000000..c5a82a4c --- /dev/null +++ b/src/views/infra/demo12/index.vue @@ -0,0 +1,252 @@ +<template> + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="queryParams.birthday" + value-format="YYYY-MM-DD" + type="date" + placeholder="选择出生日期" + clearable + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select + v-model="queryParams.sex" + placeholder="请选择性别" + clearable + class="!w-240px" + > + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-select + v-model="queryParams.enabled" + placeholder="请选择是否有效" + clearable + class="!w-240px" + > + <el-option + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo12-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo12-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column label="是否有效" align="center" prop="enabled"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> + </template> + </el-table-column> + <el-table-column label="头像" align="center" prop="avatar" /> + <el-table-column label="附件" align="center" prop="video" /> + <el-table-column label="备注" align="center" prop="memo" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo12-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo12-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo12StudentForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as Demo12StudentApi from '@/api/infra/demo12' +import Demo12StudentForm from './Demo12StudentForm.vue' + +defineOptions({ name: 'InfraDemo12Student' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + birthday: null, + birthday: [], + sex: null, + enabled: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo12StudentApi.getDemo12StudentPage(queryParams) + 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 formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo12StudentApi.deleteDemo12Student(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo12StudentApi.exportDemo12Student(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file From 45656562a82353927da0aa614a1ce0689e7bd6b0 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Tue, 14 Nov 2023 09:50:54 +0800 Subject: [PATCH 09/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E6=94=AF=E6=8C=81=E8=AE=BE=E7=BD=AE=E4=B8=BB=E5=AD=90?= =?UTF-8?q?=E8=A1=A8=E7=9A=84=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/codegen/index.ts | 10 +- src/api/infra/demo12/index.ts | 48 +++++- src/views/infra/codegen/EditTable.vue | 2 +- .../codegen/components/GenerateInfoForm.vue | 94 ++++++----- src/views/infra/demo12/Demo12StudentForm.vue | 2 +- .../components/Demo12StudentContactForm.vue | 152 +++++++++++++++++- .../components/Demo12StudentContactList.vue | 95 ++++++++++- .../components/Demo12StudentTeacherForm.vue | 152 +++++++++++++++++- .../components/Demo12StudentTeacherList.vue | 99 ++++++++++-- src/views/infra/demo12/index.vue | 28 +++- 10 files changed, 612 insertions(+), 70 deletions(-) diff --git a/src/api/infra/codegen/index.ts b/src/api/infra/codegen/index.ts index 64701efe..1b91e917 100644 --- a/src/api/infra/codegen/index.ts +++ b/src/api/infra/codegen/index.ts @@ -67,6 +67,11 @@ export type CodegenCreateListReqVO = { tableNames: string[] } +// 查询列表代码生成表定义 +export const getCodegenTableList = (dataSourceConfigId: number) => { + return request.get({ url: '/infra/codegen/table/list?dataSourceConfigId=' + dataSourceConfigId }) +} + // 查询列表代码生成表定义 export const getCodegenTablePage = (params: PageParam) => { return request.get({ url: '/infra/codegen/table/page', params }) @@ -92,11 +97,6 @@ export const syncCodegenFromDB = (id: number) => { return request.put({ url: '/infra/codegen/sync-from-db?tableId=' + id }) } -// 基于 SQL 建表语句,同步数据库的表和字段定义 -export const syncCodegenFromSQL = (id: number, sql: string) => { - return request.put({ url: '/infra/codegen/sync-from-sql?tableId=' + id + '&sql=' + sql }) -} - // 预览生成代码 export const previewCodegen = (id: number) => { return request.get({ url: '/infra/codegen/preview?tableId=' + id }) diff --git a/src/api/infra/demo12/index.ts b/src/api/infra/demo12/index.ts index 33c3fb4f..3f2be47e 100644 --- a/src/api/infra/demo12/index.ts +++ b/src/api/infra/demo12/index.ts @@ -44,14 +44,52 @@ export const exportDemo12Student = async (params) => { // ==================== 子表(学生联系人) ==================== -// 获得学生联系人列表 -export const getDemo12StudentContactListByStudentId = async (studentId) => { - return await request.get({ url: `/infra/demo12-student/demo12-student/list-by-student-id?studentId=` + studentId }) +// 获得学生联系人分页 +export const getDemo12StudentContactPage = async (params) => { + return await request.get({ url: `/infra/demo12-student/demo12-student-contact/page`, params }) +} +// 新增学生联系人 +export const createDemo12StudentContact = async (data) => { + return await request.post({ url: `/infra/demo12-student/demo12-student-contact/create`, data }) +} + +// 修改学生联系人 +export const updateDemo12StudentContact = async (data) => { + return await request.put({ url: `/infra/demo12-student/demo12-student-contact/update`, data }) +} + +// 删除学生联系人 +export const deleteDemo12StudentContact = async (id: number) => { + return await request.delete({ url: `/infra/demo12-student/demo12-student-contact/delete?id=` + id }) +} + +// 获得学生联系人 +export const getDemo12StudentContact = async (id: number) => { + return await request.get({ url: `/infra/demo12-student/demo12-student-contact/get?id=` + id }) } // ==================== 子表(学生班主任) ==================== +// 获得学生班主任分页 +export const getDemo12StudentTeacherPage = async (params) => { + return await request.get({ url: `/infra/demo12-student/demo12-student-teacher/page`, params }) +} +// 新增学生班主任 +export const createDemo12StudentTeacher = async (data) => { + return await request.post({ url: `/infra/demo12-student/demo12-student-teacher/create`, data }) +} + +// 修改学生班主任 +export const updateDemo12StudentTeacher = async (data) => { + return await request.put({ url: `/infra/demo12-student/demo12-student-teacher/update`, data }) +} + +// 删除学生班主任 +export const deleteDemo12StudentTeacher = async (id: number) => { + return await request.delete({ url: `/infra/demo12-student/demo12-student-teacher/delete?id=` + id }) +} + // 获得学生班主任 -export const getDemo12StudentTeacherByStudentId = async (studentId) => { - return await request.get({ url: `/infra/demo12-student/demo12-student/get-by-student-id?studentId=` + studentId }) +export const getDemo12StudentTeacher = async (id: number) => { + return await request.get({ url: `/infra/demo12-student/demo12-student-teacher/get?id=` + id }) } \ No newline at end of file diff --git a/src/views/infra/codegen/EditTable.vue b/src/views/infra/codegen/EditTable.vue index 9c4e7657..c94e0da6 100644 --- a/src/views/infra/codegen/EditTable.vue +++ b/src/views/infra/codegen/EditTable.vue @@ -8,7 +8,7 @@ <colum-info-form ref="columInfoRef" :columns="formData.columns" /> </el-tab-pane> <el-tab-pane label="生成信息" name="generateInfo"> - <generate-info-form ref="generateInfoRef" :table="formData.table" /> + <generate-info-form ref="generateInfoRef" :table="formData.table" :columns="formData.columns" /> </el-tab-pane> </el-tabs> <el-form> diff --git a/src/views/infra/codegen/components/GenerateInfoForm.vue b/src/views/infra/codegen/components/GenerateInfoForm.vue index 744edfe6..178b4e0f 100644 --- a/src/views/infra/codegen/components/GenerateInfoForm.vue +++ b/src/views/infra/codegen/components/GenerateInfoForm.vue @@ -3,7 +3,7 @@ <el-row> <el-col :span="12"> <el-form-item label="生成模板" prop="templateType"> - <el-select v-model="formData.templateType" @change="tplSelectChange"> + <el-select v-model="formData.templateType"> <el-option v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE)" :key="dict.value" @@ -246,48 +246,68 @@ </el-form-item> </el-col> </el-row> - <el-row v-show="formData.tplCategory === 'sub'"> - <h4 class="form-header">关联信息</h4> + + <!-- 主表信息 --> + <el-row v-if="formData.templateType === 15"> + <el-col :span="24"> + <h4 class="form-header">主表信息</h4> + </el-col> <el-col :span="12"> - <el-form-item> + <el-form-item prop="masterTableId"> <template #label> <span> - 关联子表的表名 - <el-tooltip content="关联子表的表名, 如:sys_user" placement="top"> + 关联的主表 + <el-tooltip content="关联主表(父表)的表名, 如:system_user" placement="top"> <Icon icon="ep:question-filled" /> </el-tooltip> </span> </template> - <el-select v-model="formData.subTableName" placeholder="请选择" @change="subSelectChange"> + <el-select v-model="formData.masterTableId" placeholder="请选择"> <el-option v-for="(table0, index) in tables" :key="index" :label="table0.tableName + ':' + table0.tableComment" - :value="table0.tableName" + :value="table0.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> - <el-form-item> + <el-form-item prop="subJoinColumnId"> <template #label> <span> - 子表关联的外键名 - <el-tooltip content="子表关联的外键名, 如:user_id" placement="top"> + 子表关联的字段 + <el-tooltip content="子表关联的字段, 如:user_id" placement="top"> <Icon icon="ep:question-filled" /> </el-tooltip> </span> </template> - <el-select v-model="formData.subTableFkName" placeholder="请选择"> + <el-select v-model="formData.subJoinColumnId" placeholder="请选择"> <el-option - v-for="(column, index) in subColumns" + v-for="(column, index) in props.columns" :key="index" :label="column.columnName + ':' + column.columnComment" - :value="column.columnName" + :value="column.id" /> </el-select> </el-form-item> </el-col> + <el-col :span="12"> + <el-form-item prop="subJoinMany"> + <template #label> + <span> + 关联关系 + <el-tooltip content="主表与子表的关联关系" placement="top"> + <Icon icon="ep:question-filled" /> + </el-tooltip> + </span> + </template> + <el-radio-group v-model="formData.subJoinMany" placeholder="请选择"> + <el-radio :label="true">一对多</el-radio> + <el-radio :label="false">一对一</el-radio> + </el-radio-group> + </el-form-item> + </el-col> </el-row> </el-form> </template> @@ -305,6 +325,10 @@ const props = defineProps({ table: { type: Object as PropType<Nullable<CodegenApi.CodegenTableVO>>, default: () => null + }, + columns: { + type: Array as unknown as PropType<CodegenApi.CodegenColumnVO[]>, + default: () => null } }) @@ -323,9 +347,10 @@ const formData = ref({ treeParentCode: '', treeName: '', tplCategory: '', - subTableName: '', - subTableFkName: '', - genType: '' + genType: '', + masterTableId: undefined, + subJoinColumnId: undefined, + subJoinMany: undefined }) const rules = reactive({ @@ -336,41 +361,27 @@ const rules = reactive({ businessName: [required], businessPackage: [required], className: [required], - classComment: [required] + classComment: [required], + masterTableId: [required], + subJoinColumnId: [required], + subJoinMany: [required] }) -const tables = ref([]) -const subColumns = ref([]) +const tables = ref([]) // 表定义列表 const menus = ref<any[]>([]) const menuTreeProps = { label: 'name' } -/** 选择子表名触发 */ -const subSelectChange = () => { - formData.value.subTableFkName = '' -} - -/** 选择生成模板触发 */ -const tplSelectChange = (value) => { - if (value !== 1) { - // TODO 芋艿:暂时不考虑支持树形结构 - message.error( - '暂时不考虑支持【树形】和【主子表】的代码生成。原因是:导致 vm 模板过于复杂,不利于胖友二次开发' - ) - return false - } - if (value !== 'sub') { - formData.value.subTableName = '' - formData.value.subTableFkName = '' - } -} - watch( () => props.table, - (table) => { + async (table) => { if (!table) return formData.value = table as any + // 加载表列表 + if (table.dataSourceConfigId >= 0) { + tables.value = await CodegenApi.getCodegenTableList(formData.value.dataSourceConfigId) + } }, { deep: true, @@ -380,6 +391,7 @@ watch( onMounted(async () => { try { + // 加载菜单 const resp = await MenuApi.getSimpleMenusList() menus.value = handleTree(resp) } catch {} diff --git a/src/views/infra/demo12/Demo12StudentForm.vue b/src/views/infra/demo12/Demo12StudentForm.vue index d3cb482d..af4e2733 100644 --- a/src/views/infra/demo12/Demo12StudentForm.vue +++ b/src/views/infra/demo12/Demo12StudentForm.vue @@ -42,7 +42,7 @@ </el-radio> </el-radio-group> </el-form-item> - <el-form-item label="头像"> + <el-form-item label="头像" prop="avatar"> <UploadImg v-model="formData.avatar" /> </el-form-item> <el-form-item label="附件" prop="video"> diff --git a/src/views/infra/demo12/components/Demo12StudentContactForm.vue b/src/views/infra/demo12/components/Demo12StudentContactForm.vue index d71f6146..e246678b 100644 --- a/src/views/infra/demo12/components/Demo12StudentContactForm.vue +++ b/src/views/infra/demo12/components/Demo12StudentContactForm.vue @@ -1,5 +1,155 @@ <template> - <div>123</div> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="formData.sex" placeholder="请选择性别"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-radio-group v-model="formData.enabled"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="头像" prop="avatar"> + <UploadImg v-model="formData.avatar" /> + </el-form-item> + <el-form-item label="附件" prop="video"> + <UploadFile v-model="formData.video" /> + </el-form-item> + <el-form-item label="备注" prop="memo"> + <Editor v-model="formData.memo" height="150px" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> </template> <script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo12StudentApi from '@/api/infra/demo12' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + studentId: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined +}) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number, studentId: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + formData.value.studentId = studentId + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo12StudentApi.getDemo12StudentContact(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value + if (formType.value === 'create') { + await Demo12StudentApi.createDemo12StudentContact(data) + message.success(t('common.createSuccess')) + } else { + await Demo12StudentApi.updateDemo12StudentContact(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined + } + formRef.value?.resetFields() +} </script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentContactList.vue b/src/views/infra/demo12/components/Demo12StudentContactList.vue index 65ed9df1..b9b1e717 100644 --- a/src/views/infra/demo12/components/Demo12StudentContactList.vue +++ b/src/views/infra/demo12/components/Demo12StudentContactList.vue @@ -1,6 +1,14 @@ <template> <!-- 列表 --> <ContentWrap> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo12-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> <el-table-column label="编号" align="center" prop="id" /> <el-table-column label="学生编号" align="center" prop="studentId" /> @@ -33,31 +41,108 @@ :formatter="dateFormatter" width="180px" /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo12-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo12-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo12StudentContactForm ref="formRef" @success="getList" /> </template> <script setup lang="ts"> import { DICT_TYPE } from '@/utils/dict' import * as Demo12StudentApi from '@/api/infra/demo12' +import Demo12StudentContactForm from './Demo12StudentContactForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + const props = defineProps<{ studentId: undefined // 学生编号(主表的关联字段) }>() -const loading = ref(true) // 列表的加载中 +const loading = ref(false) // 列表的加载中 const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + studentId: undefined +}) + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + queryParams.studentId = val + handleQuery() + }, + { immediate: false } +) /** 查询列表 */ const getList = async () => { loading.value = true try { - list.value = await Demo12StudentApi.getDemo12StudentContactListByStudentId(studentId.props) + const data = await Demo12StudentApi.getDemo12StudentContactPage(queryParams) + list.value = data.list + total.value = data.total } finally { loading.value = false } } -/** 初始化 **/ -onMounted(() => { +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 getList() -}) +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + if (!props.studentId) { + message.error('请选择一个学生') + return + } + formRef.value.open(type, id, props.studentId) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo12StudentApi.deleteDemo12StudentContact(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} </script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue b/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue index d71f6146..92e2b373 100644 --- a/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue +++ b/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue @@ -1,5 +1,155 @@ <template> - <div>123</div> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="formData.sex" placeholder="请选择性别"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="是否有效" prop="enabled"> + <el-radio-group v-model="formData.enabled"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="头像" prop="avatar"> + <UploadImg v-model="formData.avatar" /> + </el-form-item> + <el-form-item label="附件" prop="video"> + <UploadFile v-model="formData.video" /> + </el-form-item> + <el-form-item label="备注" prop="memo"> + <Editor v-model="formData.memo" height="150px" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> </template> <script setup lang="ts"> +import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo12StudentApi from '@/api/infra/demo12' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + studentId: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined +}) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], + enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], + avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], + memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number, studentId: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + formData.value.studentId = studentId + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo12StudentApi.getDemo12StudentTeacher(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value + if (formType.value === 'create') { + await Demo12StudentApi.createDemo12StudentTeacher(data) + message.success(t('common.createSuccess')) + } else { + await Demo12StudentApi.updateDemo12StudentTeacher(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + description: undefined, + birthday: undefined, + sex: undefined, + enabled: undefined, + avatar: undefined, + video: undefined, + memo: undefined + } + formRef.value?.resetFields() +} </script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentTeacherList.vue b/src/views/infra/demo12/components/Demo12StudentTeacherList.vue index 55f6845b..d0594534 100644 --- a/src/views/infra/demo12/components/Demo12StudentTeacherList.vue +++ b/src/views/infra/demo12/components/Demo12StudentTeacherList.vue @@ -1,6 +1,14 @@ <template> <!-- 列表 --> <ContentWrap> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo12-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> <el-table-column label="编号" align="center" prop="id" /> <el-table-column label="学生编号" align="center" prop="studentId" /> @@ -33,35 +41,108 @@ :formatter="dateFormatter" width="180px" /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo12-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo12-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo12StudentTeacherForm ref="formRef" @success="getList" /> </template> <script setup lang="ts"> import { DICT_TYPE } from '@/utils/dict' import * as Demo12StudentApi from '@/api/infra/demo12' +import Demo12StudentTeacherForm from './Demo12StudentTeacherForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + const props = defineProps<{ studentId: undefined // 学生编号(主表的关联字段) }>() -const loading = ref(true) // 列表的加载中 +const loading = ref(false) // 列表的加载中 const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + studentId: undefined +}) + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + queryParams.studentId = val + handleQuery() + }, + { immediate: false } +) /** 查询列表 */ const getList = async () => { loading.value = true try { - const data = await Demo12StudentApi.getDemo12StudentTeacherByStudentId(studentId.props) - if (!data) { - return - } - list.value.push(data) + const data = await Demo12StudentApi.getDemo12StudentTeacherPage(queryParams) + list.value = data.list + total.value = data.total } finally { loading.value = false } } -/** 初始化 **/ -onMounted(() => { +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 getList() -}) +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + if (!props.studentId) { + message.error('请选择一个学生') + return + } + formRef.value.open(type, id, props.studentId) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo12StudentApi.deleteDemo12StudentTeacher(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} </script> \ No newline at end of file diff --git a/src/views/infra/demo12/index.vue b/src/views/infra/demo12/index.vue index c5a82a4c..47ec7f21 100644 --- a/src/views/infra/demo12/index.vue +++ b/src/views/infra/demo12/index.vue @@ -94,7 +94,14 @@ <!-- 列表 --> <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table + v-loading="loading" + :data="list" + :stripe="true" + :show-overflow-tooltip="true" + highlight-current-row + @current-change="handleCurrentChange" + > <el-table-column label="编号" align="center" prop="id" /> <el-table-column label="名字" align="center" prop="name" /> <el-table-column label="简介" align="center" prop="description" /> @@ -157,6 +164,17 @@ <!-- 表单弹窗:添加/修改 --> <Demo12StudentForm ref="formRef" @success="getList" /> + <!-- 子表的列表 --> + <ContentWrap> + <el-tabs model-value="demo12StudentContact"> + <el-tab-pane label="学生联系人" name="demo12StudentContact"> + <Demo12StudentContactList :student-id="currentRow.id" /> + </el-tab-pane> + <el-tab-pane label="学生班主任" name="demo12StudentTeacher"> + <Demo12StudentTeacherList :student-id="currentRow.id" /> + </el-tab-pane> + </el-tabs> + </ContentWrap> </template> <script setup lang="ts"> @@ -165,6 +183,8 @@ import { dateFormatter } from '@/utils/formatTime' import download from '@/utils/download' import * as Demo12StudentApi from '@/api/infra/demo12' import Demo12StudentForm from './Demo12StudentForm.vue' +import Demo12StudentContactList from './components/Demo12StudentContactList.vue' +import Demo12StudentTeacherList from './components/Demo12StudentTeacherList.vue' defineOptions({ name: 'InfraDemo12Student' }) @@ -245,6 +265,12 @@ const handleExport = async () => { } } +/** 选中行操作 */ +const currentRow = ref({}) // 选中行 +const handleCurrentChange = (row) => { + currentRow.value = row +} + /** 初始化 **/ onMounted(() => { getList() From 40b1522ed0da116f361a17f9ba5d6ee5df021b16 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Wed, 15 Nov 2023 23:48:00 +0800 Subject: [PATCH 10/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=20crud=20=E5=8D=95=E8=A1=A8?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/demo/demo01/index.ts | 40 +++++++++ src/api/infra/demo01/index.ts | 43 ---------- .../demo01/Demo01ContactForm.vue} | 84 +++++++------------ src/views/infra/{ => demo}/demo01/index.vue | 78 +++++------------ 4 files changed, 92 insertions(+), 153 deletions(-) create mode 100644 src/api/infra/demo/demo01/index.ts delete mode 100644 src/api/infra/demo01/index.ts rename src/views/infra/{demo01/Demo01StudentForm.vue => demo/demo01/Demo01ContactForm.vue} (62%) rename src/views/infra/{ => demo}/demo01/index.vue (72%) diff --git a/src/api/infra/demo/demo01/index.ts b/src/api/infra/demo/demo01/index.ts new file mode 100644 index 00000000..1a4b01ca --- /dev/null +++ b/src/api/infra/demo/demo01/index.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +export interface Demo01ContactVO { + id: number + name: string + sex: number + birthday: Date + description: string + avatar: string +} + +// 查询示例联系人分页 +export const getDemo01ContactPage = async (params) => { + return await request.get({ url: `/infra/demo01-contact/page`, params }) +} + +// 查询示例联系人详情 +export const getDemo01Contact = async (id: number) => { + return await request.get({ url: `/infra/demo01-contact/get?id=` + id }) +} + +// 新增示例联系人 +export const createDemo01Contact = async (data: Demo01ContactVO) => { + return await request.post({ url: `/infra/demo01-contact/create`, data }) +} + +// 修改示例联系人 +export const updateDemo01Contact = async (data: Demo01ContactVO) => { + return await request.put({ url: `/infra/demo01-contact/update`, data }) +} + +// 删除示例联系人 +export const deleteDemo01Contact = async (id: number) => { + return await request.delete({ url: `/infra/demo01-contact/delete?id=` + id }) +} + +// 导出示例联系人 Excel +export const exportDemo01Contact = async (params) => { + return await request.download({ url: `/infra/demo01-contact/export-excel`, params }) +} \ No newline at end of file diff --git a/src/api/infra/demo01/index.ts b/src/api/infra/demo01/index.ts deleted file mode 100644 index 0154bc29..00000000 --- a/src/api/infra/demo01/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import request from '@/config/axios' - -export interface Demo01StudentVO { - id: number - name: string - description: string - birthday: Date - sex: number - enabled: boolean - avatar: string - video: string - memo: string -} - -// 查询学生列表 -export const getDemo01StudentPage = async (params) => { - return await request.get({ url: `/infra/demo01-student/page`, params }) -} - -// 查询学生详情 -export const getDemo01Student = async (id: number) => { - return await request.get({ url: `/infra/demo01-student/get?id=` + id }) -} - -// 新增学生 -export const createDemo01Student = async (data: Demo01StudentVO) => { - return await request.post({ url: `/infra/demo01-student/create`, data }) -} - -// 修改学生 -export const updateDemo01Student = async (data: Demo01StudentVO) => { - return await request.put({ url: `/infra/demo01-student/update`, data }) -} - -// 删除学生 -export const deleteDemo01Student = async (id: number) => { - return await request.delete({ url: `/infra/demo01-student/delete?id=` + id }) -} - -// 导出学生 Excel -export const exportDemo01Student = async (params) => { - return await request.download({ url: `/infra/demo01-student/export-excel`, params }) -} \ No newline at end of file diff --git a/src/views/infra/demo01/Demo01StudentForm.vue b/src/views/infra/demo/demo01/Demo01ContactForm.vue similarity index 62% rename from src/views/infra/demo01/Demo01StudentForm.vue rename to src/views/infra/demo/demo01/Demo01ContactForm.vue index dfc9823d..0452a3c0 100644 --- a/src/views/infra/demo01/Demo01StudentForm.vue +++ b/src/views/infra/demo/demo01/Demo01ContactForm.vue @@ -10,31 +10,10 @@ <el-form-item label="名字" prop="name"> <el-input v-model="formData.name" placeholder="请输入名字" /> </el-form-item> - <el-form-item label="简介" prop="description"> - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> - </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="formData.birthday" - type="date" - value-format="x" - placeholder="选择出生日期" - /> - </el-form-item> <el-form-item label="性别" prop="sex"> - <el-select v-model="formData.sex" placeholder="请选择性别"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-radio-group v-model="formData.enabled"> + <el-radio-group v-model="formData.sex"> <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" :key="dict.value" :label="dict.value" > @@ -42,15 +21,20 @@ </el-radio> </el-radio-group> </el-form-item> - <el-form-item label="头像"> + <el-form-item label="出生年" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生年" + /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <Editor v-model="formData.description" height="150px" /> + </el-form-item> + <el-form-item label="头像" prop="avatar"> <UploadImg v-model="formData.avatar" /> </el-form-item> - <el-form-item label="附件" prop="video"> - <UploadFile v-model="formData.video" /> - </el-form-item> - <el-form-item label="备注" prop="memo"> - <Editor v-model="formData.memo" height="150px" /> - </el-form-item> </el-form> <template #footer> <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> @@ -59,8 +43,8 @@ </Dialog> </template> <script setup lang="ts"> -import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as Demo01StudentApi from '@/api/infra/demo01' +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo01ContactApi from '@/api/infra/demo/demo01' const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 @@ -72,21 +56,16 @@ const formType = ref('') // 表单的类型:create - 新增;update - 修改 const formData = ref({ id: undefined, name: undefined, - description: undefined, - birthday: undefined, sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined + birthday: undefined, + description: undefined, + avatar: undefined }) const formRules = reactive({ name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], - enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] + sex: [{ required: true, message: '性别不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生年不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }] }) const formRef = ref() // 表单 Ref @@ -100,7 +79,7 @@ const open = async (type: string, id?: number) => { if (id) { formLoading.value = true try { - formData.value = await Demo01StudentApi.getDemo01Student(id) + formData.value = await Demo01ContactApi.getDemo01Contact(id) } finally { formLoading.value = false } @@ -116,12 +95,12 @@ const submitForm = async () => { // 提交请求 formLoading.value = true try { - const data = formData.value as unknown as Demo01StudentApi.Demo01StudentVO + const data = formData.value as unknown as Demo01ContactApi.Demo01ContactVO if (formType.value === 'create') { - await Demo01StudentApi.createDemo01Student(data) + await Demo01ContactApi.createDemo01Contact(data) message.success(t('common.createSuccess')) } else { - await Demo01StudentApi.updateDemo01Student(data) + await Demo01ContactApi.updateDemo01Contact(data) message.success(t('common.updateSuccess')) } dialogVisible.value = false @@ -137,14 +116,11 @@ const resetForm = () => { formData.value = { id: undefined, name: undefined, - description: undefined, - birthday: undefined, sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined + birthday: undefined, + description: undefined, + avatar: undefined } formRef.value?.resetFields() } -</script> +</script> \ No newline at end of file diff --git a/src/views/infra/demo01/index.vue b/src/views/infra/demo/demo01/index.vue similarity index 72% rename from src/views/infra/demo01/index.vue rename to src/views/infra/demo/demo01/index.vue index fb35b561..55751e1b 100644 --- a/src/views/infra/demo01/index.vue +++ b/src/views/infra/demo/demo01/index.vue @@ -17,16 +17,6 @@ class="!w-240px" /> </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="queryParams.birthday" - value-format="YYYY-MM-DD" - type="date" - placeholder="选择出生日期" - clearable - class="!w-240px" - /> - </el-form-item> <el-form-item label="性别" prop="sex"> <el-select v-model="queryParams.sex" @@ -42,21 +32,6 @@ /> </el-select> </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-select - v-model="queryParams.enabled" - placeholder="请选择是否有效" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> <el-form-item label="创建时间" prop="createTime"> <el-date-picker v-model="queryParams.createTime" @@ -75,7 +50,7 @@ type="primary" plain @click="openForm('create')" - v-hasPermi="['infra:demo01-student:create']" + v-hasPermi="['infra:demo01-contact:create']" > <Icon icon="ep:plus" class="mr-5px" /> 新增 </el-button> @@ -84,7 +59,7 @@ plain @click="handleExport" :loading="exportLoading" - v-hasPermi="['infra:demo01-student:export']" + v-hasPermi="['infra:demo01-contact:export']" > <Icon icon="ep:download" class="mr-5px" /> 导出 </el-button> @@ -97,26 +72,20 @@ <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> <el-table-column label="编号" align="center" prop="id" /> <el-table-column label="名字" align="center" prop="name" /> - <el-table-column - label="出生日期" - align="center" - prop="birthday" - :formatter="dateFormatter" - width="180px" - /> <el-table-column label="性别" align="center" prop="sex"> <template #default="scope"> <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> </template> </el-table-column> - <el-table-column label="是否有效" align="center" prop="enabled"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> - </template> - </el-table-column> + <el-table-column + label="出生年" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="简介" align="center" prop="description" /> <el-table-column label="头像" align="center" prop="avatar" /> - <el-table-column label="附件" align="center" prop="video" /> - <el-table-column label="备注" align="center" prop="memo" /> <el-table-column label="创建时间" align="center" @@ -130,7 +99,7 @@ link type="primary" @click="openForm('update', scope.row.id)" - v-hasPermi="['infra:demo01-student:update']" + v-hasPermi="['infra:demo01-contact:update']" > 编辑 </el-button> @@ -138,7 +107,7 @@ link type="danger" @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo01-student:delete']" + v-hasPermi="['infra:demo01-contact:delete']" > 删除 </el-button> @@ -155,32 +124,29 @@ </ContentWrap> <!-- 表单弹窗:添加/修改 --> - <Demo01StudentForm ref="formRef" @success="getList" /> + <Demo01ContactForm ref="formRef" @success="getList" /> </template> <script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { dateFormatter } from '@/utils/formatTime' import download from '@/utils/download' -import * as Demo01StudentApi from '@/api/infra/demo01' -import Demo01StudentForm from './Demo01StudentForm.vue' +import * as Demo01ContactApi from '@/api/infra/demo/demo01' +import Demo01ContactForm from './Demo01ContactForm.vue' -defineOptions({ name: 'InfraDemo01Student' }) +defineOptions({ name: 'Demo01Contact' }) const message = useMessage() // 消息弹窗 const { t } = useI18n() // 国际化 const loading = ref(true) // 列表的加载中 -const total = ref(0) // 列表的总页数 const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 const queryParams = reactive({ pageNo: 1, pageSize: 10, name: null, - birthday: null, - birthday: [], sex: null, - enabled: null, createTime: [] }) const queryFormRef = ref() // 搜索的表单 @@ -190,7 +156,7 @@ const exportLoading = ref(false) // 导出的加载中 const getList = async () => { loading.value = true try { - const data = await Demo01StudentApi.getDemo01StudentPage(queryParams) + const data = await Demo01ContactApi.getDemo01ContactPage(queryParams) list.value = data.list total.value = data.total } finally { @@ -222,7 +188,7 @@ const handleDelete = async (id: number) => { // 删除的二次确认 await message.delConfirm() // 发起删除 - await Demo01StudentApi.deleteDemo01Student(id) + await Demo01ContactApi.deleteDemo01Contact(id) message.success(t('common.delSuccess')) // 刷新列表 await getList() @@ -236,8 +202,8 @@ const handleExport = async () => { await message.exportConfirm() // 发起导出 exportLoading.value = true - const data = await Demo01StudentApi.exportDemo01Student(queryParams) - download.excel(data, '学生.xls') + const data = await Demo01ContactApi.exportDemo01Contact(queryParams) + download.excel(data, '示例联系人.xls') } catch { } finally { exportLoading.value = false From 3d0c4f442210e89062f0cf407a31f27e47984e06 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Thu, 16 Nov 2023 00:11:23 +0800 Subject: [PATCH 11/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E6=94=AF=E6=8C=81=E6=A0=91=E5=BD=A2=E8=A1=A8=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E7=9A=84=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codegen/components/GenerateInfoForm.vue | 58 +++++++------------ 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/src/views/infra/codegen/components/GenerateInfoForm.vue b/src/views/infra/codegen/components/GenerateInfoForm.vue index 178b4e0f..a4f5ad97 100644 --- a/src/views/infra/codegen/components/GenerateInfoForm.vue +++ b/src/views/infra/codegen/components/GenerateInfoForm.vue @@ -182,50 +182,33 @@ </el-col> </el-row> - <el-row v-show="formData.tplCategory === 'tree'"> - <h4 class="form-header">其他信息</h4> - <el-col :span="12"> - <el-form-item> - <template #label> - <span> - 树编码字段 - <el-tooltip content="树显示的编码字段名, 如:dept_id" placement="top"> - <Icon icon="ep:question-filled" /> - </el-tooltip> - </span> - </template> - <el-select v-model="formData.treeCode" placeholder="请选择"> - <el-option - v-for="(column, index) in formData.columns" - :key="index" - :label="column.columnName + ':' + column.columnComment" - :value="column.columnName" - /> - </el-select> - </el-form-item> + <!-- 树表信息 --> + <el-row v-show="formData.templateType == 2"> + <el-col :span="24"> + <h4 class="form-header">树表信息</h4> </el-col> <el-col :span="12"> - <el-form-item> + <el-form-item prop="treeParentColumnId"> <template #label> <span> - 树父编码字段 + 父编号字段 <el-tooltip content="树显示的父编码字段名, 如:parent_Id" placement="top"> <Icon icon="ep:question-filled" /> </el-tooltip> </span> </template> - <el-select v-model="formData.treeParentCode" placeholder="请选择"> + <el-select v-model="formData.treeParentColumnId" placeholder="请选择"> <el-option - v-for="(column, index) in formData.columns" + v-for="(column, index) in props.columns" :key="index" :label="column.columnName + ':' + column.columnComment" - :value="column.columnName" + :value="column.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> - <el-form-item> + <el-form-item prop="treeNameColumnId"> <template #label> <span> 树名称字段 @@ -234,13 +217,12 @@ </el-tooltip> </span> </template> - - <el-select v-model="formData.treeName" placeholder="请选择"> + <el-select v-model="formData.treeNameColumnId" placeholder="请选择"> <el-option - v-for="(column, index) in formData.columns" + v-for="(column, index) in props.columns" :key="index" :label="column.columnName + ':' + column.columnComment" - :value="column.columnName" + :value="column.id" /> </el-select> </el-form-item> @@ -248,7 +230,7 @@ </el-row> <!-- 主表信息 --> - <el-row v-if="formData.templateType === 15"> + <el-row v-if="formData.templateType == 15"> <el-col :span="24"> <h4 class="form-header">主表信息</h4> </el-col> @@ -343,14 +325,12 @@ const formData = ref({ classComment: '', parentMenuId: null, genPath: '', - treeCode: '', - treeParentCode: '', - treeName: '', - tplCategory: '', genType: '', masterTableId: undefined, subJoinColumnId: undefined, - subJoinMany: undefined + subJoinMany: undefined, + treeParentColumnId: undefined, + treeNameColumnId: undefined }) const rules = reactive({ @@ -364,7 +344,9 @@ const rules = reactive({ classComment: [required], masterTableId: [required], subJoinColumnId: [required], - subJoinMany: [required] + subJoinMany: [required], + treeParentColumnId: [required], + treeNameColumnId: [required] }) const tables = ref([]) // 表定义列表 From bbc37613b6c1aa236752926d09c997b046f117e8 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Thu, 16 Nov 2023 20:39:12 +0800 Subject: [PATCH 12/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=20tree=20=E6=A0=91=E5=BD=A2?= =?UTF-8?q?=E7=9A=84=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/demo/demo02/index.ts | 37 ++++ src/api/infra/demo02/index.ts | 49 ----- .../demo02/Demo02CategoryForm.vue} | 85 ++++----- src/views/infra/{ => demo}/demo02/index.vue | 105 ++++++++--- .../infra/demo02/DemoStudentAddressForm.vue | 126 ------------- .../infra/demo02/DemoStudentContactForm.vue | 177 ------------------ .../demo02/bak/DemoStudentAddressForm.vue | 58 ------ 7 files changed, 159 insertions(+), 478 deletions(-) create mode 100644 src/api/infra/demo/demo02/index.ts delete mode 100644 src/api/infra/demo02/index.ts rename src/views/infra/{demo02/DemoStudentForm.vue => demo/demo02/Demo02CategoryForm.vue} (55%) rename src/views/infra/{ => demo}/demo02/index.vue (51%) delete mode 100644 src/views/infra/demo02/DemoStudentAddressForm.vue delete mode 100644 src/views/infra/demo02/DemoStudentContactForm.vue delete mode 100644 src/views/infra/demo02/bak/DemoStudentAddressForm.vue diff --git a/src/api/infra/demo/demo02/index.ts b/src/api/infra/demo/demo02/index.ts new file mode 100644 index 00000000..21e45c90 --- /dev/null +++ b/src/api/infra/demo/demo02/index.ts @@ -0,0 +1,37 @@ +import request from '@/config/axios' + +export interface Demo02CategoryVO { + id: number + name: string + parentId: number +} + +// 查询示例分类列表 +export const getDemo02CategoryList = async (params) => { + return await request.get({ url: `/infra/demo02-category/list`, params }) +} + +// 查询示例分类详情 +export const getDemo02Category = async (id: number) => { + return await request.get({ url: `/infra/demo02-category/get?id=` + id }) +} + +// 新增示例分类 +export const createDemo02Category = async (data: Demo02CategoryVO) => { + return await request.post({ url: `/infra/demo02-category/create`, data }) +} + +// 修改示例分类 +export const updateDemo02Category = async (data: Demo02CategoryVO) => { + return await request.put({ url: `/infra/demo02-category/update`, data }) +} + +// 删除示例分类 +export const deleteDemo02Category = async (id: number) => { + return await request.delete({ url: `/infra/demo02-category/delete?id=` + id }) +} + +// 导出示例分类 Excel +export const exportDemo02Category = async (params) => { + return await request.download({ url: `/infra/demo02-category/export-excel`, params }) +} \ No newline at end of file diff --git a/src/api/infra/demo02/index.ts b/src/api/infra/demo02/index.ts deleted file mode 100644 index 500adde5..00000000 --- a/src/api/infra/demo02/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import request from '@/config/axios' - -export interface DemoStudentVO { - id: number -} - -// 查询学生列表 -export const getDemoStudentPage = async (params) => { - return await request.get({ url: `/infra/demo-student/page`, params }) -} - -// 查询学生详情 -export const getDemoStudent = async (id: number) => { - return await request.get({ url: `/infra/demo-student/get?id=` + id }) -} - -// 新增学生 -export const createDemoStudent = async (data: DemoStudentVO) => { - return await request.post({ url: `/infra/demo-student/create`, data }) -} - -// 修改学生 -export const updateDemoStudent = async (data: DemoStudentVO) => { - return await request.put({ url: `/infra/demo-student/update`, data }) -} - -// 删除学生 -export const deleteDemoStudent = async (id: number) => { - return await request.delete({ url: `/infra/demo-student/delete?id=` + id }) -} - -// 导出学生 Excel -export const exportDemoStudent = async (params) => { - return await request.download({ url: `/infra/demo-student/export-excel`, params }) -} - -// 获得学生联系人列表 -export const getDemoStudentContactListByStudentId = async (studentId) => { - return await request.get({ - url: `/infra/demo-student/demo-student/list-by-student-id?studentId=` + studentId - }) -} - -// 获得学生地址 -export const getDemoStudentAddressByStudentId = async (studentId) => { - return await request.get({ - url: `/infra/demo-student/demo-student/get-by-student-id?studentId=` + studentId - }) -} diff --git a/src/views/infra/demo02/DemoStudentForm.vue b/src/views/infra/demo/demo02/Demo02CategoryForm.vue similarity index 55% rename from src/views/infra/demo02/DemoStudentForm.vue rename to src/views/infra/demo/demo02/Demo02CategoryForm.vue index e9454c0f..9002d5ee 100644 --- a/src/views/infra/demo02/DemoStudentForm.vue +++ b/src/views/infra/demo/demo02/Demo02CategoryForm.vue @@ -6,16 +6,21 @@ :rules="formRules" label-width="100px" v-loading="formLoading" - /> - <!-- 子表的表单 --> - <el-tabs v-model="subTabsName"> - <el-tab-pane label="学生联系人" name="demoStudentContact"> - <DemoStudentContactForm ref="demoStudentContactFormRef" :student-id="formData.id" /> - </el-tab-pane> - <el-tab-pane label="学生地址" name="demoStudentAddress"> - <DemoStudentAddressForm ref="demoStudentAddressFormRef" :student-id="formData.id" /> - </el-tab-pane> - </el-tabs> + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="父级编号" prop="parentId"> + <el-tree-select + v-model="formData.parentId" + :data="demo02CategoryTree" + :props="defaultProps" + check-strictly + default-expand-all + placeholder="请选择父级编号" + /> + </el-form-item> + </el-form> <template #footer> <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> <el-button @click="dialogVisible = false">取 消</el-button> @@ -23,9 +28,8 @@ </Dialog> </template> <script setup lang="ts"> -import * as DemoStudentApi from '@/api/infra/demo02' -import DemoStudentContactForm from './DemoStudentContactForm.vue' -import DemoStudentAddressForm from './DemoStudentAddressForm.vue' +import * as Demo02CategoryApi from '@/api/infra/demo/demo02' +import { defaultProps, handleTree } from '@/utils/tree' const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 @@ -35,15 +39,16 @@ const dialogTitle = ref('') // 弹窗的标题 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 const formType = ref('') // 表单的类型:create - 新增;update - 修改 const formData = ref({ - id: undefined + id: undefined, + name: undefined, + parentId: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + parentId: [{ required: true, message: '父级编号不能为空', trigger: 'blur' }] }) -const formRules = reactive({}) const formRef = ref() // 表单 Ref - -/** 子表的表单 */ -const subTabsName = ref('demoStudentContact') -const demoStudentContactFormRef = ref() -const demoStudentAddressFormRef = ref() +const demo02CategoryTree = ref() // 树形结构 /** 打开弹窗 */ const open = async (type: string, id?: number) => { @@ -55,11 +60,12 @@ const open = async (type: string, id?: number) => { if (id) { formLoading.value = true try { - formData.value = await DemoStudentApi.getDemoStudent(id) + formData.value = await Demo02CategoryApi.getDemo02Category(id) } finally { formLoading.value = false } } + await getDemo02CategoryTree() } defineExpose({ open }) // 提供 open 方法,用于打开弹窗 @@ -68,31 +74,15 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成 const submitForm = async () => { // 校验表单 await formRef.value.validate() - // 校验子表单 - try { - await demoStudentContactFormRef.value.validate() - } catch (e) { - subTabsName.value = 'demoStudentContact' - return - } - try { - await demoStudentAddressFormRef.value.validate() - } catch (e) { - subTabsName.value = 'demoStudentAddress' - return - } // 提交请求 formLoading.value = true try { - const data = formData.value as unknown as DemoStudentApi.DemoStudentVO - // 拼接子表的数据 - data.demoStudentContacts = demoStudentContactFormRef.value.getData() - data.demoStudentAddress = demoStudentAddressFormRef.value.getData() + const data = formData.value as unknown as Demo02CategoryApi.Demo02CategoryVO if (formType.value === 'create') { - await DemoStudentApi.createDemoStudent(data) + await Demo02CategoryApi.createDemo02Category(data) message.success(t('common.createSuccess')) } else { - await DemoStudentApi.updateDemoStudent(data) + await Demo02CategoryApi.updateDemo02Category(data) message.success(t('common.updateSuccess')) } dialogVisible.value = false @@ -106,8 +96,19 @@ const submitForm = async () => { /** 重置表单 */ const resetForm = () => { formData.value = { - id: undefined + id: undefined, + name: undefined, + parentId: undefined } formRef.value?.resetFields() } -</script> + +/** 获得示例分类树 */ +const getDemo02CategoryTree = async () => { + demo02CategoryTree.value = [] + const data = await Demo02CategoryApi.getDemo02CategoryList() + const root: Tree = { id: 0, name: '顶级示例分类', children: [] } + root.children = handleTree(data, 'id', 'parentId') + demo02CategoryTree.value.push(root) +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo02/index.vue b/src/views/infra/demo/demo02/index.vue similarity index 51% rename from src/views/infra/demo02/index.vue rename to src/views/infra/demo/demo02/index.vue index 89fd656b..e46c77dc 100644 --- a/src/views/infra/demo02/index.vue +++ b/src/views/infra/demo/demo02/index.vue @@ -8,10 +8,35 @@ :inline="true" label-width="68px" > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> <el-form-item> <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> - <el-button type="primary" plain @click="openForm('create')"> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo02-category:create']" + > <Icon icon="ep:plus" class="mr-5px" /> 新增 </el-button> <el-button @@ -19,28 +44,52 @@ plain @click="handleExport" :loading="exportLoading" - v-hasPermi="['infra:demo-student:export']" + v-hasPermi="['infra:demo02-category:export']" > <Icon icon="ep:download" class="mr-5px" /> 导出 </el-button> + <el-button type="danger" plain @click="toggleExpandAll"> + <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠 + </el-button> </el-form-item> </el-form> </ContentWrap> <!-- 列表 --> <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table + v-loading="loading" + :data="list" + :stripe="true" + :show-overflow-tooltip="true" + row-key="id" + :default-expand-all="isExpandAll" + v-if="refreshTable" + > <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> <el-table-column label="操作" align="center"> <template #default="scope"> - <el-button link type="primary" @click="openForm('update', scope.row.id)"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo02-category:update']" + > 编辑 </el-button> <el-button link type="danger" @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo-student:delete']" + v-hasPermi="['infra:demo02-category:delete']" > 删除 </el-button> @@ -57,25 +106,27 @@ </ContentWrap> <!-- 表单弹窗:添加/修改 --> - <DemoStudentForm ref="formRef" @success="getList" /> + <Demo02CategoryForm ref="formRef" @success="getList" /> </template> <script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import { handleTree } from '@/utils/tree' import download from '@/utils/download' -import * as DemoStudentApi from '@/api/infra/demo02' -import DemoStudentForm from './DemoStudentForm.vue' +import * as Demo02CategoryApi from '@/api/infra/demo/demo02' +import Demo02CategoryForm from './Demo02CategoryForm.vue' -defineOptions({ name: 'InfraDemoStudent' }) +defineOptions({ name: 'Demo02Category' }) const message = useMessage() // 消息弹窗 const { t } = useI18n() // 国际化 const loading = ref(true) // 列表的加载中 -const total = ref(0) // 列表的总页数 const list = ref([]) // 列表的数据 const queryParams = reactive({ - pageNo: 1, - pageSize: 10 + name: null, + parentId: null, + createTime: [] }) const queryFormRef = ref() // 搜索的表单 const exportLoading = ref(false) // 导出的加载中 @@ -84,13 +135,8 @@ const exportLoading = ref(false) // 导出的加载中 const getList = async () => { loading.value = true try { - // const data = await DemoStudentApi.getDemoStudentPage(queryParams) - list.value = [ - { - id: 1 - } - ] - total.value = 10 + const data = await Demo02CategoryApi.getDemo02CategoryList(queryParams) + list.value = handleTree(data, 'id', 'parentId') } finally { loading.value = false } @@ -110,10 +156,7 @@ const resetQuery = () => { /** 添加/修改操作 */ const formRef = ref() -// const demoStudentContactFormRef = ref() const openForm = (type: string, id?: number) => { - // console.log(demoStudentContactFormRef, 'xx demoStudentContactFormRef xx') - // demoStudentContactFormRef.value.validate() formRef.value.open(type, id) } @@ -123,7 +166,7 @@ const handleDelete = async (id: number) => { // 删除的二次确认 await message.delConfirm() // 发起删除 - await DemoStudentApi.deleteDemoStudent(id) + await Demo02CategoryApi.deleteDemo02Category(id) message.success(t('common.delSuccess')) // 刷新列表 await getList() @@ -137,16 +180,26 @@ const handleExport = async () => { await message.exportConfirm() // 发起导出 exportLoading.value = true - const data = await DemoStudentApi.exportDemoStudent(queryParams) - download.excel(data, '学生.xls') + const data = await Demo02CategoryApi.exportDemo02Category(queryParams) + download.excel(data, '示例分类.xls') } catch { } finally { exportLoading.value = false } } +/** 展开/折叠操作 */ +const isExpandAll = ref(true) // 是否展开,默认全部展开 +const refreshTable = ref(true) // 重新渲染表格状态 +const toggleExpandAll = async () => { + refreshTable.value = false + isExpandAll.value = !isExpandAll.value + await nextTick() + refreshTable.value = true +} + /** 初始化 **/ onMounted(() => { getList() }) -</script> +</script> \ No newline at end of file diff --git a/src/views/infra/demo02/DemoStudentAddressForm.vue b/src/views/infra/demo02/DemoStudentAddressForm.vue deleted file mode 100644 index 6d031406..00000000 --- a/src/views/infra/demo02/DemoStudentAddressForm.vue +++ /dev/null @@ -1,126 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="名字" prop="name"> - <el-input v-model="formData.name" placeholder="请输入名字" /> - </el-form-item> - <el-form-item label="个人简介"> - <Editor v-model="formData.description" height="150px" /> - </el-form-item> - <el-form-item label="性别 1" prop="sex1"> - <el-select v-model="formData.sex1" placeholder="请选择性别 1"> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.SYSTEM_SEX1)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="性别 2" prop="sex2"> - <el-checkbox-group v-model="formData.sex2"> - <el-checkbox - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_SEX2)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-checkbox> - </el-checkbox-group> - </el-form-item> - <el-form-item label="性别 3" prop="sex3"> - <el-radio-group v-model="formData.sex3"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.SYSTEM_SEX3)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="formData.birthday" - type="date" - value-format="x" - placeholder="选择出生日期" - /> - </el-form-item> - <el-form-item label="备注" prop="memo"> - <el-input v-model="formData.memo" type="textarea" placeholder="请输入备注" /> - </el-form-item> - </el-form> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as DemoStudentApi from '@/api/infra/demo02' - -const props = defineProps<{ - studentId: undefined // 学生编号(主表的关联字段) -}>() -const formLoading = ref(false) // 表单的加载中 -const formData = ref([]) -const formRules = reactive({ - studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], - name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - video: [{ required: true, message: '视频不能为空', trigger: 'blur' }], - description: [{ required: true, message: '个人简介不能为空', trigger: 'blur' }], - sex1: [{ required: true, message: '性别 1不能为空', trigger: 'change' }], - sex2: [{ required: true, message: '性别 2不能为空', trigger: 'blur' }], - sex3: [{ required: true, message: '性别 3不能为空', trigger: 'blur' }], - birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] -}) -const formRef = ref() // 表单 Ref - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - async (val) => { - // 情况一:val 为空,说明是新增,则置空 - if (!val) { - formData.value = { - id: undefined, - studentId: undefined, - name: undefined, - avatar: undefined, - video: undefined, - description: undefined, - sex1: undefined, - sex2: [], - sex3: undefined, - birthday: undefined, - memo: undefined - } - return - } - // 情况二:val 非空,说明是修改,则加载数据 - try { - formLoading.value = true - formData.value = await DemoStudentApi.getDemoStudentAddressByStudentId(val) - } finally { - formLoading.value = false - } - }, - { immediate: true } -) - -/** 表单校验 */ -const validate = () => { - return formRef.value.validate() -} - -/** 表单值 */ -const getData = () => { - return formData.value -} - -defineExpose({ validate, getData }) -</script> diff --git a/src/views/infra/demo02/DemoStudentContactForm.vue b/src/views/infra/demo02/DemoStudentContactForm.vue deleted file mode 100644 index 5f173f14..00000000 --- a/src/views/infra/demo02/DemoStudentContactForm.vue +++ /dev/null @@ -1,177 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - > - <el-table :data="formData" class="-mt-10px"> - <el-table-column label="序号" type="index" width="100" /> - <el-table-column label="名字" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!"> - <el-input v-model="row.name" placeholder="请输入名字" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="个人简介" width="400"> - <template #default="{ row, $index }"> - <el-form-item - :prop="`${$index}.description`" - :rules="formRules.description" - class="mb-0px!" - > - <Editor v-model="row.description" height="150px" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="性别 1" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.sex1`" :rules="formRules.sex1" class="mb-0px!"> - <el-select v-model="row.sex1" placeholder="请选择性别 1"> - <el-option - v-for="dict in getStrDictOptions(DICT_TYPE.SYSTEM_SEX1)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="性别 2" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.sex2`" :rules="formRules.sex2" class="mb-0px!"> - <el-checkbox-group v-model="row.sex2"> - <el-checkbox - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_SEX2)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-checkbox> - </el-checkbox-group> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="性别 3" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.sex3`" :rules="formRules.sex3" class="mb-0px!"> - <el-radio-group v-model="row.sex3"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.SYSTEM_SEX3)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="出生日期" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.birthday`" :rules="formRules.birthday" class="mb-0px!"> - <el-date-picker - v-model="row.birthday" - type="date" - value-format="x" - placeholder="选择出生日期" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="备注" width="200"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.memo`" :rules="formRules.memo" class="mb-0px!"> - <el-input v-model="row.memo" type="textarea" placeholder="请输入备注" /> - </el-form-item> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3"> - <el-button @click="handleAdd" round>+ 添加联系人</el-button> - </el-row> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getStrDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as DemoStudentApi from '@/api/infra/demo02' - -const props = defineProps<{ - studentId: undefined // 学生编号(主表的关联字段) -}>() -const formLoading = ref(false) // 表单的加载中 -const formData = ref([]) -const formRules = reactive({ - studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], - name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - video: [{ required: true, message: '视频不能为空', trigger: 'blur' }], - description: [{ required: true, message: '个人简介不能为空', trigger: 'blur' }], - sex1: [{ required: true, message: '性别 1不能为空', trigger: 'change' }], - sex2: [{ required: true, message: '性别 2不能为空', trigger: 'blur' }], - sex3: [{ required: true, message: '性别 3不能为空', trigger: 'blur' }], - birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] -}) -const formRef = ref() // 表单 Ref - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - async (val) => { - // 情况一:val 为空,说明是新增,则置空 - if (!val) { - formData.value = [] - return - } - // 情况二:val 非空,说明是修改,则加载数据 - try { - formLoading.value = true - formData.value = await DemoStudentApi.getDemoStudentContactListByStudentId(val) - } finally { - formLoading.value = false - } - }, - { immediate: true } -) - -/** 新增按钮操作 */ -const handleAdd = () => { - const row = { - id: undefined, - studentId: undefined, - name: undefined, - avatar: undefined, - video: undefined, - description: undefined, - sex1: undefined, - sex2: [], - sex3: undefined, - birthday: undefined, - memo: undefined - } - row.studentId = props.studentId - formData.value.push(row) -} - -/** 删除按钮操作 */ -const handleDelete = (index) => { - formData.value.splice(index, 1) -} - -/** 表单校验 */ -const validate = () => { - return formRef.value.validate() -} - -/** 表单值 */ -const getData = () => { - return formData.value -} - -defineExpose({ validate, getData }) -</script> diff --git a/src/views/infra/demo02/bak/DemoStudentAddressForm.vue b/src/views/infra/demo02/bak/DemoStudentAddressForm.vue deleted file mode 100644 index af4cd8f1..00000000 --- a/src/views/infra/demo02/bak/DemoStudentAddressForm.vue +++ /dev/null @@ -1,58 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="子字段 1" prop="field1"> - <el-input v-model="formData.field1" placeholder="请输入字段 1" /> - </el-form-item> - <el-form-item label="子字段 2" prop="field2"> - <el-input v-model="formData.field2" placeholder="请输入字段 2" /> - </el-form-item> - <el-form-item label="子字段 3" prop="field3"> - <el-input v-model="formData.field3" placeholder="请输入字段 3" /> - </el-form-item> - </el-form> -</template> -<script setup lang="ts"> -const props = defineProps<{ - studentId: undefined // 学生编号 -}>() -const formLoading = ref(false) // 表单的加载中 -const formData = ref({}) -const formRules = reactive({ - field1: [required] -}) -const formRef = ref() // 表单 Ref - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - (val) => { - if (val) { - formData.value = { - field2: '番茄', - field3: '西瓜' - } - } else { - formData.value = {} - } - }, - { immediate: true } -) - -/** 表单校验 */ -const validate = () => { - return formRef.value.validate() -} - -/** 表单值 **/ -const getData = () => { - return formData.value -} - -defineExpose({ validate, getData }) -</script> From 9aca49c1ffb1344f5416d793e6c9edc56179ffab Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Thu, 16 Nov 2023 23:24:03 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=E4=B8=BB=E5=AD=90=E8=A1=A8=20normal?= =?UTF-8?q?=20=E6=A8=A1=E5=BC=8F=E7=9A=84=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/demo/demo03/normal/index.ts | 53 ++++++ .../codegen/components/GenerateInfoForm.vue | 2 +- .../demo/demo03/normal/Demo03StudentForm.vue | 153 ++++++++++++++++++ .../normal/components/Demo03CourseForm.vue} | 61 ++++--- .../normal/components/Demo03GradeForm.vue | 72 +++++++++ .../{demo03 => demo/demo03/normal}/index.vue | 133 +++++++++------ .../infra/demo03/DemoStudentAddressForm.vue | 58 ------- .../infra/demo03/DemoStudentAddressList.vue | 38 ----- .../infra/demo03/DemoStudentContactList.vue | 38 ----- src/views/infra/demo03/DemoStudentForm.vue | 132 --------------- 10 files changed, 402 insertions(+), 338 deletions(-) create mode 100644 src/api/infra/demo/demo03/normal/index.ts create mode 100644 src/views/infra/demo/demo03/normal/Demo03StudentForm.vue rename src/views/infra/{demo03/DemoStudentContactForm.vue => demo/demo03/normal/components/Demo03CourseForm.vue} (52%) create mode 100644 src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue rename src/views/infra/{demo03 => demo/demo03/normal}/index.vue (50%) delete mode 100644 src/views/infra/demo03/DemoStudentAddressForm.vue delete mode 100644 src/views/infra/demo03/DemoStudentAddressList.vue delete mode 100644 src/views/infra/demo03/DemoStudentContactList.vue delete mode 100644 src/views/infra/demo03/DemoStudentForm.vue diff --git a/src/api/infra/demo/demo03/normal/index.ts b/src/api/infra/demo/demo03/normal/index.ts new file mode 100644 index 00000000..f15ee1dc --- /dev/null +++ b/src/api/infra/demo/demo03/normal/index.ts @@ -0,0 +1,53 @@ +import request from '@/config/axios' + +export interface Demo03StudentVO { + id: number + name: string + sex: number + birthday: Date + description: string +} + +// 查询学生分页 +export const getDemo03StudentPage = async (params) => { + return await request.get({ url: `/infra/demo03-student/page`, params }) +} + +// 查询学生详情 +export const getDemo03Student = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo03Student = async (data: Demo03StudentVO) => { + return await request.post({ url: `/infra/demo03-student/create`, data }) +} + +// 修改学生 +export const updateDemo03Student = async (data: Demo03StudentVO) => { + return await request.put({ url: `/infra/demo03-student/update`, data }) +} + +// 删除学生 +export const deleteDemo03Student = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo03Student = async (params) => { + return await request.download({ url: `/infra/demo03-student/export-excel`, params }) +} + +// ==================== 子表(学生课程) ==================== + +// 获得学生课程列表 +export const getDemo03CourseListByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo03-student/demo03-course/list-by-student-id?studentId=` + studentId }) +} + +// ==================== 子表(学生班级) ==================== + +// 获得学生班级 +export const getDemo03GradeByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo03-student/demo03-grade/get-by-student-id?studentId=` + studentId }) +} \ No newline at end of file diff --git a/src/views/infra/codegen/components/GenerateInfoForm.vue b/src/views/infra/codegen/components/GenerateInfoForm.vue index a4f5ad97..d2a01cc0 100644 --- a/src/views/infra/codegen/components/GenerateInfoForm.vue +++ b/src/views/infra/codegen/components/GenerateInfoForm.vue @@ -183,7 +183,7 @@ </el-row> <!-- 树表信息 --> - <el-row v-show="formData.templateType == 2"> + <el-row v-if="formData.templateType == 2"> <el-col :span="24"> <h4 class="form-header">树表信息</h4> </el-col> diff --git a/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue b/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue new file mode 100644 index 00000000..00508228 --- /dev/null +++ b/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue @@ -0,0 +1,153 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-radio-group v-model="formData.sex"> + <el-radio + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <Editor v-model="formData.description" height="150px" /> + </el-form-item> + </el-form> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="学生课程" name="demo03Course"> + <Demo03CourseForm ref="demo03CourseFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="学生班级" name="demo03Grade"> + <Demo03GradeForm ref="demo03GradeFormRef" :student-id="formData.id" /> + </el-tab-pane> + </el-tabs> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/normal' +import Demo03CourseForm from './components/Demo03CourseForm.vue' +import Demo03GradeForm from './components/Demo03GradeForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined +}) +const formRules = reactive({ + 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 formRef = ref() // 表单 Ref + +/** 子表的表单 */ +const subTabsName = ref('demo03Course') +const demo03CourseFormRef = ref() +const demo03GradeFormRef = ref() + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Student(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 校验子表单 + try { + await demo03CourseFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo03Course' + return + } + try { + await demo03GradeFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo03Grade' + return + } + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo03StudentApi.Demo03StudentVO + // 拼接子表的数据 + data.demo03Courses = demo03CourseFormRef.value.getData() + data.demo03Grade = demo03GradeFormRef.value.getData() + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Student(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Student(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo03/DemoStudentContactForm.vue b/src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue similarity index 52% rename from src/views/infra/demo03/DemoStudentContactForm.vue rename to src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue index 50c44263..b6f58572 100644 --- a/src/views/infra/demo03/DemoStudentContactForm.vue +++ b/src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue @@ -3,23 +3,23 @@ ref="formRef" :model="formData" :rules="formRules" - label-width="0px" v-loading="formLoading" + label-width="0px" :inline-message="true" > <el-table :data="formData" class="-mt-10px"> <el-table-column label="序号" type="index" width="100" /> - <el-table-column label="名字" prop="name" width="300"> - <template #default="row"> - <el-form-item class="mb-0px!"> + <el-table-column label="名字" min-width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!"> <el-input v-model="row.name" placeholder="请输入名字" /> </el-form-item> </template> </el-table-column> - <el-table-column label="手机号码"> + <el-table-column label="分数" min-width="150"> <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.mobile`" :rules="formRules.mobile" class="mb-0px!"> - <el-input type="number" placeholder="输入手机号码" v-model="row.mobile" /> + <el-form-item :prop="`${$index}.score`" :rules="formRules.score" class="mb-0px!"> + <el-input v-model="row.score" placeholder="请输入分数" /> </el-form-item> </template> </el-table-column> @@ -31,33 +31,39 @@ </el-table> </el-form> <el-row justify="center" class="mt-3"> - <el-button @click="handleAdd" round>+ 添加联系人</el-button> + <el-button @click="handleAdd" round>+ 添加学生课程</el-button> </el-row> </template> <script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/normal' + const props = defineProps<{ - studentId: undefined // 学生编号 + studentId: undefined // 学生编号(主表的关联字段) }>() const formLoading = ref(false) // 表单的加载中 const formData = ref([]) const formRules = reactive({ - mobile: [required] + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + score: [{ required: true, message: '分数不能为空', trigger: 'blur' }] }) const formRef = ref() // 表单 Ref /** 监听主表的关联字段的变化,加载对应的子表数据 */ watch( () => props.studentId, - (val) => { - if (val) { - formData.value = [ - { - name: '芋艿', - mobile: '15601691300' - } - ] - } else { - formData.value = [] + async (val) => { + // 1. 重置表单 + formData.value = [] + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + formData.value = await Demo03StudentApi.getDemo03CourseListByStudentId(val) + } finally { + formLoading.value = false } }, { immediate: true } @@ -65,9 +71,14 @@ watch( /** 新增按钮操作 */ const handleAdd = () => { - formData.value.push({ - name: '土豆' - }) + const row = { + id: undefined, + studentId: undefined, + name: undefined, + score: undefined + } + row.studentId = props.studentId + formData.value.push(row) } /** 删除按钮操作 */ @@ -80,10 +91,10 @@ const validate = () => { return formRef.value.validate() } -/** 表单值 **/ +/** 表单值 */ const getData = () => { return formData.value } defineExpose({ validate, getData }) -</script> +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue new file mode 100644 index 00000000..12653b6c --- /dev/null +++ b/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue @@ -0,0 +1,72 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="班主任" prop="teacher"> + <el-input v-model="formData.teacher" placeholder="请输入班主任" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/normal' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + teacher: [{ required: true, message: '班主任不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 1. 重置表单 + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + teacher: undefined, + } + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + const data = await Demo03StudentApi.getDemo03GradeByStudentId(val) + if (!data) { + return + } + formData.value = data + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo03/index.vue b/src/views/infra/demo/demo03/normal/index.vue similarity index 50% rename from src/views/infra/demo03/index.vue rename to src/views/infra/demo/demo03/normal/index.vue index afd5cbfc..52029107 100644 --- a/src/views/infra/demo03/index.vue +++ b/src/views/infra/demo/demo03/normal/index.vue @@ -8,10 +8,50 @@ :inline="true" label-width="68px" > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select + v-model="queryParams.sex" + placeholder="请选择性别" + clearable + class="!w-240px" + > + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> <el-form-item> <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> - <el-button type="primary" plain @click="openForm('create')"> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > <Icon icon="ep:plus" class="mr-5px" /> 新增 </el-button> <el-button @@ -19,7 +59,7 @@ plain @click="handleExport" :loading="exportLoading" - v-hasPermi="['infra:demo-student:export']" + v-hasPermi="['infra:demo03-student:export']" > <Icon icon="ep:download" class="mr-5px" /> 导出 </el-button> @@ -29,37 +69,44 @@ <!-- 列表 --> <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - row-key="id" - > - <el-table-column type="expand"> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="性别" align="center" prop="sex"> <template #default="scope"> - <!-- 子表的表单 --> - <el-tabs model-value="DemoStudentContact"> - <el-tab-pane label="联系人信息" name="DemoStudentContact"> - <DemoStudentContactList :student-id="scope.row.id" /> - </el-tab-pane> - <el-tab-pane label="地址信息" name="DemoStudentAddress"> - <DemoStudentAddressList :student-id="scope.row.id" /> - </el-tab-pane> - </el-tabs> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> </template> </el-table-column> - <el-table-column label="编号" align="center" prop="id" /> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> <el-table-column label="操作" align="center"> <template #default="scope"> - <el-button link type="primary" @click="openForm('update', scope.row.id)"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > 编辑 </el-button> <el-button link type="danger" @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo-student:delete']" + v-hasPermi="['infra:demo03-student:delete']" > 删除 </el-button> @@ -76,27 +123,31 @@ </ContentWrap> <!-- 表单弹窗:添加/修改 --> - <DemoStudentForm ref="formRef" @success="getList" /> + <Demo03StudentForm ref="formRef" @success="getList" /> </template> <script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' import download from '@/utils/download' -import * as DemoStudentApi from '@/api/infra/demo02' -import DemoStudentForm from './DemoStudentForm.vue' -import DemoStudentContactList from './DemoStudentContactList.vue' -import DemoStudentAddressList from './DemoStudentAddressList.vue' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/normal' +import Demo03StudentForm from './Demo03StudentForm.vue' -defineOptions({ name: 'InfraDemoStudent' }) +defineOptions({ name: 'Demo03Student' }) const message = useMessage() // 消息弹窗 const { t } = useI18n() // 国际化 const loading = ref(true) // 列表的加载中 -const total = ref(0) // 列表的总页数 const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 const queryParams = reactive({ pageNo: 1, - pageSize: 10 + pageSize: 10, + name: null, + sex: null, + description: null, + createTime: [] }) const queryFormRef = ref() // 搜索的表单 const exportLoading = ref(false) // 导出的加载中 @@ -105,16 +156,9 @@ const exportLoading = ref(false) // 导出的加载中 const getList = async () => { loading.value = true try { - // const data = await DemoStudentApi.getDemoStudentPage(queryParams) - list.value = [ - { - id: 1 - }, - { - id: 10 - } - ] - total.value = 10 + const data = await Demo03StudentApi.getDemo03StudentPage(queryParams) + list.value = data.list + total.value = data.total } finally { loading.value = false } @@ -134,10 +178,7 @@ const resetQuery = () => { /** 添加/修改操作 */ const formRef = ref() -// const demoStudentContactFormRef = ref() const openForm = (type: string, id?: number) => { - // console.log(demoStudentContactFormRef, 'xx demoStudentContactFormRef xx') - // demoStudentContactFormRef.value.validate() formRef.value.open(type, id) } @@ -147,7 +188,7 @@ const handleDelete = async (id: number) => { // 删除的二次确认 await message.delConfirm() // 发起删除 - await DemoStudentApi.deleteDemoStudent(id) + await Demo03StudentApi.deleteDemo03Student(id) message.success(t('common.delSuccess')) // 刷新列表 await getList() @@ -161,7 +202,7 @@ const handleExport = async () => { await message.exportConfirm() // 发起导出 exportLoading.value = true - const data = await DemoStudentApi.exportDemoStudent(queryParams) + const data = await Demo03StudentApi.exportDemo03Student(queryParams) download.excel(data, '学生.xls') } catch { } finally { @@ -173,4 +214,4 @@ const handleExport = async () => { onMounted(() => { getList() }) -</script> +</script> \ No newline at end of file diff --git a/src/views/infra/demo03/DemoStudentAddressForm.vue b/src/views/infra/demo03/DemoStudentAddressForm.vue deleted file mode 100644 index af4cd8f1..00000000 --- a/src/views/infra/demo03/DemoStudentAddressForm.vue +++ /dev/null @@ -1,58 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="子字段 1" prop="field1"> - <el-input v-model="formData.field1" placeholder="请输入字段 1" /> - </el-form-item> - <el-form-item label="子字段 2" prop="field2"> - <el-input v-model="formData.field2" placeholder="请输入字段 2" /> - </el-form-item> - <el-form-item label="子字段 3" prop="field3"> - <el-input v-model="formData.field3" placeholder="请输入字段 3" /> - </el-form-item> - </el-form> -</template> -<script setup lang="ts"> -const props = defineProps<{ - studentId: undefined // 学生编号 -}>() -const formLoading = ref(false) // 表单的加载中 -const formData = ref({}) -const formRules = reactive({ - field1: [required] -}) -const formRef = ref() // 表单 Ref - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - (val) => { - if (val) { - formData.value = { - field2: '番茄', - field3: '西瓜' - } - } else { - formData.value = {} - } - }, - { immediate: true } -) - -/** 表单校验 */ -const validate = () => { - return formRef.value.validate() -} - -/** 表单值 **/ -const getData = () => { - return formData.value -} - -defineExpose({ validate, getData }) -</script> diff --git a/src/views/infra/demo03/DemoStudentAddressList.vue b/src/views/infra/demo03/DemoStudentAddressList.vue deleted file mode 100644 index 2354db56..00000000 --- a/src/views/infra/demo03/DemoStudentAddressList.vue +++ /dev/null @@ -1,38 +0,0 @@ -<template> - <!-- 列表 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="编号" align="center" prop="id" /> - <el-table-column label="手机" align="center" prop="mobile" /> - </el-table> - </ContentWrap> -</template> - -<script setup lang="ts"> -const props = defineProps<{ - studentId: undefined // 学生编号 -}>() -const loading = ref(true) // 列表的加载中 -const list = ref([]) // 列表的数据 - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - // const data = await DemoStudentApi.getDemoStudentPage(queryParams) - list.value = [ - { - id: props.studentId, - mobile: '88888' - } - ] - } finally { - loading.value = false - } -} - -/** 初始化 **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/infra/demo03/DemoStudentContactList.vue b/src/views/infra/demo03/DemoStudentContactList.vue deleted file mode 100644 index 76d46116..00000000 --- a/src/views/infra/demo03/DemoStudentContactList.vue +++ /dev/null @@ -1,38 +0,0 @@ -<template> - <!-- 列表 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="编号" align="center" prop="id" /> - <el-table-column label="手机" align="center" prop="mobile" /> - </el-table> - </ContentWrap> -</template> - -<script setup lang="ts"> -const props = defineProps<{ - studentId: undefined // 学生编号 -}>() -const loading = ref(true) // 列表的加载中 -const list = ref([]) // 列表的数据 - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - // const data = await DemoStudentApi.getDemoStudentPage(queryParams) - list.value = [ - { - id: props.studentId, - mobile: '15601691300' - } - ] - } finally { - loading.value = false - } -} - -/** 初始化 **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/infra/demo03/DemoStudentForm.vue b/src/views/infra/demo03/DemoStudentForm.vue deleted file mode 100644 index fe0788c4..00000000 --- a/src/views/infra/demo03/DemoStudentForm.vue +++ /dev/null @@ -1,132 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="字段 1" prop="field1"> - <el-input v-model="formData.field1" placeholder="请输入字段 1" /> - </el-form-item> - <el-form-item label="字段 2" prop="field2"> - <el-input v-model="formData.field2" placeholder="请输入字段 2" /> - </el-form-item> - <el-form-item label="字段 3" prop="field3"> - <el-input v-model="formData.field3" placeholder="请输入字段 3" /> - </el-form-item> - </el-form> - <!-- 子表的表单 --> - <el-tabs v-model="subTabsName"> - <el-tab-pane label="联系人信息" name="DemoStudentContact"> - <DemoStudentContactForm ref="demoStudentContactFormRef" :student-id="formData.id" /> - </el-tab-pane> - <el-tab-pane label="地址信息" name="DemoStudentAddress"> - <DemoStudentAddressForm ref="demoStudentAddressFormRef" :student-id="formData.id" /> - </el-tab-pane> - </el-tabs> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> - <el-button @click="dialogVisible = false">取 消</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as DemoStudentApi from '@/api/infra/demo02' -import DemoStudentContactForm from './DemoStudentContactForm.vue' -import DemoStudentAddressForm from './DemoStudentAddressForm.vue' - -const { t } = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 - -const dialogVisible = ref(false) // 弹窗的是否展示 -const dialogTitle = ref('') // 弹窗的标题 -const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 -const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const formData = ref({ - id: undefined -}) -const formRules = reactive({ - field2: [required] -}) -const formRef = ref() // 表单 Ref - -/** 子表的表单 */ -const demoStudentContactFormRef = ref() -const demoStudentAddressFormRef = ref() -const subTabsName = ref('DemoStudentContact') - -/** 打开弹窗 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 修改时,设置数据 - if (id) { - // debugger - formLoading.value = true - try { - // formData.value = await DemoStudentApi.getDemoStudent(id) - formData.value = { - id: id, - field1: '1', - field2: '22', - field3: '333' - } - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 提供 open 方法,用于打开弹窗 - -/** 提交表单 */ -const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 -const submitForm = async () => { - // 校验表单 - await formRef.value.validate() - // 校验子表单 - try { - await demoStudentContactFormRef.value.validate() - } catch (e) { - subTabsName.value = 'DemoStudentContact' - return - } - try { - await demoStudentAddressFormRef.value.validate() - } catch (e) { - subTabsName.value = 'DemoStudentAddress' - return - } - // 提交请求 - formLoading.value = true - try { - const data = formData.value as unknown as DemoStudentApi.DemoStudentVO - // 拼接子表的数据 - data.demoStudentContacts = demoStudentContactFormRef.value.getData() - data.demoStudentAddress = demoStudentAddressFormRef.value.getData() - if (formType.value === 'create') { - await DemoStudentApi.createDemoStudent(data) - message.success(t('common.createSuccess')) - } else { - await DemoStudentApi.updateDemoStudent(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 发送操作成功的事件 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 重置表单 */ -const resetForm = () => { - formData.value = { - id: undefined - } - formRef.value?.resetFields() -} -</script> From 6c405ba42039fd849a387e53df0799419d7a6000 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Thu, 16 Nov 2023 23:48:20 +0800 Subject: [PATCH 14/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=E4=B8=BB=E5=AD=90=E8=A1=A8=20inner?= =?UTF-8?q?=20=E6=A8=A1=E5=BC=8F=E7=9A=84=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/demo/demo03/inner/index.ts | 53 ++++ src/api/infra/demo11/index.ts | 57 ---- src/api/infra/demo12/index.ts | 95 ------ .../demo03/inner/Demo03StudentForm.vue} | 116 ++++---- .../inner/components/Demo03CourseForm.vue | 100 +++++++ .../inner/components/Demo03CourseList.vue | 51 ++++ .../inner/components/Demo03GradeForm.vue | 72 +++++ .../inner/components/Demo03GradeList.vue | 55 ++++ .../{demo11 => demo/demo03/inner}/index.vue | 90 +++--- .../infra/demo04/DemoStudentAddressForm.vue | 58 ---- .../infra/demo04/DemoStudentAddressList.vue | 39 --- .../infra/demo04/DemoStudentContactForm.vue | 96 ------ .../infra/demo04/DemoStudentContactList.vue | 70 ----- src/views/infra/demo04/DemoStudentForm.vue | 132 --------- src/views/infra/demo04/index.vue | 184 ------------ src/views/infra/demo11/Demo11StudentForm.vue | 183 ------------ .../components/Demo11StudentContactForm.vue | 174 ----------- .../components/Demo11StudentTeacherForm.vue | 122 -------- src/views/infra/demo12/Demo12StudentForm.vue | 183 ------------ .../components/Demo12StudentContactList.vue | 148 ---------- .../components/Demo12StudentTeacherForm.vue | 155 ---------- .../components/Demo12StudentTeacherList.vue | 148 ---------- src/views/infra/demo12/index.vue | 278 ------------------ src/views/infra/testDemo/index.vue | 4 - 24 files changed, 423 insertions(+), 2240 deletions(-) create mode 100644 src/api/infra/demo/demo03/inner/index.ts delete mode 100644 src/api/infra/demo11/index.ts delete mode 100644 src/api/infra/demo12/index.ts rename src/views/infra/{demo12/components/Demo12StudentContactForm.vue => demo/demo03/inner/Demo03StudentForm.vue} (61%) create mode 100644 src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue create mode 100644 src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue create mode 100644 src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue create mode 100644 src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue rename src/views/infra/{demo11 => demo/demo03/inner}/index.vue (74%) delete mode 100644 src/views/infra/demo04/DemoStudentAddressForm.vue delete mode 100644 src/views/infra/demo04/DemoStudentAddressList.vue delete mode 100644 src/views/infra/demo04/DemoStudentContactForm.vue delete mode 100644 src/views/infra/demo04/DemoStudentContactList.vue delete mode 100644 src/views/infra/demo04/DemoStudentForm.vue delete mode 100644 src/views/infra/demo04/index.vue delete mode 100644 src/views/infra/demo11/Demo11StudentForm.vue delete mode 100644 src/views/infra/demo11/components/Demo11StudentContactForm.vue delete mode 100644 src/views/infra/demo11/components/Demo11StudentTeacherForm.vue delete mode 100644 src/views/infra/demo12/Demo12StudentForm.vue delete mode 100644 src/views/infra/demo12/components/Demo12StudentContactList.vue delete mode 100644 src/views/infra/demo12/components/Demo12StudentTeacherForm.vue delete mode 100644 src/views/infra/demo12/components/Demo12StudentTeacherList.vue delete mode 100644 src/views/infra/demo12/index.vue delete mode 100644 src/views/infra/testDemo/index.vue diff --git a/src/api/infra/demo/demo03/inner/index.ts b/src/api/infra/demo/demo03/inner/index.ts new file mode 100644 index 00000000..f15ee1dc --- /dev/null +++ b/src/api/infra/demo/demo03/inner/index.ts @@ -0,0 +1,53 @@ +import request from '@/config/axios' + +export interface Demo03StudentVO { + id: number + name: string + sex: number + birthday: Date + description: string +} + +// 查询学生分页 +export const getDemo03StudentPage = async (params) => { + return await request.get({ url: `/infra/demo03-student/page`, params }) +} + +// 查询学生详情 +export const getDemo03Student = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo03Student = async (data: Demo03StudentVO) => { + return await request.post({ url: `/infra/demo03-student/create`, data }) +} + +// 修改学生 +export const updateDemo03Student = async (data: Demo03StudentVO) => { + return await request.put({ url: `/infra/demo03-student/update`, data }) +} + +// 删除学生 +export const deleteDemo03Student = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo03Student = async (params) => { + return await request.download({ url: `/infra/demo03-student/export-excel`, params }) +} + +// ==================== 子表(学生课程) ==================== + +// 获得学生课程列表 +export const getDemo03CourseListByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo03-student/demo03-course/list-by-student-id?studentId=` + studentId }) +} + +// ==================== 子表(学生班级) ==================== + +// 获得学生班级 +export const getDemo03GradeByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo03-student/demo03-grade/get-by-student-id?studentId=` + studentId }) +} \ No newline at end of file diff --git a/src/api/infra/demo11/index.ts b/src/api/infra/demo11/index.ts deleted file mode 100644 index 4c4c7b4e..00000000 --- a/src/api/infra/demo11/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -import request from '@/config/axios' - -export interface Demo11StudentVO { - id: number - name: string - description: string - birthday: Date - sex: number - enabled: boolean - avatar: string - video: string - memo: string -} - -// 查询学生列表 -export const getDemo11StudentPage = async (params) => { - return await request.get({ url: `/infra/demo11-student/page`, params }) -} - -// 查询学生详情 -export const getDemo11Student = async (id: number) => { - return await request.get({ url: `/infra/demo11-student/get?id=` + id }) -} - -// 新增学生 -export const createDemo11Student = async (data: Demo11StudentVO) => { - return await request.post({ url: `/infra/demo11-student/create`, data }) -} - -// 修改学生 -export const updateDemo11Student = async (data: Demo11StudentVO) => { - return await request.put({ url: `/infra/demo11-student/update`, data }) -} - -// 删除学生 -export const deleteDemo11Student = async (id: number) => { - return await request.delete({ url: `/infra/demo11-student/delete?id=` + id }) -} - -// 导出学生 Excel -export const exportDemo11Student = async (params) => { - return await request.download({ url: `/infra/demo11-student/export-excel`, params }) -} - -// ==================== 子表(学生联系人) ==================== - -// 获得学生联系人列表 -export const getDemo11StudentContactListByStudentId = async (studentId) => { - return await request.get({ url: `/infra/demo11-student/demo11-student/list-by-student-id?studentId=` + studentId }) -} - -// ==================== 子表(学生班主任) ==================== - -// 获得学生班主任 -export const getDemo11StudentTeacherByStudentId = async (studentId) => { - return await request.get({ url: `/infra/demo11-student/demo11-student/get-by-student-id?studentId=` + studentId }) -} \ No newline at end of file diff --git a/src/api/infra/demo12/index.ts b/src/api/infra/demo12/index.ts deleted file mode 100644 index 3f2be47e..00000000 --- a/src/api/infra/demo12/index.ts +++ /dev/null @@ -1,95 +0,0 @@ -import request from '@/config/axios' - -export interface Demo12StudentVO { - id: number - name: string - description: string - birthday: Date - sex: number - enabled: boolean - avatar: string - video: string - memo: string -} - -// 查询学生列表 -export const getDemo12StudentPage = async (params) => { - return await request.get({ url: `/infra/demo12-student/page`, params }) -} - -// 查询学生详情 -export const getDemo12Student = async (id: number) => { - return await request.get({ url: `/infra/demo12-student/get?id=` + id }) -} - -// 新增学生 -export const createDemo12Student = async (data: Demo12StudentVO) => { - return await request.post({ url: `/infra/demo12-student/create`, data }) -} - -// 修改学生 -export const updateDemo12Student = async (data: Demo12StudentVO) => { - return await request.put({ url: `/infra/demo12-student/update`, data }) -} - -// 删除学生 -export const deleteDemo12Student = async (id: number) => { - return await request.delete({ url: `/infra/demo12-student/delete?id=` + id }) -} - -// 导出学生 Excel -export const exportDemo12Student = async (params) => { - return await request.download({ url: `/infra/demo12-student/export-excel`, params }) -} - -// ==================== 子表(学生联系人) ==================== - -// 获得学生联系人分页 -export const getDemo12StudentContactPage = async (params) => { - return await request.get({ url: `/infra/demo12-student/demo12-student-contact/page`, params }) -} -// 新增学生联系人 -export const createDemo12StudentContact = async (data) => { - return await request.post({ url: `/infra/demo12-student/demo12-student-contact/create`, data }) -} - -// 修改学生联系人 -export const updateDemo12StudentContact = async (data) => { - return await request.put({ url: `/infra/demo12-student/demo12-student-contact/update`, data }) -} - -// 删除学生联系人 -export const deleteDemo12StudentContact = async (id: number) => { - return await request.delete({ url: `/infra/demo12-student/demo12-student-contact/delete?id=` + id }) -} - -// 获得学生联系人 -export const getDemo12StudentContact = async (id: number) => { - return await request.get({ url: `/infra/demo12-student/demo12-student-contact/get?id=` + id }) -} - -// ==================== 子表(学生班主任) ==================== - -// 获得学生班主任分页 -export const getDemo12StudentTeacherPage = async (params) => { - return await request.get({ url: `/infra/demo12-student/demo12-student-teacher/page`, params }) -} -// 新增学生班主任 -export const createDemo12StudentTeacher = async (data) => { - return await request.post({ url: `/infra/demo12-student/demo12-student-teacher/create`, data }) -} - -// 修改学生班主任 -export const updateDemo12StudentTeacher = async (data) => { - return await request.put({ url: `/infra/demo12-student/demo12-student-teacher/update`, data }) -} - -// 删除学生班主任 -export const deleteDemo12StudentTeacher = async (id: number) => { - return await request.delete({ url: `/infra/demo12-student/demo12-student-teacher/delete?id=` + id }) -} - -// 获得学生班主任 -export const getDemo12StudentTeacher = async (id: number) => { - return await request.get({ url: `/infra/demo12-student/demo12-student-teacher/get?id=` + id }) -} \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentContactForm.vue b/src/views/infra/demo/demo03/inner/Demo03StudentForm.vue similarity index 61% rename from src/views/infra/demo12/components/Demo12StudentContactForm.vue rename to src/views/infra/demo/demo03/inner/Demo03StudentForm.vue index e246678b..fe9327b9 100644 --- a/src/views/infra/demo12/components/Demo12StudentContactForm.vue +++ b/src/views/infra/demo/demo03/inner/Demo03StudentForm.vue @@ -10,8 +10,16 @@ <el-form-item label="名字" prop="name"> <el-input v-model="formData.name" placeholder="请输入名字" /> </el-form-item> - <el-form-item label="简介" prop="description"> - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> + <el-form-item label="性别" prop="sex"> + <el-radio-group v-model="formData.sex"> + <el-radio + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> </el-form-item> <el-form-item label="出生日期" prop="birthday"> <el-date-picker @@ -21,37 +29,19 @@ placeholder="选择出生日期" /> </el-form-item> - <el-form-item label="性别" prop="sex"> - <el-select v-model="formData.sex" placeholder="请选择性别"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-radio-group v-model="formData.enabled"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="头像" prop="avatar"> - <UploadImg v-model="formData.avatar" /> - </el-form-item> - <el-form-item label="附件" prop="video"> - <UploadFile v-model="formData.video" /> - </el-form-item> - <el-form-item label="备注" prop="memo"> - <Editor v-model="formData.memo" height="150px" /> + <el-form-item label="简介" prop="description"> + <Editor v-model="formData.description" height="150px" /> </el-form-item> </el-form> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="学生课程" name="demo03Course"> + <Demo03CourseForm ref="demo03CourseFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="学生班级" name="demo03Grade"> + <Demo03GradeForm ref="demo03GradeFormRef" :student-id="formData.id" /> + </el-tab-pane> + </el-tabs> <template #footer> <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> <el-button @click="dialogVisible = false">取 消</el-button> @@ -59,8 +49,10 @@ </Dialog> </template> <script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as Demo12StudentApi from '@/api/infra/demo12' +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' +import Demo03CourseForm from './components/Demo03CourseForm.vue' +import Demo03GradeForm from './components/Demo03GradeForm.vue' const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 @@ -71,40 +63,35 @@ const formLoading = ref(false) // 表单的加载中:1)修改时的数据加 const formType = ref('') // 表单的类型:create - 新增;update - 修改 const formData = ref({ id: undefined, - studentId: undefined, name: undefined, - description: undefined, - birthday: undefined, sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined + birthday: undefined, + description: undefined }) const formRules = reactive({ - studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'blur' }], birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], - enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }] }) const formRef = ref() // 表单 Ref +/** 子表的表单 */ +const subTabsName = ref('demo03Course') +const demo03CourseFormRef = ref() +const demo03GradeFormRef = ref() + /** 打开弹窗 */ -const open = async (type: string, id?: number, studentId: number) => { +const open = async (type: string, id?: number) => { dialogVisible.value = true dialogTitle.value = t('action.' + type) formType.value = type resetForm() - formData.value.studentId = studentId // 修改时,设置数据 if (id) { formLoading.value = true try { - formData.value = await Demo12StudentApi.getDemo12StudentContact(id) + formData.value = await Demo03StudentApi.getDemo03Student(id) } finally { formLoading.value = false } @@ -117,15 +104,31 @@ const emit = defineEmits(['success']) // 定义 success 事件,用于操作成 const submitForm = async () => { // 校验表单 await formRef.value.validate() + // 校验子表单 + try { + await demo03CourseFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo03Course' + return + } + try { + await demo03GradeFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo03Grade' + return + } // 提交请求 formLoading.value = true try { - const data = formData.value + const data = formData.value as unknown as Demo03StudentApi.Demo03StudentVO + // 拼接子表的数据 + data.demo03Courses = demo03CourseFormRef.value.getData() + data.demo03Grade = demo03GradeFormRef.value.getData() if (formType.value === 'create') { - await Demo12StudentApi.createDemo12StudentContact(data) + await Demo03StudentApi.createDemo03Student(data) message.success(t('common.createSuccess')) } else { - await Demo12StudentApi.updateDemo12StudentContact(data) + await Demo03StudentApi.updateDemo03Student(data) message.success(t('common.updateSuccess')) } dialogVisible.value = false @@ -140,15 +143,10 @@ const submitForm = async () => { const resetForm = () => { formData.value = { id: undefined, - studentId: undefined, name: undefined, - description: undefined, - birthday: undefined, sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined + birthday: undefined, + description: undefined } formRef.value?.resetFields() } diff --git a/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue b/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue new file mode 100644 index 00000000..87057513 --- /dev/null +++ b/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue @@ -0,0 +1,100 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + v-loading="formLoading" + label-width="0px" + :inline-message="true" + > + <el-table :data="formData" class="-mt-10px"> + <el-table-column label="序号" type="index" width="100" /> + <el-table-column label="名字" min-width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!"> + <el-input v-model="row.name" placeholder="请输入名字" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="分数" min-width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.score`" :rules="formRules.score" class="mb-0px!"> + <el-input v-model="row.score" placeholder="请输入分数" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column align="center" fixed="right" label="操作" width="60"> + <template #default="{ $index }"> + <el-button @click="handleDelete($index)" link>—</el-button> + </template> + </el-table-column> + </el-table> + </el-form> + <el-row justify="center" class="mt-3"> + <el-button @click="handleAdd" round>+ 添加学生课程</el-button> + </el-row> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + score: [{ required: true, message: '分数不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 1. 重置表单 + formData.value = [] + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + formData.value = await Demo03StudentApi.getDemo03CourseListByStudentId(val) + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 新增按钮操作 */ +const handleAdd = () => { + const row = { + id: undefined, + studentId: undefined, + name: undefined, + score: undefined + } + row.studentId = props.studentId + formData.value.push(row) +} + +/** 删除按钮操作 */ +const handleDelete = (index) => { + formData.value.splice(index, 1) +} + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue b/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue new file mode 100644 index 00000000..d912fc5d --- /dev/null +++ b/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue @@ -0,0 +1,51 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="分数" align="center" prop="score" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + </el-table> + </ContentWrap> +</template> +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(false) // 列表的加载中 +const list = ref([]) // 列表的数据 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + list.value = await Demo03StudentApi.getDemo03CourseListByStudentId(props.studentId) + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue new file mode 100644 index 00000000..e0eeb192 --- /dev/null +++ b/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue @@ -0,0 +1,72 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="班主任" prop="teacher"> + <el-input v-model="formData.teacher" placeholder="请输入班主任" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + teacher: [{ required: true, message: '班主任不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 1. 重置表单 + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + teacher: undefined, + } + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + const data = await Demo03StudentApi.getDemo03GradeByStudentId(val) + if (!data) { + return + } + formData.value = data + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue b/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue new file mode 100644 index 00000000..96905414 --- /dev/null +++ b/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue @@ -0,0 +1,55 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="班主任" align="center" prop="teacher" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + </el-table> + </ContentWrap> +</template> +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(false) // 列表的加载中 +const list = ref([]) // 列表的数据 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03GradeByStudentId(props.studentId) + if (!data) { + return + } + list.value.push(data) + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file diff --git a/src/views/infra/demo11/index.vue b/src/views/infra/demo/demo03/inner/index.vue similarity index 74% rename from src/views/infra/demo11/index.vue rename to src/views/infra/demo/demo03/inner/index.vue index 36529eb9..4ce6037d 100644 --- a/src/views/infra/demo11/index.vue +++ b/src/views/infra/demo/demo03/inner/index.vue @@ -17,16 +17,6 @@ class="!w-240px" /> </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="queryParams.birthday" - value-format="YYYY-MM-DD" - type="date" - placeholder="选择出生日期" - clearable - class="!w-240px" - /> - </el-form-item> <el-form-item label="性别" prop="sex"> <el-select v-model="queryParams.sex" @@ -42,21 +32,6 @@ /> </el-select> </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-select - v-model="queryParams.enabled" - placeholder="请选择是否有效" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> <el-form-item label="创建时间" prop="createTime"> <el-date-picker v-model="queryParams.createTime" @@ -75,7 +50,7 @@ type="primary" plain @click="openForm('create')" - v-hasPermi="['infra:demo11-student:create']" + v-hasPermi="['infra:demo03-student:create']" > <Icon icon="ep:plus" class="mr-5px" /> 新增 </el-button> @@ -84,7 +59,7 @@ plain @click="handleExport" :loading="exportLoading" - v-hasPermi="['infra:demo11-student:export']" + v-hasPermi="['infra:demo03-student:export']" > <Icon icon="ep:download" class="mr-5px" /> 导出 </el-button> @@ -95,9 +70,26 @@ <!-- 列表 --> <ContentWrap> <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <!-- 子表的列表 --> + <el-table-column type="expand"> + <template #default="scope"> + <el-tabs model-value="demo03Course"> + <el-tab-pane label="学生课程" name="demo03Course"> + <Demo03CourseList :student-id="scope.row.id" /> + </el-tab-pane> + <el-tab-pane label="学生班级" name="demo03Grade"> + <Demo03GradeList :student-id="scope.row.id" /> + </el-tab-pane> + </el-tabs> + </template> + </el-table-column> <el-table-column label="编号" align="center" prop="id" /> <el-table-column label="名字" align="center" prop="name" /> - <el-table-column label="简介" align="center" prop="description" /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> <el-table-column label="出生日期" align="center" @@ -105,19 +97,7 @@ :formatter="dateFormatter" width="180px" /> - <el-table-column label="性别" align="center" prop="sex"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> - </template> - </el-table-column> - <el-table-column label="是否有效" align="center" prop="enabled"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> - </template> - </el-table-column> - <el-table-column label="头像" align="center" prop="avatar" /> - <el-table-column label="附件" align="center" prop="video" /> - <el-table-column label="备注" align="center" prop="memo" /> + <el-table-column label="简介" align="center" prop="description" /> <el-table-column label="创建时间" align="center" @@ -131,7 +111,7 @@ link type="primary" @click="openForm('update', scope.row.id)" - v-hasPermi="['infra:demo11-student:update']" + v-hasPermi="['infra:demo03-student:update']" > 编辑 </el-button> @@ -139,7 +119,7 @@ link type="danger" @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo11-student:delete']" + v-hasPermi="['infra:demo03-student:delete']" > 删除 </el-button> @@ -156,32 +136,32 @@ </ContentWrap> <!-- 表单弹窗:添加/修改 --> - <Demo11StudentForm ref="formRef" @success="getList" /> + <Demo03StudentForm ref="formRef" @success="getList" /> </template> <script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { dateFormatter } from '@/utils/formatTime' import download from '@/utils/download' -import * as Demo11StudentApi from '@/api/infra/demo11' -import Demo11StudentForm from './Demo11StudentForm.vue' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' +import Demo03StudentForm from './Demo03StudentForm.vue' +import Demo03CourseList from './components/Demo03CourseList.vue' +import Demo03GradeList from './components/Demo03GradeList.vue' -defineOptions({ name: 'InfraDemo11Student' }) +defineOptions({ name: 'Demo03Student' }) const message = useMessage() // 消息弹窗 const { t } = useI18n() // 国际化 const loading = ref(true) // 列表的加载中 -const total = ref(0) // 列表的总页数 const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 const queryParams = reactive({ pageNo: 1, pageSize: 10, name: null, - birthday: null, - birthday: [], sex: null, - enabled: null, + description: null, createTime: [] }) const queryFormRef = ref() // 搜索的表单 @@ -191,7 +171,7 @@ const exportLoading = ref(false) // 导出的加载中 const getList = async () => { loading.value = true try { - const data = await Demo11StudentApi.getDemo11StudentPage(queryParams) + const data = await Demo03StudentApi.getDemo03StudentPage(queryParams) list.value = data.list total.value = data.total } finally { @@ -223,7 +203,7 @@ const handleDelete = async (id: number) => { // 删除的二次确认 await message.delConfirm() // 发起删除 - await Demo11StudentApi.deleteDemo11Student(id) + await Demo03StudentApi.deleteDemo03Student(id) message.success(t('common.delSuccess')) // 刷新列表 await getList() @@ -237,7 +217,7 @@ const handleExport = async () => { await message.exportConfirm() // 发起导出 exportLoading.value = true - const data = await Demo11StudentApi.exportDemo11Student(queryParams) + const data = await Demo03StudentApi.exportDemo03Student(queryParams) download.excel(data, '学生.xls') } catch { } finally { diff --git a/src/views/infra/demo04/DemoStudentAddressForm.vue b/src/views/infra/demo04/DemoStudentAddressForm.vue deleted file mode 100644 index af4cd8f1..00000000 --- a/src/views/infra/demo04/DemoStudentAddressForm.vue +++ /dev/null @@ -1,58 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="子字段 1" prop="field1"> - <el-input v-model="formData.field1" placeholder="请输入字段 1" /> - </el-form-item> - <el-form-item label="子字段 2" prop="field2"> - <el-input v-model="formData.field2" placeholder="请输入字段 2" /> - </el-form-item> - <el-form-item label="子字段 3" prop="field3"> - <el-input v-model="formData.field3" placeholder="请输入字段 3" /> - </el-form-item> - </el-form> -</template> -<script setup lang="ts"> -const props = defineProps<{ - studentId: undefined // 学生编号 -}>() -const formLoading = ref(false) // 表单的加载中 -const formData = ref({}) -const formRules = reactive({ - field1: [required] -}) -const formRef = ref() // 表单 Ref - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - (val) => { - if (val) { - formData.value = { - field2: '番茄', - field3: '西瓜' - } - } else { - formData.value = {} - } - }, - { immediate: true } -) - -/** 表单校验 */ -const validate = () => { - return formRef.value.validate() -} - -/** 表单值 **/ -const getData = () => { - return formData.value -} - -defineExpose({ validate, getData }) -</script> diff --git a/src/views/infra/demo04/DemoStudentAddressList.vue b/src/views/infra/demo04/DemoStudentAddressList.vue deleted file mode 100644 index 92143456..00000000 --- a/src/views/infra/demo04/DemoStudentAddressList.vue +++ /dev/null @@ -1,39 +0,0 @@ -<template> - <!-- 列表 --> - <ContentWrap> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="编号" align="center" prop="id" /> - <el-table-column label="手机" align="center" prop="mobile" /> - </el-table> - </ContentWrap> -</template> - -<script setup lang="ts"> -const props = defineProps<{ - studentId: undefined // 学生编号 -}>() -const loading = ref(true) // 列表的加载中 -const list = ref([]) // 列表的数据 - -// TODO 芋艿:暂时没改 -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - // const data = await DemoStudentApi.getDemoStudentPage(queryParams) - list.value = [ - { - id: props.studentId, - mobile: '88888' - } - ] - } finally { - loading.value = false - } -} - -/** 初始化 **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/infra/demo04/DemoStudentContactForm.vue b/src/views/infra/demo04/DemoStudentContactForm.vue deleted file mode 100644 index c8744eb0..00000000 --- a/src/views/infra/demo04/DemoStudentContactForm.vue +++ /dev/null @@ -1,96 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="字段 1" prop="field1"> - <el-input v-model="formData.field1" placeholder="请输入字段 1" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> - <el-button @click="dialogVisible = false">取 消</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as DemoStudentApi from '@/api/infra/demo02' -import DemoStudentContactForm from './DemoStudentContactForm.vue' -import DemoStudentAddressForm from './DemoStudentAddressForm.vue' - -const { t } = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 - -const dialogVisible = ref(false) // 弹窗的是否展示 -const dialogTitle = ref('') // 弹窗的标题 -const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 -const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const formData = ref({ - id: undefined -}) -const formRules = reactive({ - field2: [required] -}) -const formRef = ref() // 表单 Ref - -/** 打开弹窗 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 修改时,设置数据 - if (id) { - // debugger - formLoading.value = true - try { - // formData.value = await DemoStudentApi.getDemoStudent(id) - formData.value = { - id: id, - field1: '1', - field2: '22', - field3: '333' - } - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 提供 open 方法,用于打开弹窗 - -/** 提交表单 */ -const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 -const submitForm = async () => { - // 校验表单 - await formRef.value.validate() - // 提交请求 - formLoading.value = true - try { - const data = formData.value as unknown as DemoStudentApi.DemoStudentVO - if (formType.value === 'create') { - // await DemoStudentApi.createDemoStudent(data) // TODO 芋艿:临时去掉 - message.success(t('common.createSuccess')) - } else { - await DemoStudentApi.updateDemoStudent(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 发送操作成功的事件 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 重置表单 */ -const resetForm = () => { - formData.value = { - id: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/infra/demo04/DemoStudentContactList.vue b/src/views/infra/demo04/DemoStudentContactList.vue deleted file mode 100644 index b944c407..00000000 --- a/src/views/infra/demo04/DemoStudentContactList.vue +++ /dev/null @@ -1,70 +0,0 @@ -<template> - <!-- 列表 --> - <ContentWrap> - <el-button type="primary" plain @click="openForm('create')"> - <Icon icon="ep:plus" class="mr-5px" /> 新增 - </el-button> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="编号" align="center" prop="id" /> - <el-table-column label="手机" align="center" prop="mobile" /> - </el-table> - </ContentWrap> - - <!-- 表单弹窗:添加/修改 --> - <DemoStudentContactForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import DemoStudentContactForm from './DemoStudentContactForm.vue' - -const props = defineProps<{ - studentId: undefined // 学生编号 -}>() -const loading = ref(false) // 列表的加载中 -const total = ref(0) // 列表的总页数 -const list = ref([]) // 列表的数据 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - studentId: undefined -}) - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - (val) => { - queryParams.studentId = val - handleQuery() - }, - { immediate: false } -) - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - // const data = await DemoStudentApi.getDemoStudentPage(queryParams) - list.value = [ - { - id: props.studentId, - mobile: '15601691300' - } - ] - total.value = 10 - } finally { - loading.value = false - } -} - -/** 搜索按钮操作 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 添加/修改操作 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} -</script> diff --git a/src/views/infra/demo04/DemoStudentForm.vue b/src/views/infra/demo04/DemoStudentForm.vue deleted file mode 100644 index fe0788c4..00000000 --- a/src/views/infra/demo04/DemoStudentForm.vue +++ /dev/null @@ -1,132 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="字段 1" prop="field1"> - <el-input v-model="formData.field1" placeholder="请输入字段 1" /> - </el-form-item> - <el-form-item label="字段 2" prop="field2"> - <el-input v-model="formData.field2" placeholder="请输入字段 2" /> - </el-form-item> - <el-form-item label="字段 3" prop="field3"> - <el-input v-model="formData.field3" placeholder="请输入字段 3" /> - </el-form-item> - </el-form> - <!-- 子表的表单 --> - <el-tabs v-model="subTabsName"> - <el-tab-pane label="联系人信息" name="DemoStudentContact"> - <DemoStudentContactForm ref="demoStudentContactFormRef" :student-id="formData.id" /> - </el-tab-pane> - <el-tab-pane label="地址信息" name="DemoStudentAddress"> - <DemoStudentAddressForm ref="demoStudentAddressFormRef" :student-id="formData.id" /> - </el-tab-pane> - </el-tabs> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> - <el-button @click="dialogVisible = false">取 消</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as DemoStudentApi from '@/api/infra/demo02' -import DemoStudentContactForm from './DemoStudentContactForm.vue' -import DemoStudentAddressForm from './DemoStudentAddressForm.vue' - -const { t } = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 - -const dialogVisible = ref(false) // 弹窗的是否展示 -const dialogTitle = ref('') // 弹窗的标题 -const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 -const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const formData = ref({ - id: undefined -}) -const formRules = reactive({ - field2: [required] -}) -const formRef = ref() // 表单 Ref - -/** 子表的表单 */ -const demoStudentContactFormRef = ref() -const demoStudentAddressFormRef = ref() -const subTabsName = ref('DemoStudentContact') - -/** 打开弹窗 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 修改时,设置数据 - if (id) { - // debugger - formLoading.value = true - try { - // formData.value = await DemoStudentApi.getDemoStudent(id) - formData.value = { - id: id, - field1: '1', - field2: '22', - field3: '333' - } - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 提供 open 方法,用于打开弹窗 - -/** 提交表单 */ -const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 -const submitForm = async () => { - // 校验表单 - await formRef.value.validate() - // 校验子表单 - try { - await demoStudentContactFormRef.value.validate() - } catch (e) { - subTabsName.value = 'DemoStudentContact' - return - } - try { - await demoStudentAddressFormRef.value.validate() - } catch (e) { - subTabsName.value = 'DemoStudentAddress' - return - } - // 提交请求 - formLoading.value = true - try { - const data = formData.value as unknown as DemoStudentApi.DemoStudentVO - // 拼接子表的数据 - data.demoStudentContacts = demoStudentContactFormRef.value.getData() - data.demoStudentAddress = demoStudentAddressFormRef.value.getData() - if (formType.value === 'create') { - await DemoStudentApi.createDemoStudent(data) - message.success(t('common.createSuccess')) - } else { - await DemoStudentApi.updateDemoStudent(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 发送操作成功的事件 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 重置表单 */ -const resetForm = () => { - formData.value = { - id: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/infra/demo04/index.vue b/src/views/infra/demo04/index.vue deleted file mode 100644 index 9a6b8bfe..00000000 --- a/src/views/infra/demo04/index.vue +++ /dev/null @@ -1,184 +0,0 @@ -<template> - <ContentWrap> - <!-- 搜索工作栏 --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> - <el-button type="primary" plain @click="openForm('create')"> - <Icon icon="ep:plus" class="mr-5px" /> 新增 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['infra:demo-student:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 导出 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 列表 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - highlight-current-row - @current-change="handleCurrentChange" - > - <el-table-column label="编号" align="center" prop="id" /> - <el-table-column label="操作" align="center"> - <template #default="scope"> - <el-button link type="primary" @click="openForm('update', scope.row.id)"> - 编辑 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo-student:delete']" - > - 删除 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 子列表 --> - <ContentWrap> - <el-tabs model-value="DemoStudentContact"> - <el-tab-pane label="联系人信息" name="DemoStudentContact"> - <DemoStudentContactList :student-id="currentRow.id" /> - </el-tab-pane> - <el-tab-pane label="地址信息" name="DemoStudentAddress"> - <DemoStudentAddressList :student-id="currentRow.id" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> - - <!-- 表单弹窗:添加/修改 --> - <DemoStudentForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import download from '@/utils/download' -import * as DemoStudentApi from '@/api/infra/demo02' -import DemoStudentForm from './DemoStudentForm.vue' -import DemoStudentContactList from './DemoStudentContactList.vue' -import DemoStudentAddressList from './DemoStudentAddressList.vue' - -defineOptions({ name: 'InfraDemoStudent' }) - -const message = useMessage() // 消息弹窗 -const { t } = useI18n() // 国际化 - -const loading = ref(true) // 列表的加载中 -const total = ref(0) // 列表的总页数 -const list = ref([]) // 列表的数据 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10 -}) -const queryFormRef = ref() // 搜索的表单 -const exportLoading = ref(false) // 导出的加载中 -const currentRow = ref({}) // 选中行 - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - // const data = await DemoStudentApi.getDemoStudentPage(queryParams) - list.value = [ - { - id: 1 - }, - { - id: 10 - } - ] - total.value = 10 - } finally { - loading.value = false - } -} - -/** 搜索按钮操作 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 重置按钮操作 */ -const resetQuery = () => { - queryFormRef.value.resetFields() - handleQuery() -} - -/** 添加/修改操作 */ -const formRef = ref() -// const demoStudentContactFormRef = ref() -const openForm = (type: string, id?: number) => { - // console.log(demoStudentContactFormRef, 'xx demoStudentContactFormRef xx') - // demoStudentContactFormRef.value.validate() - formRef.value.open(type, id) -} - -/** 删除按钮操作 */ -const handleDelete = async (id: number) => { - try { - // 删除的二次确认 - await message.delConfirm() - // 发起删除 - await DemoStudentApi.deleteDemoStudent(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch {} -} - -/** 导出按钮操作 */ -const handleExport = async () => { - try { - // 导出的二次确认 - await message.exportConfirm() - // 发起导出 - exportLoading.value = true - const data = await DemoStudentApi.exportDemoStudent(queryParams) - download.excel(data, '学生.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 选中行操作 */ -const handleCurrentChange = (row) => { - console.log(currentRow.value, '==== currentRow.value ====') - console.log(row, '==== row ====') - currentRow.value = row -} - -/** 初始化 **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/infra/demo11/Demo11StudentForm.vue b/src/views/infra/demo11/Demo11StudentForm.vue deleted file mode 100644 index 39c21a2b..00000000 --- a/src/views/infra/demo11/Demo11StudentForm.vue +++ /dev/null @@ -1,183 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="名字" prop="name"> - <el-input v-model="formData.name" placeholder="请输入名字" /> - </el-form-item> - <el-form-item label="简介" prop="description"> - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> - </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="formData.birthday" - type="date" - value-format="x" - placeholder="选择出生日期" - /> - </el-form-item> - <el-form-item label="性别" prop="sex"> - <el-select v-model="formData.sex" placeholder="请选择性别"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-radio-group v-model="formData.enabled"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="头像"> - <UploadImg v-model="formData.avatar" /> - </el-form-item> - <el-form-item label="附件" prop="video"> - <UploadFile v-model="formData.video" /> - </el-form-item> - <el-form-item label="备注" prop="memo"> - <Editor v-model="formData.memo" height="150px" /> - </el-form-item> - </el-form> - <!-- 子表的表单 --> - <el-tabs v-model="subTabsName"> - <el-tab-pane label="学生联系人" name="demo11StudentContact"> - <Demo11StudentContactForm ref="demo11StudentContactFormRef" :student-id="formData.id" /> - </el-tab-pane> - <el-tab-pane label="学生班主任" name="demo11StudentTeacher"> - <Demo11StudentTeacherForm ref="demo11StudentTeacherFormRef" :student-id="formData.id" /> - </el-tab-pane> - </el-tabs> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> - <el-button @click="dialogVisible = false">取 消</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as Demo11StudentApi from '@/api/infra/demo11' -import Demo11StudentContactForm from './components/Demo11StudentContactForm.vue' -import Demo11StudentTeacherForm from './components/Demo11StudentTeacherForm.vue' - -const { t } = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 - -const dialogVisible = ref(false) // 弹窗的是否展示 -const dialogTitle = ref('') // 弹窗的标题 -const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 -const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const formData = ref({ - id: undefined, - name: undefined, - description: undefined, - birthday: undefined, - sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], - birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], - enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] -}) -const formRef = ref() // 表单 Ref - -/** 子表的表单 */ -const subTabsName = ref('demo11StudentContact') -const demo11StudentContactFormRef = ref() -const demo11StudentTeacherFormRef = ref() - -/** 打开弹窗 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 修改时,设置数据 - if (id) { - formLoading.value = true - try { - formData.value = await Demo11StudentApi.getDemo11Student(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 提供 open 方法,用于打开弹窗 - -/** 提交表单 */ -const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 -const submitForm = async () => { - // 校验表单 - await formRef.value.validate() - // 校验子表单 - try { - await demo11StudentContactFormRef.value.validate() - } catch (e) { - subTabsName.value = 'demo11StudentContact' - return - } - try { - await demo11StudentTeacherFormRef.value.validate() - } catch (e) { - subTabsName.value = 'demo11StudentTeacher' - return - } - // 提交请求 - formLoading.value = true - try { - const data = formData.value as unknown as Demo11StudentApi.Demo11StudentVO - // 拼接子表的数据 - data.demo11StudentContacts = demo11StudentContactFormRef.value.getData() - data.demo11StudentTeacher = demo11StudentTeacherFormRef.value.getData() - if (formType.value === 'create') { - await Demo11StudentApi.createDemo11Student(data) - message.success(t('common.createSuccess')) - } else { - await Demo11StudentApi.updateDemo11Student(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 发送操作成功的事件 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 重置表单 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - description: undefined, - birthday: undefined, - sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined - } - formRef.value?.resetFields() -} -</script> \ No newline at end of file diff --git a/src/views/infra/demo11/components/Demo11StudentContactForm.vue b/src/views/infra/demo11/components/Demo11StudentContactForm.vue deleted file mode 100644 index ba900017..00000000 --- a/src/views/infra/demo11/components/Demo11StudentContactForm.vue +++ /dev/null @@ -1,174 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - v-loading="formLoading" - label-width="0px" - :inline-message="true" - > - <el-table :data="formData" class="-mt-10px"> - <el-table-column label="序号" type="index" width="100" /> - <el-table-column label="名字" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!"> - <el-input v-model="row.name" placeholder="请输入名字" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="简介" width="200"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.description`" :rules="formRules.description" class="mb-0px!"> - <el-input v-model="row.description" type="textarea" placeholder="请输入简介" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="出生日期" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.birthday`" :rules="formRules.birthday" class="mb-0px!"> - <el-date-picker - v-model="row.birthday" - type="date" - value-format="x" - placeholder="选择出生日期" - /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="性别" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.sex`" :rules="formRules.sex" class="mb-0px!"> - <el-select v-model="row.sex" placeholder="请选择性别"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="是否有效" width="150"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.enabled`" :rules="formRules.enabled" class="mb-0px!"> - <el-radio-group v-model="row.enabled"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="头像" width="200"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.avatar`" :rules="formRules.avatar" class="mb-0px!"> - <UploadImg v-model="row.avatar" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="附件" width="200"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.video`" :rules="formRules.video" class="mb-0px!"> - <UploadFile v-model="row.video" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column label="备注" width="400"> - <template #default="{ row, $index }"> - <el-form-item :prop="`${$index}.memo`" :rules="formRules.memo" class="mb-0px!"> - <Editor v-model="row.memo" height="150px" /> - </el-form-item> - </template> - </el-table-column> - <el-table-column align="center" fixed="right" label="操作" width="60"> - <template #default="{ $index }"> - <el-button @click="handleDelete($index)" link>—</el-button> - </template> - </el-table-column> - </el-table> - </el-form> - <el-row justify="center" class="mt-3"> - <el-button @click="handleAdd" round>+ 添加学生联系人</el-button> - </el-row> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as Demo11StudentApi from '@/api/infra/demo11' - -const props = defineProps<{ - studentId: undefined // 学生编号(主表的关联字段) -}>() -const formLoading = ref(false) // 表单的加载中 -const formData = ref([]) -const formRules = reactive({ - studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], - name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], - birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], - enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] -}) -const formRef = ref() // 表单 Ref - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - async (val) => { - // 情况一:val 为空,说明是新增,则置空 - if (!val) { - formData.value = [] - return; - } - // 情况二:val 非空,说明是修改,则加载数据 - try { - formLoading.value = true - formData.value = await Demo11StudentApi.getDemo11StudentContactListByStudentId(val) - } finally { - formLoading.value = false - } - }, - { immediate: true } -) - -/** 新增按钮操作 */ -const handleAdd = () => { - const row = { - id: undefined, - studentId: undefined, - name: undefined, - description: undefined, - birthday: undefined, - sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined - } - row.studentId = props.studentId - formData.value.push(row) -} - -/** 删除按钮操作 */ -const handleDelete = (index) => { - formData.value.splice(index, 1) -} - -/** 表单校验 */ -const validate = () => { - return formRef.value.validate() -} - -/** 表单值 */ -const getData = () => { - return formData.value -} - -defineExpose({ validate, getData }) -</script> \ No newline at end of file diff --git a/src/views/infra/demo11/components/Demo11StudentTeacherForm.vue b/src/views/infra/demo11/components/Demo11StudentTeacherForm.vue deleted file mode 100644 index a8697be1..00000000 --- a/src/views/infra/demo11/components/Demo11StudentTeacherForm.vue +++ /dev/null @@ -1,122 +0,0 @@ -<template> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="名字" prop="name"> - <el-input v-model="formData.name" placeholder="请输入名字" /> - </el-form-item> - <el-form-item label="简介" prop="description"> - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> - </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="formData.birthday" - type="date" - value-format="x" - placeholder="选择出生日期" - /> - </el-form-item> - <el-form-item label="性别" prop="sex"> - <el-select v-model="formData.sex" placeholder="请选择性别"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-radio-group v-model="formData.enabled"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="头像" prop="avatar"> - <UploadImg v-model="formData.avatar" /> - </el-form-item> - <el-form-item label="附件" prop="video"> - <UploadFile v-model="formData.video" /> - </el-form-item> - <el-form-item label="备注" prop="memo"> - <Editor v-model="formData.memo" height="150px" /> - </el-form-item> - </el-form> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as Demo11StudentApi from '@/api/infra/demo11' - -const props = defineProps<{ - studentId: undefined // 学生编号(主表的关联字段) -}>() -const formLoading = ref(false) // 表单的加载中 -const formData = ref([]) -const formRules = reactive({ - studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], - name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], - birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], - enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] -}) -const formRef = ref() // 表单 Ref - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - async (val) => { - // 1. 重置表单 - formData.value = { - id: undefined, - studentId: undefined, - name: undefined, - description: undefined, - birthday: undefined, - sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined, - } - // 2. val 非空,则加载数据 - if (!val) { - return; - } - try { - formLoading.value = true - const data = await Demo11StudentApi.getDemo11StudentTeacherByStudentId(val) - if (!data) { - return - } - formData.value = data - } finally { - formLoading.value = false - } - }, - { immediate: true } -) - -/** 表单校验 */ -const validate = () => { - return formRef.value.validate() -} - -/** 表单值 */ -const getData = () => { - return formData.value -} - -defineExpose({ validate, getData }) -</script> \ No newline at end of file diff --git a/src/views/infra/demo12/Demo12StudentForm.vue b/src/views/infra/demo12/Demo12StudentForm.vue deleted file mode 100644 index af4e2733..00000000 --- a/src/views/infra/demo12/Demo12StudentForm.vue +++ /dev/null @@ -1,183 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="名字" prop="name"> - <el-input v-model="formData.name" placeholder="请输入名字" /> - </el-form-item> - <el-form-item label="简介" prop="description"> - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> - </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="formData.birthday" - type="date" - value-format="x" - placeholder="选择出生日期" - /> - </el-form-item> - <el-form-item label="性别" prop="sex"> - <el-select v-model="formData.sex" placeholder="请选择性别"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-radio-group v-model="formData.enabled"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="头像" prop="avatar"> - <UploadImg v-model="formData.avatar" /> - </el-form-item> - <el-form-item label="附件" prop="video"> - <UploadFile v-model="formData.video" /> - </el-form-item> - <el-form-item label="备注" prop="memo"> - <Editor v-model="formData.memo" height="150px" /> - </el-form-item> - </el-form> - <!-- 子表的表单 --> - <el-tabs v-model="subTabsName"> - <el-tab-pane label="学生联系人" name="demo12StudentContact"> - <Demo12StudentContactForm ref="demo12StudentContactFormRef" :student-id="formData.id" /> - </el-tab-pane> - <el-tab-pane label="学生班主任" name="demo12StudentTeacher"> - <Demo12StudentTeacherForm ref="demo12StudentTeacherFormRef" :student-id="formData.id" /> - </el-tab-pane> - </el-tabs> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> - <el-button @click="dialogVisible = false">取 消</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as Demo12StudentApi from '@/api/infra/demo12' -import Demo12StudentContactForm from './components/Demo12StudentContactForm.vue' -import Demo12StudentTeacherForm from './components/Demo12StudentTeacherForm.vue' - -const { t } = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 - -const dialogVisible = ref(false) // 弹窗的是否展示 -const dialogTitle = ref('') // 弹窗的标题 -const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 -const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const formData = ref({ - id: undefined, - name: undefined, - description: undefined, - birthday: undefined, - sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], - birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], - enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] -}) -const formRef = ref() // 表单 Ref - -/** 子表的表单 */ -const subTabsName = ref('demo12StudentContact') -const demo12StudentContactFormRef = ref() -const demo12StudentTeacherFormRef = ref() - -/** 打开弹窗 */ -const open = async (type: string, id?: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - // 修改时,设置数据 - if (id) { - formLoading.value = true - try { - formData.value = await Demo12StudentApi.getDemo12Student(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 提供 open 方法,用于打开弹窗 - -/** 提交表单 */ -const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 -const submitForm = async () => { - // 校验表单 - await formRef.value.validate() - // 校验子表单 - try { - await demo12StudentContactFormRef.value.validate() - } catch (e) { - subTabsName.value = 'demo12StudentContact' - return - } - try { - await demo12StudentTeacherFormRef.value.validate() - } catch (e) { - subTabsName.value = 'demo12StudentTeacher' - return - } - // 提交请求 - formLoading.value = true - try { - const data = formData.value as unknown as Demo12StudentApi.Demo12StudentVO - // 拼接子表的数据 - data.demo12StudentContacts = demo12StudentContactFormRef.value.getData() - data.demo12StudentTeacher = demo12StudentTeacherFormRef.value.getData() - if (formType.value === 'create') { - await Demo12StudentApi.createDemo12Student(data) - message.success(t('common.createSuccess')) - } else { - await Demo12StudentApi.updateDemo12Student(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 发送操作成功的事件 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 重置表单 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - description: undefined, - birthday: undefined, - sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined - } - formRef.value?.resetFields() -} -</script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentContactList.vue b/src/views/infra/demo12/components/Demo12StudentContactList.vue deleted file mode 100644 index b9b1e717..00000000 --- a/src/views/infra/demo12/components/Demo12StudentContactList.vue +++ /dev/null @@ -1,148 +0,0 @@ -<template> - <!-- 列表 --> - <ContentWrap> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['infra:demo12-student:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 新增 - </el-button> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="编号" align="center" prop="id" /> - <el-table-column label="学生编号" align="center" prop="studentId" /> - <el-table-column label="名字" align="center" prop="name" /> - <el-table-column label="简介" align="center" prop="description" /> - <el-table-column - label="出生日期" - align="center" - prop="birthday" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="性别" align="center" prop="sex"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> - </template> - </el-table-column> - <el-table-column label="是否有效" align="center" prop="enabled"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> - </template> - </el-table-column> - <el-table-column label="头像" align="center" prop="avatar" /> - <el-table-column label="附件" align="center" prop="video" /> - <el-table-column label="备注" align="center" prop="memo" /> - <el-table-column - label="创建时间" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="操作" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['infra:demo12-student:update']" - > - 编辑 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo12-student:delete']" - > - 删除 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 表单弹窗:添加/修改 --> - <Demo12StudentContactForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import * as Demo12StudentApi from '@/api/infra/demo12' -import Demo12StudentContactForm from './Demo12StudentContactForm.vue' - -const { t } = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 - -const props = defineProps<{ - studentId: undefined // 学生编号(主表的关联字段) -}>() -const loading = ref(false) // 列表的加载中 -const list = ref([]) // 列表的数据 -const total = ref(0) // 列表的总页数 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - studentId: undefined -}) - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - (val) => { - queryParams.studentId = val - handleQuery() - }, - { immediate: false } -) - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - const data = await Demo12StudentApi.getDemo12StudentContactPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 搜索按钮操作 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 添加/修改操作 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - if (!props.studentId) { - message.error('请选择一个学生') - return - } - formRef.value.open(type, id, props.studentId) -} - -/** 删除按钮操作 */ -const handleDelete = async (id: number) => { - try { - // 删除的二次确认 - await message.delConfirm() - // 发起删除 - await Demo12StudentApi.deleteDemo12StudentContact(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch {} -} -</script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue b/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue deleted file mode 100644 index 92e2b373..00000000 --- a/src/views/infra/demo12/components/Demo12StudentTeacherForm.vue +++ /dev/null @@ -1,155 +0,0 @@ -<template> - <Dialog :title="dialogTitle" v-model="dialogVisible"> - <el-form - ref="formRef" - :model="formData" - :rules="formRules" - label-width="100px" - v-loading="formLoading" - > - <el-form-item label="名字" prop="name"> - <el-input v-model="formData.name" placeholder="请输入名字" /> - </el-form-item> - <el-form-item label="简介" prop="description"> - <el-input v-model="formData.description" type="textarea" placeholder="请输入简介" /> - </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="formData.birthday" - type="date" - value-format="x" - placeholder="选择出生日期" - /> - </el-form-item> - <el-form-item label="性别" prop="sex"> - <el-select v-model="formData.sex" placeholder="请选择性别"> - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-radio-group v-model="formData.enabled"> - <el-radio - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.value" - > - {{ dict.label }} - </el-radio> - </el-radio-group> - </el-form-item> - <el-form-item label="头像" prop="avatar"> - <UploadImg v-model="formData.avatar" /> - </el-form-item> - <el-form-item label="附件" prop="video"> - <UploadFile v-model="formData.video" /> - </el-form-item> - <el-form-item label="备注" prop="memo"> - <Editor v-model="formData.memo" height="150px" /> - </el-form-item> - </el-form> - <template #footer> - <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> - <el-button @click="dialogVisible = false">取 消</el-button> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import * as Demo12StudentApi from '@/api/infra/demo12' - -const { t } = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 - -const dialogVisible = ref(false) // 弹窗的是否展示 -const dialogTitle = ref('') // 弹窗的标题 -const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 -const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const formData = ref({ - id: undefined, - studentId: undefined, - name: undefined, - description: undefined, - birthday: undefined, - sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined -}) -const formRules = reactive({ - studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], - name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - description: [{ required: true, message: '简介不能为空', trigger: 'blur' }], - birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], - sex: [{ required: true, message: '性别不能为空', trigger: 'change' }], - enabled: [{ required: true, message: '是否有效不能为空', trigger: 'blur' }], - avatar: [{ required: true, message: '头像不能为空', trigger: 'blur' }], - memo: [{ required: true, message: '备注不能为空', trigger: 'blur' }] -}) -const formRef = ref() // 表单 Ref - -/** 打开弹窗 */ -const open = async (type: string, id?: number, studentId: number) => { - dialogVisible.value = true - dialogTitle.value = t('action.' + type) - formType.value = type - resetForm() - formData.value.studentId = studentId - // 修改时,设置数据 - if (id) { - formLoading.value = true - try { - formData.value = await Demo12StudentApi.getDemo12StudentTeacher(id) - } finally { - formLoading.value = false - } - } -} -defineExpose({ open }) // 提供 open 方法,用于打开弹窗 - -/** 提交表单 */ -const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 -const submitForm = async () => { - // 校验表单 - await formRef.value.validate() - // 提交请求 - formLoading.value = true - try { - const data = formData.value - if (formType.value === 'create') { - await Demo12StudentApi.createDemo12StudentTeacher(data) - message.success(t('common.createSuccess')) - } else { - await Demo12StudentApi.updateDemo12StudentTeacher(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 发送操作成功的事件 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 重置表单 */ -const resetForm = () => { - formData.value = { - id: undefined, - studentId: undefined, - name: undefined, - description: undefined, - birthday: undefined, - sex: undefined, - enabled: undefined, - avatar: undefined, - video: undefined, - memo: undefined - } - formRef.value?.resetFields() -} -</script> \ No newline at end of file diff --git a/src/views/infra/demo12/components/Demo12StudentTeacherList.vue b/src/views/infra/demo12/components/Demo12StudentTeacherList.vue deleted file mode 100644 index d0594534..00000000 --- a/src/views/infra/demo12/components/Demo12StudentTeacherList.vue +++ /dev/null @@ -1,148 +0,0 @@ -<template> - <!-- 列表 --> - <ContentWrap> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['infra:demo12-student:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 新增 - </el-button> - <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> - <el-table-column label="编号" align="center" prop="id" /> - <el-table-column label="学生编号" align="center" prop="studentId" /> - <el-table-column label="名字" align="center" prop="name" /> - <el-table-column label="简介" align="center" prop="description" /> - <el-table-column - label="出生日期" - align="center" - prop="birthday" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="性别" align="center" prop="sex"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> - </template> - </el-table-column> - <el-table-column label="是否有效" align="center" prop="enabled"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> - </template> - </el-table-column> - <el-table-column label="头像" align="center" prop="avatar" /> - <el-table-column label="附件" align="center" prop="video" /> - <el-table-column label="备注" align="center" prop="memo" /> - <el-table-column - label="创建时间" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="操作" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['infra:demo12-student:update']" - > - 编辑 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo12-student:delete']" - > - 删除 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 表单弹窗:添加/修改 --> - <Demo12StudentTeacherForm ref="formRef" @success="getList" /> -</template> - -<script setup lang="ts"> -import { DICT_TYPE } from '@/utils/dict' -import * as Demo12StudentApi from '@/api/infra/demo12' -import Demo12StudentTeacherForm from './Demo12StudentTeacherForm.vue' - -const { t } = useI18n() // 国际化 -const message = useMessage() // 消息弹窗 - -const props = defineProps<{ - studentId: undefined // 学生编号(主表的关联字段) -}>() -const loading = ref(false) // 列表的加载中 -const list = ref([]) // 列表的数据 -const total = ref(0) // 列表的总页数 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - studentId: undefined -}) - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - (val) => { - queryParams.studentId = val - handleQuery() - }, - { immediate: false } -) - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - const data = await Demo12StudentApi.getDemo12StudentTeacherPage(queryParams) - list.value = data.list - total.value = data.total - } finally { - loading.value = false - } -} - -/** 搜索按钮操作 */ -const handleQuery = () => { - queryParams.pageNo = 1 - getList() -} - -/** 添加/修改操作 */ -const formRef = ref() -const openForm = (type: string, id?: number) => { - if (!props.studentId) { - message.error('请选择一个学生') - return - } - formRef.value.open(type, id, props.studentId) -} - -/** 删除按钮操作 */ -const handleDelete = async (id: number) => { - try { - // 删除的二次确认 - await message.delConfirm() - // 发起删除 - await Demo12StudentApi.deleteDemo12StudentTeacher(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch {} -} -</script> \ No newline at end of file diff --git a/src/views/infra/demo12/index.vue b/src/views/infra/demo12/index.vue deleted file mode 100644 index 47ec7f21..00000000 --- a/src/views/infra/demo12/index.vue +++ /dev/null @@ -1,278 +0,0 @@ -<template> - <ContentWrap> - <!-- 搜索工作栏 --> - <el-form - class="-mb-15px" - :model="queryParams" - ref="queryFormRef" - :inline="true" - label-width="68px" - > - <el-form-item label="名字" prop="name"> - <el-input - v-model="queryParams.name" - placeholder="请输入名字" - clearable - @keyup.enter="handleQuery" - class="!w-240px" - /> - </el-form-item> - <el-form-item label="出生日期" prop="birthday"> - <el-date-picker - v-model="queryParams.birthday" - value-format="YYYY-MM-DD" - type="date" - placeholder="选择出生日期" - clearable - class="!w-240px" - /> - </el-form-item> - <el-form-item label="性别" prop="sex"> - <el-select - v-model="queryParams.sex" - placeholder="请选择性别" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="是否有效" prop="enabled"> - <el-select - v-model="queryParams.enabled" - placeholder="请选择是否有效" - clearable - class="!w-240px" - > - <el-option - v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" - :key="dict.value" - :label="dict.label" - :value="dict.value" - /> - </el-select> - </el-form-item> - <el-form-item label="创建时间" prop="createTime"> - <el-date-picker - v-model="queryParams.createTime" - value-format="YYYY-MM-DD HH:mm:ss" - type="daterange" - start-placeholder="开始日期" - end-placeholder="结束日期" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> - <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> - <el-button - type="primary" - plain - @click="openForm('create')" - v-hasPermi="['infra:demo12-student:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 新增 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['infra:demo12-student:export']" - > - <Icon icon="ep:download" class="mr-5px" /> 导出 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 列表 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :stripe="true" - :show-overflow-tooltip="true" - highlight-current-row - @current-change="handleCurrentChange" - > - <el-table-column label="编号" align="center" prop="id" /> - <el-table-column label="名字" align="center" prop="name" /> - <el-table-column label="简介" align="center" prop="description" /> - <el-table-column - label="出生日期" - align="center" - prop="birthday" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="性别" align="center" prop="sex"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> - </template> - </el-table-column> - <el-table-column label="是否有效" align="center" prop="enabled"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" /> - </template> - </el-table-column> - <el-table-column label="头像" align="center" prop="avatar" /> - <el-table-column label="附件" align="center" prop="video" /> - <el-table-column label="备注" align="center" prop="memo" /> - <el-table-column - label="创建时间" - align="center" - prop="createTime" - :formatter="dateFormatter" - width="180px" - /> - <el-table-column label="操作" align="center"> - <template #default="scope"> - <el-button - link - type="primary" - @click="openForm('update', scope.row.id)" - v-hasPermi="['infra:demo12-student:update']" - > - 编辑 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo12-student:delete']" - > - 删除 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - :total="total" - v-model:page="queryParams.pageNo" - v-model:limit="queryParams.pageSize" - @pagination="getList" - /> - </ContentWrap> - - <!-- 表单弹窗:添加/修改 --> - <Demo12StudentForm ref="formRef" @success="getList" /> - <!-- 子表的列表 --> - <ContentWrap> - <el-tabs model-value="demo12StudentContact"> - <el-tab-pane label="学生联系人" name="demo12StudentContact"> - <Demo12StudentContactList :student-id="currentRow.id" /> - </el-tab-pane> - <el-tab-pane label="学生班主任" name="demo12StudentTeacher"> - <Demo12StudentTeacherList :student-id="currentRow.id" /> - </el-tab-pane> - </el-tabs> - </ContentWrap> -</template> - -<script setup lang="ts"> -import { getIntDictOptions, getBoolDictOptions, DICT_TYPE } from '@/utils/dict' -import { dateFormatter } from '@/utils/formatTime' -import download from '@/utils/download' -import * as Demo12StudentApi from '@/api/infra/demo12' -import Demo12StudentForm from './Demo12StudentForm.vue' -import Demo12StudentContactList from './components/Demo12StudentContactList.vue' -import Demo12StudentTeacherList from './components/Demo12StudentTeacherList.vue' - -defineOptions({ name: 'InfraDemo12Student' }) - -const message = useMessage() // 消息弹窗 -const { t } = useI18n() // 国际化 - -const loading = ref(true) // 列表的加载中 -const total = ref(0) // 列表的总页数 -const list = ref([]) // 列表的数据 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - name: null, - birthday: null, - birthday: [], - sex: null, - enabled: null, - createTime: [] -}) -const queryFormRef = ref() // 搜索的表单 -const exportLoading = ref(false) // 导出的加载中 - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - const data = await Demo12StudentApi.getDemo12StudentPage(queryParams) - 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 formRef = ref() -const openForm = (type: string, id?: number) => { - formRef.value.open(type, id) -} - -/** 删除按钮操作 */ -const handleDelete = async (id: number) => { - try { - // 删除的二次确认 - await message.delConfirm() - // 发起删除 - await Demo12StudentApi.deleteDemo12Student(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch {} -} - -/** 导出按钮操作 */ -const handleExport = async () => { - try { - // 导出的二次确认 - await message.exportConfirm() - // 发起导出 - exportLoading.value = true - const data = await Demo12StudentApi.exportDemo12Student(queryParams) - download.excel(data, '学生.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 选中行操作 */ -const currentRow = ref({}) // 选中行 -const handleCurrentChange = (row) => { - currentRow.value = row -} - -/** 初始化 **/ -onMounted(() => { - getList() -}) -</script> \ No newline at end of file diff --git a/src/views/infra/testDemo/index.vue b/src/views/infra/testDemo/index.vue deleted file mode 100644 index ca6a5b07..00000000 --- a/src/views/infra/testDemo/index.vue +++ /dev/null @@ -1,4 +0,0 @@ -<template> - <div>index</div> -</template> -<script lang="ts" setup></script> From a42d0695fec0e2831c5b3b09593c93059ce67703 Mon Sep 17 00:00:00 2001 From: YunaiV <zhijiantianya@gmail.com> Date: Fri, 17 Nov 2023 13:21:17 +0800 Subject: [PATCH 15/15] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=9A=E5=A2=9E=E5=8A=A0=E4=B8=BB=E5=AD=90=E8=A1=A8=20erp=20?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E7=9A=84=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/infra/demo/demo03/erp/index.ts | 91 +++++++ .../demo/demo03/erp/Demo03StudentForm.vue | 121 +++++++++ .../erp/components/Demo03CourseForm.vue | 99 +++++++ .../erp/components/Demo03CourseList.vue | 126 +++++++++ .../demo03/erp/components/Demo03GradeForm.vue | 99 +++++++ .../demo03/erp/components/Demo03GradeList.vue | 126 +++++++++ src/views/infra/demo/demo03/erp/index.vue | 243 ++++++++++++++++++ 7 files changed, 905 insertions(+) create mode 100644 src/api/infra/demo/demo03/erp/index.ts create mode 100644 src/views/infra/demo/demo03/erp/Demo03StudentForm.vue create mode 100644 src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue create mode 100644 src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue create mode 100644 src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue create mode 100644 src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue create mode 100644 src/views/infra/demo/demo03/erp/index.vue diff --git a/src/api/infra/demo/demo03/erp/index.ts b/src/api/infra/demo/demo03/erp/index.ts new file mode 100644 index 00000000..d408b630 --- /dev/null +++ b/src/api/infra/demo/demo03/erp/index.ts @@ -0,0 +1,91 @@ +import request from '@/config/axios' + +export interface Demo03StudentVO { + id: number + name: string + sex: number + birthday: Date + description: string +} + +// 查询学生分页 +export const getDemo03StudentPage = async (params) => { + return await request.get({ url: `/infra/demo03-student/page`, params }) +} + +// 查询学生详情 +export const getDemo03Student = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo03Student = async (data: Demo03StudentVO) => { + return await request.post({ url: `/infra/demo03-student/create`, data }) +} + +// 修改学生 +export const updateDemo03Student = async (data: Demo03StudentVO) => { + return await request.put({ url: `/infra/demo03-student/update`, data }) +} + +// 删除学生 +export const deleteDemo03Student = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo03Student = async (params) => { + return await request.download({ url: `/infra/demo03-student/export-excel`, params }) +} + +// ==================== 子表(学生课程) ==================== + +// 获得学生课程分页 +export const getDemo03CoursePage = async (params) => { + return await request.get({ url: `/infra/demo03-student/demo03-course/page`, params }) +} +// 新增学生课程 +export const createDemo03Course = async (data) => { + return await request.post({ url: `/infra/demo03-student/demo03-course/create`, data }) +} + +// 修改学生课程 +export const updateDemo03Course = async (data) => { + return await request.put({ url: `/infra/demo03-student/demo03-course/update`, data }) +} + +// 删除学生课程 +export const deleteDemo03Course = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/demo03-course/delete?id=` + id }) +} + +// 获得学生课程 +export const getDemo03Course = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/demo03-course/get?id=` + id }) +} + +// ==================== 子表(学生班级) ==================== + +// 获得学生班级分页 +export const getDemo03GradePage = async (params) => { + return await request.get({ url: `/infra/demo03-student/demo03-grade/page`, params }) +} +// 新增学生班级 +export const createDemo03Grade = async (data) => { + return await request.post({ url: `/infra/demo03-student/demo03-grade/create`, data }) +} + +// 修改学生班级 +export const updateDemo03Grade = async (data) => { + return await request.put({ url: `/infra/demo03-student/demo03-grade/update`, data }) +} + +// 删除学生班级 +export const deleteDemo03Grade = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/demo03-grade/delete?id=` + id }) +} + +// 获得学生班级 +export const getDemo03Grade = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/demo03-grade/get?id=` + id }) +} \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue b/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue new file mode 100644 index 00000000..29f1370d --- /dev/null +++ b/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue @@ -0,0 +1,121 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-radio-group v-model="formData.sex"> + <el-radio + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <Editor v-model="formData.description" height="150px" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined +}) +const formRules = reactive({ + 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 formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Student(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo03StudentApi.Demo03StudentVO + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Student(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Student(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue b/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue new file mode 100644 index 00000000..de1c06de --- /dev/null +++ b/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue @@ -0,0 +1,99 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="分数" prop="score"> + <el-input v-model="formData.score" placeholder="请输入分数" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + studentId: undefined, + name: undefined, + score: undefined +}) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + score: [{ required: true, message: '分数不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number, studentId: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + formData.value.studentId = studentId + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Course(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Course(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Course(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + score: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue b/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue new file mode 100644 index 00000000..7e06ee64 --- /dev/null +++ b/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue @@ -0,0 +1,126 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="分数" align="center" prop="score" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo03-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + <!-- 表单弹窗:添加/修改 --> + <Demo03CourseForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' +import Demo03CourseForm from './Demo03CourseForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(false) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + studentId: undefined +}) + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + queryParams.studentId = val + handleQuery() + }, + { immediate: false } +) + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03CoursePage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + if (!props.studentId) { + message.error('请选择一个学生') + return + } + formRef.value.open(type, id, props.studentId) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo03StudentApi.deleteDemo03Course(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue new file mode 100644 index 00000000..abba0032 --- /dev/null +++ b/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue @@ -0,0 +1,99 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="班主任" prop="teacher"> + <el-input v-model="formData.teacher" placeholder="请输入班主任" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + studentId: undefined, + name: undefined, + teacher: undefined +}) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + teacher: [{ required: true, message: '班主任不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number, studentId: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + formData.value.studentId = studentId + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Grade(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Grade(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Grade(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + teacher: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue b/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue new file mode 100644 index 00000000..b12f1889 --- /dev/null +++ b/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue @@ -0,0 +1,126 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="班主任" align="center" prop="teacher" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo03-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + <!-- 表单弹窗:添加/修改 --> + <Demo03GradeForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' +import Demo03GradeForm from './Demo03GradeForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(false) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + studentId: undefined +}) + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + queryParams.studentId = val + handleQuery() + }, + { immediate: false } +) + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03GradePage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + if (!props.studentId) { + message.error('请选择一个学生') + return + } + formRef.value.open(type, id, props.studentId) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo03StudentApi.deleteDemo03Grade(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/index.vue b/src/views/infra/demo/demo03/erp/index.vue new file mode 100644 index 00000000..8fdc7b42 --- /dev/null +++ b/src/views/infra/demo/demo03/erp/index.vue @@ -0,0 +1,243 @@ +<template> + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select + v-model="queryParams.sex" + placeholder="请选择性别" + clearable + class="!w-240px" + > + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo03-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + :stripe="true" + :show-overflow-tooltip="true" + highlight-current-row + @current-change="handleCurrentChange" + > + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo03-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo03StudentForm ref="formRef" @success="getList" /> + <!-- 子表的列表 --> + <ContentWrap> + <el-tabs model-value="demo03Course"> + <el-tab-pane label="学生课程" name="demo03Course"> + <Demo03CourseList :student-id="currentRow.id" /> + </el-tab-pane> + <el-tab-pane label="学生班级" name="demo03Grade"> + <Demo03GradeList :student-id="currentRow.id" /> + </el-tab-pane> + </el-tabs> + </ContentWrap> +</template> + +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' +import Demo03StudentForm from './Demo03StudentForm.vue' +import Demo03CourseList from './components/Demo03CourseList.vue' +import Demo03GradeList from './components/Demo03GradeList.vue' + +defineOptions({ name: 'Demo03Student' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + sex: null, + description: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03StudentPage(queryParams) + 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 formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo03StudentApi.deleteDemo03Student(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo03StudentApi.exportDemo03Student(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 选中行操作 */ +const currentRow = ref({}) // 选中行 +const handleCurrentChange = (row) => { + currentRow.value = row +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file