feat: 给用户管理、部门管理、权限管理、系统配置、国际化配置、角色管理、登录日志、操作日志、缓存列表、缓存监控和性能监控添加按钮级权限管理

This commit is contained in:
皓月归尘 2025-02-23 22:03:45 +08:00
parent fe708aa0c8
commit 550ebabc16
19 changed files with 657 additions and 617 deletions

View File

@ -149,7 +149,7 @@ class Log:
# else: # else:
session_id = request.app.state.session_id session_id = request.app.state.session_id
status = 1 if request.app.state.login_status else 0 status = 1 if request.app.state.login_status else 0
current_user = await User.get_or_none(username=payload.get("username")) current_user = await User.get_or_none(username=payload.get("username"),del_flag=1)
await LoginLog.create( await LoginLog.create(
user_id=current_user.id, user_id=current_user.id,
login_ip=host, login_ip=host,

View File

@ -9,6 +9,7 @@
from fastapi import APIRouter, Depends, Path, Request from fastapi import APIRouter, Depends, Path, Request
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from annotation.auth import Auth
from annotation.log import Log from annotation.log import Log
from config.constant import BusinessType, RedisKeyConfig from config.constant import BusinessType, RedisKeyConfig
from controller.login import LoginController from controller.login import LoginController
@ -26,6 +27,7 @@ cacheAPI = APIRouter(
@cacheAPI.get("/monitor", response_class=JSONResponse, response_model=GetCacheMonitorResponse, @cacheAPI.get("/monitor", response_class=JSONResponse, response_model=GetCacheMonitorResponse,
summary="获取缓存监控信息") summary="获取缓存监控信息")
@Log(title="获取缓存监控信息", business_type=BusinessType.SELECT) @Log(title="获取缓存监控信息", business_type=BusinessType.SELECT)
@Auth(permission_list=['cache:btn:infoList'])
async def get_cache_info(request: Request): async def get_cache_info(request: Request):
info = await request.app.state.redis.info() info = await request.app.state.redis.info()
db_size = await request.app.state.redis.dbsize() db_size = await request.app.state.redis.dbsize()
@ -45,6 +47,7 @@ async def get_cache_info(request: Request):
@cacheAPI.get("/names", response_class=JSONResponse, response_model=GetCacheInfoResponse, @cacheAPI.get("/names", response_class=JSONResponse, response_model=GetCacheInfoResponse,
summary="获取缓存名称列表") summary="获取缓存名称列表")
@Log(title="获取缓存名称列表", business_type=BusinessType.SELECT) @Log(title="获取缓存名称列表", business_type=BusinessType.SELECT)
@Auth(permission_list=['cache:btn:list'])
async def get_cache_names(request: Request): async def get_cache_names(request: Request):
name_list = [] name_list = []
for key_config in RedisKeyConfig: for key_config in RedisKeyConfig:
@ -62,6 +65,7 @@ async def get_cache_names(request: Request):
@cacheAPI.get("/keys/{cacheName}", response_class=JSONResponse, response_model=GetCacheKeysListResponse, @cacheAPI.get("/keys/{cacheName}", response_class=JSONResponse, response_model=GetCacheKeysListResponse,
summary="获取缓存键名列表") summary="获取缓存键名列表")
@Log(title="获取缓存键名列表", business_type=BusinessType.SELECT) @Log(title="获取缓存键名列表", business_type=BusinessType.SELECT)
@Auth(permission_list=['cache:btn:list'])
async def get_cache_keys(request: Request, cacheName: str = Path(description="缓存名称")): async def get_cache_keys(request: Request, cacheName: str = Path(description="缓存名称")):
cache_keys = await request.app.state.redis.keys(f'{cacheName}*') cache_keys = await request.app.state.redis.keys(f'{cacheName}*')
cache_key_list = [key.split(':', 1)[1] for key in cache_keys if key.startswith(f'{cacheName}:')] cache_key_list = [key.split(':', 1)[1] for key in cache_keys if key.startswith(f'{cacheName}:')]
@ -71,6 +75,7 @@ async def get_cache_keys(request: Request, cacheName: str = Path(description="
@cacheAPI.get("/info/{cacheName}/{cacheKey}", response_class=JSONResponse, response_model=GetCacheInfoResponse, @cacheAPI.get("/info/{cacheName}/{cacheKey}", response_class=JSONResponse, response_model=GetCacheInfoResponse,
summary="获取缓存信息") summary="获取缓存信息")
@Log(title="获取缓存信息", business_type=BusinessType.SELECT) @Log(title="获取缓存信息", business_type=BusinessType.SELECT)
@Auth(permission_list=['cache:btn:info'])
async def get_cache_info(request: Request, cacheName: str = Path(description="缓存名称"), async def get_cache_info(request: Request, cacheName: str = Path(description="缓存名称"),
cacheKey: str = Path(description="缓存键名")): cacheKey: str = Path(description="缓存键名")):
cache_value = await request.app.state.redis.get(f'{cacheName}:{cacheKey}') cache_value = await request.app.state.redis.get(f'{cacheName}:{cacheKey}')
@ -88,6 +93,7 @@ async def get_cache_info(request: Request, cacheName: str = Path(description="
@cacheAPI.post("/cacheName/{name}", response_class=JSONResponse, response_model=BaseResponse, @cacheAPI.post("/cacheName/{name}", response_class=JSONResponse, response_model=BaseResponse,
summary="通过键名删除缓存") summary="通过键名删除缓存")
@Log(title="通过键名删除缓存", business_type=BusinessType.DELETE) @Log(title="通过键名删除缓存", business_type=BusinessType.DELETE)
@Auth(permission_list=['cache:btn:delete'])
async def delete_cache(request: Request, name: str = Path(description="缓存名称")): async def delete_cache(request: Request, name: str = Path(description="缓存名称")):
cache_keys = await request.app.state.redis.keys(f'{name}*') cache_keys = await request.app.state.redis.keys(f'{name}*')
if cache_keys: if cache_keys:
@ -99,6 +105,7 @@ async def delete_cache(request: Request, name: str = Path(description="缓存名
summary="通过键值删除缓存") summary="通过键值删除缓存")
@cacheAPI.post("/cacheKey/{key}", response_class=JSONResponse, response_model=BaseResponse, summary="通过键值删除缓存") @cacheAPI.post("/cacheKey/{key}", response_class=JSONResponse, response_model=BaseResponse, summary="通过键值删除缓存")
@Log(title="通过键值删除缓存", business_type=BusinessType.DELETE) @Log(title="通过键值删除缓存", business_type=BusinessType.DELETE)
@Auth(permission_list=['cache:btn:delete'])
async def delete_cache_key(request: Request, key: str = Path(description="缓存键名")): async def delete_cache_key(request: Request, key: str = Path(description="缓存键名")):
cache_keys = await request.app.state.redis.keys(f'*{key}') cache_keys = await request.app.state.redis.keys(f'*{key}')
if cache_keys: if cache_keys:
@ -109,6 +116,7 @@ async def delete_cache_key(request: Request, key: str = Path(description="缓存
@cacheAPI.delete("/clearAll", response_class=JSONResponse, response_model=BaseResponse, summary="删除所有缓存") @cacheAPI.delete("/clearAll", response_class=JSONResponse, response_model=BaseResponse, summary="删除所有缓存")
@cacheAPI.post("/clearAll", response_class=JSONResponse, response_model=BaseResponse, summary="删除所有缓存") @cacheAPI.post("/clearAll", response_class=JSONResponse, response_model=BaseResponse, summary="删除所有缓存")
@Log(title="删除所有缓存", business_type=BusinessType.DELETE) @Log(title="删除所有缓存", business_type=BusinessType.DELETE)
@Auth(permission_list=['cache:btn:delete'])
async def delete_all_cache(request: Request): async def delete_all_cache(request: Request):
cache_keys = await request.app.state.redis.keys() cache_keys = await request.app.state.redis.keys()
if cache_keys: if cache_keys:

View File

@ -11,13 +11,14 @@ from typing import Optional
from fastapi import APIRouter, Depends, Path, Request, Query from fastapi import APIRouter, Depends, Path, Request, Query
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from annotation.auth import Auth
from annotation.log import Log from annotation.log import Log
from config.constant import BusinessType from config.constant import BusinessType
from config.get_redis import Redis from config.get_redis import Redis
from controller.login import LoginController from controller.login import LoginController
from models import Config from models import Config
from schemas.common import BaseResponse from schemas.common import BaseResponse, DeleteListParams
from schemas.config import AddConfigParams, DeleteConfigListParams, GetConfigInfoResponse, GetConfigListResponse from schemas.config import AddConfigParams, GetConfigInfoResponse, GetConfigListResponse
from utils.response import Response from utils.response import Response
configApi = APIRouter( configApi = APIRouter(
@ -28,8 +29,9 @@ configApi = APIRouter(
@configApi.post("/add", response_class=JSONResponse, response_model=BaseResponse, summary="新增配置") @configApi.post("/add", response_class=JSONResponse, response_model=BaseResponse, summary="新增配置")
@Log(title="新增配置", business_type=BusinessType.INSERT) @Log(title="新增配置", business_type=BusinessType.INSERT)
@Auth(permission_list=["config:btn:add"])
async def add_config(request: Request, params: AddConfigParams): async def add_config(request: Request, params: AddConfigParams):
if await Config.get_or_none(name=params.name, key=params.key): if await Config.get_or_none(name=params.name, key=params.key, del_flag=1):
return Response.error(msg="配置已存在") return Response.error(msg="配置已存在")
config = await Config.create( config = await Config.create(
name=params.name, name=params.name,
@ -48,9 +50,11 @@ async def add_config(request: Request, params: AddConfigParams):
@configApi.delete("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除配置") @configApi.delete("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除配置")
@configApi.post("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除配置") @configApi.post("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除配置")
@Log(title="删除配置", business_type=BusinessType.DELETE) @Log(title="删除配置", business_type=BusinessType.DELETE)
@Auth(permission_list=["config:btn:delete"])
async def delete_config(request: Request, id: str = Path(description="配置ID")): async def delete_config(request: Request, id: str = Path(description="配置ID")):
if config := await Config.get_or_none(id=id): if config := await Config.get_or_none(id=id, del_flag=1):
await config.delete() config.del_flag = 0
await config.save()
await Redis.init_system_config(request.app) await Redis.init_system_config(request.app)
return Response.success(msg="删除成功") return Response.success(msg="删除成功")
else: else:
@ -60,10 +64,12 @@ async def delete_config(request: Request, id: str = Path(description="配置ID")
@configApi.delete("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除配置") @configApi.delete("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除配置")
@configApi.post("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除配置") @configApi.post("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除配置")
@Log(title="批量删除配置", business_type=BusinessType.DELETE) @Log(title="批量删除配置", business_type=BusinessType.DELETE)
async def delete_config_list(request: Request, params: DeleteConfigListParams): @Auth(permission_list=["config:btn:delete"])
async def delete_config_list(request: Request, params: DeleteListParams):
for id in set(params.ids): for id in set(params.ids):
if config := await Config.get_or_none(id=id): if config := await Config.get_or_none(id=id, del_flag=1):
await config.delete() config.del_flag = 0
await config.save()
await Redis.init_system_config(request.app) await Redis.init_system_config(request.app)
return Response.success(msg="删除成功") return Response.success(msg="删除成功")
@ -71,8 +77,9 @@ async def delete_config_list(request: Request, params: DeleteConfigListParams):
@configApi.put("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改配置") @configApi.put("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改配置")
@configApi.post("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改配置") @configApi.post("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改配置")
@Log(title="修改配置", business_type=BusinessType.UPDATE) @Log(title="修改配置", business_type=BusinessType.UPDATE)
@Auth(permission_list=["config:btn:update"])
async def update_config(request: Request, params: AddConfigParams, id: str = Path(description="配置ID")): async def update_config(request: Request, params: AddConfigParams, id: str = Path(description="配置ID")):
if config := await Config.get_or_none(id=id): if config := await Config.get_or_none(id=id, del_flag=1):
config.name = params.name config.name = params.name
config.key = params.key config.key = params.key
config.value = params.value config.value = params.value
@ -87,8 +94,9 @@ async def update_config(request: Request, params: AddConfigParams, id: str = Pat
@configApi.get("/info/{id}", response_class=JSONResponse, response_model=GetConfigInfoResponse, summary="获取配置信息") @configApi.get("/info/{id}", response_class=JSONResponse, response_model=GetConfigInfoResponse, summary="获取配置信息")
@Log(title="获取配置信息", business_type=BusinessType.SELECT) @Log(title="获取配置信息", business_type=BusinessType.SELECT)
@Auth(permission_list=["config:btn:info"])
async def get_config_info(request: Request, id: str = Path(description="配置ID")): async def get_config_info(request: Request, id: str = Path(description="配置ID")):
if config := await Config.get_or_none(id=id): if config := await Config.get_or_none(id=id, del_flag=1):
data = { data = {
"id": config.id, "id": config.id,
"name": config.name, "name": config.name,
@ -108,6 +116,7 @@ async def get_config_info(request: Request, id: str = Path(description="配置ID
@configApi.get("/list", response_class=JSONResponse, response_model=GetConfigListResponse, summary="获取配置列表") @configApi.get("/list", response_class=JSONResponse, response_model=GetConfigListResponse, summary="获取配置列表")
@Log(title="获取配置列表", business_type=BusinessType.SELECT) @Log(title="获取配置列表", business_type=BusinessType.SELECT)
@Auth(permission_list=["config:btn:list"])
async def get_config_list(request: Request, async def get_config_list(request: Request,
page: int = Query(default=1, description="当前页码"), page: int = Query(default=1, description="当前页码"),
pageSize: int = Query(default=10, description="每页数量"), pageSize: int = Query(default=10, description="每页数量"),
@ -122,8 +131,8 @@ async def get_config_list(request: Request,
'type': type, 'type': type,
}.items() if v }.items() if v
} }
total = await Config.filter(**filterArgs).count() total = await Config.filter(**filterArgs, del_flag=1).count()
data = await Config.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).values( data = await Config.filter(**filterArgs, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).values(
id="id", id="id",
name="name", name="name",
key="key", key="key",

View File

@ -10,20 +10,22 @@ from typing import Optional
from fastapi import APIRouter, Depends, Query, Path, Request from fastapi import APIRouter, Depends, Query, Path, Request
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from annotation.auth import Auth
from annotation.log import Log from annotation.log import Log
from config.constant import BusinessType from config.constant import BusinessType, RedisKeyConfig
from controller.login import LoginController from controller.login import LoginController
from models import Department, Role, DepartmentRole from models import Department, Role
from schemas.common import BaseResponse from schemas.common import BaseResponse, DeleteListParams
from schemas.department import AddDepartmentParams, GetDepartmentInfoResponse, \ from schemas.department import AddDepartmentParams, GetDepartmentInfoResponse, \
GetDepartmentListResponse, AddDepartmentRoleParams, GetDepartmentRoleInfoResponse, DeleteDepartmentListParams GetDepartmentListResponse
from utils.response import Response from utils.response import Response
departmentAPI = APIRouter(prefix="/department", dependencies=[Depends(LoginController.get_current_user)]) departmentAPI = APIRouter(prefix="/department")
@departmentAPI.post("/add", response_model=BaseResponse, response_class=JSONResponse, summary="新增部门") @departmentAPI.post("/add", response_model=BaseResponse, response_class=JSONResponse, summary="新增部门")
@Log(title="新增部门", business_type=BusinessType.INSERT) @Log(title="新增部门", business_type=BusinessType.INSERT)
@Auth(["department:btn:add"])
async def add_department(request: Request, params: AddDepartmentParams, async def add_department(request: Request, params: AddDepartmentParams,
current_user: dict = Depends(LoginController.get_current_user)): current_user: dict = Depends(LoginController.get_current_user)):
parent_id = current_user.get("department_id") parent_id = current_user.get("department_id")
@ -40,6 +42,8 @@ async def add_department(request: Request, params: AddDepartmentParams,
status=params.status status=params.status
) )
if department: if department:
if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:*'):
await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:*')
return Response.success(msg="添加成功!") return Response.success(msg="添加成功!")
else: else:
return Response.error(msg="添加失败!") return Response.error(msg="添加失败!")
@ -48,9 +52,16 @@ async def add_department(request: Request, params: AddDepartmentParams,
@departmentAPI.delete("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除部门") @departmentAPI.delete("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除部门")
@departmentAPI.post("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除部门") @departmentAPI.post("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除部门")
@Log(title="删除部门", business_type=BusinessType.DELETE) @Log(title="删除部门", business_type=BusinessType.DELETE)
async def delete_department(request: Request, id: str = Path(description="部门ID")): @Auth(["department:btn:delete"])
async def delete_department(request: Request, id: str = Path(description="部门ID"),
current_user: dict = Depends(LoginController.get_current_user)):
if department := await Department.get_or_none(id=id, del_flag=1): if department := await Department.get_or_none(id=id, del_flag=1):
sub_departments = current_user.get("sub_departments")
if department.id not in sub_departments:
return Response.error(msg="删除失败,无权限!")
if await delete_department_recursive(department_id=department.id): if await delete_department_recursive(department_id=department.id):
if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:*'):
await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:*')
return Response.success(msg="删除成功!") return Response.success(msg="删除成功!")
return Response.error(msg="删除失败!") return Response.error(msg="删除失败!")
else: else:
@ -60,10 +71,16 @@ async def delete_department(request: Request, id: str = Path(description="部门
@departmentAPI.delete("/deleteList", response_model=BaseResponse, response_class=JSONResponse, summary="批量删除部门") @departmentAPI.delete("/deleteList", response_model=BaseResponse, response_class=JSONResponse, summary="批量删除部门")
@departmentAPI.post("/deleteList", response_model=BaseResponse, response_class=JSONResponse, summary="批量删除部门") @departmentAPI.post("/deleteList", response_model=BaseResponse, response_class=JSONResponse, summary="批量删除部门")
@Log(title="批量删除部门", business_type=BusinessType.DELETE) @Log(title="批量删除部门", business_type=BusinessType.DELETE)
async def delete_department_list(request: Request, params: DeleteDepartmentListParams): @Auth(["department:btn:delete"])
async def delete_department_list(request: Request, params: DeleteListParams,
current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
for item in set(params.ids): for item in set(params.ids):
if department := await Department.get_or_none(id=item, del_flag=1): if department := await Department.get_or_none(id=item, del_flag=1):
await delete_department_recursive(department_id=department.id) if item in sub_departments:
await delete_department_recursive(department_id=department.id)
if await request.app.state.redis.get(f'{RedisKeyConfig.USER_INFO.key}:*'):
await request.app.state.redis.delete(f'{RedisKeyConfig.USER_INFO.key}:*')
return Response.success(msg="删除成功!") return Response.success(msg="删除成功!")
@ -73,8 +90,8 @@ async def delete_department_recursive(department_id: str):
:param department_id: 部门ID :param department_id: 部门ID
:return: :return:
""" """
await Department.filter(id=department_id).delete() await Department.filter(id=department_id, del_flag=1).update(del_flag=0)
sub_departments = await Department.filter(parent_id=department_id).all() sub_departments = await Department.filter(parent_id=department_id, del_flag=1).all()
for sub_department in sub_departments: for sub_department in sub_departments:
await delete_department_recursive(sub_department.id) await delete_department_recursive(sub_department.id)
return True return True
@ -83,8 +100,13 @@ async def delete_department_recursive(department_id: str):
@departmentAPI.put("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改部门") @departmentAPI.put("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改部门")
@departmentAPI.post("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改部门") @departmentAPI.post("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改部门")
@Log(title="修改部门", business_type=BusinessType.UPDATE) @Log(title="修改部门", business_type=BusinessType.UPDATE)
async def update_department(request: Request, params: AddDepartmentParams, id: str = Path(description="部门ID")): @Auth(["department:btn:update"])
async def update_department(request: Request, params: AddDepartmentParams, id: str = Path(description="部门ID"),
current_user: dict = Depends(LoginController.get_current_user)):
if department := await Department.get_or_none(id=id, del_flag=1): if department := await Department.get_or_none(id=id, del_flag=1):
sub_departments = current_user.get("sub_departments")
if id not in sub_departments:
return Response.error(msg="修改失败,无权限!")
department.name = params.name department.name = params.name
department.parent_id = params.parent_id department.parent_id = params.parent_id
department.principal = params.principal department.principal = params.principal
@ -102,7 +124,9 @@ async def update_department(request: Request, params: AddDepartmentParams, id: s
@departmentAPI.get("/info/{id}", response_model=GetDepartmentInfoResponse, response_class=JSONResponse, @departmentAPI.get("/info/{id}", response_model=GetDepartmentInfoResponse, response_class=JSONResponse,
summary="查询部门详情") summary="查询部门详情")
@Log(title="查询部门详情", business_type=BusinessType.SELECT) @Log(title="查询部门详情", business_type=BusinessType.SELECT)
async def get_department(request: Request, id: str = Path(description="部门ID")): @Auth(["department:btn:info"])
async def get_department(request: Request, id: str = Path(description="部门ID"),
current_user: dict = Depends(LoginController.get_current_user)):
if department := await Department.get_or_none(id=id, del_flag=1).values( if department := await Department.get_or_none(id=id, del_flag=1).values(
id="id", id="id",
name="name", name="name",
@ -118,6 +142,9 @@ async def get_department(request: Request, id: str = Path(description="部门ID"
create_by="create_by", create_by="create_by",
update_by="update_by" update_by="update_by"
): ):
sub_departments = current_user.get("sub_departments")
if id not in sub_departments:
return Response.error(msg="查询失败,无权限!")
return Response.success(data=department) return Response.success(data=department)
else: else:
return Response.error(msg="部门不存在!") return Response.error(msg="部门不存在!")
@ -126,6 +153,7 @@ async def get_department(request: Request, id: str = Path(description="部门ID"
@departmentAPI.get("/list", response_model=GetDepartmentListResponse, response_class=JSONResponse, @departmentAPI.get("/list", response_model=GetDepartmentListResponse, response_class=JSONResponse,
summary="查询部门列表") summary="查询部门列表")
@Log(title="查询部门列表", business_type=BusinessType.SELECT) @Log(title="查询部门列表", business_type=BusinessType.SELECT)
@Auth(["department:btn:list"])
async def get_department_list( async def get_department_list(
request: Request, request: Request,
page: int = Query(default=1, description="当前页码"), page: int = Query(default=1, description="当前页码"),
@ -148,43 +176,11 @@ async def get_department_list(
'sort': sort 'sort': sort
}.items() if v }.items() if v
} }
department_id = current_user.get("department_id", "") sub_departments = current_user.get("sub_departments")
# 递归查询所有部门 total = await Department.filter(**filterArgs, del_flag=1, id__in=sub_departments).count()
all_departments = await get_department_and_subdepartments(department_id, filterArgs) data = await Department.filter(**filterArgs, del_flag=1, id__in=sub_departments).offset(
(page - 1) * pageSize).limit(
# 分页处理 pageSize).values(
total = len(all_departments)
paginated_departments = all_departments[(page - 1) * pageSize: page * pageSize]
return Response.success(data={
"result": paginated_departments,
"total": total,
"page": page
})
async def get_department_and_subdepartments(department_id: str, filterArgs: dict, visited: set = None):
"""
查询当前部门及其所有下属部门的数据并根据 id 去重
:param department_id: 当前部门 ID
:param filterArgs: 过滤条件
:param visited: 已访问的部门 ID 集合用于避免循环依赖
:return: 去重后的部门列表
"""
if visited is None:
visited = set() # 初始化已访问的部门 ID 集合
# 如果当前部门 ID 已经访问过,直接返回空列表,避免死循环
if department_id in visited:
return []
visited.add(department_id) # 标记当前部门 ID 为已访问
# 查询当前部门
current_department = await Department.filter(
id=department_id,
**filterArgs
).values(
id="id", id="id",
name="name", name="name",
parent_id="parent_id", parent_id="parent_id",
@ -199,177 +195,26 @@ async def get_department_and_subdepartments(department_id: str, filterArgs: dict
create_by="create_by", create_by="create_by",
update_by="update_by" update_by="update_by"
) )
# 查询直接子部门
sub_departments = await Department.filter(
parent_id=department_id, # 只根据 parent_id 查询
**filterArgs
).values(
id="id",
name="name",
parent_id="parent_id",
principal="principal",
phone="phone",
email="email",
remark="remark",
sort="sort",
status="status",
create_time="create_time",
update_time="update_time",
create_by="create_by",
update_by="update_by"
)
# 递归查询子部门的子部门
for department in sub_departments[:]: # 使用切片复制避免修改迭代中的列表
sub_sub_departments = await get_department_and_subdepartments(department["id"], filterArgs, visited)
sub_departments.extend(sub_sub_departments)
# 合并当前部门和所有下属部门的数据
all_departments = current_department + sub_departments
# 根据 id 去重
unique_departments = []
seen_ids = set() # 用于记录已经处理过的部门 ID
for department in all_departments:
if department["id"] not in seen_ids:
unique_departments.append(department)
seen_ids.add(department["id"])
return unique_departments
@departmentAPI.post("/addRole", response_model=BaseResponse, response_class=JSONResponse, summary="添加部门角色")
@Log(title="添加部门角色", business_type=BusinessType.INSERT)
async def add_department_role(request: Request, params: AddDepartmentRoleParams):
if await DepartmentRole.get_or_none(department_id=params.department_id, role_id=params.role_id, del_flag=1):
return Response.error(msg="该部门已存在该角色!")
if department := await Department.get_or_none(id=params.department_id, del_flag=1):
if role := await Role.get_or_none(id=params.role_id, del_flag=1):
departmentRole = await DepartmentRole.create(department_id=department.id, role_id=role.id)
if departmentRole:
return Response.success(msg="添加成功!")
else:
return Response.error(msg="添加失败!")
else:
return Response.error(msg="添加失败,角色不存在!")
else:
return Response.error(msg="添加失败,部门不存在!")
@departmentAPI.delete("/deleteRole/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="删除部门角色")
@departmentAPI.post("/deleteRole/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="删除部门角色")
@Log(title="删除部门角色", business_type=BusinessType.DELETE)
async def delete_department_role(request: Request, id: str = Path(description="部门角色ID")):
if departmentRole := await DepartmentRole.get_or_none(id=id, del_flag=1):
await departmentRole.delete()
return Response.success(msg="删除成功!")
else:
return Response.error(msg="删除失败,部门角色不存在!")
@departmentAPI.put("/updateRole/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改部门角色")
@departmentAPI.post("/updateRole/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="修改部门角色")
@Log(title="修改部门角色", business_type=BusinessType.UPDATE)
async def update_department_role(request: Request, params: AddDepartmentRoleParams,
id: str = Path(description="部门角色ID")):
if departmentRole := await DepartmentRole.get_or_none(id=id, del_flag=1):
if department := await Department.get_or_none(id=params.department_id, del_flag=1):
if role := await Role.get_or_none(id=params.role_id, del_flag=1):
departmentRole.department_id = department.id
departmentRole.role_id = role.id
await departmentRole.save()
return Response.success(msg="修改成功!")
else:
return Response.error(msg="修改失败,角色不存在!")
else:
return Response.error(msg="修改失败,部门不存在!")
else:
return Response.error(msg="修改失败,部门角色不存在!")
@departmentAPI.get("/roleInfo", response_model=GetDepartmentRoleInfoResponse, response_class=JSONResponse,
summary="获取部门角色信息")
@Log(title="获取部门角色信息", business_type=BusinessType.SELECT)
async def get_department_role_info(request: Request, id: str = Query(description="部门角色ID")):
if departmentRole := await DepartmentRole.get_or_none(id=id, del_flag=1):
data = await departmentRole.first().values(
id="id",
department_id="department__id",
department_name="department__name",
department_phone="department__phone",
department_principal="department__principal",
department_email="department__email",
role_name="role__name",
role_code="role__code",
role_id="role__id",
create_time="create_time",
update_time="update_time"
)
return Response.success(data=data)
else:
return Response.error(msg="获取失败,部门角色不存在!")
@departmentAPI.get("/roleList", response_model=GetDepartmentListResponse, response_class=JSONResponse,
summary="获取部门角色列表")
@Log(title="获取部门角色列表", business_type=BusinessType.SELECT)
async def get_department_role_list(
request: Request,
page: int = Query(default=1, description="当前页码"),
pageSize: int = Query(default=10, description="每页条数"),
department_id: Optional[str] = Query(default=None, description="部门ID"),
department_name: Optional[str] = Query(default=None, description="部门名称"),
department_phone: Optional[str] = Query(default=None, description="部门电话"),
department_principal: Optional[str] = Query(default=None, description="部门负责人"),
department_email: Optional[str] = Query(default=None, description="部门邮箱"),
role_id: Optional[str] = Query(default=None, description="角色ID"),
role_name: Optional[str] = Query(default=None, description="角色名称"),
role_code: Optional[str] = Query(default=None, description="角色编码"),
):
filterArgs = {
f'{k}__contains': v for k, v in {
'department__id': department_id,
'department__name': department_name,
'department__phone': department_phone,
'department__principal': department_principal,
'department__email': department_email,
'role__id': role_id,
'role__name': role_name,
'role__code': role_code
}.items() if v
}
total = await DepartmentRole.filter(**filterArgs).count()
data = await DepartmentRole.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).values(
id="id",
department_id="department__id",
department_name="department__name",
department_phone="department__phone",
department_principal="department__principal",
department_email="department__email",
role_name="role__name",
role_code="role__code",
role_id="role__id",
create_time="create_time",
update_time="update_time"
)
return Response.success(data={ return Response.success(data={
"result": data, "result": data,
"total": total, "total": total,
"page": page "page": page,
"pageSize": pageSize
}) })
@departmentAPI.get("/roleList/{id}", response_model=GetDepartmentListResponse, response_class=JSONResponse, @departmentAPI.get("/roleList/{id}", response_model=GetDepartmentListResponse, response_class=JSONResponse,
summary="用户获取部门角色列表") summary="用户获取部门角色列表")
@Log(title="获取部门角色列表", business_type=BusinessType.OTHER) @Log(title="获取部门角色列表", business_type=BusinessType.SELECT)
@Auth(["department:btn:list"])
async def get_department_role_list( async def get_department_role_list(
request: Request, request: Request,
id: str = Path(..., description="部门ID") id: str = Path(..., description="部门ID"),
current_user: dict = Depends(LoginController.get_current_user)
): ):
sub_departments = current_user.get("sub_departments")
if id not in sub_departments:
return Response.error(msg="查询失败,无权限!")
data = await Role.filter(department__id=id).values( data = await Role.filter(department__id=id).values(
id="id", id="id",
department_id="department__id", department_id="department__id",
@ -386,5 +231,6 @@ async def get_department_role_list(
return Response.success(data={ return Response.success(data={
"result": data, "result": data,
"total": len(data), "total": len(data),
"page": 1 "page": 1,
"pageSize": 9999
}) })

View File

@ -12,24 +12,27 @@ from fastapi import APIRouter, Depends, Path, Request, Query
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from annotation.auth import Auth
from annotation.log import Log from annotation.log import Log
from config.constant import BusinessType, RedisKeyConfig from config.constant import BusinessType, RedisKeyConfig
from controller.login import LoginController from controller.login import LoginController
from models import I18n, Locale from models import I18n, Locale
from schemas.common import BaseResponse from schemas.common import BaseResponse, DeleteListParams
from schemas.i18n import AddLocaleParams, GetLocaleInfoResponse, AddI18nParams, GetI18nInfoResponse, \ from schemas.i18n import AddLocaleParams, GetLocaleInfoResponse, AddI18nParams, GetI18nInfoResponse, \
GetI18nInfoListResponse, GetI18nListResponse GetI18nInfoListResponse, GetI18nListResponse
from utils.response import Response from utils.response import Response
i18nAPI = APIRouter( i18nAPI = APIRouter(
prefix="/i18n", prefix="/i18n",
dependencies=[Depends(LoginController.get_current_user)]
) )
@i18nAPI.post("/addLocale", response_class=JSONResponse, response_model=BaseResponse, summary="添加国际化类型") @i18nAPI.post("/addLocale", response_class=JSONResponse, response_model=BaseResponse, summary="添加国际化类型")
@Log(title="添加国际化类型", business_type=BusinessType.INSERT) @Log(title="添加国际化类型", business_type=BusinessType.INSERT)
async def add_locale(request: Request, params: AddLocaleParams, current_user=Depends(LoginController.get_current_user)): @Auth(["locale:btn:add"])
if await Locale.get_or_none(code=params.code): async def add_locale(request: Request, params: AddLocaleParams):
if await Locale.get_or_none(code=params.code, del_flag=1):
return Response.error(msg="该语言代码已存在!") return Response.error(msg="该语言代码已存在!")
locale = await Locale.create( locale = await Locale.create(
code=params.code, code=params.code,
@ -46,23 +49,41 @@ async def add_locale(request: Request, params: AddLocaleParams, current_user=Dep
@i18nAPI.post("/deleteLocale/{id}", response_class=JSONResponse, response_model=BaseResponse, @i18nAPI.post("/deleteLocale/{id}", response_class=JSONResponse, response_model=BaseResponse,
summary="删除国际化类型") summary="删除国际化类型")
@Log(title="删除国际化类型", business_type=BusinessType.DELETE) @Log(title="删除国际化类型", business_type=BusinessType.DELETE)
async def delete_locale(request: Request, id: str = Path(description="国际化类型ID"), @Auth(["locale:btn:delete"])
current_user=Depends(LoginController.get_current_user)): async def delete_locale(request: Request, id: str = Path(description="国际化类型ID")):
if locale := await Locale.get_or_none(id=id): if locale := await Locale.get_or_none(id=id, del_flag=1):
# 移除语言 # 移除语言
await I18n.filter(locale_id=locale.id).delete() await I18n.filter(locale_id=locale.id, del_flag=1).update(del_flag=0)
await locale.delete() locale.del_flag = 0
await locale.save()
return Response.success(msg="删除成功!") return Response.success(msg="删除成功!")
else: else:
return Response.error(msg="该国际化类型不存在!") return Response.error(msg="该国际化类型不存在!")
@i18nAPI.delete("/deleteLocaleList", response_class=JSONResponse, response_model=BaseResponse,
summary="批量删除国际化类型")
@i18nAPI.post("/deleteLocaleList", response_class=JSONResponse, response_model=BaseResponse,
summary="批量删除国际化类型")
@Log(title="批量删除国际化类型", business_type=BusinessType.DELETE)
@Auth(["locale:btn:delete"])
async def delete_locale_list(request: Request, params: DeleteListParams):
for id in set(params.ids):
if locale := await Locale.get_or_none(id=id, del_flag=1):
# 移除语言
await I18n.filter(locale_id=locale.id, del_flag=1).update(del_flag=0)
locale.del_flag = 0
await locale.save()
return Response.success(msg="删除成功!")
@i18nAPI.put("/updateLocale/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改国际化类型") @i18nAPI.put("/updateLocale/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改国际化类型")
@i18nAPI.post("/updateLocale/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改国际化类型") @i18nAPI.post("/updateLocale/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改国际化类型")
@Log(title="修改国际化类型", business_type=BusinessType.UPDATE) @Log(title="修改国际化类型", business_type=BusinessType.UPDATE)
@Auth(["locale:btn:update"])
async def update_locale(request: Request, params: AddLocaleParams, id: str = Path(description="国际化类型ID")): async def update_locale(request: Request, params: AddLocaleParams, id: str = Path(description="国际化类型ID")):
if locale := await Locale.get_or_none(id=id): if locale := await Locale.get_or_none(id=id, del_flag=1):
if await Locale.get_or_none(code=params.code, name=params.name, id=id): if await Locale.get_or_none(code=params.code, name=params.name, id=id, del_flag=1):
return Response.error(msg="该国际化类型已存在!") return Response.error(msg="该国际化类型已存在!")
locale.code = params.code locale.code = params.code
locale.name = params.name locale.name = params.name
@ -75,8 +96,9 @@ async def update_locale(request: Request, params: AddLocaleParams, id: str = Pat
@i18nAPI.get("/locale/info/{id}", response_class=JSONResponse, response_model=GetLocaleInfoResponse, @i18nAPI.get("/locale/info/{id}", response_class=JSONResponse, response_model=GetLocaleInfoResponse,
summary="获取国际化类型信息") summary="获取国际化类型信息")
@Log(title="获取国际化类型信息", business_type=BusinessType.SELECT) @Log(title="获取国际化类型信息", business_type=BusinessType.SELECT)
@Auth(["locale:btn:info"])
async def get_locale_info(request: Request, id: str = Path(description="国际化类型ID")): async def get_locale_info(request: Request, id: str = Path(description="国际化类型ID")):
if locale := await Locale.get_or_none(id=id): if locale := await Locale.get_or_none(id=id, del_flag=1):
locale = { locale = {
"id": locale.id, "id": locale.id,
"code": locale.code, "code": locale.code,
@ -92,7 +114,8 @@ async def get_locale_info(request: Request, id: str = Path(description="国际
@i18nAPI.get("/locale/list", response_class=JSONResponse, response_model=BaseResponse, summary="获取国际化类型列表") @i18nAPI.get("/locale/list", response_class=JSONResponse, response_model=BaseResponse, summary="获取国际化类型列表")
# @Log(title="获取国际化类型列表", business_type=BusinessType.SELECT) @Log(title="获取国际化类型列表", business_type=BusinessType.SELECT)
@Auth(["locale:btn:list"])
async def get_locale_list(request: Request, async def get_locale_list(request: Request,
page: int = Query(default=1, description="当前页码"), page: int = Query(default=1, description="当前页码"),
pageSize: int = Query(default=50, description="每页条数"), pageSize: int = Query(default=50, description="每页条数"),
@ -105,8 +128,9 @@ async def get_locale_list(request: Request,
'code': code 'code': code
}.items() if v }.items() if v
} }
total = await Locale.filter(**filterArgs).count() total = await Locale.filter(**filterArgs, del_flag=1).count()
data = await Locale.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).distinct().values( data = await Locale.filter(**filterArgs, del_flag=1).offset((page - 1) * pageSize).limit(
pageSize).distinct().values(
id="id", id="id",
code="code", code="code",
name="name", name="name",
@ -125,10 +149,11 @@ async def get_locale_list(request: Request,
@i18nAPI.post("/addI18n", response_class=JSONResponse, response_model=BaseResponse, summary="添加国际化内容") @i18nAPI.post("/addI18n", response_class=JSONResponse, response_model=BaseResponse, summary="添加国际化内容")
@Log(title="添加国际化内容", business_type=BusinessType.INSERT) @Log(title="添加国际化内容", business_type=BusinessType.INSERT)
async def add_i18n(request: Request, params: AddI18nParams, current_user=Depends(LoginController.get_current_user)): @Auth(["i18n:btn:add"])
if await I18n.get_or_none(key=params.key, locale_id=params.locale_id): async def add_i18n(request: Request, params: AddI18nParams):
if await I18n.get_or_none(key=params.key, locale_id=params.locale_id, del_flag=1):
return Response.error(msg="该国际化内容已存在!") return Response.error(msg="该国际化内容已存在!")
locale = await Locale.get_or_none(id=params.locale_id) locale = await Locale.get_or_none(id=params.locale_id, del_flag=1)
i18n = await I18n.create( i18n = await I18n.create(
key=params.key, key=params.key,
translation=params.translation, translation=params.translation,
@ -145,22 +170,36 @@ async def add_i18n(request: Request, params: AddI18nParams, current_user=Depends
@i18nAPI.post("/deleteI18n/{id}", response_class=JSONResponse, response_model=BaseResponse, @i18nAPI.post("/deleteI18n/{id}", response_class=JSONResponse, response_model=BaseResponse,
summary="删除国际化内容") summary="删除国际化内容")
@Log(title="删除国际化内容", business_type=BusinessType.DELETE) @Log(title="删除国际化内容", business_type=BusinessType.DELETE)
async def delete_i18n(request: Request, id: str = Path(description="国际化内容ID"), @Auth(["i18n:btn:delete"])
current_user=Depends(LoginController.get_current_user)): async def delete_i18n(request: Request, id: str = Path(description="国际化内容ID")):
if i18n := await I18n.get_or_none(id=id): if i18n := await I18n.get_or_none(id=id, del_flag=1):
await i18n.delete() i18n.del_flag = 0
await i18n.save()
return Response.success(msg="删除成功!") return Response.success(msg="删除成功!")
else: else:
return Response.error(msg="该国际化内容不存在!") return Response.error(msg="该国际化内容不存在!")
@i18nAPI.delete("/deleteI18nList", response_class=JSONResponse, response_model=BaseResponse,
summary="批量删除国际化内容")
@i18nAPI.post("/deleteI18nList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除国际化内容")
@Log(title="批量删除国际化内容", business_type=BusinessType.DELETE)
@Auth(["i18n:btn:delete"])
async def delete_i18n_list(request: Request, params: DeleteListParams):
for id in set(params.ids):
if i18n := await I18n.get_or_none(id=id, del_flag=1):
i18n.del_flag = 0
await i18n.save()
return Response.success(msg="删除成功!")
@i18nAPI.put("/updateI18n/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改国际化内容") @i18nAPI.put("/updateI18n/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改国际化内容")
@i18nAPI.post("/updateI18n/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改国际化内容") @i18nAPI.post("/updateI18n/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="修改国际化内容")
@Log(title="修改国际化内容", business_type=BusinessType.UPDATE) @Log(title="修改国际化内容", business_type=BusinessType.UPDATE)
async def update_i18n(request: Request, params: AddI18nParams, id: str = Path(description="国际化内容ID"), @Auth(["i18n:btn:update"])
current_user=Depends(LoginController.get_current_user)): async def update_i18n(request: Request, params: AddI18nParams, id: str = Path(description="国际化内容ID")):
if i18n := await I18n.get_or_none(id=id): if i18n := await I18n.get_or_none(id=id, del_flag=1):
locale = await Locale.get_or_none(id=params.locale_id) locale = await Locale.get_or_none(id=params.locale_id, del_flag=1)
i18n.key = params.key i18n.key = params.key
i18n.translation = params.translation i18n.translation = params.translation
i18n.locale = locale i18n.locale = locale
@ -173,8 +212,9 @@ async def update_i18n(request: Request, params: AddI18nParams, id: str = Path(de
@i18nAPI.get("/info/{id}", response_class=JSONResponse, response_model=GetI18nInfoResponse, @i18nAPI.get("/info/{id}", response_class=JSONResponse, response_model=GetI18nInfoResponse,
summary="获取国际化内容信息") summary="获取国际化内容信息")
@Log(title="获取国际化内容信息", business_type=BusinessType.SELECT) @Log(title="获取国际化内容信息", business_type=BusinessType.SELECT)
@Auth(["i18n:btn:info"])
async def get_i18n_info(request: Request, id: str = Path(description="国际化内容ID")): async def get_i18n_info(request: Request, id: str = Path(description="国际化内容ID")):
if i18n := await I18n.get_or_none(id=id): if i18n := await I18n.get_or_none(id=id, del_flag=1):
i18n = { i18n = {
"id": i18n.id, "id": i18n.id,
"key": i18n.key, "key": i18n.key,
@ -193,6 +233,7 @@ async def get_i18n_info(request: Request, id: str = Path(description="国际化
@i18nAPI.get("/list", response_class=JSONResponse, response_model=GetI18nListResponse, summary="获取国际化内容列表") @i18nAPI.get("/list", response_class=JSONResponse, response_model=GetI18nListResponse, summary="获取国际化内容列表")
@Log(title="获取国际化内容列表", business_type=BusinessType.SELECT) @Log(title="获取国际化内容列表", business_type=BusinessType.SELECT)
@Auth(["i18n:btn:list"])
async def get_i18n_list(request: Request, async def get_i18n_list(request: Request,
page: int = Query(default=1, description="当前页码"), page: int = Query(default=1, description="当前页码"),
pageSize: int = Query(default=50, description="每页条数"), pageSize: int = Query(default=50, description="每页条数"),
@ -207,8 +248,8 @@ async def get_i18n_list(request: Request,
'translation': translation 'translation': translation
}.items() if v }.items() if v
} }
total = await I18n.filter(**filterArgs).count() total = await I18n.filter(**filterArgs, del_flag=1).count()
data = await I18n.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).values( data = await I18n.filter(**filterArgs, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).values(
id="id", id="id",
key="key", key="key",
translation="translation", translation="translation",
@ -229,14 +270,11 @@ async def get_i18n_list(request: Request,
@i18nAPI.get("/infoList/{id}", response_class=JSONResponse, response_model=GetI18nInfoListResponse, @i18nAPI.get("/infoList/{id}", response_class=JSONResponse, response_model=GetI18nInfoListResponse,
summary="获取国际化列表") summary="获取国际化列表")
# @Log(title="获取国际化列表", business_type=BusinessType.SELECT) @Log(title="获取国际化列表", business_type=BusinessType.SELECT)
@Auth(["i18n:btn:infoList"])
async def get_i18n_info_list(request: Request, id: str = Path(description="国际化内容语言ID")): async def get_i18n_info_list(request: Request, id: str = Path(description="国际化内容语言ID")):
if locale := await Locale.get_or_none(id=id): if locale := await Locale.get_or_none(id=id, del_flag=1):
result = await request.app.state.redis.get(f'{RedisKeyConfig.TRANSLATION_INFO.key}:{id}') data = await I18n.filter(locale_id=locale.id, del_flag=1).order_by("key").values(
if result:
result = eval(result)
return Response.success(data=result)
data = await I18n.filter(locale_id=locale.id).values(
id="id", id="id",
key="key", key="key",
translation="translation", translation="translation",
@ -250,13 +288,6 @@ async def get_i18n_info_list(request: Request, id: str = Path(description="国
result = {} result = {}
for i18n in data: for i18n in data:
result[f"{i18n['key']}"] = i18n["translation"] result[f"{i18n['key']}"] = i18n["translation"]
await request.app.state.redis.set(f'{RedisKeyConfig.TRANSLATION_INFO.key}:{id}',
str(jsonable_encoder({
"data": result,
"locale": locale.code,
"name": locale.name,
})),
ex=timedelta(minutes=60))
return Response.success(data={ return Response.success(data={
"data": result, "data": result,
"locale": locale.code, "locale": locale.code,

View File

@ -5,6 +5,8 @@
# @File : log.py # @File : log.py
# @Software : PyCharm # @Software : PyCharm
# @Comment : 本程序 # @Comment : 本程序
from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Depends, Path, Query, Request from fastapi import APIRouter, Depends, Path, Query, Request
from fastapi.encoders import jsonable_encoder from fastapi.encoders import jsonable_encoder
@ -21,21 +23,45 @@ from utils.response import Response
logAPI = APIRouter( logAPI = APIRouter(
prefix="/log", prefix="/log",
dependencies=[Depends(LoginController.get_current_user)]
) )
@logAPI.get("/login", response_class=JSONResponse, response_model=GetLoginLogResponse, summary="用户获取登录日志") @logAPI.get("/login", response_class=JSONResponse, response_model=GetLoginLogResponse, summary="用户获取登录日志")
@Log(title="用户获取登录日志", business_type=BusinessType.SELECT)
@Auth(permission_list=["login:btn:list"])
async def get_login_log(request: Request, async def get_login_log(request: Request,
page: int = Query(default=1, description="页码"), page: int = Query(default=1, description="页码"),
pageSize: int = Query(default=10, description="每页数量"), pageSize: int = Query(default=10, description="每页数量"),
username: Optional[str] = Query(default=None, description="用户账号"),
nickname: Optional[str] = Query(default=None, description="用户昵称"),
department_id: Optional[str] = Query(default=None, description="部门ID"),
startTime: Optional[str] = Query(default=None, description="开始时间"),
endTime: Optional[str] = Query(default=None, description="结束时间"),
status: Optional[str] = Query(default=None, description="登录状态"),
current_user: dict = Depends(LoginController.get_current_user), current_user: dict = Depends(LoginController.get_current_user),
): ):
online_user_list = await LoginController.get_online_user(request) sub_departments = current_user.get("sub_departments")
online_user_list = await LoginController.get_online_user(request, sub_departments)
online_user_list = list( online_user_list = list(
filter(lambda x: x["user_id"] == current_user.get("id"), jsonable_encoder(online_user_list))) filter(lambda x: x["department_id"] in sub_departments, jsonable_encoder(online_user_list)))
user_id = current_user.get("id") filterArgs = {
result = await LoginLog.filter(user_id=user_id, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).values( f'{k}__contains': v for k, v in {
'username': username,
'nickname': nickname,
}.items() if v
}
if status is not None:
filterArgs['status'] = status
if startTime and endTime:
startTime = datetime.fromtimestamp(float(startTime) / 1000)
endTime = datetime.fromtimestamp(float(endTime) / 1000)
filterArgs['login_time__range'] = [startTime, endTime]
if not department_id:
filterArgs['user__department__id__in'] = sub_departments
else:
filterArgs['user__department__id'] = department_id
result = await LoginLog.filter(**filterArgs, user__del_flag=1, del_flag=1).offset(
(page - 1) * pageSize).limit(pageSize).values(
id="id", id="id",
user_id="user__id", user_id="user__id",
username="user__username", username="user__username",
@ -58,67 +84,113 @@ async def get_login_log(request: Request,
if item["session_id"] == log["session_id"]: if item["session_id"] == log["session_id"]:
log["online"] = True log["online"] = True
return Response.success(data={ return Response.success(data={
"total": await LoginLog.filter(user_id=user_id).count(), "total": await LoginLog.filter(**filterArgs, del_flag=1, user__del_flag=1, ).count(),
"result": result, "result": result,
"page": page, "page": page,
}) })
@logAPI.delete("/logout/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="用户强退") @logAPI.delete("/logout/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="用户强退")
@logAPI.post("/logout/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="用户强退") @logAPI.post("/logout/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="用户强退")
@Log(title="用户强退", business_type=BusinessType.DELETE) @Log(title="用户强退", business_type=BusinessType.DELETE)
# @Auth(permission_list=["user:btn:logout"]) @Auth(permission_list=["login:btn:logout"])
async def logout_user(request: Request, id: str = Path(description="会话ID"), async def logout_user(request: Request, id: str = Path(description="会话ID"),
current_user: dict = Depends(LoginController.get_current_user)): current_user: dict = Depends(LoginController.get_current_user)):
if await LoginLog.get_or_none(user_id=current_user.get("id"), session_id=id): sub_departments = current_user.get("sub_departments")
await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}") if await LoginLog.get_or_none(user__department__id__in=sub_departments, session_id=id, del_flag=1):
return Response.success(msg="强退成功!") if await request.app.state.redis.get(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}"):
await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}")
return Response.success(msg="强退成功!")
return Response.failure(msg="会话不存在!") return Response.failure(msg="会话不存在!")
@logAPI.delete("/logoutList", response_class=JSONResponse, response_model=BaseResponse, summary="用户批量强制退出")
@logAPI.post("/logoutList", response_class=JSONResponse, response_model=BaseResponse, summary="用户批量强制退出")
@Log(title="用户批量强制退出", business_type=BusinessType.DELETE)
@Auth(permission_list=["login:btn:logout"])
async def logout_user_list(request: Request, params: DeleteListParams,
current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
for id in params.ids:
if await LoginLog.get_or_none(user__department__id__in=sub_departments, session_id=id, del_flag=1):
if await request.app.state.redis.get(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}"):
await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{id}")
return Response.success(msg="批量强退成功!")
@logAPI.delete("/delete/login/{id}", response_model=BaseResponse, response_class=JSONResponse, @logAPI.delete("/delete/login/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="用户删除登录日志") summary="用户删除登录日志")
@logAPI.post("/delete/login/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="用户删除登录日志") @logAPI.post("/delete/login/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="用户删除登录日志")
@Log(title="用户删除登录日志", business_type=BusinessType.DELETE) @Log(title="用户删除登录日志", business_type=BusinessType.DELETE)
@Auth(permission_list=["login:btn:delete"]) @Auth(permission_list=["login:btn:delete"])
async def delete_login_log(id: str = Path(..., description="登录日志ID"), async def delete_login_log(request: Request, id: str = Path(..., description="登录日志ID"),
current_user: dict = Depends(LoginController.get_current_user)): current_user: dict = Depends(LoginController.get_current_user)):
if log := await LoginLog.get_or_none(id=id): sub_departments = current_user.get("sub_departments")
if log.user == current_user.get("id"): if log := await LoginLog.get_or_none(id=id, del_flag=1, user__department__id__in=sub_departments):
log.del_flag = 0 log.del_flag = 0
await log.save() await log.save()
return Response.success(msg="删除成功") if await request.app.state.redis.get(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{log.session_id}"):
else: await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{log.session_id}")
return Response.failure(msg="无权限删除") return Response.success(msg="删除成功")
else: else:
return Response.failure(msg="删除失败,登录日志不存在!") return Response.failure(msg="删除失败,登录日志不存在!")
@logAPI.delete("/deleteList/login", response_model=BaseResponse, response_class=JSONResponse, @logAPI.delete("/deleteList/login", response_model=BaseResponse, response_class=JSONResponse,
summary="用户删除登录日志") summary="用户批量删除登录日志")
@logAPI.post("/deleteList/login", response_model=BaseResponse, response_class=JSONResponse, @logAPI.post("/deleteList/login", response_model=BaseResponse, response_class=JSONResponse,
summary="用户删除登录日志") summary="用户批量删除登录日志")
@Log(title="用户批量删除登录日志", business_type=BusinessType.DELETE) @Log(title="用户批量删除登录日志", business_type=BusinessType.DELETE)
@Auth(permission_list=["login:btn:delete"]) @Auth(permission_list=["login:btn:delete"])
async def delete_login_log(params: DeleteListParams, async def delete_login_log(request: Request, params: DeleteListParams,
current_user: dict = Depends(LoginController.get_current_user)): current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
for id in set(params.ids): for id in set(params.ids):
if log := await LoginLog.get_or_none(id=id): if log := await LoginLog.get_or_none(id=id, del_flag=1, user__department__id__in=sub_departments):
if log.user == current_user.get("id"): log.del_flag = 0
log.del_flag = 0 await log.save()
await log.save() if await request.app.state.redis.get(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{log.session_id}"):
await request.app.state.redis.delete(f"{RedisKeyConfig.ACCESS_TOKEN.key}:{log.session_id}")
return Response.success(msg="删除成功") return Response.success(msg="删除成功")
@logAPI.get("/operation", response_class=JSONResponse, response_model=GetOperationLogResponse, @logAPI.get("/operation", response_class=JSONResponse, response_model=GetOperationLogResponse,
summary="用户获取操作日志") summary="用户获取操作日志")
@Auth(permission_list=["operation:btn:list"])
async def get_operation_log(request: Request, async def get_operation_log(request: Request,
page: int = Query(default=1, description="页码"), page: int = Query(default=1, description="页码"),
name: Optional[str] = Query(default=None, description="操作名称"),
type: Optional[str] = Query(default=None, description="操作类型"),
pageSize: int = Query(default=10, description="每页数量"), pageSize: int = Query(default=10, description="每页数量"),
username: Optional[str] = Query(default=None, description="用户账号"),
nickname: Optional[str] = Query(default=None, description="用户昵称"),
department_id: Optional[str] = Query(default=None, description="部门ID"),
startTime: Optional[str] = Query(default=None, description="开始时间"),
endTime: Optional[str] = Query(default=None, description="结束时间"),
status: Optional[str] = Query(default=None, description="登录状态"),
current_user: dict = Depends(LoginController.get_current_user), current_user: dict = Depends(LoginController.get_current_user),
): ):
user_id = current_user.get("id") sub_departments = current_user.get("sub_departments")
result = await OperationLog.filter(operator_id=user_id, del_flag=1).offset((page - 1) * pageSize).limit( filterArgs = {
f'{k}__contains': v for k, v in {
'operation_name': name,
'operation_type': type,
'operator__username': username,
'operator__nickname': nickname,
}.items() if v
}
if status is not None:
filterArgs['status'] = status
if startTime and endTime:
startTime = datetime.fromtimestamp(float(startTime) / 1000)
endTime = datetime.fromtimestamp(float(endTime) / 1000)
filterArgs['operation_time__range'] = [startTime, endTime]
if not department_id:
filterArgs['department__id__in'] = sub_departments
else:
filterArgs['department__id'] = department_id
result = await OperationLog.filter(**filterArgs, operator__del_flag=1, del_flag=1).offset(
(page - 1) * pageSize).limit(
pageSize).values( pageSize).values(
id="id", id="id",
operation_name="operation_name", operation_name="operation_name",
@ -142,9 +214,10 @@ async def get_operation_log(request: Request,
cost_time="cost_time" cost_time="cost_time"
) )
return Response.success(data={ return Response.success(data={
"total": await OperationLog.filter(operator_id=user_id).count(), "total": await OperationLog.filter(**filterArgs, del_flag=1, operator__del_flag=1).count(),
"result": result, "result": result,
"page": page, "page": page,
"pageSize": pageSize
}) })
@ -154,30 +227,28 @@ async def get_operation_log(request: Request,
summary="用户删除操作日志") summary="用户删除操作日志")
@Log(title="用户删除操作日志", business_type=BusinessType.DELETE) @Log(title="用户删除操作日志", business_type=BusinessType.DELETE)
@Auth(permission_list=["operation:btn:delete"]) @Auth(permission_list=["operation:btn:delete"])
async def delete_operation_log(id: str = Path(..., description="操作日志id"), async def delete_operation_log(request: Request, id: str = Path(..., description="操作日志id"),
current_user: dict = Depends(LoginController.get_current_user)): current_user: dict = Depends(LoginController.get_current_user)):
if log := await OperationLog.get_or_none(id=id): sub_departments = current_user.get("sub_departments")
if log.operator == current_user.get("id"): if log := await OperationLog.get_or_none(id=id, department__id__in=sub_departments, del_flag=1):
log.del_flag = 0 log.del_flag = 0
await log.save() await log.save()
return Response.success(msg="删除成功") return Response.success(msg="删除成功")
else:
return Response.failure(msg="无权限删除")
else: else:
return Response.failure(msg="删除失败,操作日志不存在!") return Response.failure(msg="删除失败,操作日志不存在!")
@logAPI.delete("/deleteList/operation", response_model=BaseResponse, response_class=JSONResponse, @logAPI.delete("/deleteList/operation", response_model=BaseResponse, response_class=JSONResponse,
summary="用户删除操作日志") summary="用户批量删除操作日志")
@logAPI.post("/deleteList/operation", response_model=BaseResponse, response_class=JSONResponse, @logAPI.post("/deleteList/operation", response_model=BaseResponse, response_class=JSONResponse,
summary="用户删除操作日志") summary="用户批量删除操作日志")
@Log(title="用户批量删除操作日志", business_type=BusinessType.DELETE) @Log(title="用户批量删除操作日志", business_type=BusinessType.DELETE)
@Auth(permission_list=["operation:btn:delete"]) @Auth(permission_list=["operation:btn:delete"])
async def delete_operation_log(params: DeleteListParams, async def delete_operation_log(request: Request, params: DeleteListParams,
current_user: dict = Depends(LoginController.get_current_user)): current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
for id in set(params.ids): for id in set(params.ids):
if log := await OperationLog.get_or_none(id=id): if log := await OperationLog.get_or_none(id=id, department__id__in=sub_departments, del_flag=1):
if log.operator == current_user.get("id"): log.del_flag = 0
log.del_flag = 0 await log.save()
await log.save()
return Response.success(msg="删除成功") return Response.success(msg="删除成功")

View File

@ -18,7 +18,7 @@ from config.constant import BusinessType
from config.constant import RedisKeyConfig from config.constant import RedisKeyConfig
from controller.login import CustomOAuth2PasswordRequestForm, LoginController from controller.login import CustomOAuth2PasswordRequestForm, LoginController
from controller.query import QueryController from controller.query import QueryController
from models import Department, User from models import Department, User, Role, UserRole
from schemas.common import BaseResponse from schemas.common import BaseResponse
from schemas.login import LoginParams, GetUserInfoResponse, LoginResponse, GetCaptchaResponse, GetEmailCodeParams, \ from schemas.login import LoginParams, GetUserInfoResponse, LoginResponse, GetCaptchaResponse, GetEmailCodeParams, \
ResetPasswordParams ResetPasswordParams
@ -94,7 +94,7 @@ async def login(
async def register(request: Request, params: RegisterUserParams): async def register(request: Request, params: RegisterUserParams):
register_enabled = ( register_enabled = (
True True
if await request.app.state.redis.get(f'{RedisKeyConfig.SYSTEM_CONFIG.key}:register_enabled') if await request.app.state.redis.get(f'{RedisKeyConfig.SYSTEM_CONFIG.key}:account_register_enabled')
== 'true' == 'true'
else False else False
) )
@ -106,7 +106,14 @@ async def register(request: Request, params: RegisterUserParams):
if await QueryController.register_user_before(username=params.username, phone=params.phone, email=params.email): if await QueryController.register_user_before(username=params.username, phone=params.phone, email=params.email):
return Response.error(msg="注册失败,用户已存在!") return Response.error(msg="注册失败,用户已存在!")
params.password = await Password.get_password_hash(input_password=params.password) params.password = await Password.get_password_hash(input_password=params.password)
# 默认分配注册用户
userRole = await Role.get_or_none(department__name="注册用户", code="user", del_flag=1).values(
department_id="department__id", id="id")
if not params.department_id:
params.department_id = userRole.get("department_id", "")
department = await Department.get_or_none(id=params.department_id) department = await Department.get_or_none(id=params.department_id)
userRole = await Role.get_or_none(department__id=department.id, code="user", del_flag=1).values(id="id")
print(userRole)
user = await User.create( user = await User.create(
username=params.username, username=params.username,
password=params.password, password=params.password,
@ -118,6 +125,11 @@ async def register(request: Request, params: RegisterUserParams):
status=params.status, status=params.status,
) )
if user: if user:
# 默认分配普通用户角色
await UserRole.create(
user_id=user.id,
role_id=userRole.get("id", ""),
)
userParams = LoginParams( userParams = LoginParams(
username=params.username, username=params.username,
password=params.password password=params.password
@ -140,7 +152,7 @@ async def register(request: Request, params: RegisterUserParams):
result.pop("session_id") result.pop("session_id")
result.pop("userInfo") result.pop("userInfo")
return Response.success(msg="注册成功!", data=result) return Response.success(msg="注册成功!", data=result)
return Response.error(msg="注册成功!") return Response.success(msg="注册成功!")
else: else:
return Response.error(msg="注册失败!") return Response.error(msg="注册失败!")
@ -221,12 +233,13 @@ async def info(
@loginAPI.get("/getRoutes", response_class=JSONResponse, summary="获取路由信息") @loginAPI.get("/getRoutes", response_class=JSONResponse, summary="获取路由信息")
# @Log(title="获取路由信息", business_type=BusinessType.SELECT) @Log(title="获取路由信息", business_type=BusinessType.SELECT)
async def get_routes(request: Request, current_user: dict = Depends(LoginController.get_current_user)): 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"]}') routes = await request.app.state.redis.get(f'{RedisKeyConfig.USER_ROUTES.key}:{current_user["id"]}')
if routes: if routes:
return Response.success(data=eval(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)) userRoutes = str(jsonable_encoder(routes))
await request.app.state.redis.set( await request.app.state.redis.set(
f'{RedisKeyConfig.USER_ROUTES.key}:{current_user["id"]}', f'{RedisKeyConfig.USER_ROUTES.key}:{current_user["id"]}',

View File

@ -10,8 +10,9 @@ from typing import Optional
from fastapi import APIRouter, Depends, Path, Query, Request from fastapi import APIRouter, Depends, Path, Query, Request
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from annotation.auth import Auth
from annotation.log import Log from annotation.log import Log
from config.constant import BusinessType from config.constant import BusinessType, RedisKeyConfig
from controller.login import LoginController from controller.login import LoginController
from models import Permission from models import Permission
from schemas.common import BaseResponse from schemas.common import BaseResponse
@ -26,6 +27,7 @@ permissionAPI = APIRouter(
@permissionAPI.post("/add", response_model=BaseResponse, response_class=JSONResponse, summary="新增权限") @permissionAPI.post("/add", response_model=BaseResponse, response_class=JSONResponse, summary="新增权限")
@Log(title="新增权限", business_type=BusinessType.INSERT) @Log(title="新增权限", business_type=BusinessType.INSERT)
@Auth(permission_list=["permission:btn:add"])
async def add_permission(request: Request, params: AddPermissionParams): async def add_permission(request: Request, params: AddPermissionParams):
permission = await Permission.create( permission = await Permission.create(
name=params.name, name=params.name,
@ -51,6 +53,14 @@ async def add_permission(request: Request, params: AddPermissionParams):
hidden_tag=params.hidden_tag, hidden_tag=params.hidden_tag,
) )
if permission: if permission:
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="新增权限成功!") return Response.success(msg="新增权限成功!")
else: else:
return Response.error(msg="新增权限失败!") return Response.error(msg="新增权限失败!")
@ -59,9 +69,19 @@ async def add_permission(request: Request, params: AddPermissionParams):
@permissionAPI.delete("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除权限") @permissionAPI.delete("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除权限")
@permissionAPI.post("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除权限") @permissionAPI.post("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除权限")
@Log(title="删除权限", business_type=BusinessType.DELETE) @Log(title="删除权限", business_type=BusinessType.DELETE)
@Auth(permission_list=["permission:btn:delete"])
async def delete_permission(request: Request, id: str = Path(description="权限ID")): async def delete_permission(request: Request, id: str = Path(description="权限ID")):
if permission := await Permission.get_or_none(id=id): if permission := await Permission.get_or_none(id=id, del_flag=1):
await permission.delete() permission.del_flag = 0
await permission.save()
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="删除权限成功!") return Response.success(msg="删除权限成功!")
else: else:
return Response.error(msg="删除权限失败,权限不存在!") return Response.error(msg="删除权限失败,权限不存在!")
@ -70,8 +90,9 @@ async def delete_permission(request: Request, id: str = Path(description="权限
@permissionAPI.put("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="更新权限") @permissionAPI.put("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="更新权限")
@permissionAPI.post("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="更新权限") @permissionAPI.post("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="更新权限")
@Log(title="更新权限", business_type=BusinessType.UPDATE) @Log(title="更新权限", business_type=BusinessType.UPDATE)
@Auth(permission_list=["permission:btn:update"])
async def update_permission(request: Request, params: AddPermissionParams, id: str = Path(description="权限ID"), ): async def update_permission(request: Request, params: AddPermissionParams, id: str = Path(description="权限ID"), ):
if permission := await Permission.get_or_none(id=id): if permission := await Permission.get_or_none(id=id, del_flag=1):
permission.name = params.name permission.name = params.name
permission.parent_id = params.parent_id permission.parent_id = params.parent_id
permission.path = params.path permission.path = params.path
@ -94,6 +115,14 @@ async def update_permission(request: Request, params: AddPermissionParams, id: s
permission.fixed_tag = params.fixed_tag permission.fixed_tag = params.fixed_tag
permission.hidden_tag = params.hidden_tag permission.hidden_tag = params.hidden_tag
await permission.save() await permission.save()
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="更新权限成功!") return Response.success(msg="更新权限成功!")
else: else:
return Response.error(msg="更新权限失败,权限不存在!") return Response.error(msg="更新权限失败,权限不存在!")
@ -102,8 +131,9 @@ async def update_permission(request: Request, params: AddPermissionParams, id: s
@permissionAPI.get("/info/{id}", response_model=GetPermissionInfoResponse, response_class=JSONResponse, @permissionAPI.get("/info/{id}", response_model=GetPermissionInfoResponse, response_class=JSONResponse,
summary="查询权限详情") summary="查询权限详情")
@Log(title="查询权限详情", business_type=BusinessType.SELECT) @Log(title="查询权限详情", business_type=BusinessType.SELECT)
@Auth(permission_list=["permission:btn:info"])
async def get_permission(request: Request, id: str = Path(description="权限ID")): async def get_permission(request: Request, id: str = Path(description="权限ID")):
if permission := await Permission.get_or_none(permission_id=id): if permission := await Permission.get_or_none(permission_id=id, del_flag=1):
permission = await permission.first().values( permission = await permission.first().values(
id="id", id="id",
create_by="create_by", create_by="create_by",
@ -140,6 +170,7 @@ async def get_permission(request: Request, id: str = Path(description="权限ID"
@permissionAPI.get("/list", response_model=GetPermissionListResponse, response_class=JSONResponse, @permissionAPI.get("/list", response_model=GetPermissionListResponse, response_class=JSONResponse,
summary="查询权限列表") summary="查询权限列表")
@Log(title="查询权限列表", business_type=BusinessType.SELECT) @Log(title="查询权限列表", business_type=BusinessType.SELECT)
@Auth(permission_list=["permission:btn:list"])
async def get_permission_list( async def get_permission_list(
request: Request, request: Request,
page: int = Query(default=1, description="当前页码"), page: int = Query(default=1, description="当前页码"),
@ -191,8 +222,8 @@ async def get_permission_list(
"hidden_tag": hiddenTag "hidden_tag": hiddenTag
}.items() if v }.items() if v
} }
total = await Permission.filter(**filterArgs).count() total = await Permission.filter(**filterArgs, del_flag=1).count()
result = await Permission.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).order_by( result = await Permission.filter(**filterArgs, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).order_by(
'rank').values( 'rank').values(
id="id", id="id",
create_by="create_by", create_by="create_by",

View File

@ -10,27 +10,32 @@ from typing import Optional
from fastapi import APIRouter, Depends, Path, Query, Request from fastapi import APIRouter, Depends, Path, Query, Request
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from annotation.auth import Auth
from annotation.log import Log from annotation.log import Log
from config.constant import BusinessType from config.constant import BusinessType, RedisKeyConfig
from controller.login import LoginController from controller.login import LoginController
from models import Role, Permission, RolePermission, Department from models import Role, Permission, RolePermission, Department
from schemas.common import BaseResponse from schemas.common import BaseResponse, DeleteListParams
from schemas.role import AddRoleParams, AddRolePermissionParams, GetRolePermissionInfoResponse, \ from schemas.role import AddRoleParams, AddRolePermissionParams, GetRolePermissionInfoResponse, \
GetRolePermissionListResponse GetRolePermissionListResponse
from utils.common import filterKeyValues from utils.common import filterKeyValues
from utils.response import Response from utils.response import Response
roleAPI = APIRouter( roleAPI = APIRouter(
prefix="/role", prefix="/role"
dependencies=[Depends(LoginController.get_current_user)]
) )
@roleAPI.post("/add", response_model=BaseResponse, response_class=JSONResponse, summary="新增角色") @roleAPI.post("/add", response_model=BaseResponse, response_class=JSONResponse, summary="新增角色")
@Log(title="新增角色", business_type=BusinessType.INSERT) @Log(title="新增角色", business_type=BusinessType.INSERT)
async def add_role(request: Request, params: AddRoleParams): @Auth(permission_list=["role:btn:add"])
if await Role.get_or_none(code=params.role_code, department_id=params.department_id, del_flag=1): async def add_role(request: Request, params: AddRoleParams,
current_user: dict = Depends(LoginController.get_current_user)):
if await Role.get_or_none(code=params.code, department_id=params.department_id, del_flag=1):
return Response.error(msg="角色编码已存在!") return Response.error(msg="角色编码已存在!")
sub_departments = current_user.get("sub_departments")
if params.department_id not in sub_departments:
return Response.error(msg="新增失败,无权限!")
department = await Department.get_or_none(id=params.department_id, del_flag=1) department = await Department.get_or_none(id=params.department_id, del_flag=1)
if department: if department:
role = await Role.create( role = await Role.create(
@ -42,13 +47,21 @@ async def add_role(request: Request, params: AddRoleParams):
) )
else: else:
role = await Role.create( role = await Role.create(
code=params.role_code, code=params.code,
name=params.role_name, name=params.name,
status=params.status, status=params.status,
description=params.role_description, description=params.description,
department_id=None, department_id=None,
) )
if role: if role:
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="新增角色成功!") return Response.success(msg="新增角色成功!")
return Response.error(msg="新增角色失败!") return Response.error(msg="新增角色失败!")
@ -56,19 +69,60 @@ async def add_role(request: Request, params: AddRoleParams):
@roleAPI.delete("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除角色") @roleAPI.delete("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除角色")
@roleAPI.post("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除角色") @roleAPI.post("/delete/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="删除角色")
@Log(title="删除角色", business_type=BusinessType.DELETE) @Log(title="删除角色", business_type=BusinessType.DELETE)
async def delete_role(request: Request, id: int = Path(..., description="角色ID")): @Auth(permission_list=["role:btn:delete"])
if role := await Role.get_or_none(id=id, del_flag=1): async def delete_role(request: Request, id: int = Path(..., description="角色ID"),
current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
if role := await Role.get_or_none(id=id, department__id__in=sub_departments, del_flag=1):
# 移除相应角色权限 # 移除相应角色权限
await RolePermission.filter(role_id=role.id).delete() await RolePermission.filter(role_id=role.id, del_flag=1).update(del_flag=0)
await role.delete() role.del_flag = 0
await role.save()
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="删除角色成功!") return Response.success(msg="删除角色成功!")
return Response.error(msg="删除角色失败!") return Response.error(msg="删除角色失败!")
@roleAPI.delete("/deleteList", response_model=BaseResponse, response_class=JSONResponse, summary="批量删除角色")
@roleAPI.post("/deleteList", response_model=BaseResponse, response_class=JSONResponse, summary="批量删除角色")
@Log(title="批量删除角色", business_type=BusinessType.DELETE)
@Auth(permission_list=["role:btn:delete"])
async def delete_role_list(request: Request, params: DeleteListParams,
current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
for id in set(params.ids):
if role := await Role.get_or_none(id=id, del_flag=1, department__id__in=sub_departments):
# 移除相应角色权限
await RolePermission.filter(role_id=role.id, del_flag=1).update(del_flag=0)
role.del_flag = 0
await role.save()
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="批量删除角色成功!")
@roleAPI.put("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改角色") @roleAPI.put("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改角色")
@roleAPI.post("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改角色") @roleAPI.post("/update/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="修改角色")
@Log(title="修改角色", business_type=BusinessType.UPDATE) @Log(title="修改角色", business_type=BusinessType.UPDATE)
async def update_role(request: Request, params: AddRoleParams, id: str = Path(..., description="角色ID")): @Auth(permission_list=["role:btn:update"])
async def update_role(request: Request, params: AddRoleParams, id: str = Path(..., description="角色ID"),
current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
if params.department_id not in sub_departments:
return Response.error(msg="修改失败,无权限!")
if role := await Role.get_or_none(id=id, del_flag=1): if role := await Role.get_or_none(id=id, del_flag=1):
role.code = params.code role.code = params.code
role.name = params.name role.name = params.name
@ -80,14 +134,25 @@ async def update_role(request: Request, params: AddRoleParams, id: str = Path(..
else: else:
role.department_id = None role.department_id = None
await role.save() await role.save()
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="修改角色成功!") return Response.success(msg="修改角色成功!")
return Response.error(msg="修改角色失败!") return Response.error(msg="修改角色失败!")
@roleAPI.get("/info/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="查询角色详情") @roleAPI.get("/info/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="查询角色详情")
@Log(title="查询角色详情", business_type=BusinessType.SELECT) @Log(title="查询角色详情", business_type=BusinessType.SELECT)
async def get_role_info(request: Request, id: int = Path(..., description="角色ID")): @Auth(permission_list=["role:btn:info"])
if role := await Role.get_or_none(id=id, del_flag=1).values( async def get_role_info(request: Request, id: int = Path(..., description="角色ID"),
current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
if role := await Role.get_or_none(id=id, del_flag=1, department__id__in=sub_departments).values(
id="id", id="id",
create_by="create_by", create_by="create_by",
create_time="create_time", create_time="create_time",
@ -109,6 +174,7 @@ async def get_role_info(request: Request, id: int = Path(..., description="角
@roleAPI.get("/list", response_model=BaseResponse, response_class=JSONResponse, summary="查询角色列表") @roleAPI.get("/list", response_model=BaseResponse, response_class=JSONResponse, summary="查询角色列表")
@Log(title="查询角色列表", business_type=BusinessType.SELECT) @Log(title="查询角色列表", business_type=BusinessType.SELECT)
@Auth(permission_list=["role:btn:list"])
async def get_role_list( async def get_role_list(
request: Request, request: Request,
page: int = Query(1, description="页码"), page: int = Query(1, description="页码"),
@ -128,76 +194,12 @@ async def get_role_list(
"status": status "status": status
}.items() if v }.items() if v
} }
# 如果未提供 department_id则使用当前用户的部门 ID
if not department_id: if not department_id:
department_id = current_user.get("department_id") filterArgs["department__id__in"] = current_user.get("sub_departments")
total = await Role.filter(**filterArgs, del_flag=1).count()
# 查询当前部门及其下属部门的角色 data = await Role.filter(**filterArgs, del_flag=1).offset(
all_roles = await get_role_and_subroles(department_id, filterArgs) (page - 1) * pageSize).limit(
pageSize).values(
# 分页处理
total = len(all_roles)
paginated_roles = all_roles[(page - 1) * pageSize: page * pageSize]
return Response.success(data={
"result": paginated_roles,
"total": total,
"page": page
})
async def get_department_and_subdepartments(department_id: str, visited: set = None):
"""
递归查询当前部门及其所有下属部门的 ID
:param department_id: 当前部门 ID
:param visited: 已访问的部门 ID 集合用于避免循环依赖
:return: 部门 ID 列表
"""
if visited is None:
visited = set() # 初始化已访问的部门 ID 集合
# 如果当前部门 ID 已经访问过,直接返回空列表,避免死循环
if department_id in visited:
return []
visited.add(department_id) # 标记当前部门 ID 为已访问
# 查询当前部门
current_department = await Department.filter(
id=department_id
).values_list("id", flat=True)
# 查询直接子部门
sub_departments = await Department.filter(
parent_id=department_id
).values_list("id", flat=True)
# 递归查询子部门的子部门
for sub_department_id in sub_departments[:]: # 使用切片复制避免修改迭代中的列表
sub_sub_departments = await get_department_and_subdepartments(sub_department_id, visited)
sub_departments.extend(sub_sub_departments)
# 合并当前部门和所有下属部门的 ID
return current_department + sub_departments
async def get_role_and_subroles(department_id: str, filterArgs: dict):
"""
查询当前部门及其下属部门的角色
:param department_id: 当前部门 ID
:param filterArgs: 过滤条件
:return: 角色列表
"""
# 递归查询当前部门及其下属部门的 ID
department_ids = await get_department_and_subdepartments(department_id)
# 查询这些部门的角色
roles = await Role.filter(
department__id__in=department_ids,
**filterArgs
).values(
id="id", id="id",
create_by="create_by", create_by="create_by",
create_time="create_time", create_time="create_time",
@ -214,24 +216,24 @@ async def get_role_and_subroles(department_id: str, filterArgs: dict):
department_email="department__email", department_email="department__email",
) )
# 根据 id 去重 return Response.success(data={
unique_roles = [] "result": data,
seen_ids = set() # 用于记录已经处理过的角色 ID "total": total,
for role in roles: "page": page,
if role["id"] not in seen_ids: "pageSize": pageSize
unique_roles.append(role) })
seen_ids.add(role["id"])
return unique_roles
@roleAPI.post("/addPermission", response_model=BaseResponse, response_class=JSONResponse, summary="新增角色权限") @roleAPI.post("/addPermission", response_model=BaseResponse, response_class=JSONResponse, summary="新增角色权限")
@Log(title="新增角色权限", business_type=BusinessType.INSERT) @Log(title="新增角色权限", business_type=BusinessType.INSERT)
@Auth(permission_list=["role:btn:addPermission"])
async def add_role_permission(request: Request, params: AddRolePermissionParams, async def add_role_permission(request: Request, params: AddRolePermissionParams,
id: str = Path(..., description="角色ID")): id: str = Path(..., description="角色ID"),
if role := await Role.get_or_none(id=id, del_flag=1): current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
if role := await Role.get_or_none(id=id, del_flag=1, department__id__in=sub_departments):
# 已有角色权限 # 已有角色权限
rolePermissions = await RolePermission.filter(role_id=id).all().values("permission_id") rolePermissions = await RolePermission.filter(role_id=id, del_flag=1).values("permission_id")
rolePermissions = await filterKeyValues(rolePermissions, "permission_id") rolePermissions = await filterKeyValues(rolePermissions, "permission_id")
# 利用集合筛选出角色权限中不存在的权限 # 利用集合筛选出角色权限中不存在的权限
add_list = set(params.permission_ids).difference(set(rolePermissions)) add_list = set(params.permission_ids).difference(set(rolePermissions))
@ -243,6 +245,14 @@ async def add_role_permission(request: Request, params: AddRolePermissionParams,
role_id=role.id, role_id=role.id,
permission_id=permission.id permission_id=permission.id
) )
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="新增角色权限成功!") return Response.success(msg="新增角色权限成功!")
return Response.error(msg="新增角色权限失败!") return Response.error(msg="新增角色权限失败!")
@ -252,9 +262,21 @@ async def add_role_permission(request: Request, params: AddRolePermissionParams,
@roleAPI.post("/deletePermission/{id}", response_model=BaseResponse, response_class=JSONResponse, @roleAPI.post("/deletePermission/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="删除角色权限") summary="删除角色权限")
@Log(title="删除角色权限", business_type=BusinessType.DELETE) @Log(title="删除角色权限", business_type=BusinessType.DELETE)
async def delete_role_permission(request: Request, id: int = Path(..., description="角色权限ID")): @Auth(permission_list=["role:btn:deletePermission"])
if rolePermission := await RolePermission.get_or_none(id=id, del_flag=1): async def delete_role_permission(request: Request, id: int = Path(..., description="角色权限ID"),
await rolePermission.delete() current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
if rolePermission := await RolePermission.get_or_none(id=id, del_flag=1, role__department__id__in=sub_departments):
rolePermission.del_flag = 0
await rolePermission.save()
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="删除角色权限成功!") return Response.success(msg="删除角色权限成功!")
return Response.error(msg="删除角色权限失败!") return Response.error(msg="删除角色权限失败!")
@ -263,11 +285,14 @@ async def delete_role_permission(request: Request, id: int = Path(..., descripti
@roleAPI.post("/updatePermission/{id}", response_model=BaseResponse, response_class=JSONResponse, @roleAPI.post("/updatePermission/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="修改角色权限") summary="修改角色权限")
@Log(title="修改角色权限", business_type=BusinessType.UPDATE) @Log(title="修改角色权限", business_type=BusinessType.UPDATE)
@Auth(permission_list=["role:btn:updatePermission"])
async def update_role_permission(request: Request, params: AddRolePermissionParams, async def update_role_permission(request: Request, params: AddRolePermissionParams,
id: str = Path(..., description="角色ID")): id: str = Path(..., description="角色ID"),
if role := await Role.get_or_none(id=id, del_flag=1): current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
if role := await Role.get_or_none(id=id, del_flag=1, department__id__in=sub_departments):
# 已有角色权限 # 已有角色权限
rolePermissions = await RolePermission.filter(role_id=role.id).all().values("permission_id") rolePermissions = await RolePermission.filter(role_id=role.id, del_flag=1).values("permission_id")
rolePermissions = await filterKeyValues(rolePermissions, "permission_id") rolePermissions = await filterKeyValues(rolePermissions, "permission_id")
# 利用集合筛选出角色权限中不存在的权限 # 利用集合筛选出角色权限中不存在的权限
delete_list = set(rolePermissions).difference(set(params.permission_ids)) delete_list = set(rolePermissions).difference(set(params.permission_ids))
@ -275,10 +300,18 @@ async def update_role_permission(request: Request, params: AddRolePermissionPara
add_list = set(params.permission_ids).difference(set(rolePermissions)) add_list = set(params.permission_ids).difference(set(rolePermissions))
# 循环删除角色权限 # 循环删除角色权限
for item in delete_list: for item in delete_list:
await RolePermission.filter(role_id=id, permission_id=item).delete() await RolePermission.filter(role_id=id, permission_id=item, del_flag=1).update(del_flag=0)
# 循环添加角色权限 # 循环添加角色权限
for item in add_list: for item in add_list:
await RolePermission.create(role_id=id, permission_id=item) await RolePermission.create(role_id=id, permission_id=item)
# 更新用户信息缓存
userInfos = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_INFO.key}*')
if userInfos:
await request.app.state.redis.delete(*userInfos)
# 更新用户路由缓存
userRoutes = await request.app.state.redis.keys(f'{RedisKeyConfig.USER_ROUTES.key}*')
if userRoutes:
await request.app.state.redis.delete(*userRoutes)
return Response.success(msg="修改角色权限成功!") return Response.success(msg="修改角色权限成功!")
return Response.error(msg="修改角色权限失败!") return Response.error(msg="修改角色权限失败!")
@ -286,8 +319,11 @@ async def update_role_permission(request: Request, params: AddRolePermissionPara
@roleAPI.get("/permissionInfo/{id}", response_model=GetRolePermissionInfoResponse, response_class=JSONResponse, @roleAPI.get("/permissionInfo/{id}", response_model=GetRolePermissionInfoResponse, response_class=JSONResponse,
summary="获取角色权限信息") summary="获取角色权限信息")
@Log(title="获取角色权限信息", business_type=BusinessType.SELECT) @Log(title="获取角色权限信息", business_type=BusinessType.SELECT)
async def get_role_permission_info(request: Request, id: int = Path(..., description="角色权限ID")): @Auth(permission_list=["role:btn:permissionInfo"])
if rolePermission := await RolePermission.get_or_none(id=id, del_flag=1): async def get_role_permission_info(request: Request, id: int = Path(..., description="角色权限ID"),
current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
if rolePermission := await RolePermission.get_or_none(id=id, del_flag=1, role__department__id__in=sub_departments):
data = await rolePermission.first().values( data = await rolePermission.first().values(
id="id", id="id",
create_by="create_by", create_by="create_by",
@ -309,9 +345,12 @@ async def get_role_permission_info(request: Request, id: int = Path(..., descrip
@roleAPI.get("/permissionList/{id}", response_model=GetRolePermissionListResponse, response_class=JSONResponse, @roleAPI.get("/permissionList/{id}", response_model=GetRolePermissionListResponse, response_class=JSONResponse,
summary="获取角色权限列表") summary="获取角色权限列表")
@Log(title="获取角色权限列表", business_type=BusinessType.SELECT) @Log(title="获取角色权限列表", business_type=BusinessType.SELECT)
async def get_role_permission_list(request: Request, id: str = Path(..., description="角色ID")): @Auth(permission_list=["role:btn:permissionList"])
total = await RolePermission.filter(role_id=id).count() async def get_role_permission_list(request: Request, id: str = Path(..., description="角色ID"),
data = await RolePermission.filter(role_id=id).values( current_user: dict = Depends(LoginController.get_current_user)):
sub_departments = current_user.get("sub_departments")
total = await RolePermission.filter(role_id=id, role__department__id__in=sub_departments, del_flag=1).count()
data = await RolePermission.filter(role_id=id, role__department__id__in=sub_departments, del_flag=1).values(
id="id", id="id",
create_by="create_by", create_by="create_by",
create_time="create_time", create_time="create_time",
@ -329,5 +368,6 @@ async def get_role_permission_list(request: Request, id: str = Path(..., descrip
return Response.success(data={ return Response.success(data={
"result": data, "result": data,
"total": total, "total": total,
"page": 1 "page": 1,
"pageSize": 9999
}) })

View File

@ -14,12 +14,14 @@ import psutil
from fastapi import APIRouter, Depends, Request from fastapi import APIRouter, Depends, Request
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from annotation.auth import Auth
from annotation.log import Log from annotation.log import Log
from config.constant import BusinessType from config.constant import BusinessType
from controller.login import LoginController from controller.login import LoginController
from schemas.server import GetServerInfoResponse, CpuInfo, MemoryInfo, SystemInfo, PythonInfo, SystemFiles, \ from schemas.server import GetServerInfoResponse, CpuInfo, MemoryInfo, SystemInfo, PythonInfo, SystemFiles, \
GetSystemInfoResult GetSystemInfoResult
from utils.common import bytes2human from utils.common import bytes2human
from utils.log import logger
from utils.response import Response from utils.response import Response
serverAPI = APIRouter( serverAPI = APIRouter(
@ -30,6 +32,7 @@ serverAPI = APIRouter(
@serverAPI.get("", response_class=JSONResponse, response_model=GetServerInfoResponse, summary="获取服务器信息") @serverAPI.get("", response_class=JSONResponse, response_model=GetServerInfoResponse, summary="获取服务器信息")
@Log(title="获取服务器信息", business_type=BusinessType.SELECT) @Log(title="获取服务器信息", business_type=BusinessType.SELECT)
@Auth(permission_list=["server:btn:info"])
async def get_server_info(request: Request): async def get_server_info(request: Request):
# CPU信息 # CPU信息
# 获取CPU总核心数 # 获取CPU总核心数
@ -96,17 +99,21 @@ async def get_server_info(request: Request):
io = psutil.disk_partitions() io = psutil.disk_partitions()
sys_files = [] sys_files = []
for i in io: for i in io:
o = psutil.disk_usage(i.device) try:
disk_data = SystemFiles( o = psutil.disk_usage(i.device)
dirName=i.device, disk_data = SystemFiles(
sysTypeName=i.fstype, dirName=i.device,
typeName='本地固定磁盘(' + i.mountpoint.replace('\\', '') + '', sysTypeName=i.fstype,
total=bytes2human(o.total), typeName='本地固定磁盘(' + i.mountpoint.replace('\\', '') + '',
used=bytes2human(o.used), total=bytes2human(o.total),
free=bytes2human(o.free), used=bytes2human(o.used),
usage=f'{psutil.disk_usage(i.device).percent}%', free=bytes2human(o.free),
) usage=f'{psutil.disk_usage(i.device).percent}%',
sys_files.append(disk_data) )
sys_files.append(disk_data)
except Exception as e:
logger.error(f"获取磁盘信息失败:{e}")
continue
result = GetSystemInfoResult(cpu=cpu, memory=mem, system=sys, python=py, systemFiles=sys_files) result = GetSystemInfoResult(cpu=cpu, memory=mem, system=sys, python=py, systemFiles=sys_files)
return Response.success(data=result) return Response.success(data=result)

View File

@ -15,15 +15,16 @@ from fastapi.responses import JSONResponse
from annotation.auth import Auth from annotation.auth import Auth
from annotation.log import Log from annotation.log import Log
from config.constant import BusinessType from config.constant import BusinessType, RedisKeyConfig
from config.env import UploadConfig from config.env import UploadConfig
from controller.login import LoginController from controller.login import LoginController
from controller.query import QueryController from controller.query import QueryController
from exceptions.exception import ModelValidatorException from exceptions.exception import ModelValidatorException
from models import File as FileModel from models import File as FileModel
from models import Role, Department, QueryCode from models import Role, Department, OperationLog, LoginLog
from models.code import QueryCode
from models.user import User, UserRole from models.user import User, UserRole
from schemas.common import BaseResponse from schemas.common import BaseResponse, DeleteListParams
from schemas.department import GetDepartmentListResponse from schemas.department import GetDepartmentListResponse
from schemas.file import UploadFileResponse from schemas.file import UploadFileResponse
from schemas.user import AddUserParams, GetUserListResponse, GetUserInfoResponse, UpdateUserParams, \ from schemas.user import AddUserParams, GetUserListResponse, GetUserInfoResponse, UpdateUserParams, \
@ -33,19 +34,21 @@ from utils.common import filterKeyValues
from utils.password import Password from utils.password import Password
from utils.response import Response 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="新增用户") @userAPI.post("/add", response_class=JSONResponse, response_model=BaseResponse, summary="新增用户")
@Log(title="新增用户", business_type=BusinessType.INSERT) @Log(title="新增用户", business_type=BusinessType.INSERT)
@Auth(["user:btn:addUser"])
async def add_user( async def add_user(
request: Request, 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): if await QueryController.register_user_before(username=params.username, phone=params.phone, email=params.email):
return Response.error(msg="添加失败,用户已存在!") return Response.error(msg="添加失败,用户已存在!")
params.password = await Password.get_password_hash(input_password=params.password) params.password = await Password.get_password_hash(input_password=params.password)
department = await Department.get_or_none(id=params.department_id) department = await Department.get_or_none(id=params.department_id, del_flag=1)
user = await User.create( user = await User.create(
username=params.username, username=params.username,
password=params.password, password=params.password,
@ -65,35 +68,75 @@ async def add_user(
@userAPI.delete("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除用户") @userAPI.delete("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除用户")
@userAPI.post("/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) @Log(title="删除用户", business_type=BusinessType.DELETE)
@Auth(["user:btn:deleteUser"])
async def delete_user( async def delete_user(
request: Request, request: Request,
id: str = Path(..., description="用户ID")): id: str = Path(..., description="用户ID"),
if user := await User.get_or_none(id=id): current_user: dict = Depends(LoginController.get_current_user)
await user.delete() ):
sub_departments = current_user.get("sub_departments")
if user := await User.get_or_none(id=id, department__id__in=sub_departments, del_flag=1):
user.del_flag = 0
await user.save()
# 移除用户角色
await UserRole.filter(user_id=user.id, del_flag=1).update(del_flag=0)
# 移除用户登录日志
await LoginLog.filter(user_id=user.id, del_flag=1).update(del_flag=0)
# 移除用户操作日志
await OperationLog.filter(user_id=user.id, del_flag=1).update(del_flag=0)
# 更新用户信息缓存
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}')
# 更新用户路由缓存
if await request.app.state.redis.get(f'{RedisKeyConfig.USER_ROUTES.key}:{id}'):
await request.app.state.redis.delete(f'{RedisKeyConfig.USER_ROUTES.key}:{id}')
return Response.success(msg="删除成功!") return Response.success(msg="删除成功!")
else: else:
return Response.error(msg="删除失败,用户不存在!") return Response.error(msg="删除失败,用户不存在!")
@userAPI.delete("/deleteUserList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除用户")
@userAPI.post("/deleteUserList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除用户")
@Log(title="批量删除用户", business_type=BusinessType.DELETE)
@Auth(["user:btn:deleteUser"])
async def delete_user_list(
request: Request,
params: DeleteListParams,
current_user: dict = Depends(LoginController.get_current_user)
):
sub_departments = current_user.get("sub_departments")
for id in params.ids:
if user := await User.get_or_none(id=id, department__id__in=sub_departments, del_flag=1):
user.del_flag = 0
await user.save()
return Response.success(msg="删除成功!")
@userAPI.put("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="更新用户") @userAPI.put("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="更新用户")
@userAPI.post("/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) @Log(title="更新用户", business_type=BusinessType.UPDATE)
@Auth(["user:btn:updateUser"])
async def update_user( async def update_user(
request: Request, request: Request,
params: UpdateUserParams, params: UpdateUserParams,
id: str = Path(..., description="用户ID")): id: str = Path(..., description="用户ID"),
if user := await User.get_or_none(id=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, del_flag=1):
user.username = params.username user.username = params.username
user.nickname = params.nickname user.nickname = params.nickname
user.phone = params.phone user.phone = params.phone
user.email = params.email user.email = params.email
user.gender = params.gender user.gender = params.gender
user.status = params.status user.status = params.status
if department := await Department.get_or_none(id=params.department_id): if department := await Department.get_or_none(id=params.department_id, del_flag=1):
user.department = department user.department = department
else: else:
user.department = None user.department = None
await user.save() 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="更新成功!") return Response.success(msg="更新成功!")
else: else:
return Response.error(msg="更新失败,用户不存在!") return Response.error(msg="更新失败,用户不存在!")
@ -101,8 +144,10 @@ async def update_user(
@userAPI.get("/info/{id}", response_class=JSONResponse, response_model=GetUserInfoResponse, summary="获取用户信息") @userAPI.get("/info/{id}", response_class=JSONResponse, response_model=GetUserInfoResponse, summary="获取用户信息")
@Log(title="获取用户信息", business_type=BusinessType.SELECT) @Log(title="获取用户信息", business_type=BusinessType.SELECT)
async def get_user_info(request: Request, id: str = Path(..., description="用户ID")): @Auth(["user:btn:Userinfo"])
if user := await User.get_or_none(id=id): 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, del_flag=1):
user = await user.first().values( user = await user.first().values(
id="id", id="id",
create_time="create_time", create_time="create_time",
@ -113,6 +158,7 @@ async def get_user_info(request: Request, id: str = Path(..., description="用
nickname="nickname", nickname="nickname",
gender="gender", gender="gender",
status="status", status="status",
avatar="avatar",
department_id="department__id", department_id="department__id",
) )
return Response.success(data=user) return Response.success(data=user)
@ -134,7 +180,9 @@ async def get_user_list(
gender: Optional[str] = Query(default=None, description="性别"), gender: Optional[str] = Query(default=None, description="性别"),
status: Optional[str] = Query(default=None, description="状态"), status: Optional[str] = Query(default=None, description="状态"),
department_id: Optional[str] = Query(default=None, description="部门ID"), 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 = { filterArgs = {
f'{k}__contains': v for k, v in { f'{k}__contains': v for k, v in {
'username': username, 'username': username,
@ -146,8 +194,10 @@ async def get_user_list(
'department_id': department_id 'department_id': department_id
}.items() if v }.items() if v
} }
total = await User.filter(**filterArgs).count() if not department_id:
result = await User.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).values( filterArgs['department_id__in'] = sub_departments
total = await User.filter(**filterArgs, del_flag=1).count()
result = await User.filter(**filterArgs, del_flag=1).offset((page - 1) * pageSize).limit(pageSize).values(
id="id", id="id",
create_time="create_time", create_time="create_time",
update_time="update_time", update_time="update_time",
@ -155,6 +205,7 @@ async def get_user_list(
email="email", email="email",
phone="phone", phone="phone",
nickname="nickname", nickname="nickname",
avatar="avatar",
gender="gender", gender="gender",
status="status", status="status",
department_id="department__id", department_id="department__id",
@ -162,19 +213,26 @@ async def get_user_list(
return Response.success(data={ return Response.success(data={
"result": result, "result": result,
"total": total, "total": total,
"page": page "page": page,
"pageSize": pageSize
}) })
@userAPI.post("/addRole", response_model=BaseResponse, response_class=JSONResponse, summary="添加用户角色") @userAPI.post("/addRole", response_model=BaseResponse, response_class=JSONResponse, summary="添加用户角色")
@Log(title="添加用户角色", business_type=BusinessType.INSERT) @Log(title="添加用户角色", business_type=BusinessType.INSERT)
async def add_user_role(request: Request, params: AddUserRoleParams): @Auth(["user:btn:addRole"])
if await UserRole.get_or_none(user_id=params.user_id, role_id=params.role_id, del_flag=1): 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="该用户已存在该角色!") return Response.error(msg="该用户已存在该角色!")
if user := await User.get_or_none(id=params.user_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): 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) userRole = await UserRole.create(user_id=user.id, role_id=role.id)
if userRole: 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="添加成功!") return Response.success(msg="添加成功!")
else: else:
return Response.error(msg="添加失败!") return Response.error(msg="添加失败!")
@ -189,9 +247,15 @@ async def add_user_role(request: Request, params: AddUserRoleParams):
@userAPI.post("/deleteRole/{id}", response_model=BaseResponse, response_class=JSONResponse, @userAPI.post("/deleteRole/{id}", response_model=BaseResponse, response_class=JSONResponse,
summary="删除用户角色") summary="删除用户角色")
@Log(title="删除用户角色", business_type=BusinessType.DELETE) @Log(title="删除用户角色", business_type=BusinessType.DELETE)
async def delete_user_role(request: Request, id: str = Path(description="用户角色ID")): @Auth(["user:btn:deleteRole"])
if userRole := await UserRole.get_or_none(id=id, del_flag=1): async def delete_user_role(request: Request, id: str = Path(description="用户角色ID"),
await userRole.delete() 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):
userRole.del_flag = 0
await userRole.save()
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="删除成功!") return Response.success(msg="删除成功!")
else: else:
return Response.error(msg="删除失败,用户角色不存在!") return Response.error(msg="删除失败,用户角色不存在!")
@ -201,9 +265,13 @@ async def delete_user_role(request: Request, id: str = Path(description="用户
@userAPI.post("/updateRole", response_model=BaseResponse, response_class=JSONResponse, @userAPI.post("/updateRole", response_model=BaseResponse, response_class=JSONResponse,
summary="修改用户角色") summary="修改用户角色")
@Log(title="修改用户角色", business_type=BusinessType.UPDATE) @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") userRoles = await filterKeyValues(userRoles, "role_id")
# 利用集合找到需要添加的角色 # 利用集合找到需要添加的角色
addRoles = set(params.role_ids).difference(set(userRoles)) addRoles = set(params.role_ids).difference(set(userRoles))
@ -211,20 +279,27 @@ async def update_user_role(request: Request, params: UpdateUserRoleParams):
deleteRoles = set(userRoles).difference(set(params.role_ids)) deleteRoles = set(userRoles).difference(set(params.role_ids))
# 添加角色 # 添加角色
for role_id in addRoles: 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) await UserRole.create(user_id=params.user_id, role_id=role.id)
# 删除角色 # 删除角色
for role_id in deleteRoles: 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,
await userRole.delete() user__department__id__in=sub_departments):
userRole.del_flag = 0
await userRole.save()
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="修改成功!") return Response.success(msg="修改成功!")
@userAPI.get("/roleInfo/{id}", response_model=GetUserRoleInfoResponse, response_class=JSONResponse, @userAPI.get("/roleInfo/{id}", response_model=GetUserRoleInfoResponse, response_class=JSONResponse,
summary="获取用户角色信息") summary="获取用户角色信息")
@Log(title="获取用户角色信息", business_type=BusinessType.SELECT) @Log(title="获取用户角色信息", business_type=BusinessType.SELECT)
async def get_user_role_info(request: Request, id: str = Path(description="用户角色ID")): @Auth(["user:btn:roleInfo"])
if userRole := await UserRole.get_or_none(id=id, del_flag=1): 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( data = await userRole.first().values(
id="id", id="id",
user_id="user__id", user_id="user__id",
@ -243,11 +318,14 @@ async def get_user_role_info(request: Request, id: str = Path(description="用
@userAPI.get("/roleList/{id}", response_model=GetDepartmentListResponse, response_class=JSONResponse, @userAPI.get("/roleList/{id}", response_model=GetDepartmentListResponse, response_class=JSONResponse,
summary="获取用户角色列表") summary="获取用户角色列表")
@Log(title="获取用户角色列表", business_type=BusinessType.SELECT) @Log(title="获取用户角色列表", business_type=BusinessType.SELECT)
@Auth(["user:btn:roleList"])
async def get_user_role_list( async def get_user_role_list(
request: Request, request: Request,
id: str = Path(description="用户ID"), 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", id="id",
department_id="user__department__id", department_id="user__department__id",
department_name="user__department__name", department_name="user__department__name",
@ -263,15 +341,19 @@ async def get_user_role_list(
return Response.success(data={ return Response.success(data={
"result": result, "result": result,
"total": len(result), "total": len(result),
"page": 1 "page": 1,
"pageSize": 10,
}) })
@userAPI.get("/permissionList/{id}", response_class=JSONResponse, response_model=GetUserPermissionListResponse, @userAPI.get("/permissionList/{id}", response_class=JSONResponse, response_model=GetUserPermissionListResponse,
summary="获取用户权限列表") summary="获取用户权限列表")
@Log(title="获取用户权限列表", business_type=BusinessType.SELECT) @Log(title="获取用户权限列表", business_type=BusinessType.SELECT)
async def get_user_permission_list(request: Request, id: str = Path(description="用户ID")): @Auth(["user:btn:permissionList"])
permissions = await QueryController.get_user_permissions(user_id=id) 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") permissions = await filterKeyValues(permissions, "id")
# 获取用户角色 # 获取用户角色
return Response.success(data=list(set(permissions))) return Response.success(data=list(set(permissions)))
@ -279,11 +361,13 @@ async def get_user_permission_list(request: Request, id: str = Path(description=
@userAPI.post("/avatar/{id}", response_model=UploadFileResponse, response_class=JSONResponse, summary="上传用户头像") @userAPI.post("/avatar/{id}", response_model=UploadFileResponse, response_class=JSONResponse, summary="上传用户头像")
@Log(title="上传用户头像", business_type=BusinessType.UPDATE) @Log(title="上传用户头像", business_type=BusinessType.UPDATE)
@Auth(["user:btn:uploadAvatar"])
async def upload_user_avatar( async def upload_user_avatar(
request: Request, request: Request,
id: str = Path(description="用户ID"), id: str = Path(description="用户ID"),
file: UploadFile = File(...)): file: UploadFile = File(...), current_user: dict = Depends(LoginController.get_current_user)):
if user := await User.get_or_none(id=id): sub_departments = current_user.get("sub_departments")
if user := await User.get_or_none(id=id, del_flag=1, department__id__in=sub_departments):
image_mimetypes = [ image_mimetypes = [
'image/jpeg', 'image/jpeg',
'image/png', 'image/png',
@ -335,6 +419,8 @@ async def upload_user_avatar(
create_time="create_time", create_time="create_time",
update_time="update_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.success(data=result)
return Response.failure(msg="用户不存在!") return Response.failure(msg="用户不存在!")
@ -343,8 +429,9 @@ async def upload_user_avatar(
@userAPI.post("/resetPassword/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="重置用户密码") @userAPI.post("/resetPassword/{id}", response_model=BaseResponse, response_class=JSONResponse, summary="重置用户密码")
@Log(title="重置用户密码", business_type=BusinessType.UPDATE) @Log(title="重置用户密码", business_type=BusinessType.UPDATE)
@Auth(permission_list=["user:btn:reset_password"]) @Auth(permission_list=["user:btn:reset_password"])
async def reset_user_password(request: Request, params: ResetPasswordParams, id: str = Path(description="用户ID")): async def reset_user_password(request: Request, params: ResetPasswordParams, id: str = Path(description="用户ID"),
if user := await User.get_or_none(id=id): current_user: dict = Depends(LoginController.get_current_user)):
if user := await User.get_or_none(id=id, del_flag=1, department__id__in=current_user.get("sub_departments")):
user.password = await Password.get_password_hash(params.password) user.password = await Password.get_password_hash(params.password)
await user.save() await user.save()
return Response.success(msg="重置密码成功!") return Response.success(msg="重置密码成功!")
@ -444,4 +531,4 @@ async def get_user_statistics(request: Request, current_user: dict = Depends(Log
"last_month_count": last_month_count, "last_month_count": last_month_count,
"before_14day_count_success": before_14day_count_success, "before_14day_count_success": before_14day_count_success,
"before_14day_count_fail": before_14day_count_fail, "before_14day_count_fail": before_14day_count_fail,
}) })

View File

@ -79,7 +79,7 @@ class Redis:
# 删除匹配的键 # 删除匹配的键
if keys: if keys:
await app.state.redis.delete(*keys) await app.state.redis.delete(*keys)
config = await Config.all().values() config = await Config.filter(del_flag=1).values()
for item in config: for item in config:
await app.state.redis.set(f"{RedisKeyConfig.SYSTEM_CONFIG.key}:{item.get('key')}", await app.state.redis.set(f"{RedisKeyConfig.SYSTEM_CONFIG.key}:{item.get('key')}",
item.get('value'), ) item.get('value'), )

View File

@ -130,7 +130,7 @@ class LoginController:
userInfo = await QueryController.get_user_info(user_id=user_id) userInfo = await QueryController.get_user_info(user_id=user_id)
await request.app.state.redis.set(f'{RedisKeyConfig.USER_INFO.key}:{user_id}', await request.app.state.redis.set(f'{RedisKeyConfig.USER_INFO.key}:{user_id}',
str(jsonable_encoder(userInfo)), str(jsonable_encoder(userInfo)),
ex=timedelta(minutes=5)) ex=timedelta(minutes=2))
if not userInfo: if not userInfo:
logger.warning('用户token不合法') logger.warning('用户token不合法')
raise AuthException(data='', message='用户token不合法') raise AuthException(data='', message='用户token不合法')
@ -160,11 +160,11 @@ class LoginController:
return False return False
@classmethod @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: for permission in permissions:
permission["id"] = str(permission["id"]) permission["id"] = str(permission["id"])
permission["parentId"] = str(permission["parentId"]) if permission.get("parentId") else "" permission["parentId"] = str(permission["parentId"]) if permission.get("parentId") else ""
@ -239,7 +239,7 @@ class LoginController:
return complete_data return complete_data
@classmethod @classmethod
async def get_online_user(cls, request: Request) -> list: async def get_online_user(cls, request: Request, sub_departments: list) -> list:
""" """
获取在线用户 获取在线用户
""" """
@ -251,7 +251,8 @@ class LoginController:
for item in access_token_values_list: for item in access_token_values_list:
payload = jwt.decode(item, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm]) payload = jwt.decode(item, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm])
session_id = payload.get("session_id") session_id = payload.get("session_id")
result = await LoginLog.get_or_none(session_id=session_id).values( result = await LoginLog.get_or_none(session_id=session_id, user__department__id__in=sub_departments,
del_flag=1).values(
id="id", id="id",
user_id="user__id", user_id="user__id",
username="user__username", username="user__username",
@ -268,5 +269,7 @@ class LoginController:
create_time="create_time", create_time="create_time",
update_time="update_time" update_time="update_time"
) )
if not result:
continue
online_info_list.append(result) online_info_list.append(result)
return online_info_list return online_info_list

View File

@ -9,7 +9,7 @@ from typing import Union
from tortoise.expressions import Q from tortoise.expressions import Q
from models import User, UserRole, RolePermission from models import User, UserRole, RolePermission, Department
from utils.common import filterKeyValues from utils.common import filterKeyValues
@ -65,6 +65,8 @@ class QueryController:
userRole = await filterKeyValues(userRoles, "role_code") userRole = await filterKeyValues(userRoles, "role_code")
# 获取用户角色ID # 获取用户角色ID
userRoleIds = await filterKeyValues(userRoles, "role_id") userRoleIds = await filterKeyValues(userRoles, "role_id")
# 获取用户下属部门
subDepartments = await cls.get_sub_department_ids(department_id=userInfo['department_id'])
# 根据用户角色ID获取用户权限 # 根据用户角色ID获取用户权限
permissions = [] permissions = []
for item in userRoleIds: for item in userRoleIds:
@ -78,6 +80,7 @@ class QueryController:
permissions = list(set(permissions)) permissions = list(set(permissions))
userInfo["roles"] = userRole userInfo["roles"] = userRole
userInfo["permissions"] = permissions userInfo["permissions"] = permissions
userInfo["sub_departments"] = subDepartments
return userInfo return userInfo
@classmethod @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) return await User.get_or_none(Q(username=username) | Q(email=email) | Q(phone=phone), del_flag=1)
@classmethod @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_id="role__id",
role_name="role__name", role_name="role__name",
role_code="role__code" role_code="role__code"
@ -133,3 +136,17 @@ class QueryController:
) )
permissions.extend(permission) permissions.extend(permission)
return permissions 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, del_flag=1).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))

View File

@ -8,7 +8,7 @@
from models.code import Code, QueryCode, QueryCodeLog from models.code import Code, QueryCode, QueryCodeLog
from models.config import Config from models.config import Config
from models.department import Department, DepartmentRole from models.department import Department
from models.file import File from models.file import File
from models.i18n import I18n, Locale from models.i18n import I18n, Locale
from models.log import LoginLog, OperationLog from models.log import LoginLog, OperationLog
@ -18,7 +18,6 @@ from models.user import User, UserRole
__all__ = [ __all__ = [
'Department', 'Department',
'DepartmentRole',
'File', 'File',
'LoginLog', 'LoginLog',
'OperationLog', 'OperationLog',

View File

@ -118,38 +118,3 @@ class Department(BaseModel):
table = "department" # 数据库表名 table = "department" # 数据库表名
table_description = "部门表" # 表描述 table_description = "部门表" # 表描述
ordering = ["sort", "-create_time"] # 默认按排序权重和创建时间排序 ordering = ["sort", "-create_time"] # 默认按排序权重和创建时间排序
class DepartmentRole(BaseModel):
"""
部门角色表模型
"""
department = fields.ForeignKeyField(
"models.Department",
related_name="department_roles",
description="部门ID",
source_field="department_id" # 映射到数据库字段 department_id
)
"""
部门ID
- 外键关联到 Department
- 映射到数据库字段 department_id
"""
role = fields.ForeignKeyField(
"models.Role",
related_name="department_roles",
description="角色ID",
source_field="role_id" # 映射到数据库字段 role_id
)
"""
角色ID
- 外键关联到 Role
- 映射到数据库字段 role_id
"""
class Meta:
table = "department_role" # 数据库表名
table_description = "部门角色表" # 表描述
unique_together = (("department_id", "role_id"),) # 唯一约束,防止重复分配

View File

@ -17,13 +17,11 @@ class User(BaseModel):
username = fields.CharField( username = fields.CharField(
max_length=255, max_length=255,
unique=True,
description="用户名", description="用户名",
source_field="username" # 映射到数据库字段 username source_field="username" # 映射到数据库字段 username
) )
""" """
用户名 用户名
- 必须唯一
- 最大长度为 255 个字符 - 最大长度为 255 个字符
- 映射到数据库字段 username - 映射到数据库字段 username
""" """

View File

@ -42,13 +42,6 @@ class AddConfigParams(BaseModel):
remark: Optional[str] = Field(default=None, max_length=255, description="备注信息") remark: Optional[str] = Field(default=None, max_length=255, description="备注信息")
class DeleteConfigListParams(BaseModel):
"""
批量删除配置参数模型
"""
ids: List[str] = Field(default=[], description="配置ID")
class GetConfigInfoResponse(BaseResponse): class GetConfigInfoResponse(BaseResponse):
""" """
获取配置模型信息响应 获取配置模型信息响应

View File

@ -86,13 +86,6 @@ class AddDepartmentParams(BaseModel):
} }
class DeleteDepartmentListParams(BaseModel):
"""
删除部门参数模型
"""
ids: List[str] = Field(..., description="部门ID列表")
class GetDepartmentListResult(ListQueryResult): class GetDepartmentListResult(ListQueryResult):
""" """
获取部门列表结果模型 获取部门列表结果模型
@ -105,74 +98,3 @@ class GetDepartmentListResponse(BaseResponse):
获取部门列表响应模型 获取部门列表响应模型
""" """
data: GetDepartmentListResult = Field(default=None, description="响应数据") data: GetDepartmentListResult = Field(default=None, description="响应数据")
class AddDepartmentRoleParams(BaseModel):
"""
添加部门角色参数模型
"""
department_id: str = Field(..., max_length=36, description="部门ID")
role_id: str = Field(..., max_length=36, description="角色ID")
class Config:
json_schema_extra = {
"example": {
"department_id": "550e8400-e29b-41d4-a716-446655440000",
"role_id": "550e8400-e29b-41d4-a716-446655440000"
}
}
class DepartmentRoleInfo(BaseModel):
"""
部门角色信息模型
"""
id: str = Field(..., max_length=36, description="主键ID")
department_id: str = Field(..., max_length=36, description="部门ID")
department_name: str = Field(..., max_length=100, description="部门名称")
department_phone: str = Field(..., max_length=30, description="部门电话")
department_principal: str = Field(..., max_length=64, description="部门负责人")
department_email: str = Field(..., max_length=128, description="部门邮箱")
role_name: str = Field(..., max_length=100, description="角色名称")
role_code: str = Field(..., max_length=100, description="角色编码")
role_id: str = Field(..., max_length=36, description="角色ID")
create_time: datetime = Field(..., description="创建时间")
update_time: datetime = Field(..., description="更新时间")
class Config:
json_schema_extra = {
"example": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"department_id": "550e8400-e29b-41d4-a716-446655440000",
"department_name": "研发部",
"department_phone": "1234567890",
"department_principal": "张三",
"department_email": "dev@example.com",
"role_name": "管理员",
"role_code": "admin",
"role_id": "550e8400-e29b-41d4-a716-446655440000",
"create_time": "2023-10-01T12:00:00",
"update_time": "2023-10-01T12:00:00"
}
}
class GetDepartmentRoleInfoResponse(BaseResponse):
"""
获取部门角色信息响应模型
"""
data: DepartmentRoleInfo = Field(default=None, description="响应数据")
class GetDepartmentRoleListResult(ListQueryResult):
"""
获取部门角色列表结果模型
"""
result: List[DepartmentRoleInfo] = Field(default=[], description="部门角色列表")
class GetDepartmentRoleListResponse(BaseResponse):
"""
获取部门角色列表响应模型
"""
data: GetDepartmentRoleListResult = Field(default=None, description="响应数据")