import asyncio from datetime import datetime, timezone from fastapi.logger import logger from shared.constants import PAGE_SIZE from modules.system.role.schemas import RoleForm, RoleStatusForm from modules.system.role.models import Role from modules.system.role.repository import role_repo from core.database import get_db_session from core import R from core.security import get_user_id from utils.request import like_contains, parse_id_list from utils.perm_cache import invalidate_role_perms # 查询角色分页数据 def get_role_page(request): # 页码 page = int(request.query_params.get("pageNo", 1)) # 每页数 limit = int(request.query_params.get("pageSize", PAGE_SIZE)) # 分页查询 query = role_repo.filter(Role.is_delete == 0) # 角色名称 name = request.query_params.get('name') if name: query = query.filter(Role.name.like(like_contains(name), escape='\\')) # 排序 query = query.order_by(Role.sort.asc()) # 记录总数 count = query.count() # 查询分页数据 role_list = query.limit(limit).offset((page - 1) * limit).all() # 若当前页超出末页(数据被并发删除),自动回退到第一页 if page > 1 and not role_list: page = 1 count = query.count() role_list = query.limit(limit).offset(0).all() # 实例化返回对象 result = [] # 遍历数据源 if len(role_list) > 0: for item in role_list: # 对象转字典 data = item.to_dict() # 加入列表 result.append(data) # 返回结果 return R.ok(data=result, count=count) # 根据角色ID查询详情 def get_role_detail(role_id): # 根据ID查询角色 role = role_repo.get_by_id(role_id) # 查询结果判空 if not role: return None # 对象转字典 data = role.to_dict() # 返回结果 return data # 添加角色 def add_role(request, data: RoleForm): # 唯一性校验 if role_repo.filter(Role.name == data.name, Role.is_delete == 0).first(): return R.failed("角色名称不能重复") # 表单数据赋值给对象并插入 role_repo.create(**data.model_dump(exclude={'id'}), create_user=get_user_id(request)) # 返回结果 return R.ok(msg="添加成功") # 更新角色 def update_role(request, data: RoleForm): # 记录ID判空 if not data.id or data.id <= 0: return R.failed("记录ID不能为空") # 唯一性校验(排除自身) if role_repo.filter(Role.name == data.name, Role.id != data.id, Role.is_delete == 0).first(): return R.failed("角色名称不能重复") # 根据ID查询记录 if not role_repo.get_by_id(data.id): return R.failed("记录不存在") # 构造更新数据(排除 id) updData = data.model_dump(exclude={'id'}) updData['update_user'] = get_user_id(request) updData['update_time'] = datetime.now(tz=timezone.utc) result = role_repo.update(data.id, updData) # 提交数据 if not result: return R.failed("更新失败") # 返回结果 return R.ok(msg="更新成功") # 删除角色 async def delete_role(role_id): def _delete(): # 记录ID为空判断 if not role_id: return R.failed("记录ID不存在"), None # 分裂字符串 id_list = parse_id_list(role_id) if not id_list: return R.failed("记录ID不存在"), None # 批量查询并校验 records = role_repo.filter(Role.id.in_(id_list), Role.is_delete == 0).all() if len(records) != len(id_list): return R.failed("记录不存在"), None # 批量设置删除标识 for record in records: record.is_delete = 1 return None, (id_list, records) # 同步DB操作放入线程池,避免阻塞事件循环 err, result = await asyncio.to_thread(_delete) if err: return err id_list, records = result # 清理被删角色下所有用户的权限缓存 for rid in id_list: await invalidate_role_perms(rid) # 返回结果 return R.ok(msg="本次共删除{0}条数据".format(len(records))) # 设置状态 def update_role_status(request, data: RoleStatusForm): # 根据ID查询记录 if not role_repo.get_by_id(data.id): return R.failed("记录不存在") # 更新记录 result = role_repo.update(data.id, { "status": data.status, "update_user": get_user_id(request), "update_time": datetime.now(tz=timezone.utc) }) # 提交数据 if not result: return R.failed("设置失败") # 返回结果 return R.ok(msg="设置成功") # 获取角色列表 def get_role_list(): # 查询角色列表 role_rows = role_repo.filter(Role.is_delete == 0, Role.status == 1).order_by(Role.sort.asc()).all() # 实例化角色列表 role_list = [] # 遍历数据源 if role_rows: for v in role_rows: # 对象转字典 item = v.to_dict() # 加入数组 role_list.append(item) # 返回结果 return role_list import asyncio from fastapi.logger import logger from sqlalchemy import and_ from modules.system.role.schemas import RoleMenuForm from modules.system.menu.models import Menu from modules.system.role.models import RoleMenu from modules.system.role.repository import rolemenu_repo from core.database import get_db_session from core import R from utils.perm_cache import invalidate_role_perms # 根据角色ID查询菜单列表 def get_role_menu_list(role_id): db = get_db_session() # 获取全部菜单列表(仅查询 id、title、parent_id,避免 SELECT * 全量拉取大字段) menuList = db.query(Menu.id, Menu.title, Menu.parent_id).filter(and_(Menu.is_delete == 0, Menu.status == 1)).order_by(Menu.sort.asc()).all() if len(menuList) == 0: return None # 根据角色ID查询角色菜单关系数据 role_menu = rolemenu_repo.filter(RoleMenu.role_id == role_id).all() # 菜单ID集合 idList = [] # 遍历角色菜单数据源 if role_menu: for v in role_menu: # 加入数组 idList.append(v.menu_id) # 实例化菜单列表 menu_list = [] # 遍历菜单数据 for menu in menuList: # 菜单ID menu_id = menu.id data = { 'id': menu_id, 'title': menu.title, 'open': True, 'parentId': menu.parent_id, } if menu_id in idList: data['checked'] = True # 加入数组 menu_list.append(data) # 返回结果 return menu_list # 保存角色菜单数据 async def save_role_menu(request, data: RoleMenuForm): def _save(): db = get_db_session() # 角色ID role_id = data.role_id # 菜单ID列表 menuIdList = data.menu_id or [] # 删除当前角色ID相关菜单权限 db.query(RoleMenu).filter(RoleMenu.role_id == role_id).delete() # 处理菜单数据 if menuIdList: new_menus = [] for menu_id in menuIdList: if not menu_id: continue new_menus.append(RoleMenu(role_id=role_id, menu_id=menu_id)) db.add_all(new_menus) return role_id # 同步DB操作放入线程池,避免阻塞事件循环 role_id = await asyncio.to_thread(_save) # 清理该角色下所有用户的权限缓存 await invalidate_role_perms(role_id) # 返回结果 return R.ok()