mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-21 20:55:14 +00:00
fix(system): 优化部门、菜单、公告、岗位、角色和用户管理功能
- 增加创建、更新和删除操作的异常处理 - 优化错误提示信息 - 重置表单状态以解决数据残留问题 - 统一错误处理方式,使用 message 组件替代 notification
This commit is contained in:
@@ -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.
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user