diff --git a/api/login.py b/api/login.py index 3c2c3ff..380c6f7 100644 --- a/api/login.py +++ b/api/login.py @@ -223,10 +223,11 @@ async def info( @loginAPI.get("/getRoutes", response_class=JSONResponse, summary="获取路由信息") # @Log(title="获取路由信息", business_type=BusinessType.SELECT) async def get_routes(request: Request, current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") routes = await request.app.state.redis.get(f'{RedisKeyConfig.USER_ROUTES.key}:{current_user["id"]}') if routes: return Response.success(data=eval(routes)) - routes = await LoginController.get_user_routes(current_user["id"]) + routes = await LoginController.get_user_routes(current_user["id"], sub_departments=sub_departments) userRoutes = str(jsonable_encoder(routes)) await request.app.state.redis.set( f'{RedisKeyConfig.USER_ROUTES.key}:{current_user["id"]}', diff --git a/api/role.py b/api/role.py index a64a4f8..7bf961b 100644 --- a/api/role.py +++ b/api/role.py @@ -11,7 +11,7 @@ from fastapi import APIRouter, Depends, Path, Query, Request from fastapi.responses import JSONResponse from annotation.log import Log -from config.constant import BusinessType +from config.constant import BusinessType, RedisKeyConfig from controller.login import LoginController from models import Role, Permission, RolePermission, Department from schemas.common import BaseResponse @@ -243,6 +243,7 @@ async def add_role_permission(request: Request, params: AddRolePermissionParams, role_id=role.id, permission_id=permission.id ) + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:*') return Response.success(msg="新增角色权限成功!") return Response.error(msg="新增角色权限失败!") diff --git a/api/user.py b/api/user.py index ef84923..8bb1cc9 100644 --- a/api/user.py +++ b/api/user.py @@ -5,9 +5,8 @@ # @File : user.py # @Software : PyCharm # @Comment : 本程序 -import calendar import os -from datetime import datetime, timedelta +from datetime import datetime from typing import Optional from fastapi import APIRouter, Depends, Path, Query, UploadFile, File, Request @@ -15,32 +14,34 @@ from fastapi.responses import JSONResponse from annotation.auth import Auth from annotation.log import Log -from config.constant import BusinessType +from config.constant import BusinessType, RedisKeyConfig from config.env import UploadConfig from controller.login import LoginController from controller.query import QueryController from exceptions.exception import ModelValidatorException from models import File as FileModel -from models import Role, Department, QueryCode +from models import Role, Department from models.user import User, UserRole from schemas.common import BaseResponse from schemas.department import GetDepartmentListResponse from schemas.file import UploadFileResponse from schemas.user import AddUserParams, GetUserListResponse, GetUserInfoResponse, UpdateUserParams, \ AddUserRoleParams, GetUserRoleInfoResponse, UpdateUserRoleParams, GetUserPermissionListResponse, \ - ResetPasswordParams, GetUserStatisticsResponse + ResetPasswordParams from utils.common import filterKeyValues from utils.password import Password from utils.response import Response -userAPI = APIRouter(prefix="/user", dependencies=[Depends(LoginController.get_current_user)]) +userAPI = APIRouter(prefix="/user") @userAPI.post("/add", response_class=JSONResponse, response_model=BaseResponse, summary="新增用户") @Log(title="新增用户", business_type=BusinessType.INSERT) +@Auth(["user:btn:addUser"]) async def add_user( request: Request, - params: AddUserParams + params: AddUserParams, + current_user: dict = Depends(LoginController.get_current_user) ): if await QueryController.register_user_before(username=params.username, phone=params.phone, email=params.email): return Response.error(msg="添加失败,用户已存在!") @@ -65,10 +66,14 @@ async def add_user( @userAPI.delete("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除用户") @userAPI.post("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除用户") @Log(title="删除用户", business_type=BusinessType.DELETE) +@Auth(["user:btn:deleteUser"]) async def delete_user( request: Request, - id: str = Path(..., description="用户ID")): - if user := await User.get_or_none(id=id): + id: str = Path(..., description="用户ID"), + current_user: dict = Depends(LoginController.get_current_user) +): + sub_departments = current_user.get("sub_departments") + if user := await User.get_or_none(id=id, department__id__in=sub_departments): await user.delete() return Response.success(msg="删除成功!") else: @@ -78,11 +83,15 @@ async def delete_user( @userAPI.put("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="更新用户") @userAPI.post("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="更新用户") @Log(title="更新用户", business_type=BusinessType.UPDATE) +@Auth(["user:btn:updateUser"]) async def update_user( request: Request, params: UpdateUserParams, - id: str = Path(..., description="用户ID")): - if user := await User.get_or_none(id=id): + id: str = Path(..., description="用户ID"), + current_user: dict = Depends(LoginController.get_current_user) +): + sub_departments = current_user.get("sub_departments") + if user := await User.get_or_none(id=id, department__id__in=sub_departments): user.username = params.username user.nickname = params.nickname user.phone = params.phone @@ -94,6 +103,8 @@ async def update_user( else: user.department = None await user.save() + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{id}') return Response.success(msg="更新成功!") else: return Response.error(msg="更新失败,用户不存在!") @@ -101,7 +112,9 @@ async def update_user( @userAPI.get("/info/{id}", response_class=JSONResponse, response_model=GetUserInfoResponse, summary="获取用户信息") @Log(title="获取用户信息", business_type=BusinessType.SELECT) -async def get_user_info(request: Request, id: str = Path(..., description="用户ID")): +@Auth(["user:btn:Userinfo"]) +async def get_user_info(request: Request, id: str = Path(..., description="用户ID"), + current_user: dict = Depends(LoginController.get_current_user)): if user := await User.get_or_none(id=id): user = await user.first().values( id="id", @@ -113,6 +126,7 @@ async def get_user_info(request: Request, id: str = Path(..., description="用 nickname="nickname", gender="gender", status="status", + avatar="avatar", department_id="department__id", ) return Response.success(data=user) @@ -134,7 +148,9 @@ async def get_user_list( gender: Optional[str] = Query(default=None, description="性别"), status: Optional[str] = Query(default=None, description="状态"), department_id: Optional[str] = Query(default=None, description="部门ID"), + current_user: dict = Depends(LoginController.get_current_user) ): + sub_departments = current_user.get("sub_departments") filterArgs = { f'{k}__contains': v for k, v in { 'username': username, @@ -146,6 +162,8 @@ async def get_user_list( 'department_id': department_id }.items() if v } + if not department_id: + filterArgs['department_id__in'] = sub_departments total = await User.filter(**filterArgs).count() result = await User.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).values( id="id", @@ -155,6 +173,7 @@ async def get_user_list( email="email", phone="phone", nickname="nickname", + avatar="avatar", gender="gender", status="status", department_id="department__id", @@ -168,13 +187,19 @@ async def get_user_list( @userAPI.post("/addRole", response_model=BaseResponse, response_class=JSONResponse, summary="添加用户角色") @Log(title="添加用户角色", business_type=BusinessType.INSERT) -async def add_user_role(request: Request, params: AddUserRoleParams): - if await UserRole.get_or_none(user_id=params.user_id, role_id=params.role_id, del_flag=1): +@Auth(["user:btn:addRole"]) +async def add_user_role(request: Request, params: AddUserRoleParams, + current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") + if await UserRole.get_or_none(user_id=params.user_id, role_id=params.role_id, del_flag=1, + user__department__id__in=sub_departments): return Response.error(msg="该用户已存在该角色!") - if user := await User.get_or_none(id=params.user_id, del_flag=1): - if role := await Role.get_or_none(id=params.role_id, del_flag=1): + if user := await User.get_or_none(id=params.user_id, del_flag=1, department__id__in=sub_departments): + if role := await Role.get_or_none(id=params.role_id, del_flag=1, department__id__in=sub_departments): userRole = await UserRole.create(user_id=user.id, role_id=role.id) if userRole: + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{user.id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{user.id}') return Response.success(msg="添加成功!") else: return Response.error(msg="添加失败!") @@ -189,9 +214,14 @@ async def add_user_role(request: Request, params: AddUserRoleParams): @userAPI.post("/deleteRole/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除用户角色") @Log(title="删除用户角色", business_type=BusinessType.DELETE) -async def delete_user_role(request: Request, id: str = Path(description="用户角色ID")): - if userRole := await UserRole.get_or_none(id=id, del_flag=1): +@Auth(["user:btn:deleteRole"]) +async def delete_user_role(request: Request, id: str = Path(description="用户角色ID"), + current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") + if userRole := await UserRole.get_or_none(id=id, del_flag=1, user__department__id__in=sub_departments): await userRole.delete() + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{current_user.get("id")}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{current_user.get("id")}') return Response.success(msg="删除成功!") else: return Response.error(msg="删除失败,用户角色不存在!") @@ -201,9 +231,13 @@ async def delete_user_role(request: Request, id: str = Path(description="用户 @userAPI.post("/updateRole", response_model=BaseResponse, response_class=JSONResponse, summary="修改用户角色") @Log(title="修改用户角色", business_type=BusinessType.UPDATE) -async def update_user_role(request: Request, params: UpdateUserRoleParams): +@Auth(["user:btn:updateRole"]) +async def update_user_role(request: Request, params: UpdateUserRoleParams, + current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") # 获取用户已有角色 - userRoles = await UserRole.filter(user_id=params.user_id, del_flag=1).values("role_id") + userRoles = await UserRole.filter(user_id=params.user_id, del_flag=1, + user__department__id__in=sub_departments).values("role_id") userRoles = await filterKeyValues(userRoles, "role_id") # 利用集合找到需要添加的角色 addRoles = set(params.role_ids).difference(set(userRoles)) @@ -211,20 +245,26 @@ async def update_user_role(request: Request, params: UpdateUserRoleParams): deleteRoles = set(userRoles).difference(set(params.role_ids)) # 添加角色 for role_id in addRoles: - if role := await Role.get_or_none(id=role_id, del_flag=1): + if role := await Role.get_or_none(id=role_id, del_flag=1, department__id__in=sub_departments): await UserRole.create(user_id=params.user_id, role_id=role.id) # 删除角色 for role_id in deleteRoles: - if userRole := await UserRole.get_or_none(user_id=params.user_id, role_id=role_id, del_flag=1): + if userRole := await UserRole.get_or_none(user_id=params.user_id, role_id=role_id, del_flag=1, + user__department__id__in=sub_departments): await userRole.delete() + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{params.user_id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{params.user_id}') return Response.success(msg="修改成功!") @userAPI.get("/roleInfo/{id}", response_model=GetUserRoleInfoResponse, response_class=JSONResponse, summary="获取用户角色信息") @Log(title="获取用户角色信息", business_type=BusinessType.SELECT) -async def get_user_role_info(request: Request, id: str = Path(description="用户角色ID")): - if userRole := await UserRole.get_or_none(id=id, del_flag=1): +@Auth(["user:btn:roleInfo"]) +async def get_user_role_info(request: Request, id: str = Path(description="用户角色ID"), + current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") + if userRole := await UserRole.get_or_none(id=id, del_flag=1, user__department__id__in=sub_departments): data = await userRole.first().values( id="id", user_id="user__id", @@ -243,11 +283,14 @@ async def get_user_role_info(request: Request, id: str = Path(description="用 @userAPI.get("/roleList/{id}", response_model=GetDepartmentListResponse, response_class=JSONResponse, summary="获取用户角色列表") @Log(title="获取用户角色列表", business_type=BusinessType.SELECT) +@Auth(["user:btn:roleList"]) async def get_user_role_list( request: Request, id: str = Path(description="用户ID"), + current_user: dict = Depends(LoginController.get_current_user) ): - result = await UserRole.filter(user_id=id).values( + sub_departments = current_user.get("sub_departments") + result = await UserRole.filter(user_id=id, del_flag=1, user__department__id__in=sub_departments).values( id="id", department_id="user__department__id", department_name="user__department__name", @@ -270,8 +313,11 @@ async def get_user_role_list( @userAPI.get("/permissionList/{id}", response_class=JSONResponse, response_model=GetUserPermissionListResponse, summary="获取用户权限列表") @Log(title="获取用户权限列表", business_type=BusinessType.SELECT) -async def get_user_permission_list(request: Request, id: str = Path(description="用户ID")): - permissions = await QueryController.get_user_permissions(user_id=id) +@Auth(["user:btn:permissionList"]) +async def get_user_permission_list(request: Request, id: str = Path(description="用户ID"), + current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") + permissions = await QueryController.get_user_permissions(user_id=id, sub_departments=sub_departments) permissions = await filterKeyValues(permissions, "id") # 获取用户角色 return Response.success(data=list(set(permissions))) @@ -279,11 +325,13 @@ async def get_user_permission_list(request: Request, id: str = Path(description= @userAPI.post("/avatar/{id}", response_model=UploadFileResponse, response_class=JSONResponse, summary="上传用户头像") @Log(title="上传用户头像", business_type=BusinessType.UPDATE) +@Auth(["user:btn:uploadAvatar"]) async def upload_user_avatar( request: Request, id: str = Path(description="用户ID"), - file: UploadFile = File(...)): - if user := await User.get_or_none(id=id): + file: UploadFile = File(...), current_user: dict = Depends(LoginController.get_current_user)): + sub_departments = current_user.get("sub_departments") + if user := await User.get_or_none(id=id, department__id__in=sub_departments): image_mimetypes = [ 'image/jpeg', 'image/png', @@ -335,6 +383,8 @@ async def upload_user_avatar( create_time="create_time", update_time="update_time", ) + if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:{user.id}'): + await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:{user.id}') return Response.success(data=result) return Response.failure(msg="用户不存在!") @@ -343,105 +393,10 @@ async def upload_user_avatar( @userAPI.post("/resetPassword/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="重置用户密码") @Log(title="重置用户密码", business_type=BusinessType.UPDATE) @Auth(permission_list=["user:btn:reset_password"]) -async def reset_user_password(request: Request, params: ResetPasswordParams, id: str = Path(description="用户ID")): - if user := await User.get_or_none(id=id): +async def reset_user_password(request: Request, params: ResetPasswordParams, id: str = Path(description="用户ID"), + current_user: dict = Depends(LoginController.get_current_user)): + if user := await User.get_or_none(id=id, department__id__in=current_user.get("sub_departments")): user.password = await Password.get_password_hash(params.password) await user.save() return Response.success(msg="重置密码成功!") return Response.failure(msg="用户不存在!") - - -@userAPI.get("/statistics", response_model=GetUserStatisticsResponse, response_class=JSONResponse, - summary="获取用户查询统计") -@Log(title="获取用户查询统计", business_type=BusinessType.SELECT) -async def get_user_statistics(request: Request, current_user: dict = Depends(LoginController.get_current_user)): - user_id = current_user.get("id") - # 获取当前时间 - now = datetime.now() - - # 今日开始时间 - today_start_time = now.replace(hour=0, minute=0, second=0, microsecond=0) - - # 今日结束时间 - today_end_time = now.replace(hour=23, minute=59, second=59, microsecond=999999) - - # 当月开始时间 - this_month_start_time = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0) - - # 计算当月的最后一天 - this_month_last_day = calendar.monthrange(now.year, now.month)[1] - - # 当月结束时间 - this_month_end_time = now.replace( - day=this_month_last_day, hour=23, minute=59, second=59, microsecond=999999 - ) - - # 计算上个月的年和月 - if now.month == 1: # 处理1月(上月是去年的12月) - last_month_year = now.year - 1 - last_month = 12 - else: - last_month_year = now.year - last_month = now.month - 1 - - # 上月开始时间 - last_month_start_time = datetime(last_month_year, last_month, 1, 0, 0, 0, 0) - - # 计算上个月最后一天 - last_month_last_day = calendar.monthrange(last_month_year, last_month)[1] - - # 上月结束时间 - last_month_end_time = datetime(last_month_year, last_month, last_month_last_day, 23, 59, 59, 999999) - - # 计算今日查询数量 - today_count = await QueryCode.filter(create_time__gte=today_start_time, create_time__lte=today_end_time, - session__operator__id=user_id).count() - # 计算当月查询数量 - this_month_count = await QueryCode.filter(create_time__gte=this_month_start_time, - create_time__lte=this_month_end_time, - session__operator__id=user_id).count() - # 计算上月查询数量 - last_month_count = await QueryCode.filter(create_time__gte=last_month_start_time, - create_time__lte=last_month_end_time, - session__operator__id=user_id).count() - - async def get_last_14_days_count(status: int = 1): - today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) - - # 保存结果的列表 - result = [] - - # 遍历最近7天(包括今天) - for i in range(14): - day = today - timedelta(days=i) - - # 当天的开始时间和结束时间 - day_start = day # 00:00:00 - day_end = (day + timedelta(days=1)) # 23:59:59 - - # 统计当天查询数量 - count = await QueryCode.filter( - create_time__gte=day_start, - create_time__lte=day_end, - session__operator__id=user_id, - status=status - ).count() - - # 添加到结果列表(格式化日期为 YYYY-MM-DD) - result.append({"date": day.strftime("%Y-%m-%d"), "count": count}) - - # 结果按日期升序排列(可选,确保从过去到现在排序) - result.sort(key=lambda x: x["date"]) - return result - - # 过去14天内的查询数量 - before_14day_count_success = await get_last_14_days_count(1) - before_14day_count_fail = await get_last_14_days_count(0) - - return Response.success(data={ - "today_count": today_count, - "this_month_count": this_month_count, - "last_month_count": last_month_count, - "before_14day_count_success": before_14day_count_success, - "before_14day_count_fail": before_14day_count_fail, - }) diff --git a/controller/login.py b/controller/login.py index f86983a..7810f07 100644 --- a/controller/login.py +++ b/controller/login.py @@ -160,11 +160,11 @@ class LoginController: return False @classmethod - async def get_user_routes(cls, user_id: str) -> Union[list, None]: + async def get_user_routes(cls, user_id: str, sub_departments: list) -> Union[list, None]: """ 获取用户路由 """ - permissions = await QueryController.get_user_permissions(user_id=user_id) + permissions = await QueryController.get_user_permissions(user_id=user_id, sub_departments=sub_departments) for permission in permissions: permission["id"] = str(permission["id"]) permission["parentId"] = str(permission["parentId"]) if permission.get("parentId") else "" diff --git a/controller/query.py b/controller/query.py index 10c7960..dd160f9 100644 --- a/controller/query.py +++ b/controller/query.py @@ -8,8 +8,8 @@ from typing import Union from tortoise.expressions import Q - -from models import User, UserRole, RolePermission +from fastapi import Request +from models import User, UserRole, RolePermission, Department from utils.common import filterKeyValues @@ -65,6 +65,8 @@ class QueryController: userRole = await filterKeyValues(userRoles, "role_code") # 获取用户角色ID userRoleIds = await filterKeyValues(userRoles, "role_id") + # 获取用户下属部门 + subDepartments = await cls.get_sub_department_ids(department_id=userInfo['department_id']) # 根据用户角色ID获取用户权限 permissions = [] for item in userRoleIds: @@ -78,6 +80,7 @@ class QueryController: permissions = list(set(permissions)) userInfo["roles"] = userRole userInfo["permissions"] = permissions + userInfo["sub_departments"] = subDepartments return userInfo @classmethod @@ -92,12 +95,12 @@ class QueryController: return await User.get_or_none(Q(username=username) | Q(email=email) | Q(phone=phone), del_flag=1) @classmethod - async def get_user_permissions(cls, user_id: str) -> Union[list, None]: + async def get_user_permissions(cls, user_id: str,sub_departments: list = []) -> Union[list, None]: """ 获取用户权限 """ # 获取用户角色 - userRoles = await UserRole.filter(user_id=user_id, del_flag=1).values( + userRoles = await UserRole.filter(user_id=user_id, del_flag=1, user__department__id__in=sub_departments).values( role_id="role__id", role_name="role__name", role_code="role__code" @@ -133,3 +136,16 @@ class QueryController: ) permissions.extend(permission) return permissions + + @classmethod + async def get_sub_department_ids(cls, department_id: str) -> list: + # 递归获取指定部门及其所有下属部门的 ID + async def fetch_sub_deps(dep_id: str): + sub_deps = await Department.filter(parent_id=dep_id).all() + sub_deps_list = [dep.id for dep in sub_deps] + for sub_dep in sub_deps: + sub_deps_list.extend(await fetch_sub_deps(sub_dep.id)) # 递归获取下属部门 + return sub_deps_list + dataList = await fetch_sub_deps(department_id) + dataList.append(department_id) + return list(set(dataList))