diff --git a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py index fe927c7..03416b7 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py @@ -1,22 +1,35 @@ -from fastapi import APIRouter, Request -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, CurrentUserModel -from module_admin.service.dept_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * +from module_admin.aspect.data_scope import GetDataScope +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel, DeptQueryModel +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.dept_service import DeptService +from module_admin.service.login_service import LoginService +from utils.log_util import logger +from utils.response_util import ResponseUtil deptController = APIRouter(prefix='/system/dept', dependencies=[Depends(LoginService.get_current_user)]) -@deptController.get("/list/exclude/{dept_id}", response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))]) -async def get_system_dept_tree_for_edit_option(request: Request, dept_id: int, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +@deptController.get( + '/list/exclude/{dept_id}', + response_model=List[DeptModel], + dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))], +) +async def get_system_dept_tree_for_edit_option( + request: Request, + dept_id: int, + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): dept_query = DeptModel(deptId=dept_id) dept_query_result = await DeptService.get_dept_for_edit_option_services(query_db, dept_query, data_scope_sql) logger.info('获取成功') @@ -24,18 +37,30 @@ async def get_system_dept_tree_for_edit_option(request: Request, dept_id: int, q return ResponseUtil.success(data=dept_query_result) -@deptController.get("/list", response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))]) -async def get_system_dept_list(request: Request, dept_query: DeptQueryModel = Depends(DeptQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +@deptController.get( + '/list', response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))] +) +async def get_system_dept_list( + request: Request, + dept_query: DeptQueryModel = Depends(DeptQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): dept_query_result = await DeptService.get_dept_list_services(query_db, dept_query, data_scope_sql) logger.info('获取成功') return ResponseUtil.success(data=dept_query_result) -@deptController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) +@deptController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) @ValidateFields(validate_model='add_dept') @log_decorator(title='部门管理', business_type=BusinessType.INSERT) -async def add_system_dept(request: Request, add_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_dept( + request: Request, + add_dept: DeptModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_dept.create_by = current_user.user.user_name add_dept.create_time = datetime.now() add_dept.update_by = current_user.user.user_name @@ -46,10 +71,16 @@ async def add_system_dept(request: Request, add_dept: DeptModel, query_db: Async return ResponseUtil.success(data=add_dept_result) -@deptController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) +@deptController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) @ValidateFields(validate_model='edit_dept') @log_decorator(title='部门管理', business_type=BusinessType.UPDATE) -async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def edit_system_dept( + request: Request, + edit_dept: DeptModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): if not current_user.user.admin: await DeptService.check_dept_data_scope_services(query_db, edit_dept.dept_id, data_scope_sql) edit_dept.update_by = current_user.user.user_name @@ -60,9 +91,15 @@ async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: Asy return ResponseUtil.success(msg=edit_dept_result.message) -@deptController.delete("/{dept_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) +@deptController.delete('/{dept_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) @log_decorator(title='部门管理', business_type=BusinessType.DELETE) -async def delete_system_dept(request: Request, dept_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def delete_system_dept( + request: Request, + dept_ids: str, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): dept_id_list = dept_ids.split(',') for dept_id in dept_id_list: if not current_user.user.admin: @@ -76,8 +113,16 @@ async def delete_system_dept(request: Request, dept_ids: str, query_db: AsyncSes return ResponseUtil.success(msg=delete_dept_result.message) -@deptController.get("/{dept_id}", response_model=DeptModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dept:query'))]) -async def query_detail_system_dept(request: Request, dept_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +@deptController.get( + '/{dept_id}', response_model=DeptModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dept:query'))] +) +async def query_detail_system_dept( + request: Request, + dept_id: int, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): if not current_user.user.admin: await DeptService.check_dept_data_scope_services(query_db, dept_id, data_scope_sql) detail_dept_result = await DeptService.dept_detail_services(query_db, dept_id) diff --git a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py index 7dfc8a1..cfd7c2e 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py @@ -1,10 +1,11 @@ -from sqlalchemy import select, update, delete, or_, func, bindparam +from sqlalchemy import bindparam, func, or_, select, update # noqa: F401 from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.util import immutabledict +from typing import List from module_admin.entity.do.dept_do import SysDept +from module_admin.entity.do.role_do import SysRoleDept # noqa: F401 from module_admin.entity.do.user_do import SysUser -from module_admin.entity.do.role_do import SysRoleDept -from module_admin.entity.vo.dept_vo import * +from module_admin.entity.vo.dept_vo import DeptModel class DeptDao: @@ -20,10 +21,7 @@ class DeptDao: :param dept_id: 部门id :return: 在用部门信息对象 """ - dept_info = (await db.execute( - select(SysDept) - .where(SysDept.dept_id == dept_id) - )).scalars().first() + dept_info = (await db.execute(select(SysDept).where(SysDept.dept_id == dept_id))).scalars().first() return dept_info @@ -35,11 +33,11 @@ class DeptDao: :param dept_id: 部门id :return: 部门信息对象 """ - dept_info = (await db.execute( - select(SysDept) - .where(SysDept.dept_id == dept_id, - SysDept.del_flag == '0') - )).scalars().first() + dept_info = ( + (await db.execute(select(SysDept).where(SysDept.dept_id == dept_id, SysDept.del_flag == '0'))) + .scalars() + .first() + ) return dept_info @@ -51,11 +49,18 @@ class DeptDao: :param dept: 部门参数对象 :return: 部门信息对象 """ - dept_info = (await db.execute( - select(SysDept) - .where(SysDept.parent_id == dept.parent_id if dept.parent_id else True, - SysDept.dept_name == dept.dept_name if dept.dept_name else True) - )).scalars().first() + dept_info = ( + ( + await db.execute( + select(SysDept).where( + SysDept.parent_id == dept.parent_id if dept.parent_id else True, + SysDept.dept_name == dept.dept_name if dept.dept_name else True, + ) + ) + ) + .scalars() + .first() + ) return dept_info @@ -68,15 +73,26 @@ class DeptDao: :param data_scope_sql: 数据权限对应的查询sql语句 :return: 部门列表信息 """ - dept_result = (await db.execute( - select(SysDept) - .where(SysDept.dept_id != dept_info.dept_id, - ~SysDept.dept_id.in_(select(SysDept.dept_id).where(func.find_in_set(dept_info.dept_id, SysDept.ancestors))), - SysDept.del_flag == '0', SysDept.status == '0', - eval(data_scope_sql)) - .order_by(SysDept.order_num) - .distinct() - )).scalars().all() + dept_result = ( + ( + await db.execute( + select(SysDept) + .where( + SysDept.dept_id != dept_info.dept_id, + ~SysDept.dept_id.in_( + select(SysDept.dept_id).where(func.find_in_set(dept_info.dept_id, SysDept.ancestors)) + ), + SysDept.del_flag == '0', + SysDept.status == '0', + eval(data_scope_sql), + ) + .order_by(SysDept.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return dept_result @@ -88,10 +104,9 @@ class DeptDao: :param dept_id: 部门id :return: 子部门信息列表 """ - dept_result = (await db.execute( - select(SysDept) - .where(func.find_in_set(dept_id, SysDept.ancestors)) - )).scalars().all() + dept_result = ( + (await db.execute(select(SysDept).where(func.find_in_set(dept_id, SysDept.ancestors)))).scalars().all() + ) return dept_result @@ -104,15 +119,23 @@ class DeptDao: :param data_scope_sql: 数据权限对应的查询sql语句 :return: 在用部门列表信息 """ - dept_result = (await db.execute( - select(SysDept) - .where(SysDept.status == '0', - SysDept.del_flag == '0', - SysDept.dept_name.like(f'%{dept_info.dept_name}%') if dept_info.dept_name else True, - eval(data_scope_sql)) - .order_by(SysDept.order_num) - .distinct() - )).scalars().all() + dept_result = ( + ( + await db.execute( + select(SysDept) + .where( + SysDept.status == '0', + SysDept.del_flag == '0', + SysDept.dept_name.like(f'%{dept_info.dept_name}%') if dept_info.dept_name else True, + eval(data_scope_sql), + ) + .order_by(SysDept.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return dept_result @@ -125,15 +148,23 @@ class DeptDao: :param data_scope_sql: 数据权限对应的查询sql语句 :return: 部门列表信息对象 """ - dept_result = (await db.execute( - select(SysDept) - .where(SysDept.del_flag == '0', - SysDept.status == page_object.status if page_object.status else True, - SysDept.dept_name.like(f'%{page_object.dept_name}%') if page_object.dept_name else True, - eval(data_scope_sql)) - .order_by(SysDept.order_num) - .distinct() - )).scalars().all() + dept_result = ( + ( + await db.execute( + select(SysDept) + .where( + SysDept.del_flag == '0', + SysDept.status == page_object.status if page_object.status else True, + SysDept.dept_name.like(f'%{page_object.dept_name}%') if page_object.dept_name else True, + eval(data_scope_sql), + ) + .order_by(SysDept.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return dept_result @@ -159,10 +190,7 @@ class DeptDao: :param dept: 需要更新的部门字典 :return: 编辑校验结果 """ - await db.execute( - update(SysDept), - [dept] - ) + await db.execute(update(SysDept), [dept]) @classmethod async def update_dept_children_dao(cls, db: AsyncSession, update_dept: List): @@ -174,17 +202,15 @@ class DeptDao: """ await db.execute( update(SysDept) - .where(SysDept.dept_id == bindparam('dept_id')) - .values( + .where(SysDept.dept_id == bindparam('dept_id')) + .values( { 'dept_id': bindparam('dept_id'), 'ancestors': bindparam('ancestors'), } ), update_dept, - execution_options=immutabledict( - {"synchronize_session": None} - ) + execution_options=immutabledict({'synchronize_session': None}), ) @classmethod @@ -195,11 +221,7 @@ class DeptDao: :param dept_id_list: 部门id列表 :return: """ - await db.execute( - update(SysDept) - .where(SysDept.dept_id.in_(dept_id_list)) - .values(status='0') - ) + await db.execute(update(SysDept).where(SysDept.dept_id.in_(dept_id_list)).values(status='0')) @classmethod async def delete_dept_dao(cls, db: AsyncSession, dept: DeptModel): @@ -211,8 +233,8 @@ class DeptDao: """ await db.execute( update(SysDept) - .where(SysDept.dept_id == dept.dept_id) - .values(del_flag='2', update_by=dept.update_by, update_time=dept.update_time) + .where(SysDept.dept_id == dept.dept_id) + .values(del_flag='2', update_by=dept.update_by, update_time=dept.update_time) ) @classmethod @@ -223,15 +245,13 @@ class DeptDao: :param dept_id: 部门id :return: 所有子部门(正常状态)的数量 """ - normal_children_dept_count = (await db.execute( - select(func.count('*')) + normal_children_dept_count = ( + await db.execute( + select(func.count('*')) .select_from(SysDept) - .where( - SysDept.status == '0', - SysDept.del_flag == '0', - func.find_in_set(dept_id, SysDept.ancestors) + .where(SysDept.status == '0', SysDept.del_flag == '0', func.find_in_set(dept_id, SysDept.ancestors)) ) - )).scalar() + ).scalar() return normal_children_dept_count @@ -243,13 +263,14 @@ class DeptDao: :param dept_id: 部门id :return: 所有子部门(所有状态)的数量 """ - children_dept_count = (await db.execute( - select(func.count('*')) + children_dept_count = ( + await db.execute( + select(func.count('*')) .select_from(SysDept) - .where(SysDept.del_flag == '0', - SysDept.parent_id == dept_id) + .where(SysDept.del_flag == '0', SysDept.parent_id == dept_id) .limit(1) - )).scalar() + ) + ).scalar() return children_dept_count @@ -261,10 +282,10 @@ class DeptDao: :param dept_id: 部门id :return: 部门下的用户数量 """ - dept_user_count = (await db.execute( - select(func.count('*')) - .select_from(SysUser) - .where(SysUser.dept_id == dept_id, SysUser.del_flag == '0') - )).scalar() + dept_user_count = ( + await db.execute( + select(func.count('*')).select_from(SysUser).where(SysUser.dept_id == dept_id, SysUser.del_flag == '0') + ) + ).scalar() return dept_user_count diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py index 0572927..96ac8da 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysDept(Base): """ 部门表 """ + __tablename__ = 'sys_dept' dept_id = Column(Integer, primary_key=True, autoincrement=True, comment='部门id') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py index f91d820..dcad117 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py @@ -1,8 +1,8 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import Network, NotBlank, Size -from typing import Union, Optional, List, Literal -from datetime import datetime +from typing import Literal, Optional from module_admin.annotation.pydantic_annotation import as_query @@ -10,6 +10,7 @@ class DeptModel(BaseModel): """ 部门表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) dept_id: Optional[int] = Field(default=None, description='部门id') @@ -57,6 +58,7 @@ class DeptQueryModel(DeptModel): """ 部门管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -65,6 +67,7 @@ class DeleteDeptModel(BaseModel): """ 删除部门模型 """ + model_config = ConfigDict(alias_generator=to_camel) dept_ids: str = Field(default=None, description='需要删除的部门id') diff --git a/ruoyi-fastapi-backend/module_admin/service/dept_service.py b/ruoyi-fastapi-backend/module_admin/service/dept_service.py index 85685a2..3fe5208 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dept_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dept_service.py @@ -1,7 +1,9 @@ -from module_admin.dao.dept_dao import * -from module_admin.entity.vo.common_vo import CrudResponseModel +from sqlalchemy.ext.asyncio import AsyncSession from config.constant import CommonConstant from exceptions.exception import ServiceException, ServiceWarning +from module_admin.dao.dept_dao import DeptDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel from utils.common_util import CamelCaseUtil @@ -25,8 +27,9 @@ class DeptService: return dept_tree_result @classmethod - async def get_dept_for_edit_option_services(cls, query_db: AsyncSession, page_object: DeptModel, - data_scope_sql: str): + async def get_dept_for_edit_option_services( + cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str + ): """ 获取部门编辑部门树信息service :param query_db: orm对象 @@ -75,7 +78,9 @@ class DeptService: :return: 校验结果 """ dept_id = -1 if page_object.dept_id is None else page_object.dept_id - dept = await DeptDao.get_dept_detail_by_info(query_db, DeptModel(deptName=page_object.dept_name, parentId=page_object.parent_id)) + dept = await DeptDao.get_dept_detail_by_info( + query_db, DeptModel(deptName=page_object.dept_name, parentId=page_object.parent_id) + ) if dept and dept.dept_id != dept_id: return CommonConstant.NOT_UNIQUE return CommonConstant.UNIQUE @@ -114,7 +119,10 @@ class DeptService: raise ServiceException(message=f'修改部门{page_object.dept_name}失败,部门名称已存在') elif page_object.dept_id == page_object.parent_id: raise ServiceException(message=f'修改部门{page_object.dept_name}失败,上级部门不能是自己') - elif page_object.status == CommonConstant.DEPT_DISABLE and (await DeptDao.count_normal_children_dept_dao(query_db, page_object.dept_id)) > 0: + elif ( + page_object.status == CommonConstant.DEPT_DISABLE + and (await DeptDao.count_normal_children_dept_dao(query_db, page_object.dept_id)) > 0 + ): raise ServiceException(message=f'修改部门{page_object.dept_name}失败,该部门包含未停用的子部门') new_parent_dept = await DeptDao.get_dept_by_id(query_db, page_object.parent_id) old_dept = await DeptDao.get_dept_by_id(query_db, page_object.dept_id) @@ -126,7 +134,11 @@ class DeptService: await cls.update_dept_children(query_db, page_object.dept_id, new_ancestors, old_ancestors) edit_dept = page_object.model_dump(exclude_unset=True) await DeptDao.edit_dept_dao(query_db, edit_dept) - if page_object.status == CommonConstant.DEPT_NORMAL and page_object.ancestors and page_object.ancestors != 0: + if ( + page_object.status == CommonConstant.DEPT_NORMAL + and page_object.ancestors + and page_object.ancestors != 0 + ): await cls.update_parent_dept_status_normal(query_db, page_object) await query_db.commit() return CrudResponseModel(is_success=True, message='更新成功') @@ -183,8 +195,9 @@ class DeptService: :param permission_list: 部门列表信息 :return: 部门树形嵌套数据 """ - permission_list = [dict(id=item.dept_id, label=item.dept_name, parentId=item.parent_id) for item in - permission_list] + permission_list = [ + dict(id=item.dept_id, label=item.dept_name, parentId=item.parent_id) for item in permission_list + ] # 转成id为key的字典 mapping: dict = dict(zip([i['id'] for i in permission_list], permission_list))