From 0b4ce5f3965ba716d3c39ea2abac0d1769adb2d1 Mon Sep 17 00:00:00 2001 From: zhangtao <9480807882@qq.com> Date: Thu, 6 Mar 2025 22:25:41 +0800 Subject: [PATCH] =?UTF-8?q?fix(system):=20=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E9=97=A8=E3=80=81=E8=8F=9C=E5=8D=95=E3=80=81=E5=85=AC=E5=91=8A?= =?UTF-8?q?=E3=80=81=E5=B2=97=E4=BD=8D=E3=80=81=E8=A7=92=E8=89=B2=E5=92=8C?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 增加创建、更新和删除操作的异常处理 - 优化错误提示信息 - 重置表单状态以解决数据残留问题 - 统一错误处理方式,使用 message 组件替代 notification --- .../api/v1/services/system/dept_service.py | 13 ++++++ .../api/v1/services/system/menu_service.py | 14 +++++++ .../api/v1/services/system/notice_service.py | 13 ++++++ .../v1/services/system/position_service.py | 13 ++++++ .../api/v1/services/system/role_service.py | 13 ++++++ .../api/v1/services/system/user_service.py | 2 +- backend/dev_sql.db | Bin 233472 -> 233472 bytes frontend/src/utils/request.js | 37 +++++------------ frontend/src/views/system/dept/index.vue | 20 +++++++++ frontend/src/views/system/menu/index.vue | 36 +++++++++++++++++ frontend/src/views/system/notice/index.vue | 18 +++++++++ frontend/src/views/system/position/index.vue | 16 ++++++++ frontend/src/views/system/role/index.vue | 16 ++++++++ frontend/src/views/system/user/index.vue | 38 ++++++++++++++++++ 14 files changed, 221 insertions(+), 28 deletions(-) diff --git a/backend/app/api/v1/services/system/dept_service.py b/backend/app/api/v1/services/system/dept_service.py index d8748c7d..03a781e4 100644 --- a/backend/app/api/v1/services/system/dept_service.py +++ b/backend/app/api/v1/services/system/dept_service.py @@ -10,6 +10,7 @@ from app.api.v1.schemas.system.dept_schema import ( DeptOutSchema ) from app.core.base_schema import BatchSetAvailable +from app.core.exceptions import CustomException from app.utils.common_util import ( get_parent_id_map, get_parent_recursion, @@ -59,6 +60,9 @@ class DeptService: :param data: 部门创建对象 :return: 新创建的部门对象 """ + dept = await DeptCRUD(auth).get(name=data.name) + if dept: + raise CustomException(msg='创建失败,该部门已存在') dept = await DeptCRUD(auth).create(data=data) return DeptOutSchema.model_validate(dept).model_dump() @@ -71,6 +75,12 @@ class DeptService: :param data: 部门更新对象 :return: 更新后的部门对象 """ + dept = await DeptCRUD(auth).get_dept_by_id(id=data.id) + if not dept: + raise CustomException(msg='更新失败,该部门不存在') + exist_dept = await DeptCRUD(auth).get(name=data.name) + if exist_dept and exist_dept.id != data.id: + raise CustomException(msg='更新失败,部门名称重复') dept = await DeptCRUD(auth).update(id=data.id, data=data) if data.available: await cls.batch_set_available_services(auth=auth, data=BatchSetAvailable(ids=[data.id], available=True)) @@ -86,6 +96,9 @@ class DeptService: :param auth: 认证对象 :param id: 部门ID """ + dept = await DeptCRUD(auth).get_dept_by_id(id=id) + if not dept: + raise CustomException(msg='删除失败,该部门不存在') await DeptCRUD(auth).delete(ids=[id]) @classmethod diff --git a/backend/app/api/v1/services/system/menu_service.py b/backend/app/api/v1/services/system/menu_service.py index a5c33134..a3f189b8 100644 --- a/backend/app/api/v1/services/system/menu_service.py +++ b/backend/app/api/v1/services/system/menu_service.py @@ -10,6 +10,7 @@ from app.api.v1.schemas.system.menu_schema import ( MenuOutSchema ) from app.core.base_schema import BatchSetAvailable +from app.core.exceptions import CustomException from app.utils.common_util import ( get_parent_id_map, get_parent_recursion, @@ -39,6 +40,9 @@ class MenuService: @classmethod async def create_menu(cls, auth: AuthSchema, data: MenuCreateSchema) -> Dict: + menu = await MenuCRUD(auth).get(name=data.name) + if menu: + raise CustomException(msg='创建失败,该菜单已存在') if data.parent_id: parent_menu = await MenuCRUD(auth).get_menu_by_id(id=data.parent_id) data.parent_name = parent_menu.name @@ -48,6 +52,13 @@ class MenuService: @classmethod async def update_menu(cls, auth: AuthSchema, data: MenuUpdateSchema) -> Dict: + menu = await MenuCRUD(auth).get_menu_by_id(id=data.id) + if not menu: + raise CustomException(msg='更新失败,该菜单不存在') + exist_menu = await MenuCRUD(auth).get(name=data.name) + if exist_menu and exist_menu.id != data.id: + raise CustomException(msg='更新失败,菜单名称重复') + if data.parent_id: parent_menu = await MenuCRUD(auth).get_menu_by_id(id=data.parent_id) data.parent_name = parent_menu.name @@ -60,6 +71,9 @@ class MenuService: @classmethod async def delete_menu(cls, auth: AuthSchema, id: int) -> None: + menu = await MenuCRUD(auth).get_menu_by_id(id=id) + if not menu: + raise CustomException(msg='删除失败,该菜单不存在') await MenuCRUD(auth).delete(ids=[id]) @classmethod diff --git a/backend/app/api/v1/services/system/notice_service.py b/backend/app/api/v1/services/system/notice_service.py index 35bcb824..90d8bc7f 100644 --- a/backend/app/api/v1/services/system/notice_service.py +++ b/backend/app/api/v1/services/system/notice_service.py @@ -7,6 +7,7 @@ from app.api.v1.schemas.system.notice_schema import NoticeCreateSchema, NoticeUp from app.core.base_schema import BatchSetAvailable from app.api.v1.params.system.notice_param import NoticeQueryParams from app.api.v1.cruds.system.notice_crud import NoticeCRUD +from app.core.exceptions import CustomException from app.utils.excel_util import ExcelUtil @@ -27,16 +28,28 @@ class NoticeService: @classmethod async def create_notice_services(cls, auth: AuthSchema, data: NoticeCreateSchema) -> Dict: + config = await NoticeCRUD(auth).get(notice_title=data.notice_title) + if config: + raise CustomException(msg='创建失败,该公告通知已存在') config_obj = await NoticeCRUD(auth).create_notice(data=data) return NoticeOutSchema.model_validate(config_obj).model_dump() @classmethod async def update_notice_services(cls, auth: AuthSchema, data: NoticeUpdateSchema) -> Dict: + config = await NoticeCRUD(auth).get_notice_by_id(id=data.id) + if not config: + raise CustomException(msg='更新失败,该公告通知不存在') + exist_config = await NoticeCRUD(auth).get(notice_title=data.notice_title) + if exist_config and exist_config.id != data.id: + raise CustomException(msg='更新失败,公告通知标题重复') config_obj = await NoticeCRUD(auth).update_notice(id=data.id, data=data) return NoticeOutSchema.model_validate(config_obj).model_dump() @classmethod async def delete_notice_services(cls, auth: AuthSchema, id: int) -> None: + config = await NoticeCRUD(auth).get_notice_by_id(id=id) + if not config: + raise CustomException(msg='删除失败,该公告通知不存在') await NoticeCRUD(auth).delete_notice(ids=[id]) @classmethod diff --git a/backend/app/api/v1/services/system/position_service.py b/backend/app/api/v1/services/system/position_service.py index bcbeb095..07b5080e 100644 --- a/backend/app/api/v1/services/system/position_service.py +++ b/backend/app/api/v1/services/system/position_service.py @@ -10,6 +10,7 @@ from app.api.v1.schemas.system.position_schema import ( PositionOutSchema, ) from app.core.base_schema import BatchSetAvailable +from app.core.exceptions import CustomException from app.utils.excel_util import ExcelUtil from app.api.v1.params.system.position_param import PositionQueryParams @@ -32,18 +33,30 @@ class PositionService: @classmethod async def create_position(cls, auth: AuthSchema, data: PositionCreateSchema) -> Dict: """创建岗位""" + position = await PositionCRUD(auth).get(name=data.name) + if position: + raise CustomException(msg='创建失败,该岗位已存在') new_position = await PositionCRUD(auth).create(data=data) return PositionOutSchema.model_validate(new_position).model_dump() @classmethod async def update_position(cls, auth: AuthSchema, data: PositionUpdateSchema) -> Dict: """更新岗位""" + position = await PositionCRUD(auth).get_position_by_id(id=data.id) + if not position: + raise CustomException(msg='更新失败,该岗位不存在') + exist_position = await PositionCRUD(auth).get(name=data.name) + if exist_position and exist_position.id != data.id: + raise CustomException(msg='更新失败,岗位名称重复') updated_position = await PositionCRUD(auth).update(id=data.id, data=data) return PositionOutSchema.model_validate(updated_position).model_dump() @classmethod async def delete_position(cls, auth: AuthSchema, id: int) -> None: """删除岗位""" + position = await PositionCRUD(auth).get_position_by_id(id=id) + if not position: + raise CustomException(msg='删除失败,该岗位不存在') await PositionCRUD(auth).delete(ids=[id]) @classmethod diff --git a/backend/app/api/v1/services/system/role_service.py b/backend/app/api/v1/services/system/role_service.py index 8f9edfb2..0ca94322 100644 --- a/backend/app/api/v1/services/system/role_service.py +++ b/backend/app/api/v1/services/system/role_service.py @@ -4,6 +4,7 @@ from typing import Dict, List from app.api.v1.cruds.system.dept_crud import DeptCRUD from app.core.base_schema import BatchSetAvailable +from app.core.exceptions import CustomException from app.utils.common_util import get_child_id_map, get_child_recursion, get_parent_id_map, get_parent_recursion from app.api.v1.cruds.system.role_crud import RoleCRUD, MenuCRUD from app.api.v1.schemas.system.auth_schema import AuthSchema @@ -36,18 +37,30 @@ class RoleService: @classmethod async def create_role(cls, auth: AuthSchema, data: RoleCreateSchema) -> Dict: """创建角色""" + role = await RoleCRUD(auth).get(name=data.name) + if role: + raise CustomException(msg='创建失败,该角色已存在') new_role = await RoleCRUD(auth).create(data=data) return RoleOutSchema.model_validate(new_role).model_dump() @classmethod async def update_role(cls, auth: AuthSchema, data: RoleUpdateSchema) -> Dict: """更新角色""" + role = await RoleCRUD(auth).get_role_by_id(id=data.id) + if not role: + raise CustomException(msg='更新失败,该角色不存在') + exist_role = await RoleCRUD(auth).get(name=data.name) + if exist_role and exist_role.id != data.id: + raise CustomException(msg='更新失败,角色名称重复') updated_role = await RoleCRUD(auth).update(id=data.id, data=data) return RoleOutSchema.model_validate(updated_role).model_dump() @classmethod async def delete_role(cls, auth: AuthSchema, id: int) -> None: """删除角色""" + role = await RoleCRUD(auth).get_role_by_id(id=id) + if not role: + raise CustomException(msg='删除失败,该角色不存在') await RoleCRUD(auth).delete(ids=[id]) @classmethod diff --git a/backend/app/api/v1/services/system/user_service.py b/backend/app/api/v1/services/system/user_service.py index 7eba2ffe..2fa298c3 100644 --- a/backend/app/api/v1/services/system/user_service.py +++ b/backend/app/api/v1/services/system/user_service.py @@ -244,7 +244,7 @@ class UserService: # 检查用户名是否存在 user = await UserCRUD(auth).get_user_by_username(username=data.username) if user: - raise CustomException(msg='用户名已存在') + raise CustomException(msg='注册失败,用户名已存在') data.password = PwdUtil.set_password_hash(password=data.password) dict_data = data.model_dump(exclude_unset=True) diff --git a/backend/dev_sql.db b/backend/dev_sql.db index 78e8051b07a36a7aa1c5f273efd9e0e53fd8c35f..40c2ba141a5917dc9209ce13d496f4eb243be26e 100644 GIT binary patch delta 1521 zcmbVM-*4Jh6gIGhuw;RXMblQcIG(bX5%5oftx6S3NCFuU@uOtCFk@f9#2D8$Ay7p$ zTN_n-St>S7lcpxprm2&vN-dMtsjAvZeb{6Fgh>nO`j*E%tkNzaqY161sq)kP?sx9_ z&N-jY#oe)syJOp@P2j3))&y>SGVB`q^ZxeZyFaylb-nNKp(MdEGaTXf_!)|#+uysc znokX)OlyAP$LG=8s7W2MTM+Z;0Wx|pW^GTRd!wg6eZ%BL-rRh3;=L)`rqgB%*ggmZ z5MC@xN^A1knO0^;c$>sYW*VoaahM6`7>Xl(9-NtB395B(hwNtRqdtaash0KH->)DD z^0aN;dHVaXc_fd#etsn1o^)hJnwN&n4kX~*T$*@i+8DJdN>&KJNu48VjqKQDmIL3|fYrG`$IT_kY&bypVNa~ex1Rn3@(JUe5 zFs`B`Clavq7&oG1^|G(3J{LS6Yy|12|J1+=8*Rw`t6?AO{>fvH;L6BlnIFxFHh^W*I z=^-V~2(uwyXjNS~HydU>kkt^=p)RYKSs>J$1W9GNu|kFAj1rawvLMCEnPP4+Dt|N^ zmce2`ij{&?bS~J4%?0SlT!!^1>GTp`_9sG8ZCc1JH$X6~RMmu3Pn4F|O7S?Z6hHhp zkZP962o4RVfxHIv;(sW8S)oe2E~ZnkfOB-W%1BbcBgq02ONMGu1#fzMk)`>0As)?^ z7PGa4!s4{ducy~>alV{VSCNp#A=VtNsm(-`*W^d^hyKF?4{~|FR#nPwnp6T~>?J z1ow~GY8kh6jrbbeXlDCE#Qul9;Y95R!4%h+sQA~TU`a+M4}lcD8gH~E#*wKJG`SS?H~ z49zzwFcxq#FfcIju`}>9^RaJMRQSz1nSI_Lmc}YZ;mz#x|328xQo#I2epv&v01UTX KU|e>A=>PyGLL#*Q diff --git a/frontend/src/utils/request.js b/frontend/src/utils/request.js index d5d23a2c..aba73065 100644 --- a/frontend/src/utils/request.js +++ b/frontend/src/utils/request.js @@ -4,6 +4,7 @@ import router from "@/router"; import { getNewToken } from "@/api/system/auth"; import { save_token } from "@/utils/util"; import notification from "ant-design-vue/es/notification"; +import { message } from 'ant-design-vue'; // 创建 axios 实例 const request = axios.create({ @@ -13,7 +14,7 @@ const request = axios.create({ // 异常拦截处理器 const errorHandler = async (error) => { - console.log(error); + // console.error(error); if (!error.response) { return Promise.reject(error); @@ -27,20 +28,14 @@ const errorHandler = async (error) => { storage.remove("Access-Token"); storage.remove("Refresh-Token"); - notification.error({ - message: "错误", - description: data.msg, - }); + message.error(data.msg); router.push("/login"); return Promise.reject(error); } if (data.status_code === 401) { if (!access_token) { - notification.error({ - message: "错误", - description: data.msg, - }); + message.error(data.msg); router.push("/login"); return Promise.reject(error); } @@ -60,26 +55,16 @@ const errorHandler = async (error) => { ); return request(error.response.config).then((response) => response); } - - notification.error({ - message: "错误", - description: result.msg, - }); + message.error(result.msg); router.push("/login"); return Promise.reject(error); }) .catch((error) => { - notification.error({ - message: "错误", - description: data.msg, - }); + message.error(data.msg); return Promise.reject(error); }); } else { - notification.error({ - message: "错误", - description: data.msg, - }); + message.error(data.msg); return Promise.reject(error); } }; @@ -98,18 +83,16 @@ request.interceptors.request.use((config) => { // 响应拦截器 request.interceptors.response.use((response) => { // 打印全局响应 - console.log(response); + console.log(response.data); // 如果是文件下载类型的响应,直接返回 if (response.config.responseType === 'blob') { return response; } if (response.data.status_code !== 200) { - notification.error({ - message: "错误", - description: response.data.msg, - }); + message.error(response.data.msg); return Promise.reject(response); } + // message.success(response.data.msg); return response; }, errorHandler); diff --git a/frontend/src/views/system/dept/index.vue b/frontend/src/views/system/dept/index.vue index 0e9f12e6..eaef7ea0 100644 --- a/frontend/src/views/system/dept/index.vue +++ b/frontend/src/views/system/dept/index.vue @@ -435,11 +435,30 @@ const handleMoreClick: MenuProps['onClick'] = e => { }); }; + // 弹窗关键字处理 const modalHandle = (modalType: string, record?: tableDataType) => { modalTitle.value = modalType; openModal.value = true; + // 重新创建 createState 和 updateState 以重置为初始状态 + Object.assign(createState, { + name: '', + order: 1, + available: true, + parent_id: undefined, + description: '' + }); + + Object.assign(updateState, { + id: undefined, + name: '', + order: 1, + available: true, + parent_id: undefined, + description: '' + }); + if (modalType === 'view' && record !== undefined) { detailStateLoading.value = true; detailState.value = record @@ -478,6 +497,7 @@ const handleModalSumbit = () => { loadingData(); }).catch(error => { console.error(error); + modalSubmitLoading.value = false; }); }).catch(error => { modalSubmitLoading.value = false; diff --git a/frontend/src/views/system/menu/index.vue b/frontend/src/views/system/menu/index.vue index 6fd26350..acfe6a58 100644 --- a/frontend/src/views/system/menu/index.vue +++ b/frontend/src/views/system/menu/index.vue @@ -550,6 +550,42 @@ const modalHandle = (modalType: string, record?: tableDataType) => { modalTitle.value = modalType; openModal.value = true; + // 重新创建 createState 和 updateState 以重置为初始状态 + Object.assign(createState, { + name: '', + type: 1, + icon: '', + order: 1, + permission: '', + route_name: '', + route_path: '', + component_path: '', + redirect: '', + parent_id: undefined, + cache: true, + hidden: false, + available: true, + description: '' + }); + + Object.assign(updateState, { + id: undefined, + name: '', + type: 1, + icon: '', + order: 1, + permission: '', + route_name: '', + route_path: '', + component_path: '', + redirect: '', + parent_id: undefined, + cache: true, + hidden: false, + available: true, + description: '' + }); + if (modalType === 'view' && record !== undefined) { detailStateLoading.value = true; detailState.value = record; diff --git a/frontend/src/views/system/notice/index.vue b/frontend/src/views/system/notice/index.vue index 45a6848b..557b5ecb 100644 --- a/frontend/src/views/system/notice/index.vue +++ b/frontend/src/views/system/notice/index.vue @@ -380,6 +380,24 @@ const modalHandle = (modalType: string, index?: number) => { modalTitle.value = modalType; openModal.value = true; + // 重新创建 createState 和 updateState 以重置为初始状态 + Object.assign(createState, { + notice_title: '', + notice_type: 1, + notice_content: '', + available: true, + description: '' + }); + + Object.assign(updateState, { + id: undefined, + notice_title: '', + notice_type: 1, + notice_content: '', + available: true, + description: '' + }); + if (modalType === 'view' && index !== undefined) { detailStateLoading.value = true; diff --git a/frontend/src/views/system/position/index.vue b/frontend/src/views/system/position/index.vue index f8da6c8e..1a78aa4f 100644 --- a/frontend/src/views/system/position/index.vue +++ b/frontend/src/views/system/position/index.vue @@ -348,6 +348,22 @@ const modalHandle = (modalType: string, index?: number) => { modalTitle.value = modalType; openModal.value = true; + // 重新创建 createState 和 updateState 以重置为初始状态 + Object.assign(createState, { + name: '', + order: 1, + available: true, + description: '' + }); + + Object.assign(updateState, { + id: undefined, + name: '', + order: 1, + available: true, + description: '' + }); + if (modalType === 'view' && index !== undefined) { detailStateLoading.value = true; diff --git a/frontend/src/views/system/role/index.vue b/frontend/src/views/system/role/index.vue index af6ca7f3..e85a1f71 100644 --- a/frontend/src/views/system/role/index.vue +++ b/frontend/src/views/system/role/index.vue @@ -408,6 +408,22 @@ const modalHandle = (modalType: string, index?: number) => { modalTitle.value = modalType; openModal.value = true; + // 重新创建 createState 和 updateState 以重置为初始状态 + Object.assign(createState, { + name: '', + order: 1, + available: true, + description: '' + }); + + Object.assign(updateState, { + id: undefined, + name: '', + order: 1, + available: true, + description: '' + }); + if (modalType === 'view' && index !== undefined) { detailStateLoading.value = true; diff --git a/frontend/src/views/system/user/index.vue b/frontend/src/views/system/user/index.vue index 191f6a24..e6adfd6a 100644 --- a/frontend/src/views/system/user/index.vue +++ b/frontend/src/views/system/user/index.vue @@ -639,6 +639,44 @@ const modalHandle = (modalType: string, index?: number) => { modalTitle.value = modalType; openModal.value = true; + // 重新创建 createState 和 updateState 以重置为初始状态 + Object.assign(createState, { + username: '', + name: '', + dept_id: undefined, + dept_name: '', + role_ids: undefined, + roleNames: undefined, + position_ids: undefined, + positionNames: undefined, + password: '', + gender: undefined, + email: '', + mobile: '', + is_superuser: false, + available: true, + description: '' + }); + + Object.assign(updateState, { + id: undefined, + username: '', + name: '', + dept_id: undefined, + dept_name: '', + role_ids: [], + roleNames: undefined, + position_ids: [], + positionNames: undefined, + password: '', + gender: undefined, + email: '', + mobile: '', + is_superuser: false, + available: true, + description: '', + }); + if (modalType === 'view' && index !== undefined) { detailStateLoading.value = true;