fix(system): 优化部门、菜单、公告、岗位、角色和用户管理功能

- 增加创建、更新和删除操作的异常处理
- 优化错误提示信息
- 重置表单状态以解决数据残留问题
- 统一错误处理方式,使用 message 组件替代 notification
This commit is contained in:
zhangtao
2025-03-06 22:25:41 +08:00
parent a6b6ed7e0c
commit 0b4ce5f396
14 changed files with 221 additions and 28 deletions
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
Binary file not shown.
+10 -27
View File
@@ -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);
+20
View File
@@ -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;
+36
View File
@@ -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;
@@ -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;
@@ -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;
+16
View File
@@ -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;
+38
View File
@@ -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;