From 39248bc48bd1c2b66e18337dadd70d50b2bfaae6 Mon Sep 17 00:00:00 2001 From: houzhongjian <houzhongyi@126.com> Date: 星期五, 13 九月 2024 16:31:12 +0800 Subject: [PATCH] 框架及页面bug修改 --- src/api/system/menu/index.ts | 31 + src/views/infra/storage/index_rec.vue | 161 ++++++ src/utils/routerHelper.ts | 1 src/plugins/unocss/index.ts | 1 src/layout/components/Logo/src/Logo.vue | 14 src/components/bpmnProcessDesigner/package/utils.ts | 2 src/api/system/app/index.ts | 7 src/api/system/appgroup/index.ts | 41 + src/api/login/index.ts | 5 src/router/modules/remaining.ts | 17 src/views/system/appmenu/AppMenuForm.vue | 256 ++++++++++ src/views/bpm/processInstance/index.vue | 1 src/views/system/appmenu/index.vue | 203 ++++++++ src/utils/constants.ts | 9 src/views/bpm/task/copy/index.vue | 2 src/views/system/appgroup/AppGroupForm.vue | 130 +++++ src/api/infra/storage/types.ts | 6 src/api/infra/storage/index.ts | 15 src/permission.ts | 3 src/api/system/oauth2/token.ts | 19 /dev/null | 212 -------- src/views/Login/components/LoginForm.vue | 104 --- src/views/infra/server/index.vue | 3 src/components/bpmnProcessDesigner/package/penal/listeners/ElementListeners.vue | 2 src/utils/dict.ts | 2 src/config/axios/index.ts | 2 src/views/system/appgroup/index.vue | 176 +++++++ src/api/system/appmenu/index.ts | 49 + src/api/system/tenant/index.ts | 5 src/components/FormCreate/src/components/useApiSelect.tsx | 2 30 files changed, 1,155 insertions(+), 326 deletions(-) diff --git a/src/api/infra/demo/demo01/index.ts b/src/api/infra/demo/demo01/index.ts deleted file mode 100644 index e34a05d..0000000 --- a/src/api/infra/demo/demo01/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -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 }) -} diff --git a/src/api/infra/demo/demo02/index.ts b/src/api/infra/demo/demo02/index.ts deleted file mode 100644 index 736a123..0000000 --- a/src/api/infra/demo/demo02/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import request from '@/config/axios' - -export interface Demo02CategoryVO { - id: number - name: string - parentId: number -} - -// 查询示例分类列表 -export const getDemo02CategoryList = async () => { - return await request.get({ url: `/infra/demo02-category/list` }) -} - -// 查询示例分类详情 -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 }) -} diff --git a/src/api/infra/demo/demo03/erp/index.ts b/src/api/infra/demo/demo03/erp/index.ts deleted file mode 100644 index a2ab539..0000000 --- a/src/api/infra/demo/demo03/erp/index.ts +++ /dev/null @@ -1,91 +0,0 @@ -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 }) -} diff --git a/src/api/infra/demo/demo03/inner/index.ts b/src/api/infra/demo/demo03/inner/index.ts deleted file mode 100644 index e366307..0000000 --- a/src/api/infra/demo/demo03/inner/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -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 - }) -} diff --git a/src/api/infra/demo/demo03/normal/index.ts b/src/api/infra/demo/demo03/normal/index.ts deleted file mode 100644 index e366307..0000000 --- a/src/api/infra/demo/demo03/normal/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -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 - }) -} diff --git a/src/api/infra/storage/index.ts b/src/api/infra/storage/index.ts new file mode 100644 index 0000000..a1aa7dc --- /dev/null +++ b/src/api/infra/storage/index.ts @@ -0,0 +1,15 @@ +import request from '@/config/axios' + +/** + * 获取磁盘信息 + */ +export const getDiskInfo = () => { + return request.get({ url: '/infra/actuator/disk/info' }) +} + +/** + * 获取内存信息 + */ +export const getMemoryInfo = () => { + return request.get({ url: '/infra/actuator/memory/info' }) +} diff --git a/src/api/infra/storage/types.ts b/src/api/infra/storage/types.ts new file mode 100644 index 0000000..0f683ef --- /dev/null +++ b/src/api/infra/storage/types.ts @@ -0,0 +1,6 @@ +export interface StorageMonitorInfoVO { + name: string + max: number + rest: number + restPPT: number +} diff --git a/src/api/login/index.ts b/src/api/login/index.ts index ef86563..e6d9f52 100644 --- a/src/api/login/index.ts +++ b/src/api/login/index.ts @@ -42,6 +42,11 @@ return request.get({ url: '/system/auth/get-permission-info' }) } +// 获取用应用户权限信息 +export const getUserAppInfo = (id: number) => { + return request.get({ url: '/system/auth/get-app-permission-info?id=' + id }) +} + //获取登录验证码 export const sendSmsCode = (data: SmsCodeVO) => { return request.post({ url: '/system/auth/send-sms-code', data }) diff --git a/src/api/system/app/index.ts b/src/api/system/app/index.ts index ef8b952..d247a19 100644 --- a/src/api/system/app/index.ts +++ b/src/api/system/app/index.ts @@ -19,11 +19,16 @@ createTime: Date } -// 查询列表 +// 查询分页列表 export const getAppPage = (params: PageParam) => { return request.get({ url: '/system/app/page', params }) } +// 查询列表 +export const getAppList = () => { + return request.get({ url: '/system/app/getAppList' }) +} + // 获得 export const getApp = (id: number) => { return request.get({ url: '/system/app/get?id=' + id }) diff --git a/src/api/system/appgroup/index.ts b/src/api/system/appgroup/index.ts new file mode 100644 index 0000000..b19444a --- /dev/null +++ b/src/api/system/appgroup/index.ts @@ -0,0 +1,41 @@ +import request from '@/config/axios' + +export interface AppGroupVO { + id: number + node: string + name: string + icon: string + sort: number + remark: string + createTime: Date +} + +// 查询分页列表 +export const getAppGroupPage = (params: PageParam) => { + return request.get({ url: '/system/app-group/page', params }) +} + +// 查询列表 +export const getAppGroupList = () => { + return request.get({ url: '/system/app-group/getAppGroupList' }) +} + +// 获得 +export const getAppGroup = (id: number) => { + return request.get({ url: '/system/app-group/get?id=' + id }) +} + +// 新增 +export const createAppGroup = (data: AppGroupVO) => { + return request.post({ url: '/system/app-group/create', data }) +} + +// 修改 +export const updateAppGroup = (data: AppGroupVO) => { + return request.put({ url: '/system/app-group/update', data }) +} + +// 删除 +export const deleteAppGroup = (id: number) => { + return request.delete({ url: '/system/app-group/delete?id=' + id }) +} diff --git a/src/api/system/appmenu/index.ts b/src/api/system/appmenu/index.ts new file mode 100644 index 0000000..91d39a0 --- /dev/null +++ b/src/api/system/appmenu/index.ts @@ -0,0 +1,49 @@ +import request from '@/config/axios' + +export interface AppMenuVO { + id: number + name: string + permission: string + type: number + sort: number + parentId: number + path: string + icon: string + component: string + componentName?: string + status: number + visible: boolean + keepAlive: boolean + alwaysShow?: boolean + createTime: Date +} + +// 查询菜单(精简)列表 +export const getSimpleMenusList = () => { + return request.get({ url: '/system/app-menu/simple-list' }) +} + +// 查询菜单列表 +export const getMenuList = (params) => { + return request.get({ url: '/system/app-menu/list', params }) +} + +// 获取菜单详情 +export const getMenu = (id: number) => { + return request.get({ url: '/system/app-menu/get?id=' + id }) +} + +// 新增菜单 +export const createMenu = (data: AppMenuVO) => { + return request.post({ url: '/system/app-menu/create', data }) +} + +// 修改菜单 +export const updateMenu = (data: AppMenuVO) => { + return request.put({ url: '/system/app-menu/update', data }) +} + +// 删除菜单 +export const deleteMenu = (id: number) => { + return request.delete({ url: '/system/app-menu/delete?id=' + id }) +} diff --git a/src/api/system/menu/index.ts b/src/api/system/menu/index.ts index 5a80668..1ed651a 100644 --- a/src/api/system/menu/index.ts +++ b/src/api/system/menu/index.ts @@ -16,6 +16,7 @@ keepAlive: boolean alwaysShow?: boolean createTime: Date + appId: number } // 查询菜单(精简)列表 @@ -23,9 +24,19 @@ return request.get({ url: '/system/menu/simple-list' }) } +// 查询应用菜单(精简)列表 +export const getSimpleAppMenusList = () => { + return request.get({ url: '/system/menu/simple-app-menus' }) +} + // 查询菜单列表 export const getMenuList = (params) => { return request.get({ url: '/system/menu/list', params }) +} + +// 查询应用菜单列表 +export const getAppMenuList = (params) => { + return request.get({ url: '/system/menu/app-menu-list', params }) } // 获取菜单详情 @@ -33,9 +44,19 @@ return request.get({ url: '/system/menu/get?id=' + id }) } +// 获取应用菜单详情 +export const getAppMenu = (id: number) => { + return request.get({ url: '/system/menu/getAppMenu?id=' + id }) +} + // 新增菜单 export const createMenu = (data: MenuVO) => { return request.post({ url: '/system/menu/create', data }) +} + +// 新增应用菜单 +export const createAppMenu = (data: MenuVO) => { + return request.post({ url: '/system/menu/createAppMenu', data }) } // 修改菜单 @@ -43,7 +64,17 @@ return request.put({ url: '/system/menu/update', data }) } +// 修改应用菜单 +export const updateAppMenu = (data: MenuVO) => { + return request.put({ url: '/system/menu/updateAppMenu', data }) +} + // 删除菜单 export const deleteMenu = (id: number) => { return request.delete({ url: '/system/menu/delete?id=' + id }) } + +// 删除应用菜单 +export const deleteAppMenu = (id: number) => { + return request.delete({ url: '/system/menu/deleteAppMenu?id=' + id }) +} diff --git a/src/api/system/oauth2/token.ts b/src/api/system/oauth2/token.ts index ac89ae8..02ea572 100644 --- a/src/api/system/oauth2/token.ts +++ b/src/api/system/oauth2/token.ts @@ -1,14 +1,12 @@ import request from '@/config/axios' export interface OAuth2TokenVO { - id: number - accessToken: string - refreshToken: string - userId: number - userType: number - clientId: string - createTime: Date - expiresTime: Date + grantType: string + scope: string + refreshToken: any + username: string + password: string + redirectUri: string } // 查询 token列表 @@ -16,6 +14,11 @@ return request.get({ url: '/system/oauth2-token/page', params }) } +// 单点登录授权 +export const OAuth2Login = (params: OAuth2TokenVO) => { + return request.post({ url: '/system/oauth2/token', data: params }) +} + // 删除 token export const deleteAccessToken = (accessToken: string) => { return request.delete({ url: '/system/oauth2-token/delete?accessToken=' + accessToken }) diff --git a/src/api/system/tenant/index.ts b/src/api/system/tenant/index.ts index 95aa059..33bf327 100644 --- a/src/api/system/tenant/index.ts +++ b/src/api/system/tenant/index.ts @@ -37,6 +37,11 @@ return request.get({ url: '/system/tenant/page', params }) } +// 查询租户列表 +export const getSimpleTenant = () => { + return request.get({ url: '/system/tenant/simple-list' }) +} + // 查询租户详情 export const getTenant = (id: number) => { return request.get({ url: '/system/tenant/get?id=' + id }) diff --git a/src/components/FormCreate/src/components/useApiSelect.tsx b/src/components/FormCreate/src/components/useApiSelect.tsx index 8765036..d668cb8 100644 --- a/src/components/FormCreate/src/components/useApiSelect.tsx +++ b/src/components/FormCreate/src/components/useApiSelect.tsx @@ -185,7 +185,7 @@ </el-select> ) } - debugger + // debugger return ( <el-select class="w-1/1" diff --git a/src/components/bpmnProcessDesigner/package/penal/listeners/ElementListeners.vue b/src/components/bpmnProcessDesigner/package/penal/listeners/ElementListeners.vue index de5445c..c557b59 100644 --- a/src/components/bpmnProcessDesigner/package/penal/listeners/ElementListeners.vue +++ b/src/components/bpmnProcessDesigner/package/penal/listeners/ElementListeners.vue @@ -370,7 +370,7 @@ } // 移除监听器 const removeListener = (index) => { - debugger + // debugger ElMessageBox.confirm('确认移除该监听器吗?', '提示', { confirmButtonText: '确 认', cancelButtonText: '取 消' diff --git a/src/components/bpmnProcessDesigner/package/utils.ts b/src/components/bpmnProcessDesigner/package/utils.ts index 8996788..a7de5f0 100644 --- a/src/components/bpmnProcessDesigner/package/utils.ts +++ b/src/components/bpmnProcessDesigner/package/utils.ts @@ -2,7 +2,7 @@ const bpmnInstances = () => (window as any)?.bpmnInstances // 创建监听器实例 export function createListenerObject(options, isTask, prefix) { - debugger + // debugger const listenerObj = Object.create(null) listenerObj.event = options.event isTask && (listenerObj.id = options.id) // 任务监听器特有的 id 字段 diff --git a/src/config/axios/index.ts b/src/config/axios/index.ts index 79e558d..e37d624 100644 --- a/src/config/axios/index.ts +++ b/src/config/axios/index.ts @@ -14,7 +14,7 @@ ...config, responseType: responseType, headers: { - 'Content-Type': headersType || default_headers + 'Content-Type': headersType || default_headers, } }) } diff --git a/src/layout/components/Logo/src/Logo.vue b/src/layout/components/Logo/src/Logo.vue index d241130..d5790b0 100644 --- a/src/layout/components/Logo/src/Logo.vue +++ b/src/layout/components/Logo/src/Logo.vue @@ -2,6 +2,7 @@ import { computed, onMounted, ref, unref, watch } from 'vue' import { useAppStore } from '@/store/modules/app' import { useDesign } from '@/hooks/web/useDesign' +import * as authUtil from "@/utils/auth"; defineOptions({ name: 'Logo' }) @@ -13,11 +14,22 @@ const show = ref(true) +const homePath = ref('/index') + const title = computed(() => appStore.getTitle) const layout = computed(() => appStore.getLayout) const collapse = computed(() => appStore.getCollapse) + +let tenantId = authUtil.getTenantId() +console.log(tenantId) +if (tenantId && tenantId === 1) { + homePath.value = '/index' +} else { + homePath.value = '/home2' +} +console.log(homePath.value) onMounted(() => { if (unref(collapse)) show.value = false @@ -64,7 +76,7 @@ layout !== 'classic' ? `${prefixCls}__Top` : '', 'flex !h-[var(--logo-height)] items-center cursor-pointer pl-8px relative decoration-none overflow-hidden' ]" - to="/" + :to="homePath" > <img class="h-[calc(var(--logo-height)-10px)] w-[calc(var(--logo-height)-10px)]" diff --git a/src/permission.ts b/src/permission.ts index b04bc3c..9120c1a 100644 --- a/src/permission.ts +++ b/src/permission.ts @@ -73,7 +73,8 @@ } if (!userStore.getIsSetUser) { isRelogin.show = true - await userStore.setUserInfoAction() + await userStore. + setUserInfoAction() isRelogin.show = false // 后端过滤菜单 await permissionStore.generateRoutes() diff --git a/src/plugins/unocss/index.ts b/src/plugins/unocss/index.ts index d366b5a..8422174 100644 --- a/src/plugins/unocss/index.ts +++ b/src/plugins/unocss/index.ts @@ -1 +1,2 @@ import 'virtual:uno.css' +import 'uno.css' diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index b889036..825f9f0 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -1,4 +1,4 @@ -import { Layout } from '@/utils/routerHelper' +import {Layout} from '@/utils/routerHelper' const { t } = useI18n() /** @@ -51,11 +51,22 @@ } }, { + path: '/home2', + component: () => import('@/views/Home/Index2.vue'), + name: 'Home2', + meta: { + hidden: true, + noTagsView: true + }, + }, + { path: '/', component: Layout, - redirect: '/index', name: 'Home', - meta: {}, + meta: { + hidden: true, + noTagsView: true + }, children: [ { path: 'index', diff --git a/src/utils/constants.ts b/src/utils/constants.ts index ae06f28..b21f067 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -28,6 +28,15 @@ } /** + * 应用菜单的类型枚举 + */ +export const SystemAppMenuTypeEnum = { + DIR: 1, // 应用 + MENU: 2, // 菜单 + BUTTON: 3 // 按钮 +} + +/** * 角色的类型枚举 */ export const SystemRoleTypeEnum = { diff --git a/src/utils/dict.ts b/src/utils/dict.ts index 03ed2fd..12724e0 100644 --- a/src/utils/dict.ts +++ b/src/utils/dict.ts @@ -116,6 +116,8 @@ // ========== SYSTEM 模块 ========== SYSTEM_USER_SEX = 'system_user_sex', SYSTEM_MENU_TYPE = 'system_menu_type', + SYSTEM_APP_MENU_TYPE = 'system_app_menu_type', + SYSTEM_APP_TYPE = 'system_app_type', SYSTEM_ROLE_TYPE = 'system_role_type', SYSTEM_DATA_SCOPE = 'system_data_scope', SYSTEM_NOTICE_TYPE = 'system_notice_type', diff --git a/src/utils/routerHelper.ts b/src/utils/routerHelper.ts index f292751..e9c8c64 100644 --- a/src/utils/routerHelper.ts +++ b/src/utils/routerHelper.ts @@ -21,6 +21,7 @@ /* Layout */ export const Layout = () => import('@/layout/Layout.vue') + export const getParentLayout = () => { return () => new Promise((resolve) => { diff --git a/src/views/Login/components/LoginForm.vue b/src/views/Login/components/LoginForm.vue index 6e7f0d8..7b161e3 100644 --- a/src/views/Login/components/LoginForm.vue +++ b/src/views/Login/components/LoginForm.vue @@ -82,49 +82,6 @@ mode="pop" @success="handleLogin" /> - <!--<el-col :span="24" style="padding-right: 10px; padding-left: 10px"> - <el-form-item> - <el-row :gutter="5" justify="space-between" style="width: 100%"> - <el-col :span="8"> - <XButton - :title="t('login.btnMobile')" - class="w-[100%]" - @click="setLoginState(LoginStateEnum.MOBILE)" - /> - </el-col> - <el-col :span="8"> - <XButton - :title="t('login.btnQRCode')" - class="w-[100%]" - @click="setLoginState(LoginStateEnum.QR_CODE)" - /> - </el-col> - <el-col :span="8"> - <XButton - :title="t('login.btnRegister')" - class="w-[100%]" - @click="setLoginState(LoginStateEnum.REGISTER)" - /> - </el-col> - </el-row> - </el-form-item> - </el-col>--> - <!--<el-divider content-position="center">{{ t('login.otherLogin') }}</el-divider> - <el-col :span="24" style="padding-right: 10px; padding-left: 10px"> - <el-form-item> - <div class="w-[100%] flex justify-between"> - <Icon - v-for="(item, key) in socialList" - :key="key" - :icon="item.icon" - :size="30" - class="anticon cursor-pointer" - color="#999" - @click="doSocialLogin(item.type)" - /> - </div> - </el-form-item> - </el-col>--> </el-row> </el-form> </template> @@ -176,13 +133,6 @@ rememberMe: true // 默认记录我。如果不需要,可手动修改 } }) - -const socialList = [ - { icon: 'ant-design:wechat-filled', type: 30 }, - { icon: 'ant-design:dingtalk-circle-filled', type: 20 }, - { icon: 'ant-design:github-filled', type: 0 }, - { icon: 'ant-design:alipay-circle-filled', type: 0 } -] // 获取验证码 const getCode = async () => { @@ -253,54 +203,24 @@ if (!redirect.value) { redirect.value = '/' } - // 判断是否为SSO登录 - if (redirect.value.indexOf('sso') !== -1) { - window.location.href = window.location.href.replace('/login?redirect=', '') - } else { - push({ path: redirect.value || permissionStore.addRouters[0].path }) - } + let tenantId = authUtil.getTenantId() + // if(tenantId != 1) { + // //只要不是系统租户,登录成功跳转到home2页面 + // window.location.href = '/home2' + // } else { + // 判断是否为SSO登录 + if (redirect.value.indexOf('sso') !== -1) { + window.location.href = window.location.href.replace('/login?redirect=', '') + } else { + push({ path: redirect.value || permissionStore.addRouters[0].path }) + } + // } } finally { loginLoading.value = false loading.value.close() } } -// 社交登录 -const doSocialLogin = async (type: number) => { - if (type === 0) { - message.error('此方式未配置') - } else { - loginLoading.value = true - if (loginData.tenantEnable === 'true') { - // 尝试先通过 tenantName 获取租户 - await getTenantId() - // 如果获取不到,则需要弹出提示,进行处理 - if (!authUtil.getTenantId()) { - try { - const data = await message.prompt('请输入租户名称', t('common.reminder')) - if (data?.action !== 'confirm') throw 'cancel' - const res = await LoginApi.getTenantIdByName(data.value) - authUtil.setTenantId(res) - } catch (error) { - if (error === 'cancel') return - } finally { - loginLoading.value = false - } - } - } - // 计算 redirectUri - // tricky: type、redirect需要先encode一次,否则钉钉回调会丢失。 - // 配合 Login/SocialLogin.vue#getUrlValue() 使用 - const redirectUri = - location.origin + - '/social-login?' + - encodeURIComponent(`type=${type}&redirect=${redirect.value || '/'}`) - - // 进行跳转 - const res = await LoginApi.socialAuthRedirect(type, encodeURIComponent(redirectUri)) - window.location.href = res - } -} watch( () => currentRoute.value, (route: RouteLocationNormalizedLoaded) => { diff --git a/src/views/bpm/processInstance/index.vue b/src/views/bpm/processInstance/index.vue index 4f4c4bc..3951a83 100644 --- a/src/views/bpm/processInstance/index.vue +++ b/src/views/bpm/processInstance/index.vue @@ -221,7 +221,6 @@ const processDefinitionDetail = await DefinitionApi.getProcessDefinition( row.processDefinitionId ) - debugger if (processDefinitionDetail.formType === 20) { message.error('重新发起流程失败,原因:该流程使用业务表单,不支持重新发起') return diff --git a/src/views/bpm/task/copy/index.vue b/src/views/bpm/task/copy/index.vue index d576ac7..dd41b2e 100644 --- a/src/views/bpm/task/copy/index.vue +++ b/src/views/bpm/task/copy/index.vue @@ -1,3 +1,5 @@ +<!-- 工作流 - 抄送我的流程 --> +<template> <ContentWrap> <!-- 搜索工作栏 --> <el-form ref="queryFormRef" :inline="true" class="-mb-15px" label-width="68px"> diff --git a/src/views/data/job/ScheduleJobFormLog.vue b/src/views/data/job/ScheduleJobFormLog.vue deleted file mode 100644 index e69de29..0000000 --- a/src/views/data/job/ScheduleJobFormLog.vue +++ /dev/null diff --git a/src/views/infra/demo/demo01/Demo01ContactForm.vue b/src/views/infra/demo/demo01/Demo01ContactForm.vue deleted file mode 100644 index 5d28112..0000000 --- a/src/views/infra/demo/demo01/Demo01ContactForm.vue +++ /dev/null @@ -1,126 +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="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-item label="头像" prop="avatar"> - <UploadImg v-model="formData.avatar" /> - </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 Demo01ContactApi from '@/api/infra/demo/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, - sex: undefined, - birthday: undefined, - description: undefined, - avatar: 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 Demo01ContactApi.getDemo01Contact(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 Demo01ContactApi.Demo01ContactVO - if (formType.value === 'create') { - await Demo01ContactApi.createDemo01Contact(data) - message.success(t('common.createSuccess')) - } else { - await Demo01ContactApi.updateDemo01Contact(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, - avatar: undefined - } - formRef.value?.resetFields() -} -</script> diff --git a/src/views/infra/demo/demo01/index.vue b/src/views/infra/demo/demo01/index.vue deleted file mode 100644 index cf70829..0000000 --- a/src/views/infra/demo/demo01/index.vue +++ /dev/null @@ -1,212 +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="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:demo01-contact:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 新增 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - v-hasPermi="['infra:demo01-contact: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="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="avatar" /> - <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-contact:update']" - > - 编辑 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo01-contact: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> - - <!-- 表单弹窗:添加/修改 --> - <Demo01ContactForm 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 Demo01ContactApi from '@/api/infra/demo/demo01' -import Demo01ContactForm from './Demo01ContactForm.vue' - -defineOptions({ name: 'Demo01Contact' }) - -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, - createTime: [] -}) -const queryFormRef = ref() // 搜索的表单 -const exportLoading = ref(false) // 导出的加载中 - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - const data = await Demo01ContactApi.getDemo01ContactPage(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 Demo01ContactApi.deleteDemo01Contact(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch {} -} - -/** 导出按钮操作 */ -const handleExport = async () => { - try { - // 导出的二次确认 - await message.exportConfirm() - // 发起导出 - exportLoading.value = true - const data = await Demo01ContactApi.exportDemo01Contact(queryParams) - download.excel(data, '示例联系人.xls') - } catch { - } finally { - exportLoading.value = false - } -} - -/** 初始化 **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/infra/demo/demo02/Demo02CategoryForm.vue b/src/views/infra/demo/demo02/Demo02CategoryForm.vue deleted file mode 100644 index f4c5f8e..0000000 --- a/src/views/infra/demo/demo02/Demo02CategoryForm.vue +++ /dev/null @@ -1,114 +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="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> - </template> - </Dialog> -</template> -<script setup lang="ts"> -import * as Demo02CategoryApi from '@/api/infra/demo/demo02' -import { defaultProps, handleTree } from '@/utils/tree' - -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, - parentId: undefined -}) -const formRules = reactive({ - name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], - parentId: [{ required: true, message: '父级编号不能为空', trigger: 'blur' }] -}) -const formRef = ref() // 表单 Ref -const demo02CategoryTree = 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 Demo02CategoryApi.getDemo02Category(id) - } finally { - formLoading.value = false - } - } - await getDemo02CategoryTree() -} -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 Demo02CategoryApi.Demo02CategoryVO - if (formType.value === 'create') { - await Demo02CategoryApi.createDemo02Category(data) - message.success(t('common.createSuccess')) - } else { - await Demo02CategoryApi.updateDemo02Category(data) - message.success(t('common.updateSuccess')) - } - dialogVisible.value = false - // 发送操作成功的事件 - emit('success') - } finally { - formLoading.value = false - } -} - -/** 重置表单 */ -const resetForm = () => { - formData.value = { - id: undefined, - name: undefined, - parentId: undefined - } - formRef.value?.resetFields() -} - -/** 获得示例分类树 */ -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> diff --git a/src/views/infra/demo/demo02/index.vue b/src/views/infra/demo/demo02/index.vue deleted file mode 100644 index 0870dc5..0000000 --- a/src/views/infra/demo/demo02/index.vue +++ /dev/null @@ -1,205 +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="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:demo02-category:create']" - > - <Icon icon="ep:plus" class="mr-5px" /> 新增 - </el-button> - <el-button - type="success" - plain - @click="handleExport" - :loading="exportLoading" - 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" - 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)" - v-hasPermi="['infra:demo02-category:update']" - > - 编辑 - </el-button> - <el-button - link - type="danger" - @click="handleDelete(scope.row.id)" - v-hasPermi="['infra:demo02-category: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> - - <!-- 表单弹窗:添加/修改 --> - <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 Demo02CategoryApi from '@/api/infra/demo/demo02' -import Demo02CategoryForm from './Demo02CategoryForm.vue' - -defineOptions({ name: 'Demo02Category' }) - -const message = useMessage() // 消息弹窗 -const { t } = useI18n() // 国际化 - -const loading = ref(true) // 列表的加载中 -const list = ref([]) // 列表的数据 -const queryParams = reactive({ - name: null, - parentId: null, - createTime: [] -}) -const queryFormRef = ref() // 搜索的表单 -const exportLoading = ref(false) // 导出的加载中 - -/** 查询列表 */ -const getList = async () => { - loading.value = true - try { - const data = await Demo02CategoryApi.getDemo02CategoryList(queryParams) - list.value = handleTree(data, 'id', 'parentId') - } 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 Demo02CategoryApi.deleteDemo02Category(id) - message.success(t('common.delSuccess')) - // 刷新列表 - await getList() - } catch {} -} - -/** 导出按钮操作 */ -const handleExport = async () => { - try { - // 导出的二次确认 - await message.exportConfirm() - // 发起导出 - exportLoading.value = true - 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> diff --git a/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue b/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue deleted file mode 100644 index 758c7e5..0000000 --- a/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue +++ /dev/null @@ -1,121 +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="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> diff --git a/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue b/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue deleted file mode 100644 index 9d3888d..0000000 --- a/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue +++ /dev/null @@ -1,99 +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="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> diff --git a/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue b/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue deleted file mode 100644 index 3dce77e..0000000 --- a/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue +++ /dev/null @@ -1,130 +0,0 @@ -<template> - <!-- 列表 --> - <ContentWrap> - <el-button - v-hasPermi="['infra:demo03-student:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 新增 - </el-button> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="编号" prop="id" /> - <el-table-column align="center" label="名字" prop="name" /> - <el-table-column align="center" label="分数" prop="score" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="创建时间" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="操作"> - <template #default="scope"> - <el-button - v-hasPermi="['infra:demo03-student:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 编辑 - </el-button> - <el-button - v-hasPermi="['infra:demo03-student:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 删除 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <!-- 表单弹窗:添加/修改 --> - <Demo03CourseForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -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?: number // 学生编号(主表的关联字段) -}>() -const loading = ref(false) // 列表的加载中 -const list = ref([]) // 列表的数据 -const total = ref(0) // 列表的总页数 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - studentId: undefined as unknown -}) - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - (val: number) => { - if (!val) { - return - } - queryParams.studentId = val - handleQuery() - }, - { immediate: true, deep: true } -) - -/** 查询列表 */ -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> diff --git a/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue deleted file mode 100644 index 5687294..0000000 --- a/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue +++ /dev/null @@ -1,99 +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="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> diff --git a/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue b/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue deleted file mode 100644 index 635f321..0000000 --- a/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue +++ /dev/null @@ -1,130 +0,0 @@ -<template> - <!-- 列表 --> - <ContentWrap> - <el-button - v-hasPermi="['infra:demo03-student:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 新增 - </el-button> - <el-table v-loading="loading" :data="list" :show-overflow-tooltip="true" :stripe="true"> - <el-table-column align="center" label="编号" prop="id" /> - <el-table-column align="center" label="名字" prop="name" /> - <el-table-column align="center" label="班主任" prop="teacher" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="创建时间" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="操作"> - <template #default="scope"> - <el-button - v-hasPermi="['infra:demo03-student:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 编辑 - </el-button> - <el-button - v-hasPermi="['infra:demo03-student:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 删除 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @pagination="getList" - /> - </ContentWrap> - <!-- 表单弹窗:添加/修改 --> - <Demo03GradeForm ref="formRef" @success="getList" /> -</template> - -<script lang="ts" setup> -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?: number // 学生编号(主表的关联字段) -}>() -const loading = ref(false) // 列表的加载中 -const list = ref([]) // 列表的数据 -const total = ref(0) // 列表的总页数 -const queryParams = reactive({ - pageNo: 1, - pageSize: 10, - studentId: undefined as unknown -}) - -/** 监听主表的关联字段的变化,加载对应的子表数据 */ -watch( - () => props.studentId, - (val: number) => { - if (!val) { - return - } - queryParams.studentId = val - handleQuery() - }, - { immediate: true, deep: true } -) - -/** 查询列表 */ -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> diff --git a/src/views/infra/demo/demo03/erp/index.vue b/src/views/infra/demo/demo03/erp/index.vue deleted file mode 100644 index b8e65b2..0000000 --- a/src/views/infra/demo/demo03/erp/index.vue +++ /dev/null @@ -1,246 +0,0 @@ -<template> - <ContentWrap> - <!-- 搜索工作栏 --> - <el-form - ref="queryFormRef" - :inline="true" - :model="queryParams" - class="-mb-15px" - label-width="68px" - > - <el-form-item label="名字" prop="name"> - <el-input - v-model="queryParams.name" - class="!w-240px" - clearable - placeholder="请输入名字" - @keyup.enter="handleQuery" - /> - </el-form-item> - <el-form-item label="性别" prop="sex"> - <el-select v-model="queryParams.sex" class="!w-240px" clearable 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="createTime"> - <el-date-picker - v-model="queryParams.createTime" - :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" - class="!w-240px" - end-placeholder="结束日期" - start-placeholder="开始日期" - type="daterange" - value-format="YYYY-MM-DD HH:mm:ss" - /> - </el-form-item> - <el-form-item> - <el-button @click="handleQuery"> - <Icon class="mr-5px" icon="ep:search" /> - 搜索 - </el-button> - <el-button @click="resetQuery"> - <Icon class="mr-5px" icon="ep:refresh" /> - 重置 - </el-button> - <el-button - v-hasPermi="['infra:demo03-student:create']" - plain - type="primary" - @click="openForm('create')" - > - <Icon class="mr-5px" icon="ep:plus" /> - 新增 - </el-button> - <el-button - v-hasPermi="['infra:demo03-student:export']" - :loading="exportLoading" - plain - type="success" - @click="handleExport" - > - <Icon class="mr-5px" icon="ep:download" /> - 导出 - </el-button> - </el-form-item> - </el-form> - </ContentWrap> - - <!-- 列表 --> - <ContentWrap> - <el-table - v-loading="loading" - :data="list" - :show-overflow-tooltip="true" - :stripe="true" - highlight-current-row - @current-change="handleCurrentChange" - > - <el-table-column align="center" label="编号" prop="id" /> - <el-table-column align="center" label="名字" prop="name" /> - <el-table-column align="center" label="性别" prop="sex"> - <template #default="scope"> - <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> - </template> - </el-table-column> - <el-table-column - :formatter="dateFormatter" - align="center" - label="出生日期" - prop="birthday" - width="180px" - /> - <el-table-column align="center" label="简介" prop="description" /> - <el-table-column - :formatter="dateFormatter" - align="center" - label="创建时间" - prop="createTime" - width="180px" - /> - <el-table-column align="center" label="操作"> - <template #default="scope"> - <el-button - v-hasPermi="['infra:demo03-student:update']" - link - type="primary" - @click="openForm('update', scope.row.id)" - > - 编辑 - </el-button> - <el-button - v-hasPermi="['infra:demo03-student:delete']" - link - type="danger" - @click="handleDelete(scope.row.id)" - > - 删除 - </el-button> - </template> - </el-table-column> - </el-table> - <!-- 分页 --> - <Pagination - v-model:limit="queryParams.pageSize" - v-model:page="queryParams.pageNo" - :total="total" - @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 lang="ts" setup> -import { DICT_TYPE, getIntDictOptions } 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> diff --git a/src/views/infra/demo/demo03/inner/Demo03StudentForm.vue b/src/views/infra/demo/demo03/inner/Demo03StudentForm.vue deleted file mode 100644 index 98c1b7b..0000000 --- a/src/views/infra/demo/demo03/inner/Demo03StudentForm.vue +++ /dev/null @@ -1,153 +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="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/inner' -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> diff --git a/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue b/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue deleted file mode 100644 index 77da45f..0000000 --- a/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue +++ /dev/null @@ -1,100 +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="名字" 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> diff --git a/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue b/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue deleted file mode 100644 index 965b473..0000000 --- a/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue +++ /dev/null @@ -1,51 +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="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> diff --git a/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue deleted file mode 100644 index e14bac4..0000000 --- a/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue +++ /dev/null @@ -1,72 +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="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> diff --git a/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue b/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue deleted file mode 100644 index e631384..0000000 --- a/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue +++ /dev/null @@ -1,55 +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="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> diff --git a/src/views/infra/demo/demo03/inner/index.vue b/src/views/infra/demo/demo03/inner/index.vue deleted file mode 100644 index 6d662cc..0000000 --- a/src/views/infra/demo/demo03/inner/index.vue +++ /dev/null @@ -1,227 +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="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"> - <!-- 子表的列表 --> - <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="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" /> -</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/inner' -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 - } -} - -/** 初始化 **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue b/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue deleted file mode 100644 index 4815357..0000000 --- a/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue +++ /dev/null @@ -1,153 +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="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> diff --git a/src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue b/src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue deleted file mode 100644 index f439c3f..0000000 --- a/src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue +++ /dev/null @@ -1,100 +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="名字" 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/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' }], - 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> diff --git a/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue deleted file mode 100644 index c711954..0000000 --- a/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue +++ /dev/null @@ -1,72 +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="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> diff --git a/src/views/infra/demo/demo03/normal/index.vue b/src/views/infra/demo/demo03/normal/index.vue deleted file mode 100644 index 0ea677d..0000000 --- a/src/views/infra/demo/demo03/normal/index.vue +++ /dev/null @@ -1,212 +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="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"> - <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" /> -</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/normal' -import Demo03StudentForm from './Demo03StudentForm.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 - } -} - -/** 初始化 **/ -onMounted(() => { - getList() -}) -</script> diff --git a/src/views/infra/server/index.vue b/src/views/infra/server/index.vue index da839bd..84e4bce 100644 --- a/src/views/infra/server/index.vue +++ b/src/views/infra/server/index.vue @@ -14,9 +14,6 @@ /** 初始化 */ onMounted(async () => { try { - // 友情提示:如果访问出现 404 问题: - // 1)boot 参考 https://doc.iocoder.cn/server-monitor/ 解决; - // 2)cloud 参考 https://cloud.iocoder.cn/server-monitor/ 解决 const data = await ConfigApi.getConfigKey('url.spring-boot-admin') if (data && data.length > 0) { src.value = data diff --git a/src/views/infra/storage/index_rec.vue b/src/views/infra/storage/index_rec.vue new file mode 100644 index 0000000..f6dfc23 --- /dev/null +++ b/src/views/infra/storage/index_rec.vue @@ -0,0 +1,161 @@ +<template> + <el-scrollbar height="calc(100vh - 88px - 40px - 50px)"> + <el-row> + <!-- 磁盘使用量统计 --> + <el-col :span="12" class="mt-3"> + <el-card class="ml-3" :gutter="12" shadow="hover"> +<!-- <div ref="chartRef" style="width: 100%; height: 90%"></div>--> + <Echart :options="usedDiskEchartChika" :height="420" /> +<!-- <Echart :options="usedDiskEchartChika" :height="420" />--> + </el-card> + </el-col> + </el-row> + </el-scrollbar> +</template> +<script lang="ts" setup> +import { ref, onMounted } from "vue"; +import * as StorageApi from '@/api/infra/storage' +import { StorageMonitorInfoVO } from '@/api/infra/storage/types' +const disks = ref<StorageMonitorInfoVO>() +const disk = ref<StorageMonitorInfoVO>() + +// 基本信息 +const readDiskInfo = async () => { + const data = await StorageApi.getDiskInfo() + disks.value = data + disk.value = data[0] +} + +// 内存使用情况 +const usedDiskEchartChika = reactive<any>({ + title: { + // 仪表盘标题。 + text: '磁盘使用情况', + left: 'center', + show: true, // 是否显示标题,默认 true。 + offsetCenter: [0, '20%'], //相对于仪表盘中心的偏移位置,数组第一项是水平方向的偏移,第二项是垂直方向的偏移。可以是绝对的数值,也可以是相对于仪表盘半径的百分比。 + color: 'yellow', // 文字的颜色,默认 #333。 + fontSize: 20 // 文字的字体大小,默认 15。 + }, + toolbox: { + show: false, + feature: { + restore: { show: true }, + saveAsImage: { show: true } + } + }, + series: [ + { + name: '峰值', + type: 'gauge', + min: 0, + max: 500, + splitNumber: 10, + //这是指针的颜色 + color: '#F5C74E', + radius: '85%', + center: ['50%', '50%'], + startAngle: 225, + endAngle: -45, + axisLine: { + // 坐标轴线 + lineStyle: { + // 属性lineStyle控制线条样式 + color: [ + [0.2, '#7FFF00'], + [0.8, '#00FFFF'], + [1, '#FF0000'] + ], + //width: 6 外框的大小(环的宽度) + width: 10 + } + }, + axisTick: { + // 坐标轴小标记 + //里面的线长是5(短线) + length: 5, // 属性length控制线长 + lineStyle: { + // 属性lineStyle控制线条样式 + color: '#76D9D7' + } + }, + splitLine: { + // 分隔线 + length: 20, // 属性length控制线长 + lineStyle: { + // 属性lineStyle(详见lineStyle)控制线条样式 + color: '#76D9D7' + } + }, + axisLabel: { + color: '#76D9D7', + distance: 15, + fontSize: 15 + }, + pointer: { + // 指针的大小 + width: 7, + show: true + }, + detail: { + textStyle: { + fontWeight: 'normal', + // 里面文字下的数值大小(50) + fontSize: 15, + color: '#FFFFFF' + }, + valueAnimation: true + }, + progress: { + show: true + } + } + ] +}) + + +/** 加载数据 */ +const getSummary = () => { + // 初始化命令图表 + usedDiskInstance() +} + +const usedDiskInstance = async () => { + try { + const data = await StorageApi.getDiskInfo() + disks.value = data + disk.value = data[0] + // data.forEach((disk) => { + console.log(disk.value) + console.log(disk.value.name) + console.log(disk.value!.restPPT) + // 仪表盘详情,用于显示数据。 + usedDiskEchartChika.series[0].detail = { + show: true, // 是否显示详情,默认 true。 + offsetCenter: [0, '50%'], // 相对于仪表盘中心的偏移位置,数组第一项是水平方向的偏移,第二项是垂直方向的偏移。可以是绝对的数值,也可以是相对于仪表盘半径的百分比。 + color: 'auto', // 文字的颜色,默认 auto。 + fontSize: 30, // 文字的字体大小,默认 15。 + formatter: disk.value!.restPPT // 格式化函数或者字符串 + } + console.log(disk.value.restPPT) + usedDiskEchartChika.series[0].data[0] = { + value: disk.value!.restPPT, + name: '磁盘消耗' + } + console.log(disk.value) + usedDiskEchartChika.tooltip = { + formatter: '{b} <br/>{a} : ' + disk.value!.restPPT + } + // }) + } catch {} +} + +/** 初始化 **/ +onMounted(() => { + readDiskInfo() + // 读取 redis 信息 + // readDiskInfo() + // // 加载数据 + getSummary() +}) +</script> diff --git a/src/views/system/appgroup/AppGroupForm.vue b/src/views/system/appgroup/AppGroupForm.vue new file mode 100644 index 0000000..6b60e72 --- /dev/null +++ b/src/views/system/appgroup/AppGroupForm.vue @@ -0,0 +1,130 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle" width="50%"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="80px" + > + <el-row> + <el-col :span="12"> + <el-form-item label="分组编号" prop="appCode"> + <el-input v-model="formData.code" placeholder="请输入应用分组编号" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="分组名称" prop="appName"> + <el-input v-model="formData.name" placeholder="请输入应用分组名称" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="分组图标" prop="icon"> + <UploadImg v-model="formData.icon" :limit="1" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="排序" prop="orderNum"> + <el-input-number v-model="formData.sort" placeholder="请输入排序" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="备注" prop="remark"> + <el-input v-model="formData.remark" clearable type="textarea" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> + import * as AppGroupApi from '@/api/system/appgroup' + + defineOptions({ name: 'SystemAppGroupForm' }) + + 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, + code: undefined, + name: undefined, + icon: undefined, + sort: undefined, + remark: undefined + }) + const formRules = reactive({ + code: [{ required: true, message: '分组编号不能为空', trigger: 'blur' }], + name: [{ 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 AppGroupApi.getAppGroup(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 AppGroupApi.AppGroupVO + if (formType.value === 'create') { + await AppGroupApi.createAppGroup(data) + message.success(t('common.createSuccess')) + } else { + await AppGroupApi.updateAppGroup(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } + } + + /** 重置表单 */ + const resetForm = () => { + formData.value = { + id: undefined, + code: undefined, + name: undefined, + icon: undefined, + sort: undefined, + remark: undefined, + } + formRef.value?.resetFields() + } +</script> diff --git a/src/views/system/appgroup/index.vue b/src/views/system/appgroup/index.vue new file mode 100644 index 0000000..0e662ba --- /dev/null +++ b/src/views/system/appgroup/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 label="分组编号" prop="appCode"> + <el-input + v-model="queryParams.code" + placeholder="请输入分组编号" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="分组名称" prop="appName"> + <el-input + v-model="queryParams.name" + placeholder="请输入分组名称" + clearable + @keyup.enter="handleQuery" + 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="['system:app-group:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> + 新增 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list"> + <el-table-column label="分组编号" align="center" prop="code" /> + <el-table-column label="分组名称" align="center" prop="name" /> + <el-table-column label="分组图标" align="center" prop="logo"> + <template #default="scope"> + <img width="40px" height="40px" :src="scope.row.icon" /> + </template> + </el-table-column> + <el-table-column label="排序" align="center" prop="sort" /> + <el-table-column label="备注" align="center" prop="remark" width="200" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + width="180" + :formatter="dateFormatter" + /> + <el-table-column label="操作" align="center" min-width="110" fixed="right"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['system:app-group:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['system:app-group: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> + + <!-- 表单弹窗:添加/修改 --> + <AppGroupForm ref="formRef" @success="getList" /> + +</template> +<script lang="ts" setup> + import {dateFormatter} from '@/utils/formatTime' + import * as AppGroupApi from '@/api/system/appgroup' + import AppGroupForm from './AppGroupForm.vue' + import * as TenantApi from "@/api/system/tenant"; + + defineOptions({name: 'SystemAppGroup'}) + + const message = useMessage() // 消息弹窗 + const {t} = useI18n() // 国际化 + + const loading = ref(true) // 列表的加载中 + const total = ref(0) // 列表的总页数 + const list = ref([]) // 列表的数据 + const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + code: undefined, + name: undefined, + createTime: [] + }) + const queryFormRef = ref() // 搜索的表单 + + /** 查询列表 */ + const getList = async () => { + loading.value = true + try { + const data = await AppGroupApi.getAppGroupPage(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 AppGroupApi.deleteAppGroup(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch { + } + } + + /** 初始化 **/ + onMounted(async () => { + await getList() + }) + +</script> diff --git a/src/views/system/appmenu/AppMenuForm.vue b/src/views/system/appmenu/AppMenuForm.vue new file mode 100644 index 0000000..3a7ad72 --- /dev/null +++ b/src/views/system/appmenu/AppMenuForm.vue @@ -0,0 +1,256 @@ +<template> + <Dialog v-model="dialogVisible" :title="dialogTitle"> + <el-form + ref="formRef" + v-loading="formLoading" + :model="formData" + :rules="formRules" + label-width="100px" + > + <el-form-item label="应用名称"> + <el-tree-select + v-model="formData.parentId" + :data="appMenuTree" + :default-expanded-keys="[0]" + :props="defaultProps" + check-strictly + node-key="id" + /> + </el-form-item> + <el-form-item label="菜单名称" prop="name"> + <el-input v-model="formData.name" clearable placeholder="请输入菜单名称" /> + </el-form-item> + <el-form-item label="菜单类型" prop="type"> + <el-radio-group v-model="formData.type"> + <el-radio-button + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_APP_MENU_TYPE)" + :key="dict.label" + :label="dict.value" + > + {{ dict.label }} + </el-radio-button> + </el-radio-group> + </el-form-item> + <el-form-item v-if="formData.type !== 3" label="菜单图标"> + <IconSelect v-model="formData.icon" clearable /> + </el-form-item> + <el-form-item v-if="formData.type !== 3" label="路由地址" prop="path"> + <template #label> + <Tooltip + message="访问的路由地址,如:`user`。如需外网地址时,则以 `http(s)://` 开头" + title="路由地址" + /> + </template> + <el-input v-model="formData.path" clearable placeholder="请输入路由地址" /> + </el-form-item> + <el-form-item v-if="formData.type === 2" label="组件地址" prop="component"> + <el-input v-model="formData.component" clearable placeholder="例如说:system/user/index" /> + </el-form-item> + <el-form-item v-if="formData.type === 2" label="组件名字" prop="componentName"> + <el-input v-model="formData.componentName" clearable placeholder="例如说:SystemUser" /> + </el-form-item> + <el-form-item v-if="formData.type !== 1" label="权限标识" prop="permission"> + <template #label> + <Tooltip + message="Controller 方法上的权限字符,如:@PreAuthorize(`@ss.hasPermission('system:user:list')`)" + title="权限标识" + /> + </template> + <el-input v-model="formData.permission" clearable placeholder="请输入权限标识" /> + </el-form-item> + <el-form-item label="显示排序" prop="sort"> + <el-input-number v-model="formData.sort" :min="0" clearable controls-position="right" /> + </el-form-item> + <el-form-item label="菜单状态" prop="status"> + <el-radio-group v-model="formData.status"> + <el-radio + v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" + :key="dict.label" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item v-if="formData.type !== 3" label="显示状态" prop="visible"> + <template #label> + <Tooltip message="选择隐藏时,路由将不会出现在侧边栏,但仍然可以访问" title="显示状态" /> + </template> + <el-radio-group v-model="formData.visible"> + <el-radio key="true" :label="true" border>显示</el-radio> + <el-radio key="false" :label="false" border>隐藏</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item v-if="formData.type !== 3" label="总是显示" prop="alwaysShow"> + <template #label> + <Tooltip + message="选择不是时,当该菜单只有一个子菜单时,不展示自己,直接展示子菜单" + title="总是显示" + /> + </template> + <el-radio-group v-model="formData.alwaysShow"> + <el-radio key="true" :label="true" border>总是</el-radio> + <el-radio key="false" :label="false" border>不是</el-radio> + </el-radio-group> + </el-form-item> + <el-form-item v-if="formData.type === 2" label="缓存状态" prop="keepAlive"> + <template #label> + <Tooltip + message="选择缓存时,则会被 `keep-alive` 缓存,必须填写「组件名称」字段" + title="缓存状态" + /> + </template> + <el-radio-group v-model="formData.keepAlive"> + <el-radio key="true" :label="true" border>缓存</el-radio> + <el-radio key="false" :label="false" border>不缓存</el-radio> + </el-radio-group> + </el-form-item> + </el-form> + <template #footer> + <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script lang="ts" setup> +import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' +import * as MenuApi from '@/api/system/menu' +import { CACHE_KEY, useCache } from '@/hooks/web/useCache' +import { CommonStatusEnum, SystemAppMenuTypeEnum } from '@/utils/constants' +import { defaultProps, handleTree } from '@/utils/tree' + +defineOptions({ name: 'SystemAppMenuForm' }) + +const { wsCache } = useCache() +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: '', + permission: '', + type: SystemAppMenuTypeEnum.DIR, + sort: Number(undefined), + parentId: 0, + path: '', + icon: '', + component: '', + componentName: '', + status: CommonStatusEnum.ENABLE, + visible: true, + keepAlive: true, + alwaysShow: true +}) +const formRules = reactive({ + name: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' }], + sort: [{ required: true, message: '菜单顺序不能为空', trigger: 'blur' }], + path: [{ required: true, message: '路由地址不能为空', trigger: 'blur' }], + status: [{ required: true, message: '状态不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number, parentId?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + if (parentId) { + formData.value.parentId = parentId + } + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await MenuApi.getAppMenu(id) + } finally { + formLoading.value = false + } + } + // 获得菜单列表 + await getTree() +} +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 { + if ( + formData.value.type === SystemAppMenuTypeEnum.DIR || + formData.value.type === SystemAppMenuTypeEnum.MENU + ) { + if (!isExternal(formData.value.path)) { + if (formData.value.parentId === 0 && formData.value.path.charAt(0) !== '/') { + message.error('路径必须以 / 开头') + return + } /*else if (formData.value.parentId !== 0 && formData.value.path.charAt(0) === '/') { + message.error('路径不能以 / 开头') + return + }*/ + } + } + const data = formData.value as unknown as MenuApi.MenuVO + if (formType.value === 'create') { + await MenuApi.createAppMenu(data) + message.success(t('common.createSuccess')) + } else { + await MenuApi.updateAppMenu(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + // 清空,从而触发刷新 + wsCache.delete(CACHE_KEY.ROLE_ROUTERS) + } +} + +/** 获取下拉框[上级菜单]的数据 */ +const appMenuTree = ref<Tree[]>([]) // 树形结构 +const getTree = async () => { + appMenuTree.value = [] + const res = await MenuApi.getSimpleAppMenusList() + let menu: Tree = { id: 0, name: '主应用', children: [] } + menu.children = handleTree(res) + appMenuTree.value.push(menu) +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: '', + permission: '', + type: SystemAppMenuTypeEnum.DIR, + sort: Number(undefined), + parentId: 0, + path: '', + icon: '', + component: '', + componentName: '', + status: CommonStatusEnum.ENABLE, + visible: true, + keepAlive: true, + alwaysShow: true + } + formRef.value?.resetFields() +} + +/** 判断 path 是不是外部的 HTTP 等链接 */ +const isExternal = (path: string) => { + return /^(https?:|mailto:|tel:)/.test(path) +} +</script> diff --git a/src/views/system/appmenu/index.vue b/src/views/system/appmenu/index.vue new file mode 100644 index 0000000..66b4f35 --- /dev/null +++ b/src/views/system/appmenu/index.vue @@ -0,0 +1,203 @@ +<template> + <!-- 搜索工作栏 --> + <ContentWrap> + <el-form + ref="queryFormRef" + :inline="true" + :model="queryParams" + class="-mb-15px" + label-width="68px" + > + <el-form-item label="菜单名称" prop="name"> + <el-input + v-model="queryParams.name" + class="!w-240px" + clearable + placeholder="请输入菜单名称" + @keyup.enter="handleQuery" + /> + </el-form-item> + <el-form-item label="状态" prop="status"> + <el-select + v-model="queryParams.status" + class="!w-240px" + clearable + placeholder="请选择菜单状态" + > + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"> + <Icon class="mr-5px" icon="ep:search" /> + 搜索 + </el-button> + <el-button @click="resetQuery"> + <Icon class="mr-5px" icon="ep:refresh" /> + 重置 + </el-button> + <el-button plain type="danger" @click="toggleExpandAll"> + <Icon class="mr-5px" icon="ep:sort" /> + 展开/折叠 + </el-button> + <el-button plain @click="refreshMenu"> + <Icon class="mr-5px" icon="ep:refresh" /> + 刷新菜单缓存 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-if="refreshTable" + v-loading="loading" + :data="list" + :default-expand-all="isExpandAll" + row-key="id" + > + <el-table-column :show-overflow-tooltip="true" label="菜单名称" prop="name" width="250" /> + <el-table-column align="center" label="图标" prop="icon" width="100"> + <template #default="scope"> + <Icon :icon="scope.row.icon" /> + </template> + </el-table-column> + <el-table-column label="排序" prop="sort" width="60" /> + <el-table-column :show-overflow-tooltip="true" label="权限标识" prop="permission" /> + <el-table-column :show-overflow-tooltip="true" label="组件路径" prop="component" /> + <el-table-column :show-overflow-tooltip="true" label="组件名称" prop="componentName" /> + <el-table-column label="状态" prop="status" width="80"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" /> + </template> + </el-table-column> + <el-table-column align="center" label="操作"> + <template #default="scope"> + <el-button + v-hasPermi="['system:app-menu:update']" + link + type="primary" + @click="openForm('update', scope.row.id)" + > + 修改 + </el-button> + <el-button + v-hasPermi="['system:app-menu:create']" + link + type="primary" + @click="openForm('create', undefined, scope.row.id)" + > + 新增 + </el-button> + <el-button + v-hasPermi="['system:app-menu:delete']" + link + type="danger" + @click="handleDelete(scope.row.id)" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <AppMenuForm ref="formRef" @success="getList" /> +</template> +<script lang="ts" setup> +import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' +import { handleTree } from '@/utils/tree' +import * as MenuApi from '@/api/system/menu' +import AppMenuForm from './AppMenuForm.vue' +import { CACHE_KEY, useCache } from '@/hooks/web/useCache' + +defineOptions({ name: 'SystemAppMenu' }) + +const { wsCache } = useCache() +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const loading = ref(true) // 列表的加载中 +const list = ref<any>([]) // 列表的数据 +const queryParams = reactive({ + name: undefined, + status: undefined +}) +const queryFormRef = ref() // 搜索的表单 +const isExpandAll = ref(false) // 是否展开,默认全部折叠 +const refreshTable = ref(true) // 重新渲染表格状态 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await MenuApi.getAppMenuList(queryParams) + list.value = handleTree(data) + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number, parentId?: number) => { + formRef.value.open(type, id, parentId) +} + +/** 展开/折叠操作 */ +const toggleExpandAll = () => { + refreshTable.value = false + isExpandAll.value = !isExpandAll.value + nextTick(() => { + refreshTable.value = true + }) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await MenuApi.deleteAppMenu(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 刷新菜单缓存按钮操作 */ +const refreshMenu = async () => { + try { + await message.confirm('即将更新缓存刷新浏览器!', '刷新菜单缓存') + // 清空,从而触发刷新 + wsCache.delete(CACHE_KEY.USER) + wsCache.delete(CACHE_KEY.ROLE_ROUTERS) + // 刷新浏览器 + location.reload() + } catch {} +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> -- Gitblit v1.9.3