From 77b4eb10b160392e15383345982ad3516d185a14 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sun, 30 Jun 2024 21:04:50 +0800 Subject: [PATCH 001/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96@log=5Fdecora?= =?UTF-8?q?tor=E5=8F=82=E6=95=B0=E7=9A=84=E7=B1=BB=E5=9E=8B=E6=8F=90?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/config/enums.py | 27 ++++++++++++++++++ .../module_admin/annotation/log_annotation.py | 12 ++++++-- .../controller/cache_controller.py | 2 +- .../controller/config_controller.py | 15 +++++----- .../controller/dept_controller.py | 11 ++++---- .../controller/dict_controller.py | 23 +++++++-------- .../module_admin/controller/job_controller.py | 23 +++++++-------- .../module_admin/controller/log_controller.py | 19 +++++++------ .../controller/login_controller.py | 3 +- .../controller/menu_controller.py | 11 ++++---- .../controller/notice_controller.py | 11 ++++---- .../controller/online_controller.py | 7 +++-- .../module_admin/controller/post_controler.py | 13 +++++---- .../controller/role_controller.py | 25 +++++++++-------- .../controller/server_controller.py | 2 +- .../controller/user_controller.py | 28 ++++++++++--------- 16 files changed, 140 insertions(+), 92 deletions(-) create mode 100644 ruoyi-fastapi-backend/config/enums.py diff --git a/ruoyi-fastapi-backend/config/enums.py b/ruoyi-fastapi-backend/config/enums.py new file mode 100644 index 0000000..b02e5f3 --- /dev/null +++ b/ruoyi-fastapi-backend/config/enums.py @@ -0,0 +1,27 @@ +from enum import Enum + + +class BusinessType(Enum): + """ + 业务操作类型 + OTHER: 其它 + INSERT: 新增 + UPDATE: 修改 + DELETE: 删除 + GRANT: 授权 + EXPORT: 导出 + IMPORT: 导入 + FORCE: 强退 + GENCODE: 生成代码 + CLEAN: 清空数据 + """ + OTHER = 0 + INSERT = 1 + UPDATE = 2 + DELETE = 3 + GRANT = 4 + EXPORT = 5 + IMPORT = 6 + FORCE = 7 + GENCODE = 8 + CLEAN = 9 diff --git a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py index fa7c1b3..6474b07 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py @@ -7,15 +7,17 @@ import json import time from datetime import datetime import requests +import warnings from user_agents import parse -from typing import Optional +from typing import Optional, Union, Literal from module_admin.service.login_service import LoginService from module_admin.service.log_service import OperationLogService, LoginLogService from module_admin.entity.vo.log_vo import OperLogModel, LogininforModel from config.env import AppConfig +from config.enums import BusinessType -def log_decorator(title: str, business_type: int, log_type: Optional[str] = 'operation'): +def log_decorator(title: str, business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], BusinessType], log_type: Optional[Literal['login', 'operation']] = 'operation'): """ 日志装饰器 :param log_type: 日志类型(login表示登录日志,为空表示为操作日志) @@ -23,6 +25,12 @@ def log_decorator(title: str, business_type: int, log_type: Optional[str] = 'ope :param business_type: 业务类型(0其它 1新增 2修改 3删除 4授权 5导出 6导入 7强退 8生成代码 9清空数据) :return: """ + warnings.simplefilter('always', category=DeprecationWarning) + if isinstance(business_type, BusinessType): + business_type = business_type.value + else: + warnings.warn('@log_decorator的business_type参数未来版本将不再支持int类型,请使用BusinessType枚举类型', category=DeprecationWarning, stacklevel=2) + def decorator(func): @wraps(func) async def wrapper(*args, **kwargs): diff --git a/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py b/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py index b33a287..74b1a25 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py @@ -2,9 +2,9 @@ from fastapi import APIRouter from fastapi import Depends from module_admin.service.login_service import LoginService from module_admin.service.cache_service import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from utils.response_util import * from utils.log_util import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth cacheController = APIRouter(prefix='/monitor/cache', dependencies=[Depends(LoginService.get_current_user)]) diff --git a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py index bc442d0..f08dd71 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py @@ -3,12 +3,13 @@ from fastapi import Depends from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.config_service import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.response_util import * from utils.log_util import * from utils.page_util import * from utils.common_util import bytes2file_response -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.annotation.log_annotation import log_decorator configController = APIRouter(prefix='/system/config', dependencies=[Depends(LoginService.get_current_user)]) @@ -27,7 +28,7 @@ async def get_system_config_list(request: Request, config_page_query: ConfigPage @configController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))]) -@log_decorator(title='参数管理', business_type=1) +@log_decorator(title='参数管理', business_type=BusinessType.INSERT) async def add_system_config(request: Request, add_config: ConfigModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_config.create_by = current_user.user.user_name @@ -47,7 +48,7 @@ async def add_system_config(request: Request, add_config: ConfigModel, query_db: @configController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))]) -@log_decorator(title='参数管理', business_type=2) +@log_decorator(title='参数管理', business_type=BusinessType.UPDATE) async def edit_system_config(request: Request, edit_config: ConfigModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_config.update_by = current_user.user.user_name @@ -65,7 +66,7 @@ async def edit_system_config(request: Request, edit_config: ConfigModel, query_d @configController.delete("/refreshCache", dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) -@log_decorator(title='参数管理', business_type=2) +@log_decorator(title='参数管理', business_type=BusinessType.UPDATE) async def refresh_system_config(request: Request, query_db: AsyncSession = Depends(get_db)): try: refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db) @@ -81,7 +82,7 @@ async def refresh_system_config(request: Request, query_db: AsyncSession = Depen @configController.delete("/{config_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) -@log_decorator(title='参数管理', business_type=3) +@log_decorator(title='参数管理', business_type=BusinessType.DELETE) async def delete_system_config(request: Request, config_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_config = DeleteConfigModel(configIds=config_ids) @@ -121,7 +122,7 @@ async def query_system_config(request: Request, config_key: str): @configController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))]) -@log_decorator(title='参数管理', business_type=5) +@log_decorator(title='参数管理', business_type=BusinessType.EXPORT) async def export_system_config_list(request: Request, config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 diff --git a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py index 476ca3a..ccfdd64 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py @@ -3,11 +3,12 @@ from fastapi import Depends from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.dept_service import * -from utils.response_util import * -from utils.log_util import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType +from utils.response_util import * +from utils.log_util import * deptController = APIRouter(prefix='/system/dept', dependencies=[Depends(LoginService.get_current_user)]) @@ -37,7 +38,7 @@ async def get_system_dept_list(request: Request, dept_query: DeptQueryModel = De @deptController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) -@log_decorator(title='部门管理', business_type=1) +@log_decorator(title='部门管理', business_type=BusinessType.INSERT) async def add_system_dept(request: Request, add_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_dept.create_by = current_user.user.user_name @@ -57,7 +58,7 @@ async def add_system_dept(request: Request, add_dept: DeptModel, query_db: Async @deptController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) -@log_decorator(title='部门管理', business_type=2) +@log_decorator(title='部门管理', business_type=BusinessType.UPDATE) async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_dept.update_by = current_user.user.user_name @@ -75,7 +76,7 @@ async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: Asy @deptController.delete("/{dept_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) -@log_decorator(title='部门管理', business_type=3) +@log_decorator(title='部门管理', business_type=BusinessType.DELETE) async def delete_system_dept(request: Request, dept_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: delete_dept = DeleteDeptModel(deptIds=dept_ids) diff --git a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py index a686ef8..c999a91 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py @@ -3,12 +3,13 @@ from fastapi import Depends from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.dict_service import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.response_util import * from utils.log_util import * from utils.page_util import PageResponseModel from utils.common_util import bytes2file_response -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.annotation.log_annotation import log_decorator dictController = APIRouter(prefix='/system/dict', dependencies=[Depends(LoginService.get_current_user)]) @@ -27,7 +28,7 @@ async def get_system_dict_type_list(request: Request, dict_type_page_query: Dict @dictController.post("/type", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) -@log_decorator(title='字典管理', business_type=1) +@log_decorator(title='字典管理', business_type=BusinessType.INSERT) async def add_system_dict_type(request: Request, add_dict_type: DictTypeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_dict_type.create_by = current_user.user.user_name @@ -47,7 +48,7 @@ async def add_system_dict_type(request: Request, add_dict_type: DictTypeModel, q @dictController.put("/type", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) -@log_decorator(title='字典管理', business_type=2) +@log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def edit_system_dict_type(request: Request, edit_dict_type: DictTypeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_dict_type.update_by = current_user.user.user_name @@ -65,7 +66,7 @@ async def edit_system_dict_type(request: Request, edit_dict_type: DictTypeModel, @dictController.delete("/type/refreshCache", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) -@log_decorator(title='字典管理', business_type=2) +@log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends(get_db)): try: refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db) @@ -81,7 +82,7 @@ async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends @dictController.delete("/type/{dict_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) -@log_decorator(title='字典管理', business_type=3) +@log_decorator(title='字典管理', business_type=BusinessType.DELETE) async def delete_system_dict_type(request: Request, dict_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids) @@ -120,7 +121,7 @@ async def query_detail_system_dict_type(request: Request, dict_id: int, query_db @dictController.post("/type/export", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) -@log_decorator(title='字典管理', business_type=5) +@log_decorator(title='字典管理', business_type=BusinessType.EXPORT) async def export_system_dict_type_list(request: Request, dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 @@ -158,7 +159,7 @@ async def get_system_dict_data_list(request: Request, dict_data_page_query: Dict @dictController.post("/data", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) -@log_decorator(title='字典管理', business_type=1) +@log_decorator(title='字典管理', business_type=BusinessType.INSERT) async def add_system_dict_data(request: Request, add_dict_data: DictDataModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_dict_data.create_by = current_user.user.user_name @@ -178,7 +179,7 @@ async def add_system_dict_data(request: Request, add_dict_data: DictDataModel, q @dictController.put("/data", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) -@log_decorator(title='字典管理', business_type=2) +@log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def edit_system_dict_data(request: Request, edit_dict_data: DictDataModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_dict_data.update_by = current_user.user.user_name @@ -196,7 +197,7 @@ async def edit_system_dict_data(request: Request, edit_dict_data: DictDataModel, @dictController.delete("/data/{dict_codes}", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) -@log_decorator(title='字典管理', business_type=3) +@log_decorator(title='字典管理', business_type=BusinessType.DELETE) async def delete_system_dict_data(request: Request, dict_codes: str, query_db: AsyncSession = Depends(get_db)): try: delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes) @@ -224,7 +225,7 @@ async def query_detail_system_dict_data(request: Request, dict_code: int, query_ @dictController.post("/data/export", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) -@log_decorator(title='字典管理', business_type=5) +@log_decorator(title='字典管理', business_type=BusinessType.EXPORT) async def export_system_dict_data_list(request: Request, dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 diff --git a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py index 04cc6e0..1739b67 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py @@ -4,12 +4,13 @@ from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.job_service import * from module_admin.service.job_log_service import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.response_util import * from utils.log_util import * from utils.page_util import * from utils.common_util import bytes2file_response -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.annotation.log_annotation import log_decorator jobController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)]) @@ -28,7 +29,7 @@ async def get_system_job_list(request: Request, job_page_query: JobPageQueryMode @jobController.post("/job", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))]) -@log_decorator(title='定时任务管理', business_type=1) +@log_decorator(title='定时任务管理', business_type=BusinessType.INSERT) async def add_system_job(request: Request, add_job: JobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_job.create_by = current_user.user.user_name @@ -48,7 +49,7 @@ async def add_system_job(request: Request, add_job: JobModel, query_db: AsyncSes @jobController.put("/job", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))]) -@log_decorator(title='定时任务管理', business_type=2) +@log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_job.update_by = current_user.user.user_name @@ -66,7 +67,7 @@ async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: As @jobController.put("/job/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) -@log_decorator(title='定时任务管理', business_type=2) +@log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_job.update_by = current_user.user.user_name @@ -85,7 +86,7 @@ async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: As @jobController.put("/job/run", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) -@log_decorator(title='定时任务管理', business_type=2) +@log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) async def execute_system_job(request: Request, execute_job: JobModel, query_db: AsyncSession = Depends(get_db)): try: execute_job_result = await JobService.execute_job_once_services(query_db, execute_job) @@ -101,7 +102,7 @@ async def execute_system_job(request: Request, execute_job: JobModel, query_db: @jobController.delete("/job/{job_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) -@log_decorator(title='定时任务管理', business_type=3) +@log_decorator(title='定时任务管理', business_type=BusinessType.DELETE) async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_job = DeleteJobModel(jobIds=job_ids) @@ -129,7 +130,7 @@ async def query_detail_system_job(request: Request, job_id: int, query_db: Async @jobController.post("/job/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) -@log_decorator(title='定时任务管理', business_type=5) +@log_decorator(title='定时任务管理', business_type=BusinessType.EXPORT) async def export_system_job_list(request: Request, job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 @@ -155,7 +156,7 @@ async def get_system_job_log_list(request: Request, job_log_page_query: JobLogPa @jobController.delete("/jobLog/clean", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) -@log_decorator(title='定时任务日志管理', business_type=9) +@log_decorator(title='定时任务日志管理', business_type=BusinessType.CLEAN) async def clear_system_job_log(request: Request, query_db: AsyncSession = Depends(get_db)): try: clear_job_log_result = await JobLogService.clear_job_log_services(query_db) @@ -171,7 +172,7 @@ async def clear_system_job_log(request: Request, query_db: AsyncSession = Depend @jobController.delete("/jobLog/{job_log_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) -@log_decorator(title='定时任务日志管理', business_type=3) +@log_decorator(title='定时任务日志管理', business_type=BusinessType.DELETE) async def delete_system_job_log(request: Request, job_log_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_job_log = DeleteJobLogModel(jobLogIds=job_log_ids) @@ -188,7 +189,7 @@ async def delete_system_job_log(request: Request, job_log_ids: str, query_db: As @jobController.post("/jobLog/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) -@log_decorator(title='定时任务日志管理', business_type=5) +@log_decorator(title='定时任务日志管理', business_type=BusinessType.EXPORT) async def export_system_job_log_list(request: Request, job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 diff --git a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py index a0a18c5..715567b 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py @@ -3,12 +3,13 @@ from fastapi import Depends from config.get_db import get_db from module_admin.service.login_service import LoginService from module_admin.service.log_service import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.response_util import * from utils.log_util import * from utils.page_util import * from utils.common_util import bytes2file_response -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.annotation.log_annotation import log_decorator logController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)]) @@ -27,7 +28,7 @@ async def get_system_operation_log_list(request: Request, operation_log_page_que @logController.delete("/operlog/clean", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) -@log_decorator(title='操作日志管理', business_type=9) +@log_decorator(title='操作日志管理', business_type=BusinessType.CLEAN) async def clear_system_operation_log(request: Request, query_db: AsyncSession = Depends(get_db)): try: clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db) @@ -43,7 +44,7 @@ async def clear_system_operation_log(request: Request, query_db: AsyncSession = @logController.delete("/operlog/{oper_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) -@log_decorator(title='操作日志管理', business_type=3) +@log_decorator(title='操作日志管理', business_type=BusinessType.DELETE) async def delete_system_operation_log(request: Request, oper_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_operation_log = DeleteOperLogModel(operIds=oper_ids) @@ -60,7 +61,7 @@ async def delete_system_operation_log(request: Request, oper_ids: str, query_db: @logController.post("/operlog/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))]) -@log_decorator(title='操作日志管理', business_type=5) +@log_decorator(title='操作日志管理', business_type=BusinessType.EXPORT) async def export_system_operation_log_list(request: Request, operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 @@ -86,7 +87,7 @@ async def get_system_login_log_list(request: Request, login_log_page_query: Logi @logController.delete("/logininfor/clean", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) -@log_decorator(title='登录日志管理', business_type=9) +@log_decorator(title='登录日志管理', business_type=BusinessType.CLEAN) async def clear_system_login_log(request: Request, query_db: AsyncSession = Depends(get_db)): try: clear_login_log_result = await LoginLogService.clear_login_log_services(query_db) @@ -102,7 +103,7 @@ async def clear_system_login_log(request: Request, query_db: AsyncSession = Depe @logController.delete("/logininfor/{info_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) -@log_decorator(title='登录日志管理', business_type=3) +@log_decorator(title='登录日志管理', business_type=BusinessType.DELETE) async def delete_system_login_log(request: Request, info_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_login_log = DeleteLoginLogModel(infoIds=info_ids) @@ -119,7 +120,7 @@ async def delete_system_login_log(request: Request, info_ids: str, query_db: Asy @logController.get("/logininfor/unlock/{user_name}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:unlock'))]) -@log_decorator(title='登录日志管理', business_type=0) +@log_decorator(title='登录日志管理', business_type=BusinessType.OTHER) async def clear_system_login_log(request: Request, user_name: str, query_db: AsyncSession = Depends(get_db)): try: unlock_user = UnlockUser(userName=user_name) @@ -136,7 +137,7 @@ async def clear_system_login_log(request: Request, user_name: str, query_db: Asy @logController.post("/logininfor/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))]) -@log_decorator(title='登录日志管理', business_type=5) +@log_decorator(title='登录日志管理', business_type=BusinessType.EXPORT) async def export_system_login_log_list(request: Request, login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 diff --git a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py index 74b495c..4861ca4 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py @@ -4,6 +4,7 @@ from module_admin.entity.vo.login_vo import * from module_admin.dao.login_dao import * from module_admin.annotation.log_annotation import log_decorator from config.env import JwtConfig, RedisInitKeyConfig +from config.enums import BusinessType from utils.response_util import ResponseUtil from utils.log_util import * from datetime import timedelta @@ -13,7 +14,7 @@ loginController = APIRouter() @loginController.post("/login", response_model=Token) -@log_decorator(title='用户登录', business_type=0, log_type='login') +@log_decorator(title='用户登录', business_type=BusinessType.OTHER, log_type='login') async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = Depends(), query_db: AsyncSession = Depends(get_db)): captcha_enabled = True if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") == 'true' else False user = UserLogin( diff --git a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py index 949fd1a..e50eebe 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py @@ -3,10 +3,11 @@ from fastapi import Depends from config.get_db import get_db from module_admin.service.login_service import LoginService from module_admin.service.menu_service import * -from utils.response_util import * -from utils.log_util import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType +from utils.response_util import * +from utils.log_util import * menuController = APIRouter(prefix='/system/menu', dependencies=[Depends(LoginService.get_current_user)]) @@ -46,7 +47,7 @@ async def get_system_menu_list(request: Request, menu_query: MenuQueryModel = De @menuController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) -@log_decorator(title='菜单管理', business_type=1) +@log_decorator(title='菜单管理', business_type=BusinessType.INSERT) async def add_system_menu(request: Request, add_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_menu.create_by = current_user.user.user_name @@ -66,7 +67,7 @@ async def add_system_menu(request: Request, add_menu: MenuModel, query_db: Async @menuController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) -@log_decorator(title='菜单管理', business_type=2) +@log_decorator(title='菜单管理', business_type=BusinessType.UPDATE) async def edit_system_menu(request: Request, edit_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_menu.update_by = current_user.user.user_name @@ -84,7 +85,7 @@ async def edit_system_menu(request: Request, edit_menu: MenuModel, query_db: Asy @menuController.delete("/{menu_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) -@log_decorator(title='菜单管理', business_type=3) +@log_decorator(title='菜单管理', business_type=BusinessType.DELETE) async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_menu = DeleteMenuModel(menuIds=menu_ids) diff --git a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py index 0e2c0d7..1b86daa 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py @@ -3,11 +3,12 @@ from fastapi import Depends from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.notice_service import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.response_util import * from utils.log_util import * from utils.page_util import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.annotation.log_annotation import log_decorator noticeController = APIRouter(prefix='/system/notice', dependencies=[Depends(LoginService.get_current_user)]) @@ -26,7 +27,7 @@ async def get_system_notice_list(request: Request, notice_page_query: NoticePage @noticeController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))]) -@log_decorator(title='通知公告管理', business_type=1) +@log_decorator(title='通知公告管理', business_type=BusinessType.INSERT) async def add_system_notice(request: Request, add_notice: NoticeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_notice.create_by = current_user.user.user_name @@ -46,7 +47,7 @@ async def add_system_notice(request: Request, add_notice: NoticeModel, query_db: @noticeController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))]) -@log_decorator(title='通知公告管理', business_type=2) +@log_decorator(title='通知公告管理', business_type=BusinessType.UPDATE) async def edit_system_notice(request: Request, edit_notice: NoticeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_notice.update_by = current_user.user.user_name @@ -64,7 +65,7 @@ async def edit_system_notice(request: Request, edit_notice: NoticeModel, query_d @noticeController.delete("/{notice_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))]) -@log_decorator(title='通知公告管理', business_type=3) +@log_decorator(title='通知公告管理', business_type=BusinessType.DELETE) async def delete_system_notice(request: Request, notice_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_notice = DeleteNoticeModel(noticeIds=notice_ids) diff --git a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py index 747cc13..71531ea 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py @@ -3,11 +3,12 @@ from fastapi import Depends from config.get_db import get_db from module_admin.service.login_service import LoginService, AsyncSession from module_admin.service.online_service import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.response_util import * from utils.log_util import * from utils.page_util import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.annotation.log_annotation import log_decorator onlineController = APIRouter(prefix='/monitor/online', dependencies=[Depends(LoginService.get_current_user)]) @@ -26,7 +27,7 @@ async def get_monitor_online_list(request: Request, online_page_query: OnlineQue @onlineController.delete("/{token_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))]) -@log_decorator(title='在线用户', business_type=7) +@log_decorator(title='在线用户', business_type=BusinessType.FORCE) async def delete_monitor_online(request: Request, token_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_online = DeleteOnlineModel(tokenIds=token_ids) diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py index 2128a68..fbeb670 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py @@ -4,12 +4,13 @@ from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.post_service import * from module_admin.entity.vo.post_vo import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.response_util import * from utils.log_util import * from utils.page_util import * from utils.common_util import bytes2file_response -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.annotation.log_annotation import log_decorator postController = APIRouter(prefix='/system/post', dependencies=[Depends(LoginService.get_current_user)]) @@ -28,7 +29,7 @@ async def get_system_post_list(request: Request, post_page_query: PostPageQueryM @postController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))]) -@log_decorator(title='岗位管理', business_type=1) +@log_decorator(title='岗位管理', business_type=BusinessType.INSERT) async def add_system_post(request: Request, add_post: PostModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_post.create_by = current_user.user.user_name @@ -48,7 +49,7 @@ async def add_system_post(request: Request, add_post: PostModel, query_db: Async @postController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))]) -@log_decorator(title='岗位管理', business_type=2) +@log_decorator(title='岗位管理', business_type=BusinessType.UPDATE) async def edit_system_post(request: Request, edit_post: PostModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_post.update_by = current_user.user.user_name @@ -66,7 +67,7 @@ async def edit_system_post(request: Request, edit_post: PostModel, query_db: Asy @postController.delete("/{post_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))]) -@log_decorator(title='岗位管理', business_type=3) +@log_decorator(title='岗位管理', business_type=BusinessType.DELETE) async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSession = Depends(get_db)): try: delete_post = DeletePostModel(postIds=post_ids) @@ -94,7 +95,7 @@ async def query_detail_system_post(request: Request, post_id: int, query_db: Asy @postController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:post:export'))]) -@log_decorator(title='岗位管理', business_type=5) +@log_decorator(title='岗位管理', business_type=BusinessType.EXPORT) async def export_system_post_list(request: Request, post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 diff --git a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index 068d94f..a20b25c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -5,13 +5,14 @@ from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.role_service import * from module_admin.service.dept_service import DeptService, DeptModel from module_admin.service.user_service import UserService, UserRoleQueryModel, UserRolePageQueryModel, CrudUserRoleModel +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.aspect.data_scope import GetDataScope +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.response_util import * from utils.log_util import * from utils.page_util import PageResponseModel from utils.common_util import bytes2file_response -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.aspect.data_scope import GetDataScope -from module_admin.annotation.log_annotation import log_decorator roleController = APIRouter(prefix='/system/role', dependencies=[Depends(LoginService.get_current_user)]) @@ -42,7 +43,7 @@ async def get_system_role_list(request: Request, role_page_query: RolePageQueryM @roleController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))]) -@log_decorator(title='角色管理', business_type=1) +@log_decorator(title='角色管理', business_type=BusinessType.INSERT) async def add_system_role(request: Request, add_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_role.create_by = current_user.user.user_name @@ -62,7 +63,7 @@ async def add_system_role(request: Request, add_role: AddRoleModel, query_db: As @roleController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=2) +@log_decorator(title='角色管理', business_type=BusinessType.UPDATE) async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_role.update_by = current_user.user.user_name @@ -80,7 +81,7 @@ async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: @roleController.put("/dataScope", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=4) +@log_decorator(title='角色管理', business_type=BusinessType.GRANT) async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: role_data_scope.update_by = current_user.user.user_name @@ -98,7 +99,7 @@ async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleM @roleController.delete("/{role_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))]) -@log_decorator(title='角色管理', business_type=3) +@log_decorator(title='角色管理', business_type=BusinessType.DELETE) async def delete_system_role(request: Request, role_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: delete_role = DeleteRoleModel( @@ -130,7 +131,7 @@ async def query_detail_system_role(request: Request, role_id: int, query_db: Asy @roleController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))]) -@log_decorator(title='角色管理', business_type=5) +@log_decorator(title='角色管理', business_type=BusinessType.EXPORT) async def export_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): try: # 获取全量数据 @@ -144,7 +145,7 @@ async def export_system_role_list(request: Request, role_page_query: RolePageQue @roleController.put("/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=2) +@log_decorator(title='角色管理', business_type=BusinessType.UPDATE) async def reset_system_role_status(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_role.update_by = current_user.user.user_name @@ -185,7 +186,7 @@ async def get_system_unallocated_user_list(request: Request, user_role: UserRole @roleController.put("/authUser/selectAll", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=4) +@log_decorator(title='角色管理', business_type=BusinessType.GRANT) async def add_system_role_user(request: Request, add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db)): try: add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user) @@ -201,7 +202,7 @@ async def add_system_role_user(request: Request, add_role_user: CrudUserRoleMode @roleController.put("/authUser/cancel", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=4) +@log_decorator(title='角色管理', business_type=BusinessType.GRANT) async def cancel_system_role_user(request: Request, cancel_user_role: CrudUserRoleModel, query_db: AsyncSession = Depends(get_db)): try: cancel_user_role_result = await UserService.delete_user_role_services(query_db, cancel_user_role) @@ -217,7 +218,7 @@ async def cancel_system_role_user(request: Request, cancel_user_role: CrudUserRo @roleController.put("/authUser/cancelAll", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=4) +@log_decorator(title='角色管理', business_type=BusinessType.GRANT) async def batch_cancel_system_role_user(request: Request, batch_cancel_user_role: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db)): try: batch_cancel_user_role_result = await UserService.delete_user_role_services(query_db, batch_cancel_user_role) diff --git a/ruoyi-fastapi-backend/module_admin/controller/server_controller.py b/ruoyi-fastapi-backend/module_admin/controller/server_controller.py index 8d040ff..c21db20 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/server_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/server_controller.py @@ -2,9 +2,9 @@ from fastapi import APIRouter, Request from fastapi import Depends from module_admin.service.login_service import LoginService from module_admin.service.server_service import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from utils.response_util import * from utils.log_util import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth serverController = APIRouter(prefix='/monitor/server', dependencies=[Depends(LoginService.get_current_user)]) diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index 93c13ca..96f1a2f 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -5,14 +5,15 @@ from config.env import UploadConfig from module_admin.service.login_service import LoginService from module_admin.service.user_service import * from module_admin.service.dept_service import DeptService +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.aspect.data_scope import GetDataScope +from module_admin.annotation.log_annotation import log_decorator +from config.enums import BusinessType from utils.page_util import PageResponseModel from utils.response_util import * from utils.log_util import * from utils.common_util import bytes2file_response from utils.upload_util import UploadUtil -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.aspect.data_scope import GetDataScope -from module_admin.annotation.log_annotation import log_decorator userController = APIRouter(prefix='/system/user', dependencies=[Depends(LoginService.get_current_user)]) @@ -42,7 +43,7 @@ async def get_system_user_list(request: Request, user_page_query: UserPageQueryM @userController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) -@log_decorator(title='用户管理', business_type=1) +@log_decorator(title='用户管理', business_type=BusinessType.INSERT) async def add_system_user(request: Request, add_user: AddUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: add_user.password = PwdUtil.get_password_hash(add_user.password) @@ -63,7 +64,7 @@ async def add_system_user(request: Request, add_user: AddUserModel, query_db: As @userController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) -@log_decorator(title='用户管理', business_type=2) +@log_decorator(title='用户管理', business_type=BusinessType.UPDATE) async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_user.update_by = current_user.user.user_name @@ -81,7 +82,7 @@ async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: @userController.delete("/{user_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))]) -@log_decorator(title='用户管理', business_type=3) +@log_decorator(title='用户管理', business_type=BusinessType.DELETE) async def delete_system_user(request: Request, user_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: delete_user = DeleteUserModel( @@ -102,7 +103,7 @@ async def delete_system_user(request: Request, user_ids: str, query_db: AsyncSes @userController.put("/resetPwd", dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))]) -@log_decorator(title='用户管理', business_type=2) +@log_decorator(title='用户管理', business_type=BusinessType.UPDATE) async def reset_system_user_pwd(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_user.password = PwdUtil.get_password_hash(edit_user.password) @@ -122,7 +123,7 @@ async def reset_system_user_pwd(request: Request, edit_user: EditUserModel, quer @userController.put("/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) -@log_decorator(title='用户管理', business_type=2) +@log_decorator(title='用户管理', business_type=BusinessType.UPDATE) async def change_system_user_status(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_user.update_by = current_user.user.user_name @@ -164,7 +165,7 @@ async def query_detail_system_user(request: Request, user_id: Optional[Union[int @userController.post("/profile/avatar") -@log_decorator(title='个人信息', business_type=2) +@log_decorator(title='个人信息', business_type=BusinessType.UPDATE) async def change_system_user_profile_avatar(request: Request, avatarfile: bytes = File(), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: relative_path = f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}' @@ -197,7 +198,7 @@ async def change_system_user_profile_avatar(request: Request, avatarfile: bytes @userController.put("/profile") -@log_decorator(title='个人信息', business_type=2) +@log_decorator(title='个人信息', business_type=BusinessType.UPDATE) async def change_system_user_profile_info(request: Request, user_info: UserInfoModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: edit_user = EditUserModel( @@ -227,7 +228,7 @@ async def change_system_user_profile_info(request: Request, user_info: UserInfoM @userController.put("/profile/updatePwd") -@log_decorator(title='个人信息', business_type=2) +@log_decorator(title='个人信息', business_type=BusinessType.UPDATE) async def reset_system_user_password(request: Request, reset_password: ResetPasswordModel = Depends(ResetPasswordModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: reset_user = ResetUserModel( @@ -250,7 +251,7 @@ async def reset_system_user_password(request: Request, reset_password: ResetPass @userController.post("/importData", dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) -@log_decorator(title='用户管理', business_type=6) +@log_decorator(title='用户管理', business_type=BusinessType.IMPORT) async def batch_import_system_user(request: Request, file: UploadFile = File(...), update_support: bool = Query(alias='updateSupport'), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: batch_import_result = await UserService.batch_import_user_services(query_db, file, update_support, current_user) @@ -277,7 +278,7 @@ async def export_system_user_template(request: Request, query_db: AsyncSession = @userController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:user:export'))]) -@log_decorator(title='用户管理', business_type=5) +@log_decorator(title='用户管理', business_type=BusinessType.EXPORT) async def export_system_user_list(request: Request, user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): try: # 获取全量数据 @@ -303,6 +304,7 @@ async def get_system_allocated_role_list(request: Request, user_id: int, query_d @userController.put("/authRole", response_model=UserRoleResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) +@log_decorator(title='用户管理', business_type=BusinessType.GRANT) async def update_system_role_user(request: Request, user_id: int = Query(alias='userId'), role_ids: str = Query(alias='roleIds'), query_db: AsyncSession = Depends(get_db)): try: add_user_role_result = await UserService.add_user_role_services(query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids)) -- Gitee From c64519d8f95631c2fa1b3096e722565ad5b3a99f Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sun, 30 Jun 2024 21:40:35 +0800 Subject: [PATCH 002/129] =?UTF-8?q?chore:=20=E5=8D=87=E7=BA=A7=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E7=BB=84=E4=BB=B6=E4=BE=9D=E8=B5=96=E5=88=B0=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-frontend/package.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ruoyi-fastapi-frontend/package.json b/ruoyi-fastapi-frontend/package.json index d4bc0f5..6a2c4c6 100644 --- a/ruoyi-fastapi-frontend/package.json +++ b/ruoyi-fastapi-frontend/package.json @@ -20,29 +20,29 @@ "@antv/g2plot": "^2.4.31", "@element-plus/icons-vue": "2.3.1", "@vueup/vue-quill": "1.2.0", - "@vueuse/core": "10.6.1", + "@vueuse/core": "10.11.0", "ant-design-vue": "^4.1.1", - "axios": "0.27.2", - "echarts": "5.4.3", - "element-plus": "2.4.3", + "axios": "0.28.1", + "echarts": "5.5.1", + "element-plus": "2.7.6", "file-saver": "2.0.5", "fuse.js": "6.6.2", "js-cookie": "3.0.5", "jsencrypt": "3.3.2", "nprogress": "0.2.0", "pinia": "2.1.7", - "vue": "3.3.9", + "vue": "3.4.31", "vue-cropper": "1.1.1", - "vue-router": "4.2.5" + "vue-router": "4.4.0" }, "devDependencies": { - "@vitejs/plugin-vue": "4.5.0", + "@vitejs/plugin-vue": "5.0.5", "@vue/compiler-sfc": "3.3.9", "less": "^4.2.0", - "sass": "1.69.5", - "unplugin-auto-import": "0.17.1", - "unplugin-vue-setup-extend-plus": "1.0.0", - "vite": "5.0.4", + "sass": "1.77.5", + "unplugin-auto-import": "0.17.6", + "unplugin-vue-setup-extend-plus": "1.0.1", + "vite": "5.3.2", "vite-plugin-compression": "0.5.1", "vite-plugin-svg-icons": "2.0.1" } -- Gitee From d0e82b56abb02e51561c0f15490c919c20b9bc09 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sun, 30 Jun 2024 21:55:37 +0800 Subject: [PATCH 003/129] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E7=AB=AF=E5=B7=A6=E4=BE=A7=E8=8F=9C=E5=8D=95=E6=97=A0?= =?UTF-8?q?=E6=B3=95=E6=98=BE=E7=A4=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-frontend/src/layout/index.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ruoyi-fastapi-frontend/src/layout/index.vue b/ruoyi-fastapi-frontend/src/layout/index.vue index 3ddb165..bad8dae 100644 --- a/ruoyi-fastapi-frontend/src/layout/index.vue +++ b/ruoyi-fastapi-frontend/src/layout/index.vue @@ -40,10 +40,13 @@ const classObj = computed(() => ({ const { width, height } = useWindowSize(); const WIDTH = 992; // refer to Bootstrap's responsive design -watchEffect(() => { +watch(() => device.value, () => { if (device.value === 'mobile' && sidebar.value.opened) { useAppStore().closeSideBar({ withoutAnimation: false }) } +}) + +watchEffect(() => { if (width.value - 1 < WIDTH) { useAppStore().toggleDevice('mobile') useAppStore().closeSideBar({ withoutAnimation: true }) -- Gitee From f1baf96f951a1bcca204bf23bc990939c1b6f71e Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 1 Jul 2024 21:35:29 +0800 Subject: [PATCH 004/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E9=97=A8=E7=AE=A1=E7=90=86dao=E5=B1=82status=E5=92=8Cdel=5Ffla?= =?UTF-8?q?g=E7=B1=BB=E5=9E=8B=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/dao/dept_dao.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py index c5169a5..e15278b 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py @@ -22,8 +22,8 @@ class DeptDao: dept_info = (await db.execute( select(SysDept) .where(SysDept.dept_id == dept_id, - SysDept.status == 0, - SysDept.del_flag == 0) + SysDept.status == '0', + SysDept.del_flag == '0') )).scalars().first() return dept_info @@ -39,7 +39,7 @@ class DeptDao: dept_info = (await db.execute( select(SysDept) .where(SysDept.dept_id == dept_id, - SysDept.del_flag == 0) + SysDept.del_flag == '0') )).scalars().first() return dept_info @@ -55,7 +55,7 @@ class DeptDao: dept_info = (await db.execute( select(SysDept) .where(SysDept.dept_id == dept_id, - SysDept.del_flag == 0) + SysDept.del_flag == '0') )).scalars().first() return dept_info @@ -89,7 +89,7 @@ class DeptDao: select(SysDept) .where(SysDept.dept_id != dept_info.dept_id, SysDept.parent_id != dept_info.dept_id, - SysDept.del_flag == 0, SysDept.status == 0, + SysDept.del_flag == '0', SysDept.status == '0', eval(data_scope_sql)) .order_by(SysDept.order_num) .distinct() @@ -108,7 +108,7 @@ class DeptDao: dept_result = (await db.execute( select(SysDept) .where(SysDept.parent_id == dept_id, - SysDept.del_flag == 0) + SysDept.del_flag == '0') )).scalars().all() return list_format_datetime(dept_result) @@ -122,7 +122,7 @@ class DeptDao: """ ancestors = (await db.execute( select(SysDept.ancestors) - .where(SysDept.del_flag == 0) + .where(SysDept.del_flag == '0') )).scalars().all() return ancestors @@ -138,8 +138,8 @@ class DeptDao: """ dept_result = (await db.execute( select(SysDept) - .where(SysDept.status == 0, - SysDept.del_flag == 0, + .where(SysDept.status == '0', + SysDept.del_flag == '0', SysDept.dept_name.like(f'%{dept_info.dept_name}%') if dept_info.dept_name else True, eval(data_scope_sql)) .order_by(SysDept.order_num) @@ -159,7 +159,7 @@ class DeptDao: """ dept_result = (await db.execute( select(SysDept) - .where(SysDept.del_flag == 0, + .where(SysDept.del_flag == '0', SysDept.status == page_object.status if page_object.status else True, SysDept.dept_name.like(f'%{page_object.dept_name}%') if page_object.dept_name else True, eval(data_scope_sql)) -- Gitee From adb6d63eb46313624858cfd225eafdc086d04bc8 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 1 Jul 2024 21:39:22 +0800 Subject: [PATCH 005/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=AD=97?= =?UTF-8?q?=E5=85=B8=E7=AE=A1=E7=90=86dao=E5=B1=82status=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93=E4=BF=9D=E6=8C=81=E4=B8=80?= =?UTF-8?q?=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/dao/dict_dao.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py index fd98c95..603d347 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py @@ -186,8 +186,8 @@ class DictDataDao: dict_data_list = (await db.execute( select(SysDictData) .select_from(SysDictType) - .where(SysDictType.dict_type == dict_type if dict_type else True, SysDictType.status == 0) - .join(SysDictData, and_(SysDictType.dict_type == SysDictData.dict_type, SysDictData.status == 0), isouter=True) + .where(SysDictType.dict_type == dict_type if dict_type else True, SysDictType.status == '0') + .join(SysDictData, and_(SysDictType.dict_type == SysDictData.dict_type, SysDictData.status == '0'), isouter=True) .order_by(SysDictData.dict_sort) .distinct() )).scalars().all() @@ -202,7 +202,7 @@ class DictDataDao: :param dict_data: 字典数据对象 :return: """ - db_data_type = SysDictData(**dict_data.dict()) + db_data_type = SysDictData(**dict_data.model_dump()) db.add(db_data_type) await db.flush() -- Gitee From d8011c873859f810be6177b7d851cb31156b2c24 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 1 Jul 2024 21:41:10 +0800 Subject: [PATCH 006/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E7=AE=A1=E7=90=86dao=E5=B1=82status?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93=E4=BF=9D?= =?UTF-8?q?=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/dao/job_dao.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py index cfd6982..6fd1181 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py @@ -70,7 +70,7 @@ class JobDao: """ job_list = (await db.execute( select(SysJob) - .where(SysJob.status == 0) + .where(SysJob.status == '0') .distinct() )).scalars().all() -- Gitee From 7bb947c14a7c70c61f2a078db7a9d5f0ba66f3ed Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 1 Jul 2024 21:44:04 +0800 Subject: [PATCH 007/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=A8=A1=E5=9D=97dao=E5=B1=82status=E5=92=8Cdel=5Ffla?= =?UTF-8?q?g=E7=B1=BB=E5=9E=8B=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/dao/login_dao.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/login_dao.py b/ruoyi-fastapi-backend/module_admin/dao/login_dao.py index 2c80c7f..baa77ab 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/login_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/login_dao.py @@ -14,7 +14,7 @@ async def login_by_account(db: AsyncSession, user_name: str): user = (await db.execute( select(SysUser, SysDept) .where(SysUser.user_name == user_name, SysUser.del_flag == '0') - .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == 0, SysDept.del_flag == 0), isouter=True) + .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0'), isouter=True) .distinct() )).first() -- Gitee From 1fa14118ff69d817ab34aea4d1f4493e9aad11a4 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 1 Jul 2024 21:46:43 +0800 Subject: [PATCH 008/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E7=AE=A1=E7=90=86dao=E5=B1=82status=E5=92=8Cdel=5Ffla?= =?UTF-8?q?g=E7=B1=BB=E5=9E=8B=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/dao/menu_dao.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py index 7f8545b..b600dfa 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py @@ -56,7 +56,7 @@ class MenuDao: if 1 in role_id_list: menu_query_all = (await db.execute( select(SysMenu) - .where(SysMenu.status == 0) + .where(SysMenu.status == '0') .order_by(SysMenu.order_num) .distinct() )).scalars().all() @@ -64,13 +64,13 @@ class MenuDao: menu_query_all = (await db.execute( select(SysMenu) .select_from(SysUser) - .where(SysUser.status == 0, SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) .join(SysRole, - and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == 0, SysRole.del_flag == 0), + and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), isouter=True) .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == 0)) + .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) .order_by(SysMenu.order_num) .distinct() )).scalars().all() @@ -101,10 +101,10 @@ class MenuDao: menu_query_all = (await db.execute( select(SysMenu) .select_from(SysUser) - .where(SysUser.status == 0, SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) .join(SysRole, - and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == 0, SysRole.del_flag == 0), + and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), isouter=True) .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, -- Gitee From d7d8dcda1c491ce54b6ca01ac5071b7081e82b6c Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 1 Jul 2024 21:48:14 +0800 Subject: [PATCH 009/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E7=AE=A1=E7=90=86dao=E5=B1=82status=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93=E4=BF=9D=E6=8C=81=E4=B8=80?= =?UTF-8?q?=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/dao/post_dao.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py index d485d38..a1945ed 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py @@ -21,7 +21,7 @@ class PostDao: post_info = (await db.execute( select(SysPost) .where(SysPost.post_id == post_id, - SysPost.status == 0) + SysPost.status == '0') )).scalars().first() return post_info -- Gitee From 0d2aa3e8b83c41847aee9e25350e357279b6197f Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 1 Jul 2024 21:50:15 +0800 Subject: [PATCH 010/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E7=AE=A1=E7=90=86dao=E5=B1=82status=E5=92=8Cdel=5Ffla?= =?UTF-8?q?g=E7=B1=BB=E5=9E=8B=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/dao/role_dao.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py index 9c43550..1d5a1fa 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py @@ -22,7 +22,7 @@ class RoleDao: """ query_role_info = (await db.execute( select(SysRole) - .where(SysRole.status == 0, SysRole.del_flag == 0, SysRole.role_name == role_name) + .where(SysRole.status == '0', SysRole.del_flag == '0', SysRole.role_name == role_name) .order_by(desc(SysRole.create_time)) .distinct() )).scalars().first() @@ -39,7 +39,7 @@ class RoleDao: """ query_role_info = (await db.execute( select(SysRole) - .where(SysRole.del_flag == 0, + .where(SysRole.del_flag == '0', SysRole.role_name == role.role_name if role.role_name else True, SysRole.role_key == role.role_key if role.role_key else True) .order_by(desc(SysRole.create_time)) @@ -59,8 +59,8 @@ class RoleDao: role_info = (await db.execute( select(SysRole) .where(SysRole.role_id == role_id, - SysRole.status == 0, - SysRole.del_flag == 0) + SysRole.status == '0', + SysRole.del_flag == '0') )).scalars().first() return role_info @@ -75,7 +75,7 @@ class RoleDao: """ query_role_info = (await db.execute( select(SysRole) - .where(SysRole.del_flag == 0, SysRole.role_id == role_id) + .where(SysRole.del_flag == '0', SysRole.role_id == role_id) .distinct() )).scalars().first() @@ -90,7 +90,7 @@ class RoleDao: """ role_info = (await db.execute( select(SysRole) - .where(SysRole.role_id != 1, SysRole.status == 0, SysRole.del_flag == 0) + .where(SysRole.role_id != 1, SysRole.status == '0', SysRole.del_flag == '0') )).scalars().all() return role_info @@ -105,7 +105,7 @@ class RoleDao: :return: 角色列表信息对象 """ query = select(SysRole) \ - .where(SysRole.del_flag == 0, + .where(SysRole.del_flag == '0', SysRole.role_name.like(f'%{query_object.role_name}%') if query_object.role_name else True, SysRole.role_key.like(f'%{query_object.role_key}%') if query_object.role_key else True, SysRole.status == query_object.status if query_object.status else True, -- Gitee From 71b4a10991dd0d8a6960332d547cd84acdc2a73a Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 1 Jul 2024 21:56:17 +0800 Subject: [PATCH 011/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=AE=A1=E7=90=86dao=E5=B1=82status=E5=92=8Cdel=5Ffla?= =?UTF-8?q?g=E7=B1=BB=E5=9E=8B=E4=B8=8E=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E4=BF=9D=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/dao/user_dao.py | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py index d73c6f0..5a8a7c4 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py @@ -25,7 +25,7 @@ class UserDao: """ query_user_info = (await db.execute( select(SysUser) - .where(SysUser.status == 0, SysUser.del_flag == 0, SysUser.user_name == user_name) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_name == user_name) .order_by(desc(SysUser.create_time)) .distinct() )).scalars().first() @@ -42,7 +42,7 @@ class UserDao: """ query_user_info = (await db.execute( select(SysUser) - .where(SysUser.del_flag == 0, SysUser.user_name == user.user_name) + .where(SysUser.del_flag == '0', SysUser.user_name == user.user_name) .order_by(desc(SysUser.create_time)) .distinct() )).scalars().first() @@ -59,50 +59,50 @@ class UserDao: """ query_user_basic_info = (await db.execute( select(SysUser) - .where(SysUser.status == 0, SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) .distinct() )).scalars().first() query_user_dept_info = (await db.execute( select(SysDept) .select_from(SysUser) - .where(SysUser.status == 0, SysUser.del_flag == 0, SysUser.user_id == user_id) - .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == 0, SysDept.del_flag == 0)) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0')) .distinct() )).scalars().first() query_user_role_info = (await db.execute( select(SysRole) .select_from(SysUser) - .where(SysUser.status == 0, SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == 0, SysRole.del_flag == 0)) + .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0')) .distinct() )).scalars().all() query_user_post_info = (await db.execute( select(SysPost) .select_from(SysUser) - .where(SysUser.status == 0, SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserPost, SysUser.user_id == SysUserPost.user_id, isouter=True) - .join(SysPost, and_(SysUserPost.post_id == SysPost.post_id, SysPost.status == 0)) + .join(SysPost, and_(SysUserPost.post_id == SysPost.post_id, SysPost.status == '0')) .distinct() )).scalars().all() role_id_list = [item.role_id for item in query_user_role_info] if 1 in role_id_list: query_user_menu_info = (await db.execute( select(SysMenu) - .where(SysMenu.status == 0) + .where(SysMenu.status == '0') .distinct() )).scalars().all() else: query_user_menu_info = (await db.execute( select(SysMenu) .select_from(SysUser) - .where(SysUser.status == 0, SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) .join(SysRole, - and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == 0, SysRole.del_flag == 0), + and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), isouter=True) .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == 0)) + .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) .order_by(SysMenu.order_num) .distinct() )).scalars().all() @@ -127,41 +127,41 @@ class UserDao: """ query_user_basic_info = (await db.execute( select(SysUser) - .where(SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) .distinct() )).scalars().first() query_user_dept_info = (await db.execute( select(SysDept) .select_from(SysUser) - .where(SysUser.del_flag == 0, SysUser.user_id == user_id) - .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == 0, SysDept.del_flag == 0)) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0')) .distinct() )).scalars().first() query_user_role_info = (await db.execute( select(SysRole) .select_from(SysUser) - .where(SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == 0, SysRole.del_flag == 0)) + .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0')) .distinct() )).scalars().all() query_user_post_info = (await db.execute( select(SysPost) .select_from(SysUser) - .where(SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserPost, SysUser.user_id == SysUserPost.user_id, isouter=True) - .join(SysPost, and_(SysUserPost.post_id == SysPost.post_id, SysPost.status == 0)) + .join(SysPost, and_(SysUserPost.post_id == SysPost.post_id, SysPost.status == '0')) .distinct() )).scalars().all() query_user_menu_info = (await db.execute( select(SysMenu) .select_from(SysUser) - .where(SysUser.del_flag == 0, SysUser.user_id == user_id) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == 0, SysRole.del_flag == 0), + .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), isouter=True) .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == 0)) + .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) .distinct() )).scalars().all() results = dict( @@ -186,7 +186,7 @@ class UserDao: :return: 用户列表信息对象 """ query = select(SysUser, SysDept) \ - .where(SysUser.del_flag == 0, + .where(SysUser.del_flag == '0', or_(SysUser.dept_id == query_object.dept_id, SysUser.dept_id.in_( select(SysDept.dept_id).where(func.find_in_set(query_object.dept_id, SysDept.ancestors)) )) if query_object.dept_id else True, @@ -202,7 +202,7 @@ class UserDao: if query_object.begin_time and query_object.end_time else True, eval(data_scope_sql) ) \ - .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == 0, SysDept.del_flag == 0), + .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0'), isouter=True) \ .distinct() user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) @@ -260,7 +260,7 @@ class UserDao: """ allocated_role_list = (await db.execute( select(SysRole) - .where(SysRole.del_flag == 0, + .where(SysRole.del_flag == '0', SysRole.role_id != 1, SysRole.role_name == query_object.role_name if query_object.role_name else True, SysRole.role_key == query_object.role_key if query_object.role_key else True, @@ -283,7 +283,7 @@ class UserDao: :return: 角色已分配的用户列表信息 """ query = select(SysUser) \ - .where(SysUser.del_flag == 0, + .where(SysUser.del_flag == '0', SysUser.user_id != 1, SysUser.user_name == query_object.user_name if query_object.user_name else True, SysUser.phonenumber == query_object.phonenumber if query_object.phonenumber else True, @@ -306,7 +306,7 @@ class UserDao: :return: 角色未分配的用户列表信息 """ query = select(SysUser) \ - .where(SysUser.del_flag == 0, + .where(SysUser.del_flag == '0', SysUser.user_id != 1, SysUser.user_name == query_object.user_name if query_object.user_name else True, SysUser.phonenumber == query_object.phonenumber if query_object.phonenumber else True, @@ -402,7 +402,7 @@ class UserDao: dept_basic_info = (await db.execute( select(SysDept) .where(SysDept.dept_id == dept_id, - SysDept.status == 0, - SysDept.del_flag == 0) + SysDept.status == '0', + SysDept.del_flag == '0') )).scalars().first() return dept_basic_info -- Gitee From e8a4922541ad63cf184c1d68f66b79ae1981a9f1 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 3 Jul 2024 09:38:50 +0800 Subject: [PATCH 012/129] =?UTF-8?q?style:=20=E5=88=A0=E9=99=A4=E5=A4=9A?= =?UTF-8?q?=E4=BD=99print?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/service/login_service.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ruoyi-fastapi-backend/module_admin/service/login_service.py b/ruoyi-fastapi-backend/module_admin/service/login_service.py index baeb7aa..9870351 100644 --- a/ruoyi-fastapi-backend/module_admin/service/login_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/login_service.py @@ -73,7 +73,6 @@ class LoginService: else: await cls.__check_login_captcha(request, login_user) user = await login_by_account(query_db, login_user.user_name) - print(user) if not user: logger.warning("用户不存在") raise LoginException(data="", message="用户不存在") -- Gitee From 6109c45dbecbd107a1ca2f927a613efe5825bbfe Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 3 Jul 2024 16:41:20 +0800 Subject: [PATCH 013/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=B8=B8?= =?UTF-8?q?=E9=87=8F=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/config/constant.py | 76 +++++++++++++++++++ .../module_admin/service/login_service.py | 25 +++--- ruoyi-fastapi-backend/utils/response_util.py | 11 +-- 3 files changed, 95 insertions(+), 17 deletions(-) create mode 100644 ruoyi-fastapi-backend/config/constant.py diff --git a/ruoyi-fastapi-backend/config/constant.py b/ruoyi-fastapi-backend/config/constant.py new file mode 100644 index 0000000..552d717 --- /dev/null +++ b/ruoyi-fastapi-backend/config/constant.py @@ -0,0 +1,76 @@ +class CommonConstant: + """ + 常用常量 + WWW: www主域 + HTTP: http请求 + HTTPS: https请求 + UNIQUE: 校验是否唯一的返回标识(是) + NOT_UNIQUE: 校验是否唯一的返回标识(否) + """ + WWW = 'www.' + HTTP = 'http://' + HTTPS = 'https://' + UNIQUE = True + NOT_UNIQUE = False + + +class HttpStatusConstant: + """ + 返回状态码 + SUCCESS: 操作成功 + CREATED: 对象创建成功 + ACCEPTED: 请求已经被接受 + NO_CONTENT: 操作已经执行成功,但是没有返回数据 + MOVED_PERM: 资源已被移除 + SEE_OTHER: 重定向 + NOT_MODIFIED: 资源没有被修改 + BAD_REQUEST: 参数列表错误(缺少,格式不匹配) + UNAUTHORIZED: 未授权 + FORBIDDEN: 访问受限,授权过期 + NOT_FOUND: 资源,服务未找到 + BAD_METHOD: 不允许的http方法 + CONFLICT: 资源冲突,或者资源被锁 + UNSUPPORTED_TYPE: 不支持的数据,媒体类型 + ERROR: 系统内部错误 + NOT_IMPLEMENTED: 接口未实现 + WARN: 系统警告消息 + """ + SUCCESS = 200 + CREATED = 201 + ACCEPTED = 202 + NO_CONTENT = 204 + MOVED_PERM = 301 + SEE_OTHER = 303 + NOT_MODIFIED = 304 + BAD_REQUEST = 400 + UNAUTHORIZED = 401 + FORBIDDEN = 403 + NOT_FOUND = 404 + BAD_METHOD = 405 + CONFLICT = 409 + UNSUPPORTED_TYPE = 415 + ERROR = 500 + NOT_IMPLEMENTED = 501 + WARN = 601 + + +class MenuConstant: + """ + 菜单常量 + TYPE_DIR: 菜单类型(目录) + TYPE_MENU: 菜单类型(菜单) + TYPE_BUTTON: 菜单类型(按钮) + YES_FRAME: 是否菜单外链(是) + NO_FRAME: 是否菜单外链(否) + LAYOUT: Layout组件标识 + PARENT_VIEW: ParentView组件标识 + INNER_LINK: InnerLink组件标识 + """ + TYPE_DIR = 'M' + TYPE_MENU = 'C' + TYPE_BUTTON = 'F' + YES_FRAME = 0 + NO_FRAME = 1 + LAYOUT = 'Layout' + PARENT_VIEW = 'ParentView' + INNER_LINK = 'InnerLink' diff --git a/ruoyi-fastapi-backend/module_admin/service/login_service.py b/ruoyi-fastapi-backend/module_admin/service/login_service.py index 9870351..358d840 100644 --- a/ruoyi-fastapi-backend/module_admin/service/login_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/login_service.py @@ -10,6 +10,7 @@ from module_admin.entity.vo.login_vo import * from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.login_dao import * from exceptions.exception import LoginException, AuthException +from config.constant import CommonConstant, MenuConstant from config.env import AppConfig, JwtConfig, RedisInitKeyConfig from config.get_db import get_db from utils.common_util import CamelCaseUtil @@ -231,7 +232,7 @@ class LoginService: :return: 当前用户路由信息对象 """ query_user = await UserDao.get_user_by_id(query_db, user_id=user_id) - user_router_menu = sorted([row for row in query_user.get('user_menu_info') if row.menu_type in ['M', 'C']], key=lambda x: x.order_num) + user_router_menu = sorted([row for row in query_user.get('user_menu_info') if row.menu_type in [MenuConstant.TYPE_DIR, MenuConstant.TYPE_MENU]], key=lambda x: x.order_num) menus = cls.__generate_menus(0, user_router_menu) user_router = cls.__generate_user_router_menu(menus) return [router.model_dump(exclude_unset=True, by_alias=True) for router in user_router] @@ -278,7 +279,7 @@ class LoginService: ) ) c_menus = permission.children - if c_menus and permission.menu_type == 'M': + if c_menus and permission.menu_type == MenuConstant.TYPE_DIR: router.always_show = True router.redirect = 'noRedirect' router.children = cls.__generate_user_router_menu(c_menus) @@ -309,7 +310,7 @@ class LoginService: router_path = RouterUtil.inner_link_replace_each(permission.path) children = RouterModel( path=router_path, - component='InnerLink', + component=MenuConstant.INNER_LINK, name=router_path.capitalize(), meta=MetaModel( title=permission.menu_name, @@ -457,7 +458,7 @@ class RouterUtil: if menu.parent_id != 0 and cls.is_inner_link(menu): router_path = cls.inner_link_replace_each(router_path) # 非外链并且是一级目录(类型为目录) - if menu.parent_id == 0 and menu.menu_type == 'M' and menu.is_frame == 1: + if menu.parent_id == 0 and menu.menu_type == MenuConstant.TYPE_DIR and menu.is_frame == MenuConstant.NO_FRAME: router_path = f'/{menu.path}' # 非外链并且是一级目录(类型为菜单) elif cls.is_menu_frame(menu): @@ -471,13 +472,13 @@ class RouterUtil: :param menu: 菜单数对象 :return: 组件信息 """ - component = 'Layout' + component = MenuConstant.LAYOUT if menu.component and not cls.is_menu_frame(menu): component = menu.component elif (menu.component is None or menu.component == '') and menu.parent_id != 0 and cls.is_inner_link(menu): - component = 'InnerLink' + component = MenuConstant.INNER_LINK elif (menu.component is None or menu.component == '') and cls.is_parent_view(menu): - component = 'ParentView' + component = MenuConstant.PARENT_VIEW return component @classmethod @@ -487,7 +488,7 @@ class RouterUtil: :param menu: 菜单数对象 :return: 是否为菜单内部跳转 """ - return menu.parent_id == 0 and menu.menu_type == 'C' and menu.is_frame == 1 + return menu.parent_id == 0 and menu.menu_type == MenuConstant.TYPE_MENU and menu.is_frame == MenuConstant.NO_FRAME @classmethod def is_inner_link(cls, menu: MenuTreeModel): @@ -496,7 +497,7 @@ class RouterUtil: :param menu: 菜单数对象 :return: 是否为内链组件 """ - return menu.is_frame == 1 and cls.is_http(menu.path) + return menu.is_frame == MenuConstant.NO_FRAME and cls.is_http(menu.path) @classmethod def is_parent_view(cls, menu: MenuTreeModel): @@ -505,7 +506,7 @@ class RouterUtil: :param menu: 菜单数对象 :return: 是否为parent_view组件 """ - return menu.parent_id != 0 and menu.menu_type == 'M' + return menu.parent_id != 0 and menu.menu_type == MenuConstant.TYPE_DIR @classmethod def is_http(cls, link: str): @@ -514,7 +515,7 @@ class RouterUtil: :param link: 链接 :return: 是否为http(s)://开头 """ - return link.startswith('http://') or link.startswith('https://') + return link.startswith(CommonConstant.HTTP) or link.startswith(CommonConstant.HTTPS) @classmethod def inner_link_replace_each(cls, path: str): @@ -523,7 +524,7 @@ class RouterUtil: :param path: 内链域名 :return: 替换后的内链域名 """ - old_values = ["http://", "https://", "www.", ".", ":"] + old_values = [CommonConstant.HTTP, CommonConstant.HTTPS, CommonConstant.WWW, ".", ":"] new_values = ["", "", "", "/", "/"] for old, new in zip(old_values, new_values): path = path.replace(old, new) diff --git a/ruoyi-fastapi-backend/utils/response_util.py b/ruoyi-fastapi-backend/utils/response_util.py index a741074..512c939 100644 --- a/ruoyi-fastapi-backend/utils/response_util.py +++ b/ruoyi-fastapi-backend/utils/response_util.py @@ -4,6 +4,7 @@ from fastapi.encoders import jsonable_encoder from typing import Any, Dict, Optional from pydantic import BaseModel from datetime import datetime +from config.constant import HttpStatusConstant class ResponseUtil: @@ -24,7 +25,7 @@ class ResponseUtil: :return: 成功响应结果 """ result = { - 'code': 200, + 'code': HttpStatusConstant.SUCCESS, 'msg': msg } @@ -57,7 +58,7 @@ class ResponseUtil: :return: 失败响应结果 """ result = { - 'code': 601, + 'code': HttpStatusConstant.WARN, 'msg': msg } @@ -90,7 +91,7 @@ class ResponseUtil: :return: 未认证响应结果 """ result = { - 'code': 401, + 'code': HttpStatusConstant.UNAUTHORIZED, 'msg': msg } @@ -123,7 +124,7 @@ class ResponseUtil: :return: 未认证响应结果 """ result = { - 'code': 403, + 'code': HttpStatusConstant.FORBIDDEN, 'msg': msg } @@ -156,7 +157,7 @@ class ResponseUtil: :return: 错误响应结果 """ result = { - 'code': 500, + 'code': HttpStatusConstant.ERROR, 'msg': msg } -- Gitee From cfa68999a90129d9da4f1897c996fd9f44a75074 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 3 Jul 2024 21:08:00 +0800 Subject: [PATCH 014/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E@NotBlank?= =?UTF-8?q?=E5=92=8C@Size=E8=A3=85=E9=A5=B0=E5=99=A8=E7=94=A8=E4=BA=8E?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/exception.py | 10 +++ .../annotation/check_annotation.py | 79 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py diff --git a/ruoyi-fastapi-backend/exceptions/exception.py b/ruoyi-fastapi-backend/exceptions/exception.py index 28c39a6..281bb64 100644 --- a/ruoyi-fastapi-backend/exceptions/exception.py +++ b/ruoyi-fastapi-backend/exceptions/exception.py @@ -36,3 +36,13 @@ class ModelValidatorException(Exception): def __init__(self, data: str = None, message: str = None): self.data = data self.message = message + + +class FieldValidatorException(Exception): + """ + 自定义字段校验异常FieldValidatorException + """ + + def __init__(self, data: str = None, message: str = None): + self.data = data + self.message = message diff --git a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py new file mode 100644 index 0000000..005d91d --- /dev/null +++ b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py @@ -0,0 +1,79 @@ +from typing import Optional +from pydantic import BaseModel +from exceptions.exception import FieldValidatorException + + +class NotBlank: + """ + 字段非空校验装饰器 + """ + def __init__(self, field_name: str, message: Optional[str] = None): + """ + 字段非空校验装饰器 + :param field_name: 需要校验的字段名称 + :param message: 校验失败的提示信息 + :return: + """ + self.field_name = field_name + self.message = message + + def __call__(self, func): + def wrapper(*args, **kwargs): + check_model = args[0] + if isinstance(check_model, BaseModel): + field_value = getattr(check_model, self.field_name) + if field_value is None or field_value == '' or field_value == [] or field_value == () or field_value == {}: + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不能为空') + return func(*args, **kwargs) + return wrapper + + +class Size: + """ + 字段大小校验装饰器 + """ + def __init__(self, field_name: str, gt: Optional[float] = None, ge: Optional[float] = None, + lt: Optional[float] = None, le: Optional[float] = None, min_length: Optional[int] = 0, + max_length: Optional[int] = None, message: Optional[str] = None): + """ + 字段大小校验装饰器 + :param field_name: 需要校验的字段名称 + :param gt: 数字型字段值必须要大于gt + :param ge: 数字型字段值必须要大于等于ge + :param lt: 数字型字段值必须要小于ge + :param le: 数字型字段值必须要小于等于ge + :param min_length: 字符串型字段长度不能小于min_length + :param max_length: 字符串型字段长度不能大于max_length + :param message: 校验失败的提示信息 + :return: + """ + self.field_name = field_name + self.gt = gt + self.ge = ge + self.lt = lt + self.le = le + self.min_length = min_length if min_length >= 0 else 0 + self.max_length = max_length + self.message = message + + def __call__(self, func): + def wrapper(*args, **kwargs): + check_model = args[0] + if isinstance(check_model, BaseModel): + field_value = getattr(check_model, self.field_name) + if isinstance(field_value, float): + if self.gt is not None and field_value <= self.gt: + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须大于{self.gt}') + elif self.ge is not None and field_value < self.ge: + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须大于等于{self.ge}') + elif self.lt is not None and field_value >= self.lt: + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须小于{self.lt}') + elif self.le is not None and field_value > self.le: + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须小于等于{self.le}') + elif isinstance(field_value, str): + if len(field_value) < self.min_length: + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}长度不能小于{self.min_length}') + elif self.max_length is not None and len(field_value) > self.max_length: + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}长度不能大于{self.max_length}') + return func(*args, **kwargs) + return wrapper -- Gitee From 2f3e5171b01ca50e7cb8544df7acd11e6de27a11 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 3 Jul 2024 21:09:43 +0800 Subject: [PATCH 015/129] =?UTF-8?q?feat&perf:=20=E5=B2=97=E4=BD=8D?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/post_vo.py | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py index 8ba3495..abf5337 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py @@ -1,7 +1,8 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime +from module_admin.annotation.check_annotation import NotBlank, Size from module_admin.annotation.pydantic_annotation import as_query, as_form @@ -11,24 +12,38 @@ class PostModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - post_id: Optional[int] = None - post_code: Optional[str] = None - post_name: Optional[str] = None - post_sort: Optional[int] = None - status: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None + post_id: Optional[int] = Field(default=None, description='岗位ID') + post_code: Optional[str] = Field(default=None, description='岗位编码') + post_name: Optional[str] = Field(default=None, description='岗位名称') + post_sort: Optional[int] = Field(default=None, description='显示顺序') + status: Optional[Literal['0', '1']] = Field(default=None, description='状态(0正常 1停用)') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注') + + @NotBlank(field_name='post_code', message='岗位编码不能为空') + @Size(field_name='post_code', min_length=0, max_length=64, message='岗位编码长度不能超过64个字符') + def get_post_code(self): + return self.post_code + + @NotBlank(field_name='post_name', message='岗位名称不能为空') + @Size(field_name='post_name', min_length=0, max_length=50, message='岗位名称长度不能超过50个字符') + def get_post_name(self): + return self.post_name + + @NotBlank(field_name='post_sort', message='显示顺序不能为空') + def get_post_sort(self): + return self.post_sort class PostQueryModel(PostModel): """ 岗位管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -37,8 +52,8 @@ class PostPageQueryModel(PostQueryModel): """ 岗位管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class DeletePostModel(BaseModel): @@ -47,4 +62,4 @@ class DeletePostModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - post_ids: str + post_ids: str = Field(description='需要删除的岗位ID') -- Gitee From 549948ba37152ac0b0408a23d0ed0b97f1ccd74f Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 09:54:49 +0800 Subject: [PATCH 016/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9EFieldValidato?= =?UTF-8?q?rException=E5=85=A8=E5=B1=80=E5=BC=82=E5=B8=B8=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/handle.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index 040a11f..accd51e 100644 --- a/ruoyi-fastapi-backend/exceptions/handle.py +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -1,6 +1,6 @@ from fastapi import FastAPI, Request from fastapi.exceptions import HTTPException -from exceptions.exception import AuthException, PermissionException, ModelValidatorException +from exceptions.exception import AuthException, PermissionException, ModelValidatorException, FieldValidatorException from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder @@ -23,6 +23,11 @@ def handle_exception(app: FastAPI): async def model_validator_exception_handler(request: Request, exc: ModelValidatorException): return ResponseUtil.failure(data=exc.data, msg=exc.message) + # 自定义模型检验异常 + @app.exception_handler(FieldValidatorException) + async def field_validator_exception_handler(request: Request, exc: FieldValidatorException): + return ResponseUtil.failure(data=exc.data, msg=exc.message) + # 处理其他http请求异常 @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): -- Gitee From 2a20042680bf620301938edcdccfc8691601e192 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 10:56:05 +0800 Subject: [PATCH 017/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E@ValidateFiel?= =?UTF-8?q?ds=E5=AD=97=E6=AE=B5=E6=A0=A1=E9=AA=8C=E8=A3=85=E9=A5=B0?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/check_annotation.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py index 005d91d..ab8c849 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py @@ -1,8 +1,35 @@ +from functools import wraps from typing import Optional from pydantic import BaseModel from exceptions.exception import FieldValidatorException +class ValidateFields: + """ + 字段校验装饰器 + """ + def __init__(self, validate_model: str, validate_function: str = 'validate_fields'): + """ + 字段校验装饰器 + :param validate_model: 需要校验的pydantic模型在函数中的名称 + :param validate_function: pydantic模型中定义的校验函数名称 + :return: + """ + self.validate_model = validate_model + self.validate_function = validate_function + + def __call__(self, func): + @wraps(func) + async def wrapper(*args, **kwargs): + check_model = kwargs.get(self.validate_model) + if isinstance(check_model, BaseModel) and hasattr(check_model, self.validate_function): + validate_function = getattr(check_model, self.validate_function, None) + if validate_function is not None and callable(validate_function): + validate_function() + return await func(*args, **kwargs) + return wrapper + + class NotBlank: """ 字段非空校验装饰器 @@ -18,6 +45,7 @@ class NotBlank: self.message = message def __call__(self, func): + @wraps(func) def wrapper(*args, **kwargs): check_model = args[0] if isinstance(check_model, BaseModel): @@ -57,6 +85,7 @@ class Size: self.message = message def __call__(self, func): + @wraps(func) def wrapper(*args, **kwargs): check_model = args[0] if isinstance(check_model, BaseModel): -- Gitee From 66595d10a37846e8b5977e76d73c6dc4502b9788 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 10:56:23 +0800 Subject: [PATCH 018/129] =?UTF-8?q?feat:=20=E5=B2=97=E4=BD=8D=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E=E5=92=8C=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/post_controler.py | 3 +++ ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py index fbeb670..6351a5c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py @@ -5,6 +5,7 @@ from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.post_service import * from module_admin.entity.vo.post_vo import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.annotation.check_annotation import ValidateFields from module_admin.annotation.log_annotation import log_decorator from config.enums import BusinessType from utils.response_util import * @@ -29,6 +30,7 @@ async def get_system_post_list(request: Request, post_page_query: PostPageQueryM @postController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))]) +@ValidateFields(validate_model='add_post') @log_decorator(title='岗位管理', business_type=BusinessType.INSERT) async def add_system_post(request: Request, add_post: PostModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -49,6 +51,7 @@ async def add_system_post(request: Request, add_post: PostModel, query_db: Async @postController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))]) +@ValidateFields(validate_model='edit_post') @log_decorator(title='岗位管理', business_type=BusinessType.UPDATE) async def edit_system_post(request: Request, edit_post: PostModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py index abf5337..233cebf 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py @@ -37,6 +37,11 @@ class PostModel(BaseModel): def get_post_sort(self): return self.post_sort + def validate_fields(self): + self.get_post_code() + self.get_post_name() + self.get_post_sort() + class PostQueryModel(PostModel): """ -- Gitee From b5d0b5a170a23e6bdcddc0bd7a1be137525de73f Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 10:56:44 +0800 Subject: [PATCH 019/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E4=B8=B2=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/utils/string_util.py | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 ruoyi-fastapi-backend/utils/string_util.py diff --git a/ruoyi-fastapi-backend/utils/string_util.py b/ruoyi-fastapi-backend/utils/string_util.py new file mode 100644 index 0000000..a03fd6b --- /dev/null +++ b/ruoyi-fastapi-backend/utils/string_util.py @@ -0,0 +1,31 @@ +class StringUtil: + """ + 字符串工具类 + """ + + @classmethod + def is_blank(cls, string: str) -> bool: + """ + 校验字符串是否为''或全空格 + :param string: 需要校验的字符串 + :return: 校验结果 + """ + if string is None: + return False + str_len = len(string) + if str_len == 0: + return True + else: + for i in range(str_len): + if string[i] != ' ': + return False + return True + + @classmethod + def is_empty(cls, string) -> bool: + """ + 校验字符串是否为''或None + :param string: 需要校验的字符串 + :return: 校验结果 + """ + return string is None or len(string) == 0 -- Gitee From 2b3849a573b76abd32fe0902c772c3519a8a35ef Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 10:57:37 +0800 Subject: [PATCH 020/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E@Xss=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=A0=A1=E9=AA=8C=E8=A3=85=E9=A5=B0=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/check_annotation.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py index ab8c849..7ae15e1 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py @@ -1,7 +1,9 @@ +import re from functools import wraps from typing import Optional from pydantic import BaseModel from exceptions.exception import FieldValidatorException +from utils.string_util import StringUtil class ValidateFields: @@ -106,3 +108,33 @@ class Size: raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}长度不能大于{self.max_length}') return func(*args, **kwargs) return wrapper + + +class Xss: + """ + 字段Xss校验装饰器 + """ + HTML_PATTERN = '<(\S*?)[^>]*>.*?|<.*? />' + + def __init__(self, field_name: str, message: Optional[str] = None): + """ + 字段Xss校验装饰器 + :param field_name: 需要校验的字段名称 + :param message: 校验失败的提示信息 + :return: + """ + self.field_name = field_name + self.message = message + + def __call__(self, func): + @wraps(func) + def wrapper(*args, **kwargs): + check_model = args[0] + if isinstance(check_model, BaseModel): + field_value = getattr(check_model, self.field_name) + if not StringUtil.is_blank(field_value): + pattern = re.compile(self.HTML_PATTERN) + if pattern.search(field_value): + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不能包含脚本字符') + return func(*args, **kwargs) + return wrapper -- Gitee From 212f981b6ac423541101346f1d92d5b3a83939e2 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 11:52:05 +0800 Subject: [PATCH 021/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E@Pattern?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=A0=A1=E9=AA=8C=E8=A3=85=E9=A5=B0=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/check_annotation.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py index 7ae15e1..807e0bd 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py @@ -58,6 +58,34 @@ class NotBlank: return wrapper +class Pattern: + """ + 字段正则校验装饰器 + """ + def __init__(self, field_name: str, regexp: str, message: Optional[str] = None): + """ + 字段正则校验装饰器 + :param field_name: 需要校验的字段名称 + :param regexp: 正则表达式 + :param message: 校验失败的提示信息 + :return: + """ + self.field_name = field_name + self.regexp = regexp + self.message = message + + def __call__(self, func): + @wraps(func) + def wrapper(*args, **kwargs): + check_model = args[0] + if isinstance(check_model, BaseModel): + field_value = getattr(check_model, self.field_name) + if isinstance(field_value, str) and not re.match(self.regexp, field_value): + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}格式不正确') + return func(*args, **kwargs) + return wrapper + + class Size: """ 字段大小校验装饰器 -- Gitee From d98d5e8c41752e692a60a3ad9bc745ddf1da69c6 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 14:32:46 +0800 Subject: [PATCH 022/129] =?UTF-8?q?feat&perf:=20=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/config_vo.py | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py index 6c7ada7..af8525c 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py @@ -1,7 +1,8 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from typing import Union, Optional, List from datetime import datetime +from module_admin.annotation.check_annotation import NotBlank, Size from module_admin.annotation.pydantic_annotation import as_query, as_form @@ -11,24 +12,44 @@ class ConfigModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - config_id: Optional[int] = None - config_name: Optional[str] = None - config_key: Optional[str] = None - config_value: Optional[str] = None - config_type: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None + config_id: Optional[int] = Field(default=None, description='参数主键') + config_name: Optional[str] = Field(default=None, description='参数名称') + config_key: Optional[str] = Field(default=None, description='参数键名') + config_value: Optional[str] = Field(default=None, description='参数键值') + config_type: Optional[str] = Field(default=None, description='系统内置(Y是 N否)') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注') + + @NotBlank(field_name='config_key', message='参数名称不能为空') + @Size(field_name='config_key', min_length=0, max_length=100, message='参数名称长度不能超过100个字符') + def get_config_key(self): + return self.config_key + + @NotBlank(field_name='config_name', message='参数键名不能为空') + @Size(field_name='config_name', min_length=0, max_length=100, message='参数键名长度不能超过100个字符') + def get_config_name(self): + return self.config_name + + @NotBlank(field_name='config_value', message='参数键值不能为空') + @Size(field_name='config_value', min_length=0, max_length=500, message='参数键值长度不能超过500个字符') + def get_config_value(self): + return self.config_value + + def validate_fields(self): + self.get_config_key() + self.get_config_name() + self.get_config_value() class ConfigQueryModel(ConfigModel): """ 参数配置管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -37,8 +58,8 @@ class ConfigPageQueryModel(ConfigQueryModel): """ 参数配置管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class DeleteConfigModel(BaseModel): @@ -47,4 +68,4 @@ class DeleteConfigModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - config_ids: str + config_ids: str = Field(description='需要删除的参数主键') -- Gitee From a66061aa8917a636329e5d9d9525bf824bfbf422 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 17:29:44 +0800 Subject: [PATCH 023/129] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0fastapi?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E8=87=B30.111.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/requirements.txt b/ruoyi-fastapi-backend/requirements.txt index a0ee800..292ca2f 100644 --- a/ruoyi-fastapi-backend/requirements.txt +++ b/ruoyi-fastapi-backend/requirements.txt @@ -1,7 +1,7 @@ APScheduler==3.10.4 asyncmy==0.2.9 DateTime==5.4 -fastapi[all]==0.109.1 +fastapi[all]==0.111.0 loguru==0.7.2 openpyxl==3.1.2 pandas==2.1.4 -- Gitee From 0ca5aab05aad54f1952115fe7fa56774f4f647ae Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 17:29:54 +0800 Subject: [PATCH 024/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E@NetWork?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=A0=A1=E9=AA=8C=E8=A3=85=E9=A5=B0=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/check_annotation.py | 128 +++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py index 807e0bd..0ca85c6 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py @@ -1,11 +1,58 @@ import re from functools import wraps -from typing import Optional -from pydantic import BaseModel +from typing import Literal, Optional +from pydantic import ( + BaseModel, + Field, + AnyUrl, + AnyHttpUrl, + HttpUrl, + AnyWebsocketUrl, + WebsocketUrl, + FileUrl, + FtpUrl, + PostgresDsn, + CockroachDsn, + AmqpDsn, + RedisDsn, + MongoDsn, + KafkaDsn, + NatsDsn, + MySQLDsn, + MariaDBDsn, + ClickHouseDsn, + EmailStr, + NameEmail, + IPvAnyAddress, + ValidationError +) from exceptions.exception import FieldValidatorException from utils.string_util import StringUtil +class NetWorkAnnotationModel(BaseModel): + any_url: Optional[AnyUrl] = Field(default=None, description='接受任何URL类型') + any_http_url: Optional[AnyHttpUrl] = Field(default=None, description='接受任何http或https URL的类型') + http_url: Optional[HttpUrl] = Field(default=None, description='接受任何最大长度2083 & http或https URL的类型') + any_websocket_url: Optional[AnyWebsocketUrl] = Field(default=None, description='接受任何ws或wss URL的类型') + websocket_url: Optional[WebsocketUrl] = Field(default=None, description='接受任何最大长度 2083 & ws或wss URL的类型') + file_url: Optional[FileUrl] = Field(default=None, description='接受任何文件URL的类型') + ftp_url: Optional[FtpUrl] = Field(default=None, description='接受ftp URL的类型') + postgres_dsn: Optional[PostgresDsn] = Field(default=None, description='接受任何Postgres DSN的类型') + cockroach_dsn: Optional[CockroachDsn] = Field(default=None, description='接受任何Cockroach DSN的类型') + amqp_dsn: Optional[AmqpDsn] = Field(default=None, description='接受任何AMQP DSN的类型') + redis_dsn: Optional[RedisDsn] = Field(default=None, description='接受任何Redis DSN的类型') + mongo_dsn: Optional[MongoDsn] = Field(default=None, description='接受任何MongoDB DSN的类型') + kafka_dsn: Optional[KafkaDsn] = Field(default=None, description='接受任何Kafka DSN的类型') + nats_dsn: Optional[NatsDsn] = Field(default=None, description='接受任何NATS DSN的类型') + mysql_dsn: Optional[MySQLDsn] = Field(default=None, description='接受任何MySQL DSN的类型') + mariadb_dsn: Optional[MariaDBDsn] = Field(default=None, description='接受任何MariaDB DSN的类型') + clickhouse_dsn: Optional[ClickHouseDsn] = Field(default=None, description='接受任何ClickHouse DSN的类型') + email_str: Optional[EmailStr] = Field(default=None, description='验证电子邮件地址') + name_email: Optional[NameEmail] = Field(default=None, description='验证RFC 5322指定的名称和电子邮件地址组合') + ipv_any_address: Optional[IPvAnyAddress] = Field(default=None, description='验证IPv4或IPv6地址') + + class ValidateFields: """ 字段校验装饰器 @@ -32,6 +79,83 @@ class ValidateFields: return wrapper +class NetWork: + """ + 字段网络类型校验装饰器 + """ + def __init__( + self, + field_name: str, + field_type: Literal['AnyUrl', 'AnyHttpUrl', 'HttpUrl', 'AnyWebsocketUrl', 'WebsocketUrl', 'FileUrl', + 'FtpUrl', 'PostgresDsn', 'CockroachDsn', 'AmqpDsn', 'RedisDsn', 'MongoDsn', 'KafkaDsn', + 'NatsDsn', 'MySQLDsn', 'MariaDBDsn', 'ClickHouseDsn', 'EmailStr', 'NameEmail', + 'IPvAnyAddress'], + message: Optional[str] = None + ): + """ + 字段网络类型校验装饰器 + :param field_name: 需要校验的字段名称 + :param field_type: 需要校验的字段类型 + :param message: 校验失败的提示信息 + :return: + """ + self.field_name = field_name + self.field_type = field_type + self.message = message + + def __call__(self, func): + @wraps(func) + def wrapper(*args, **kwargs): + check_model = args[0] + if isinstance(check_model, BaseModel): + field_value = getattr(check_model, self.field_name) + try: + if self.field_type == 'AnyUrl': + NetWorkAnnotationModel(any_url=field_value) + elif self.field_type == 'AnyHttpUrl': + NetWorkAnnotationModel(any_http_url=field_value) + elif self.field_type == 'HttpUrl': + NetWorkAnnotationModel(http_url=field_value) + elif self.field_type == 'AnyWebsocketUrl': + NetWorkAnnotationModel(any_websocket_url=field_value) + elif self.field_type == 'WebsocketUrl': + NetWorkAnnotationModel(websocket_url=field_value) + elif self.field_type == 'FileUrl': + NetWorkAnnotationModel(file_url=field_value) + elif self.field_type == 'FtpUrl': + NetWorkAnnotationModel(ftp_url=field_value) + elif self.field_type == 'PostgresDsn': + NetWorkAnnotationModel(postgres_dsn=field_value) + elif self.field_type == 'CockroachDsn': + NetWorkAnnotationModel(cockroach_dsn=field_value) + elif self.field_type == 'AmqpDsn': + NetWorkAnnotationModel(amqp_dsn=field_value) + elif self.field_type == 'RedisDsn': + NetWorkAnnotationModel(redis_dsn=field_value) + elif self.field_type == 'MongoDsn': + NetWorkAnnotationModel(mongo_dsn=field_value) + elif self.field_type == 'KafkaDsn': + NetWorkAnnotationModel(kafka_dsn=field_value) + elif self.field_type == 'NatsDsn': + NetWorkAnnotationModel(nats_dsn=field_value) + elif self.field_type == 'MySQLDsn': + NetWorkAnnotationModel(mysql_dsn=field_value) + elif self.field_type == 'MariaDBDsn': + NetWorkAnnotationModel(mariadb_dsn=field_value) + elif self.field_type == 'ClickHouseDsn': + NetWorkAnnotationModel(clickhouse_dsn=field_value) + elif self.field_type == 'EmailStr': + NetWorkAnnotationModel(email_str=field_value) + elif self.field_type == 'NameEmail': + NetWorkAnnotationModel(name_email=field_value) + elif self.field_type == 'IPvAnyAddress': + NetWorkAnnotationModel(ipv_any_address=field_value) + except (ValidationError, ValueError): + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不是正确的{self.field_type}类型') + return func(*args, **kwargs) + return wrapper + + class NotBlank: """ 字段非空校验装饰器 -- Gitee From cebbe90eac199689f40b7b6ca861a8cc67103b53 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 4 Jul 2024 17:30:14 +0800 Subject: [PATCH 025/129] =?UTF-8?q?feat&perf:=20=E9=83=A8=E9=97=A8?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/dept_vo.py | 67 +++++++++++++------ 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py index 9a8eb3e..8ae4c9a 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py @@ -1,7 +1,8 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime +from module_admin.annotation.check_annotation import NetWork, NotBlank, Size from module_admin.annotation.pydantic_annotation import as_query @@ -11,20 +12,44 @@ class DeptModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - dept_id: Optional[int] = None - parent_id: Optional[int] = None - ancestors: Optional[str] = None - dept_name: Optional[str] = None - order_num: Optional[int] = None - leader: Optional[str] = None - phone: Optional[str] = None - email: Optional[str] = None - status: Optional[str] = None - del_flag: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None + dept_id: Optional[int] = Field(default=None, description='部门id') + parent_id: Optional[int] = Field(default=None, description='父部门id') + ancestors: Optional[str] = Field(default=None, description='祖级列表') + dept_name: Optional[str] = Field(default=None, description='部门名称') + order_num: Optional[int] = Field(default=None, description='显示顺序') + leader: Optional[str] = Field(default=None, description='负责人') + phone: Optional[str] = Field(default=None, description='联系电话') + email: Optional[str] = Field(default=None, description='邮箱') + status: Optional[Literal['0', '1']] = Field(default=None, description='部门状态(0正常 1停用)') + del_flag: Optional[Literal['0', '2']] = Field(default=None, description='删除标志(0代表存在 2代表删除)') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + + @NotBlank(field_name='dept_name', message='部门名称不能为空') + @Size(field_name='dept_name', min_length=0, max_length=30, message='部门名称长度不能超过30个字符') + def get_dept_name(self): + return self.dept_name + + @NotBlank(field_name='order_num', message='显示顺序不能为空') + def get_order_num(self): + return self.order_num + + @Size(field_name='phone', min_length=0, max_length=11, message='联系电话长度不能超过11个字符') + def get_phone(self): + return self.phone + + @NetWork(field_name='email', field_type='EmailStr', message='邮箱格式不正确') + @Size(field_name='email', min_length=0, max_length=50, message='邮箱长度不能超过50个字符') + def get_email(self): + return self.email + + def validate_fields(self): + self.get_dept_name() + self.get_order_num() + self.get_phone() + self.get_email() @as_query @@ -32,8 +57,8 @@ class DeptQueryModel(DeptModel): """ 部门管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') class DeleteDeptModel(BaseModel): @@ -42,6 +67,6 @@ class DeleteDeptModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - dept_ids: str - update_by: Optional[str] = None - update_time: Optional[str] = None + dept_ids: str = Field(default=None, description='需要删除的部门id') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[str] = Field(default=None, description='更新时间') -- Gitee From d1cc297169d8cdceb3e64e8146db2f0458c2b2fd Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 08:11:52 +0800 Subject: [PATCH 026/129] =?UTF-8?q?refactor:=20check=5Fannotation.py?= =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BAvalidate=5Fannotation.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...k_annotation.py => validate_annotation.py} | 36 +++++++++---------- .../module_admin/controller/post_controler.py | 2 +- .../module_admin/entity/vo/config_vo.py | 2 +- .../module_admin/entity/vo/dept_vo.py | 2 +- .../module_admin/entity/vo/post_vo.py | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) rename ruoyi-fastapi-backend/module_admin/annotation/{check_annotation.py => validate_annotation.py} (92%) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py similarity index 92% rename from ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py rename to ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py index 0ca85c6..32744f0 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/check_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py @@ -70,9 +70,9 @@ class ValidateFields: def __call__(self, func): @wraps(func) async def wrapper(*args, **kwargs): - check_model = kwargs.get(self.validate_model) - if isinstance(check_model, BaseModel) and hasattr(check_model, self.validate_function): - validate_function = getattr(check_model, self.validate_function, None) + validate_model = kwargs.get(self.validate_model) + if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.validate_function): + validate_function = getattr(validate_model, self.validate_function, None) if validate_function is not None and callable(validate_function): validate_function() return await func(*args, **kwargs) @@ -106,9 +106,9 @@ class NetWork: def __call__(self, func): @wraps(func) def wrapper(*args, **kwargs): - check_model = args[0] - if isinstance(check_model, BaseModel): - field_value = getattr(check_model, self.field_name) + validate_model = args[0] + if isinstance(validate_model, BaseModel): + field_value = getattr(validate_model, self.field_name) try: if self.field_type == 'AnyUrl': NetWorkAnnotationModel(any_url=field_value) @@ -173,9 +173,9 @@ class NotBlank: def __call__(self, func): @wraps(func) def wrapper(*args, **kwargs): - check_model = args[0] - if isinstance(check_model, BaseModel): - field_value = getattr(check_model, self.field_name) + validate_model = args[0] + if isinstance(validate_model, BaseModel): + field_value = getattr(validate_model, self.field_name) if field_value is None or field_value == '' or field_value == [] or field_value == () or field_value == {}: raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不能为空') return func(*args, **kwargs) @@ -201,9 +201,9 @@ class Pattern: def __call__(self, func): @wraps(func) def wrapper(*args, **kwargs): - check_model = args[0] - if isinstance(check_model, BaseModel): - field_value = getattr(check_model, self.field_name) + validate_model = args[0] + if isinstance(validate_model, BaseModel): + field_value = getattr(validate_model, self.field_name) if isinstance(field_value, str) and not re.match(self.regexp, field_value): raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}格式不正确') return func(*args, **kwargs) @@ -241,9 +241,9 @@ class Size: def __call__(self, func): @wraps(func) def wrapper(*args, **kwargs): - check_model = args[0] - if isinstance(check_model, BaseModel): - field_value = getattr(check_model, self.field_name) + validate_model = args[0] + if isinstance(validate_model, BaseModel): + field_value = getattr(validate_model, self.field_name) if isinstance(field_value, float): if self.gt is not None and field_value <= self.gt: raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须大于{self.gt}') @@ -281,9 +281,9 @@ class Xss: def __call__(self, func): @wraps(func) def wrapper(*args, **kwargs): - check_model = args[0] - if isinstance(check_model, BaseModel): - field_value = getattr(check_model, self.field_name) + validate_model = args[0] + if isinstance(validate_model, BaseModel): + field_value = getattr(validate_model, self.field_name) if not StringUtil.is_blank(field_value): pattern = re.compile(self.HTML_PATTERN) if pattern.search(field_value): diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py index 6351a5c..1049ccb 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py @@ -5,8 +5,8 @@ from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.post_service import * from module_admin.entity.vo.post_vo import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.annotation.check_annotation import ValidateFields from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py index af8525c..b10a14a 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py @@ -2,8 +2,8 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from typing import Union, Optional, List from datetime import datetime -from module_admin.annotation.check_annotation import NotBlank, Size from module_admin.annotation.pydantic_annotation import as_query, as_form +from module_admin.annotation.validate_annotation import NotBlank, Size class ConfigModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py index 8ae4c9a..c55b186 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py @@ -2,8 +2,8 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from typing import Union, Optional, List, Literal from datetime import datetime -from module_admin.annotation.check_annotation import NetWork, NotBlank, Size from module_admin.annotation.pydantic_annotation import as_query +from module_admin.annotation.validate_annotation import NetWork, NotBlank, Size class DeptModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py index 233cebf..c2056c8 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py @@ -2,8 +2,8 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from typing import Union, Optional, List, Literal from datetime import datetime -from module_admin.annotation.check_annotation import NotBlank, Size from module_admin.annotation.pydantic_annotation import as_query, as_form +from module_admin.annotation.validate_annotation import NotBlank, Size class PostModel(BaseModel): -- Gitee From 45063936eb9995ef5ab9363adf81a23a66ec0a9a Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 08:31:19 +0800 Subject: [PATCH 027/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=AE=A1=E7=90=86vo=E5=B1=82config=5Ftype=E7=9A=84?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py index b10a14a..7dd7a5f 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py @@ -1,6 +1,6 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form from module_admin.annotation.validate_annotation import NotBlank, Size @@ -16,7 +16,7 @@ class ConfigModel(BaseModel): config_name: Optional[str] = Field(default=None, description='参数名称') config_key: Optional[str] = Field(default=None, description='参数键名') config_value: Optional[str] = Field(default=None, description='参数键值') - config_type: Optional[str] = Field(default=None, description='系统内置(Y是 N否)') + config_type: Optional[Literal['Y', 'N']] = Field(default=None, description='系统内置(Y是 N否)') create_by: Optional[str] = Field(default=None, description='创建者') create_time: Optional[datetime] = Field(default=None, description='创建时间') update_by: Optional[str] = Field(default=None, description='更新者') -- Gitee From fad9f484e86c3e4915baa5659613ba85d5d9b19c Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 08:31:38 +0800 Subject: [PATCH 028/129] =?UTF-8?q?feat&perf:=20=E5=AD=97=E5=85=B8?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/dict_vo.py | 111 ++++++++++++------ 1 file changed, 76 insertions(+), 35 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py index e4cda55..7a303c1 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py @@ -1,8 +1,9 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form +from module_admin.annotation.validate_annotation import NotBlank, Pattern, Size class DictTypeModel(BaseModel): @@ -11,15 +12,30 @@ class DictTypeModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - dict_id: Optional[int] = None - dict_name: Optional[str] = None - dict_type: Optional[str] = None - status: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None + dict_id: Optional[int] = Field(default=None, description='字典主键') + dict_name: Optional[str] = Field(default=None, description='字典名称') + dict_type: Optional[str] = Field(default=None, description='字典类型') + status: Optional[Literal['0', '1']] = Field(default=None, description='状态(0正常 1停用)') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注') + + @NotBlank(field_name='dict_name', message='字典名称不能为空') + @Size(field_name='dict_name', min_length=0, max_length=100, message='字典类型名称长度不能超过100个字符') + def get_dict_name(self): + return self.dict_name + + @NotBlank(field_name='dict_type', message='字典类型不能为空') + @Size(field_name='dict_type', min_length=0, max_length=100, message='字典类型类型长度不能超过100个字符') + @Pattern(field_name='dict_type', regexp='^[a-z][a-z0-9_]*$', message='字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)') + def get_dict_type(self): + return self.dict_type + + def validate_fields(self): + self.get_dict_name() + self.get_dict_type() class DictDataModel(BaseModel): @@ -28,28 +44,53 @@ class DictDataModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - dict_code: Optional[int] = None - dict_sort: Optional[int] = None - dict_label: Optional[str] = None - dict_value: Optional[str] = None - dict_type: Optional[str] = None - css_class: Optional[str] = None - list_class: Optional[str] = None - is_default: Optional[str] = None - status: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None + dict_code: Optional[int] = Field(default=None, description='字典编码') + dict_sort: Optional[int] = Field(default=None, description='字典排序') + dict_label: Optional[str] = Field(default=None, description='字典标签') + dict_value: Optional[str] = Field(default=None, description='字典键值') + dict_type: Optional[str] = Field(default=None, description='字典类型') + css_class: Optional[str] = Field(default=None, description='样式属性(其他样式扩展)') + list_class: Optional[str] = Field(default=None, description='表格回显样式') + is_default: Optional[Literal['Y', 'N']] = Field(default=None, description='是否默认(Y是 N否)') + status: Optional[Literal['0', '1']] = Field(default=None, description='状态(0正常 1停用)') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注') + + @NotBlank(field_name='dict_label', message='字典标签不能为空') + @Size(field_name='dict_label', min_length=0, max_length=100, message='字典标签长度不能超过100个字符') + def get_dict_label(self): + return self.dict_label + + @NotBlank(field_name='dict_value', message='字典键值不能为空') + @Size(field_name='dict_value', min_length=0, max_length=100, message='字典键值长度不能超过100个字符') + def get_dict_value(self): + return self.dict_value + + @NotBlank(field_name='dict_type', message='字典类型不能为空') + @Size(field_name='dict_type', min_length=0, max_length=100, message='字典类型长度不能超过100个字符') + def get_dict_type(self): + return self.dict_type + + @Size(field_name='css_class', min_length=0, max_length=100, message='样式属性长度不能超过100个字符') + def get_css_class(self): + return self.css_class + + def validate_fields(self): + self.get_dict_label() + self.get_dict_value() + self.get_dict_type() + self.get_css_class() class DictTypeQueryModel(DictTypeModel): """ 字典类型管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -58,8 +99,8 @@ class DictTypePageQueryModel(DictTypeQueryModel): """ 字典类型管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class DeleteDictTypeModel(BaseModel): @@ -68,15 +109,15 @@ class DeleteDictTypeModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - dict_ids: str + dict_ids: str = Field(description='需要删除的字典主键') class DictDataQueryModel(DictDataModel): """ 字典数据管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -85,8 +126,8 @@ class DictDataPageQueryModel(DictDataQueryModel): """ 字典数据管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class DeleteDictDataModel(BaseModel): @@ -95,4 +136,4 @@ class DeleteDictDataModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - dict_codes: str + dict_codes: str = Field(description='需要删除的字典编码') -- Gitee From cd131ba7a2a55b86d45525093672b29843907a64 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 08:50:42 +0800 Subject: [PATCH 029/129] =?UTF-8?q?feat&perf:=20=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo?= =?UTF-8?q?=E5=B1=82=E4=BC=98=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/job_vo.py | 97 +++++++++++-------- 1 file changed, 56 insertions(+), 41 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py index f6f91d3..c3efb7f 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py @@ -1,8 +1,9 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form +from module_admin.annotation.validate_annotation import NotBlank, Size class JobModel(BaseModel): @@ -11,22 +12,36 @@ class JobModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - job_id: Optional[int] = None - job_name: Optional[str] = None - job_group: Optional[str] = None - job_executor: Optional[str] = None - invoke_target: Optional[str] = None - job_args: Optional[str] = None - job_kwargs: Optional[str] = None - cron_expression: Optional[str] = None - misfire_policy: Optional[str] = None - concurrent: Optional[str] = None - status: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None + job_id: Optional[int] = Field(default=None, description='任务ID') + job_name: Optional[str] = Field(default=None, description='任务名称') + job_group: Optional[str] = Field(default=None, description='任务组名') + job_executor: Optional[str] = Field(default=None, description='任务执行器') + invoke_target: Optional[str] = Field(default=None, description='调用目标字符串') + job_args: Optional[str] = Field(default=None, description='位置参数') + job_kwargs: Optional[str] = Field(default=None, description='关键字参数') + cron_expression: Optional[str] = Field(default=None, description='cron执行表达式') + misfire_policy: Optional[Literal['1', '2', '3']] = Field(default=None, description='计划执行错误策略(1立即执行 2执行一次 3放弃执行)') + concurrent: Optional[Literal['0', '1']] = Field(default=None, description='是否并发执行(0允许 1禁止)') + status: Optional[Literal['0', '1']] = Field(default=None, description='状态(0正常 1暂停)') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注信息') + + @NotBlank(field_name='invoke_target', message='调用目标字符串不能为空') + @Size(field_name='invoke_target', min_length=0, max_length=500, message='调用目标字符串长度不能超过500个字符') + def get_invoke_target(self): + return self.invoke_target + + @NotBlank(field_name='cron_expression', message='Cron执行表达式不能为空') + @Size(field_name='cron_expression', min_length=0, max_length=255, message='Cron执行表达式不能超过255个字符') + def get_cron_expression(self): + return self.cron_expression + + def validate_fields(self): + self.get_invoke_target() + self.get_cron_expression() class JobLogModel(BaseModel): @@ -35,26 +50,26 @@ class JobLogModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - job_log_id: Optional[int] = None - job_name: Optional[str] = None - job_group: Optional[str] = None - job_executor: Optional[str] = None - invoke_target: Optional[str] = None - job_args: Optional[str] = None - job_kwargs: Optional[str] = None - job_trigger: Optional[str] = None - job_message: Optional[str] = None - status: Optional[str] = None - exception_info: Optional[str] = None - create_time: Optional[datetime] = None + job_log_id: Optional[int] = Field(default=None, description='任务日志ID') + job_name: Optional[str] = Field(default=None, description='任务名称') + job_group: Optional[str] = Field(default=None, description='任务组名') + job_executor: Optional[str] = Field(default=None, description='任务执行器') + invoke_target: Optional[str] = Field(default=None, description='调用目标字符串') + job_args: Optional[str] = Field(default=None, description='位置参数') + job_kwargs: Optional[str] = Field(default=None, description='关键字参数') + job_trigger: Optional[str] = Field(default=None, description='任务触发器') + job_message: Optional[str] = Field(default=None, description='日志信息') + status: Optional[Literal['0', '1']] = Field(default=None, description='执行状态(0正常 1失败)') + exception_info: Optional[str] = Field(default=None, description='异常信息') + create_time: Optional[datetime] = Field(default=None, description='创建时间') class JobQueryModel(JobModel): """ 定时任务管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -63,15 +78,15 @@ class JobPageQueryModel(JobQueryModel): """ 定时任务管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class EditJobModel(JobModel): """ 编辑定时任务模型 """ - type: Optional[str] = None + type: Optional[str] = Field(default=None, description='操作类型') class DeleteJobModel(BaseModel): @@ -80,15 +95,15 @@ class DeleteJobModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - job_ids: str + job_ids: str = Field(description='需要删除的定时任务ID') class JobLogQueryModel(JobLogModel): """ 定时任务日志不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -97,8 +112,8 @@ class JobLogPageQueryModel(JobLogQueryModel): """ 定时任务日志管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class DeleteJobLogModel(BaseModel): @@ -107,4 +122,4 @@ class DeleteJobLogModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - job_log_ids: str + job_log_ids: str = Field(description='需要删除的定时任务日志ID') -- Gitee From 57dd4178f4ef2c5d155f0984e2da46cff9fa846d Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 09:07:17 +0800 Subject: [PATCH 030/129] =?UTF-8?q?feat&perf:=20=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/menu_vo.py | 82 +++++++++++++------ 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py index 08f22e1..7175c74 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py @@ -1,8 +1,9 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from datetime import datetime -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from module_admin.annotation.pydantic_annotation import as_query +from module_admin.annotation.validate_annotation import NotBlank, Size class MenuModel(BaseModel): @@ -11,25 +12,58 @@ class MenuModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - menu_id: Optional[int] = None - menu_name: Optional[str] = None - parent_id: Optional[int] = None - order_num: Optional[int] = None - path: Optional[str] = None - component: Optional[str] = None - query: Optional[str] = None - is_frame: Optional[int] = None - is_cache: Optional[int] = None - menu_type: Optional[str] = None - visible: Optional[str] = None - status: Optional[str] = None - perms: Optional[str] = None - icon: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None + menu_id: Optional[int] = Field(default=None, description='菜单ID') + menu_name: Optional[str] = Field(default=None, description='菜单名称') + parent_id: Optional[int] = Field(default=None, description='父菜单ID') + order_num: Optional[int] = Field(default=None, description='显示顺序') + path: Optional[str] = Field(default=None, description='路由地址') + component: Optional[str] = Field(default=None, description='组件路径') + query: Optional[str] = Field(default=None, description='路由参数') + is_frame: Optional[Literal[0, 1]] = Field(default=None, description='是否为外链(0是 1否)') + is_cache: Optional[Literal[0, 1]] = Field(default=None, description='是否缓存(0缓存 1不缓存)') + menu_type: Optional[Literal['M', 'C', 'F']] = Field(default=None, description='菜单类型(M目录 C菜单 F按钮)') + visible: Optional[Literal['0', '1']] = Field(default=None, description='菜单状态(0显示 1隐藏)') + status: Optional[Literal['0', '1']] = Field(default=None, description='菜单状态(0正常 1停用)') + perms: Optional[str] = Field(default=None, description='权限标识') + icon: Optional[str] = Field(default=None, description='菜单图标') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注') + + @NotBlank(field_name='menu_name', message='菜单名称不能为空') + @Size(field_name='menu_name', min_length=0, max_length=50, message='菜单名称长度不能超过50个字符') + def get_menu_name(self): + return self.menu_name + + @NotBlank(field_name='order_num', message='显示顺序不能为空') + def get_order_num(self): + return self.order_num + + @Size(field_name='path', min_length=0, max_length=200, message='路由地址长度不能超过200个字符') + def get_path(self): + return self.path + + @Size(field_name='component', min_length=0, max_length=255, message='组件路径长度不能超过255个字符') + def get_component(self): + return self.component + + @NotBlank(field_name='menu_type', message='菜单类型不能为空') + def get_menu_type(self): + return self.menu_type + + @Size(field_name='perms', min_length=0, max_length=100, message='权限标识长度不能超过100个字符') + def get_perms(self): + return self.perms + + def validate_fields(self): + self.get_menu_name() + self.get_order_num() + self.get_path() + self.get_component() + self.get_menu_type() + self.get_perms() @as_query @@ -37,8 +71,8 @@ class MenuQueryModel(MenuModel): """ 菜单管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') class DeleteMenuModel(BaseModel): @@ -47,4 +81,4 @@ class DeleteMenuModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - menu_ids: str + menu_ids: str = Field(description='需要删除的菜单ID') -- Gitee From b6f1827fe0113931d638874ea1520e5e34f075ce Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 09:13:54 +0800 Subject: [PATCH 031/129] =?UTF-8?q?feat&perf:=20=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E5=85=AC=E5=91=8A=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo?= =?UTF-8?q?=E5=B1=82=E4=BC=98=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/notice_vo.py | 44 ++++++++++++------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py index 8403fa2..d95a6dc 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py @@ -1,8 +1,9 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form +from module_admin.annotation.validate_annotation import NotBlank, Size, Xss class NoticeModel(BaseModel): @@ -11,24 +12,33 @@ class NoticeModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - notice_id: Optional[int] = None - notice_title: Optional[str] = None - notice_type: Optional[str] = None - notice_content: Optional[bytes] = None - status: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None + notice_id: Optional[int] = Field(default=None, description='公告ID') + notice_title: Optional[str] = Field(default=None, description='公告标题') + notice_type: Optional[Literal['1', '2']] = Field(default=None, description='公告类型(1通知 2公告)') + notice_content: Optional[bytes] = Field(default=None, description='公告内容') + status: Optional[Literal['0', '1']] = Field(default=None, description='公告状态(0正常 1关闭)') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注') + + @Xss(field_name='notice_title', message='公告标题不能包含脚本字符') + @NotBlank(field_name='notice_title', message='公告标题不能为空') + @Size(field_name='notice_title', min_length=0, max_length=50, message='公告标题不能超过50个字符') + def get_notice_title(self): + return self.notice_title + + def validate_fields(self): + self.get_notice_title() class NoticeQueryModel(NoticeModel): """ 通知公告管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -37,8 +47,8 @@ class NoticePageQueryModel(NoticeQueryModel): """ 通知公告管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class DeleteNoticeModel(BaseModel): @@ -47,4 +57,4 @@ class DeleteNoticeModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - notice_ids: str + notice_ids: str = Field(description='需要删除的公告ID') -- Gitee From 5dcef7b408e165ac28737f790dee5e87e0aab643 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 09:31:04 +0800 Subject: [PATCH 032/129] =?UTF-8?q?feat&perf:=20=E8=A7=92=E8=89=B2?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/role_vo.py | 90 +++++++++++-------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py index 5ec58f1..439ff8b 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py @@ -1,8 +1,9 @@ -from pydantic import BaseModel, ConfigDict, field_validator, model_validator +from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form +from module_admin.annotation.validate_annotation import NotBlank, Size class RoleModel(BaseModel): @@ -11,21 +12,21 @@ class RoleModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - role_id: Optional[int] = None - role_name: Optional[str] = None - role_key: Optional[str] = None - role_sort: Optional[int] = None - data_scope: Optional[str] = None - menu_check_strictly: Optional[Union[int, bool]] = None - dept_check_strictly: Optional[Union[int, bool]] = None - status: Optional[str] = None - del_flag: Optional[str] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None - admin: Optional[bool] = False + role_id: Optional[int] = Field(default=None, description='角色ID') + role_name: Optional[str] = Field(default=None, description='角色名称') + role_key: Optional[str] = Field(default=None, description='角色权限字符串') + role_sort: Optional[int] = Field(default=None, description='显示顺序') + data_scope: Optional[Literal['1', '2', '3', '4']] = Field(default=None, description='数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)') + menu_check_strictly: Optional[Union[int, bool]] = Field(default=None, description='菜单树选择项是否关联显示') + dept_check_strictly: Optional[Union[int, bool]] = Field(default=None, description='部门树选择项是否关联显示') + status: Optional[Literal['0', '1']] = Field(default=None, description='角色状态(0正常 1停用)') + del_flag: Optional[Literal['0', '2']] = Field(default=None, description='删除标志(0代表存在 2代表删除)') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注') + admin: Optional[bool] = Field(default=False, description='是否为admin') @field_validator('menu_check_strictly', 'dept_check_strictly') @classmethod @@ -48,6 +49,25 @@ class RoleModel(BaseModel): self.admin = False return self + @NotBlank(field_name='role_name', message='角色名称不能为空') + @Size(field_name='role_name', min_length=0, max_length=30, message='角色名称长度不能超过30个字符') + def get_role_name(self): + return self.role_name + + @NotBlank(field_name='role_key', message='权限字符不能为空') + @Size(field_name='role_key', min_length=0, max_length=100, message='权限字符长度不能超过100个字符') + def get_role_key(self): + return self.role_key + + @NotBlank(field_name='role_sort', message='显示顺序不能为空') + def get_role_sort(self): + return self.role_sort + + def validate_fields(self): + self.get_role_name() + self.get_role_key() + self.get_role_sort() + class RoleMenuModel(BaseModel): """ @@ -55,8 +75,8 @@ class RoleMenuModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - role_id: Optional[int] = None - menu_id: Optional[int] = None + role_id: Optional[int] = Field(default=None, description='角色ID') + menu_id: Optional[int] = Field(default=None, description='菜单ID') class RoleDeptModel(BaseModel): @@ -65,16 +85,16 @@ class RoleDeptModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - role_id: Optional[int] = None - dept_id: Optional[int] = None + role_id: Optional[int] = Field(default=None, description='角色ID') + dept_id: Optional[int] = Field(default=None, description='部门ID') class RoleQueryModel(RoleModel): """ 角色管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -83,8 +103,8 @@ class RolePageQueryModel(RoleQueryModel): """ 角色管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class RoleMenuQueryModel(BaseModel): @@ -93,8 +113,8 @@ class RoleMenuQueryModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - menus: List = [] - checked_keys: List[int] = [] + menus: List = Field(default=[], description='菜单信息') + checked_keys: List[int] = Field(default=[], description='已选择的菜单ID信息') class RoleDeptQueryModel(BaseModel): @@ -103,17 +123,17 @@ class RoleDeptQueryModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - depts: List = [] - checked_keys: List[int] = [] + depts: List = Field(default=[], description='部门信息') + checked_keys: List[int] = Field(default=[], description='已选择的部门ID信息') class AddRoleModel(RoleModel): """ 新增角色模型 """ - dept_ids: List = [] - menu_ids: List = [] - type: Optional[str] = None + dept_ids: List = Field(default=[], description='部门ID信息') + menu_ids: List = Field(default=[], description='菜单ID信息') + type: Optional[str] = Field(default=None, description='操作类型') class DeleteRoleModel(BaseModel): @@ -122,6 +142,6 @@ class DeleteRoleModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - role_ids: str - update_by: Optional[str] = None - update_time: Optional[datetime] = None + role_ids: str = Field(description='需要删除的菜单ID') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') -- Gitee From 0fa264a7bc6677e2473ff3a8ef6a21b16cdd81df Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 09:56:49 +0800 Subject: [PATCH 033/129] =?UTF-8?q?feat&perf:=20=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98?= =?UTF-8?q?=E5=8C=96=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/user_vo.py | 163 ++++++++++-------- 1 file changed, 95 insertions(+), 68 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py index fa761ef..6c47258 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py @@ -1,12 +1,13 @@ import re -from pydantic import BaseModel, ConfigDict, model_validator +from pydantic import BaseModel, Field, ConfigDict, model_validator from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.entity.vo.role_vo import RoleModel from module_admin.entity.vo.dept_vo import DeptModel from module_admin.entity.vo.post_vo import PostModel from module_admin.annotation.pydantic_annotation import as_query, as_form +from module_admin.annotation.validate_annotation import NetWork, NotBlank, Size, Xss from exceptions.exception import ModelValidatorException @@ -14,7 +15,7 @@ class TokenData(BaseModel): """ token解析结果 """ - user_id: Union[int, None] = None + user_id: Union[int, None] = Field(default=None, description='用户ID') class UserModel(BaseModel): @@ -23,26 +24,26 @@ class UserModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - user_id: Optional[int] = None - dept_id: Optional[int] = None - user_name: Optional[str] = None - nick_name: Optional[str] = None - user_type: Optional[str] = None - email: Optional[str] = None - phonenumber: Optional[str] = None - sex: Optional[str] = None - avatar: Optional[str] = None - password: Optional[str] = None - status: Optional[str] = None - del_flag: Optional[str] = None - login_ip: Optional[str] = None - login_date: Optional[datetime] = None - create_by: Optional[str] = None - create_time: Optional[datetime] = None - update_by: Optional[str] = None - update_time: Optional[datetime] = None - remark: Optional[str] = None - admin: Optional[bool] = False + user_id: Optional[int] = Field(default=None, description='用户ID') + dept_id: Optional[int] = Field(default=None, description='部门ID') + user_name: Optional[str] = Field(default=None, description='用户账号') + nick_name: Optional[str] = Field(default=None, description='用户昵称') + user_type: Optional[str] = Field(default=None, description='用户类型(00系统用户)') + email: Optional[str] = Field(default=None, description='用户邮箱') + phonenumber: Optional[str] = Field(default=None, description='手机号码') + sex: Optional[Literal['0', '1', '2']] = Field(default=None, description='用户性别(0男 1女 2未知)') + avatar: Optional[str] = Field(default=None, description='头像地址') + password: Optional[str] = Field(default=None, description='密码') + status: Optional[Literal['0', '1']] = Field(default=None, description='帐号状态(0正常 1停用)') + del_flag: Optional[Literal['0', '2']] = Field(default=None, description='删除标志(0代表存在 2代表删除)') + login_ip: Optional[str] = Field(default=None, description='最后登录IP') + login_date: Optional[datetime] = Field(default=None, description='最后登录时间') + create_by: Optional[str] = Field(default=None, description='创建者') + create_time: Optional[datetime] = Field(default=None, description='创建时间') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') + remark: Optional[str] = Field(default=None, description='备注') + admin: Optional[bool] = Field(default=False, description='是否为admin') @model_validator(mode='after') def check_password(self) -> 'UserModel': @@ -60,6 +61,32 @@ class UserModel(BaseModel): self.admin = False return self + @Xss(field_name='user_name', message='用户账号不能包含脚本字符') + @NotBlank(field_name='user_name', message='用户账号不能为空') + @Size(field_name='user_name', min_length=0, max_length=30, message='用户账号长度不能超过30个字符') + def get_user_name(self): + return self.user_name + + @Xss(field_name='nick_name', message='用户昵称不能包含脚本字符') + @Size(field_name='nick_name', min_length=0, max_length=30, message='用户昵称长度不能超过30个字符') + def get_nick_name(self): + return self.nick_name + + @NetWork(field_name='email', field_type='EmailStr', message='邮箱格式不正确') + @Size(field_name='email', min_length=0, max_length=50, message='邮箱长度不能超过50个字符') + def get_email(self): + return self.email + + @Size(field_name='phonenumber', min_length=0, max_length=11, message='手机号码长度不能超过11个字符') + def get_phonenumber(self): + return self.phonenumber + + def validate_fields(self): + self.get_user_name() + self.get_nick_name() + self.get_email() + self.get_phonenumber() + class UserRoleModel(BaseModel): """ @@ -67,8 +94,8 @@ class UserRoleModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - user_id: Optional[int] = None - role_id: Optional[int] = None + user_id: Optional[int] = Field(default=None, description='用户ID') + role_id: Optional[int] = Field(default=None, description='角色ID') class UserPostModel(BaseModel): @@ -77,23 +104,23 @@ class UserPostModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - user_id: Optional[int] = None - post_id: Optional[int] = None + user_id: Optional[int] = Field(default=None, description='用户ID') + post_id: Optional[int] = Field(default=None, description='岗位ID') class UserInfoModel(UserModel): - post_ids: Optional[Union[str, None]] = None - role_ids: Optional[Union[str, None]] = None - dept: Optional[Union[DeptModel, None]] = None - role: Optional[List[Union[RoleModel, None]]] = [] + post_ids: Optional[Union[str, None]] = Field(default=None, description='岗位ID信息') + role_ids: Optional[Union[str, None]] = Field(default=None, description='角色ID信息') + dept: Optional[Union[DeptModel, None]] = Field(default=None, description='部门信息') + role: Optional[List[Union[RoleModel, None]]] = Field(default=[], description='角色信息') class CurrentUserModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - permissions: List - roles: List - user: Union[UserInfoModel, None] + permissions: List = Field(description='权限信息') + roles: List = Field(description='角色信息') + user: Union[UserInfoModel, None] = Field(description='用户信息') class UserDetailModel(BaseModel): @@ -102,11 +129,11 @@ class UserDetailModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - data: Optional[Union[UserInfoModel, None]] = None - post_ids: Optional[List] = None - posts: List[Union[PostModel, None]] - role_ids: Optional[List] = None - roles: List[Union[RoleModel, None]] + data: Optional[Union[UserInfoModel, None]] = Field(default=None, description='用户信息') + post_ids: Optional[List] = Field(default=None, description='岗位ID信息') + posts: List[Union[PostModel, None]] = Field(description='岗位信息') + role_ids: Optional[List] = Field(default=None, description='角色ID信息') + roles: List[Union[RoleModel, None]] = Field(description='角色信息') class UserProfileModel(BaseModel): @@ -115,17 +142,17 @@ class UserProfileModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - data: Union[UserInfoModel, None] - post_group: Union[str, None] - role_group: Union[str, None] + data: Union[UserInfoModel, None] = Field(description='用户信息') + post_group: Union[str, None] = Field(description='岗位信息') + role_group: Union[str, None] = Field(description='角色信息') class UserQueryModel(UserModel): """ 用户管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -134,24 +161,24 @@ class UserPageQueryModel(UserQueryModel): """ 用户管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class AddUserModel(UserModel): """ 新增用户模型 """ - role_ids: Optional[List] = [] - post_ids: Optional[List] = [] - type: Optional[str] = None + role_ids: Optional[List] = Field(default=[], description='角色ID信息') + post_ids: Optional[List] = Field(default=[], description='岗位ID信息') + type: Optional[str] = Field(default=None, description='操作类型') class EditUserModel(AddUserModel): """ 编辑用户模型 """ - role: Optional[List] = [] + role: Optional[List] = Field(default=[], description='角色信息') @as_query @@ -161,8 +188,8 @@ class ResetPasswordModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - old_password: Optional[str] = None - new_password: Optional[str] = None + old_password: Optional[str] = Field(default=None, description='旧密码') + new_password: Optional[str] = Field(default=None, description='新密码') @model_validator(mode='after') def check_new_password(self) -> 'ResetPasswordModel': @@ -177,9 +204,9 @@ class ResetUserModel(UserModel): """ 重置用户密码模型 """ - old_password: Optional[str] = None - sms_code: Optional[str] = None - session_id: Optional[str] = None + old_password: Optional[str] = Field(default=None, description='旧密码') + sms_code: Optional[str] = Field(default=None, description='验证码') + session_id: Optional[str] = Field(default=None, description='会话id') class DeleteUserModel(BaseModel): @@ -188,16 +215,16 @@ class DeleteUserModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - user_ids: str - update_by: Optional[str] = None - update_time: Optional[datetime] = None + user_ids: str = Field(description='需要删除的用户ID') + update_by: Optional[str] = Field(default=None, description='更新者') + update_time: Optional[datetime] = Field(default=None, description='更新时间') class UserRoleQueryModel(UserModel): """ 用户角色关联管理不分页查询模型 """ - role_id: Optional[int] = None + role_id: Optional[int] = Field(default=None, description='角色ID') @as_query @@ -205,15 +232,15 @@ class UserRolePageQueryModel(UserRoleQueryModel): """ 用户角色关联管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class SelectedRoleModel(RoleModel): """ 是否选择角色模型 """ - flag: Optional[bool] = False + flag: Optional[bool] = Field(default=False, description='选择标识') class UserRoleResponseModel(BaseModel): @@ -222,8 +249,8 @@ class UserRoleResponseModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - roles: List[Union[SelectedRoleModel, None]] = [] - user: UserInfoModel + roles: List[Union[SelectedRoleModel, None]] = Field(default=[], description='角色信息') + user: UserInfoModel = Field(description='用户信息') @as_query @@ -233,7 +260,7 @@ class CrudUserRoleModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - user_id: Optional[int] = None - user_ids: Optional[str] = None - role_id: Optional[int] = None - role_ids: Optional[str] = None + user_id: Optional[int] = Field(default=None, description='用户ID') + user_ids: Optional[str] = Field(default=None, description='用户ID信息') + role_id: Optional[int] = Field(default=None, description='角色ID') + role_ids: Optional[str] = Field(default=None, description='角色ID信息') -- Gitee From a12713f89a32caf20c7541be29efad33d79a392a Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 11:07:06 +0800 Subject: [PATCH 034/129] =?UTF-8?q?perf:=20=E7=BC=93=E5=AD=98=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/cache_vo.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py index f2fc9ff..8fa1231 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from typing import Optional, List, Any @@ -9,9 +9,9 @@ class CacheMonitorModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - command_stats: Optional[List] = [] - db_size: Optional[int] = None - info: Optional[dict] = {} + command_stats: Optional[List] = Field(default=[], description='命令统计') + db_size: Optional[int] = Field(default=None, description='Key数量') + info: Optional[dict] = Field(default={}, description='Redis信息') class CacheInfoModel(BaseModel): @@ -20,7 +20,7 @@ class CacheInfoModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - cache_key: Optional[str] = None - cache_name: Optional[str] = None - cache_value: Optional[Any] = None - remark: Optional[str] = None + cache_key: Optional[str] = Field(default=None, description='缓存键名') + cache_name: Optional[str] = Field(default=None, description='缓存名称') + cache_value: Optional[Any] = Field(default=None, description='缓存内容') + remark: Optional[str] = Field(default=None, description='备注') -- Gitee From b7260a40adad5b9d086c2d3ccc7a8373dcb3d1be Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 11:07:22 +0800 Subject: [PATCH 035/129] =?UTF-8?q?perf:=20=E9=80=9A=E7=94=A8=E6=A8=A1?= =?UTF-8?q?=E5=9D=97vo=E5=B1=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/common_vo.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py index 64e929e..b99534e 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from typing import Optional, Any @@ -7,9 +7,9 @@ class CrudResponseModel(BaseModel): """ 操作响应模型 """ - is_success: bool - message: str - result: Optional[Any] = None + is_success: bool = Field(description='操作是否成功') + message: str = Field(description='响应信息') + result: Optional[Any] = Field(default=None, description='响应结果') class UploadResponseModel(BaseModel): @@ -18,7 +18,7 @@ class UploadResponseModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - file_name: Optional[str] = None - new_file_name: Optional[str] = None - original_filename: Optional[str] = None - url: Optional[str] = None + file_name: Optional[str] = Field(default=None, description='新文件映射路径') + new_file_name: Optional[str] = Field(default=None, description='新文件名称') + original_filename: Optional[str] = Field(default=None, description='原文件名称') + url: Optional[str] = Field(default=None, description='新文件url') -- Gitee From fffff50a006fe30418ff12201000dee3a0a226c6 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 11:07:33 +0800 Subject: [PATCH 036/129] =?UTF-8?q?perf:=20=E7=99=BB=E5=BD=95=E6=A8=A1?= =?UTF-8?q?=E5=9D=97vo=E5=B1=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/login_vo.py | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py index 76bb7b8..c3ee684 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py @@ -1,5 +1,5 @@ import re -from pydantic import BaseModel, ConfigDict, model_validator +from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel from typing import Optional, List, Union from exceptions.exception import ModelValidatorException @@ -9,22 +9,22 @@ from module_admin.entity.vo.menu_vo import MenuModel class UserLogin(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - user_name: str - password: str - code: Optional[str] = None - uuid: Optional[str] = None - login_info: Optional[dict] = None - captcha_enabled: Optional[bool] = None + user_name: str = Field(description='用户名称') + password: str = Field(description='用户密码') + code: Optional[str] = Field(default=None, description='验证码') + uuid: Optional[str] = Field(default=None, description='会话编号') + login_info: Optional[dict] = Field(default=None, description='登录信息,前端无需传递') + captcha_enabled: Optional[bool] = Field(default=None, description='是否启用验证码,前端无需传递') class UserRegister(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - username: str - password: str - confirm_password: str - code: Optional[str] = None - uuid: Optional[str] = None + username: str = Field(description='用户名称') + password: str = Field(description='用户密码') + confirm_password: str = Field(description='用户二次确认密码') + code: Optional[str] = Field(default=None, description='验证码') + uuid: Optional[str] = Field(default=None, description='会话编号') @model_validator(mode='after') def check_password(self) -> 'UserRegister': @@ -36,48 +36,48 @@ class UserRegister(BaseModel): class Token(BaseModel): - access_token: str - token_type: str + access_token: str = Field(description='token信息') + token_type: str = Field(description='token类型') class CaptchaCode(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - captcha_enabled: bool - register_enabled: bool - img: str - uuid: str + captcha_enabled: bool = Field(description='是否启用验证码') + register_enabled: bool = Field(description='是否启用注册') + img: str = Field(description='验证码图片') + uuid: str = Field(description='会话编号') class SmsCode(BaseModel): - is_success: Optional[bool] = None - sms_code: str - session_id: str - message: Optional[str] = None + is_success: Optional[bool] = Field(default=None, description='操作是否成功') + sms_code: str = Field(description='短信验证码') + session_id: str = Field(description='会话编号') + message: Optional[str] = Field(default=None, description='响应信息') class MenuTreeModel(MenuModel): - children: Optional[Union[List['MenuTreeModel'], None]] = None + children: Optional[Union[List['MenuTreeModel'], None]] = Field(default=None, description='子菜单') class MetaModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - title: Optional[str] = None - icon: Optional[str] = None - no_cache: Optional[bool] = None - link: Optional[str] = None + title: Optional[str] = Field(default=None, description='设置路由在侧边栏和面包屑中展示的名字') + icon: Optional[str] = Field(default=None, description='设置路由的图标') + no_cache: Optional[bool] = Field(default=None, description='设置为true,则不会被 缓存') + link: Optional[str] = Field(default=None, description='内链地址(http(s)://开头)') class RouterModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - name: Optional[str] = None - path: Optional[str] = None - hidden: Optional[bool] = None - redirect: Optional[str] = None - component: Optional[str] = None - query: Optional[str] = None - always_show: Optional[bool] = None - meta: Optional[MetaModel] = None - children: Optional[Union[List['RouterModel'], None]] = None + name: Optional[str] = Field(default=None, description='路由名称') + path: Optional[str] = Field(default=None, description='路由地址') + hidden: Optional[bool] = Field(default=None, description='是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现') + redirect: Optional[str] = Field(default=None, description='重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击') + component: Optional[str] = Field(default=None, description='组件地址') + query: Optional[str] = Field(default=None, description='路由参数:如 {"id": 1, "name": "ry"}') + always_show: Optional[bool] = Field(default=None, description='当你一个路由下面的children声明的路由大于1个时,自动会变成嵌套的模式--如组件页面') + meta: Optional[MetaModel] = Field(default=None, description='其他元素') + children: Optional[Union[List['RouterModel'], None]] = Field(default=None, description='子路由') -- Gitee From 68906b7e816dd82784bc9bad9bde2c0937cad773 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 11:07:55 +0800 Subject: [PATCH 037/129] =?UTF-8?q?perf:=20=E5=9C=A8=E7=BA=BF=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=9B=91=E6=8E=A7=E6=A8=A1=E5=9D=97vo=E5=B1=82?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/online_vo.py | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py index 616fd2a..663a7a6 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from typing import Union, Optional, List from datetime import datetime @@ -11,14 +11,14 @@ class OnlineModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - token_id: Optional[str] = None - user_name: Optional[str] = None - dept_name: Optional[str] = None - ipaddr: Optional[str] = None - login_location: Optional[str] = None - browser: Optional[str] = None - os: Optional[str] = None - login_time: Optional[datetime] = None + token_id: Optional[str] = Field(default=None, description='会话编号') + user_name: Optional[str] = Field(default=None, description='部门名称') + dept_name: Optional[str] = Field(default=None, description='用户名称') + ipaddr: Optional[str] = Field(default=None, description='登录IP地址') + login_location: Optional[str] = Field(default=None, description='登录地址') + browser: Optional[str] = Field(default=None, description='浏览器类型') + os: Optional[str] = Field(default=None, description='操作系统') + login_time: Optional[datetime] = Field(default=None, description='登录时间') @as_query @@ -26,8 +26,8 @@ class OnlineQueryModel(OnlineModel): """ 岗位管理不分页查询模型 """ - begin_time: Optional[str] = None - end_time: Optional[str] = None + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') class DeleteOnlineModel(BaseModel): @@ -36,4 +36,4 @@ class DeleteOnlineModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - token_ids: str + token_ids: str = Field(description='需要强退的会话编号') -- Gitee From f8c246796d52577be6c2523eb8f1c848a5ce0ef7 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 11:19:31 +0800 Subject: [PATCH 038/129] =?UTF-8?q?perf:=20=E6=9C=8D=E5=8A=A1=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/server_vo.py | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/server_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/server_vo.py index 4323ddf..f7693be 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/server_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/server_vo.py @@ -1,4 +1,4 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from typing import Optional, List @@ -6,51 +6,51 @@ from typing import Optional, List class CpuInfo(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - cpu_num: Optional[int] = None - used: Optional[float] = None - sys: Optional[float] = None - free: Optional[float] = None + cpu_num: Optional[int] = Field(default=None, description='核心数') + used: Optional[float] = Field(default=None, description='CPU用户使用率') + sys: Optional[float] = Field(default=None, description='CPU系统使用率') + free: Optional[float] = Field(default=None, description='CPU当前空闲率') class MemoryInfo(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - total: Optional[str] = None - used: Optional[str] = None - free: Optional[str] = None - usage: Optional[float] = None + total: Optional[str] = Field(default=None, description='内存总量') + used: Optional[str] = Field(default=None, description='已用内存') + free: Optional[str] = Field(default=None, description='剩余内存') + usage: Optional[float] = Field(default=None, description='使用率') class SysInfo(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - computer_ip: Optional[str] = None - computer_name: Optional[str] = None - os_arch: Optional[str] = None - os_name: Optional[str] = None - user_dir: Optional[str] = None + computer_ip: Optional[str] = Field(default=None, description='服务器IP') + computer_name: Optional[str] = Field(default=None, description='服务器名称') + os_arch: Optional[str] = Field(default=None, description='系统架构') + os_name: Optional[str] = Field(default=None, description='操作系统') + user_dir: Optional[str] = Field(default=None, description='项目路径') class PyInfo(MemoryInfo): model_config = ConfigDict(alias_generator=to_camel) - name: Optional[str] = None - version: Optional[str] = None - start_time: Optional[str] = None - run_time: Optional[str] = None - home: Optional[str] = None + name: Optional[str] = Field(default=None, description='Python名称') + version: Optional[str] = Field(default=None, description='Python版本') + start_time: Optional[str] = Field(default=None, description='启动时间') + run_time: Optional[str] = Field(default=None, description='运行时长') + home: Optional[str] = Field(default=None, description='安装路径') class SysFiles(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - dir_name: Optional[str] = None - sys_type_name: Optional[str] = None - type_name: Optional[str] = None - total: Optional[str] = None - used: Optional[str] = None - free: Optional[str] = None - usage: Optional[str] = None + dir_name: Optional[str] = Field(default=None, description='盘符路径') + sys_type_name: Optional[str] = Field(default=None, description='盘符类型') + type_name: Optional[str] = Field(default=None, description='文件类型') + total: Optional[str] = Field(default=None, description='总大小') + used: Optional[str] = Field(default=None, description='已经使用量') + free: Optional[str] = Field(default=None, description='剩余大小') + usage: Optional[str] = Field(default=None, description='资源的使用率') class ServerMonitorModel(BaseModel): @@ -59,8 +59,8 @@ class ServerMonitorModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - cpu: Optional[CpuInfo] - py: Optional[PyInfo] - mem: Optional[MemoryInfo] - sys: Optional[SysInfo] - sys_files: Optional[List[SysFiles]] + cpu: Optional[CpuInfo] = Field(description='CPU相关信息') + py: Optional[PyInfo] = Field(description='Python相关信息') + mem: Optional[MemoryInfo] = Field(description='內存相关信息') + sys: Optional[SysInfo] = Field(description='服务器相关信息') + sys_files: Optional[List[SysFiles]] = Field(description='磁盘相关信息') -- Gitee From 9f09d379366b9d396c1ce5f56f913bc1eb4ab133 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 11:43:52 +0800 Subject: [PATCH 039/129] =?UTF-8?q?perf:=20=E6=97=A5=E5=BF=97=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97vo=E5=B1=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/entity/vo/log_vo.py | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py index 604bb5d..0d47af9 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py @@ -1,6 +1,6 @@ -from pydantic import BaseModel, ConfigDict +from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List +from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form @@ -11,23 +11,23 @@ class OperLogModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - oper_id: Optional[int] = None - title: Optional[str] = None - business_type: Optional[int] = None - method: Optional[str] = None - request_method: Optional[str] = None - operator_type: Optional[int] = None - oper_name: Optional[str] = None - dept_name: Optional[str] = None - oper_url: Optional[str] = None - oper_ip: Optional[str] = None - oper_location: Optional[str] = None - oper_param: Optional[str] = None - json_result: Optional[str] = None - status: Optional[int] = None - error_msg: Optional[str] = None - oper_time: Optional[datetime] = None - cost_time: Optional[int] = None + oper_id: Optional[int] = Field(default=None, description='日志主键') + title: Optional[str] = Field(default=None, description='模块标题') + business_type: Optional[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']] = Field(default=None, description='业务类型(0其它 1新增 2修改 3删除 4授权 5导出 6导入 7强退 8生成代码 9清空数据)') + method: Optional[str] = Field(default=None, description='方法名称') + request_method: Optional[str] = Field(default=None, description='请求方式') + operator_type: Optional[Literal[0, 1, 2]] = Field(default=None, description='操作类别(0其它 1后台用户 2手机端用户)') + oper_name: Optional[str] = Field(default=None, description='操作人员') + dept_name: Optional[str] = Field(default=None, description='部门名称') + oper_url: Optional[str] = Field(default=None, description='请求URL') + oper_ip: Optional[str] = Field(default=None, description='主机地址') + oper_location: Optional[str] = Field(default=None, description='操作地点') + oper_param: Optional[str] = Field(default=None, description='请求参数') + json_result: Optional[str] = Field(default=None, description='返回参数') + status: Optional[Literal[0, 1, '0', '1']] = Field(default=None, description='操作状态(0正常 1异常)') + error_msg: Optional[str] = Field(default=None, description='错误消息') + oper_time: Optional[datetime] = Field(default=None, description='操作时间') + cost_time: Optional[int] = Field(default=None, description='消耗时间') class LogininforModel(BaseModel): @@ -36,25 +36,25 @@ class LogininforModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) - info_id: Optional[int] = None - user_name: Optional[str] = None - ipaddr: Optional[str] = None - login_location: Optional[str] = None - browser: Optional[str] = None - os: Optional[str] = None - status: Optional[str] = None - msg: Optional[str] = None - login_time: Optional[datetime] = None + info_id: Optional[int] = Field(default=None, description='访问ID') + user_name: Optional[str] = Field(default=None, description='用户账号') + ipaddr: Optional[str] = Field(default=None, description='登录IP地址') + login_location: Optional[str] = Field(default=None, description='登录地点') + browser: Optional[str] = Field(default=None, description='浏览器类型') + os: Optional[str] = Field(default=None, description='操作系统') + status: Optional[Literal['0', '1']] = Field(default=None, description='登录状态(0成功 1失败)') + msg: Optional[str] = Field(default=None, description='提示消息') + login_time: Optional[datetime] = Field(default=None, description='访问时间') class OperLogQueryModel(OperLogModel): """ 操作日志管理不分页查询模型 """ - order_by_column: Optional[str] = None - is_asc: Optional[str] = None - begin_time: Optional[str] = None - end_time: Optional[str] = None + order_by_column: Optional[str] = Field(default=None, description='排序的字段名称') + is_asc: Optional[Literal['ascending', 'descending']] = Field(default=None, description='排序方式(ascending升序 descending降序)') + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @as_query @@ -63,8 +63,8 @@ class OperLogPageQueryModel(OperLogQueryModel): """ 操作日志管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class DeleteOperLogModel(BaseModel): @@ -73,17 +73,17 @@ class DeleteOperLogModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - oper_ids: str + oper_ids: str = Field(description='需要删除的日志主键') class LoginLogQueryModel(LogininforModel): """ 登录日志管理不分页查询模型 """ - order_by_column: Optional[str] = None - is_asc: Optional[str] = None - begin_time: Optional[str] = None - end_time: Optional[str] = None + order_by_column: Optional[str] = Field(default=None, description='排序的字段名称') + is_asc: Optional[Literal['ascending', 'descending']] = Field(default=None, description='排序方式(ascending升序 descending降序)') + begin_time: Optional[str] = Field(default=None, description='开始时间') + end_time: Optional[str] = Field(default=None, description='结束时间') @@ -93,8 +93,8 @@ class LoginLogPageQueryModel(LoginLogQueryModel): """ 登录日志管理分页查询模型 """ - page_num: int = 1 - page_size: int = 10 + page_num: int = Field(default=1, description='当前页码') + page_size: int = Field(default=10, description='每页记录数') class DeleteLoginLogModel(BaseModel): @@ -103,7 +103,7 @@ class DeleteLoginLogModel(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - info_ids: str + info_ids: str = Field(description='需要删除的访问ID') class UnlockUser(BaseModel): @@ -112,4 +112,4 @@ class UnlockUser(BaseModel): """ model_config = ConfigDict(alias_generator=to_camel) - user_name: str + user_name: str = Field(description='用户名称') -- Gitee From ffc932951bd26f95b141a91de906aafd22381aef Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:50:36 +0800 Subject: [PATCH 040/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96validate=5Fan?= =?UTF-8?q?notation=E4=B8=AD=E5=90=84=E8=A3=85=E9=A5=B0=E5=99=A8=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../annotation/validate_annotation.py | 99 ++++++++++--------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py index 32744f0..aeb4ff7 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py @@ -72,7 +72,7 @@ class ValidateFields: async def wrapper(*args, **kwargs): validate_model = kwargs.get(self.validate_model) if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.validate_function): - validate_function = getattr(validate_model, self.validate_function, None) + validate_function = getattr(validate_model, self.validate_function) if validate_function is not None and callable(validate_function): validate_function() return await func(*args, **kwargs) @@ -107,51 +107,52 @@ class NetWork: @wraps(func) def wrapper(*args, **kwargs): validate_model = args[0] - if isinstance(validate_model, BaseModel): + if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): field_value = getattr(validate_model, self.field_name) - try: - if self.field_type == 'AnyUrl': - NetWorkAnnotationModel(any_url=field_value) - elif self.field_type == 'AnyHttpUrl': - NetWorkAnnotationModel(any_http_url=field_value) - elif self.field_type == 'HttpUrl': - NetWorkAnnotationModel(http_url=field_value) - elif self.field_type == 'AnyWebsocketUrl': - NetWorkAnnotationModel(any_websocket_url=field_value) - elif self.field_type == 'WebsocketUrl': - NetWorkAnnotationModel(websocket_url=field_value) - elif self.field_type == 'FileUrl': - NetWorkAnnotationModel(file_url=field_value) - elif self.field_type == 'FtpUrl': - NetWorkAnnotationModel(ftp_url=field_value) - elif self.field_type == 'PostgresDsn': - NetWorkAnnotationModel(postgres_dsn=field_value) - elif self.field_type == 'CockroachDsn': - NetWorkAnnotationModel(cockroach_dsn=field_value) - elif self.field_type == 'AmqpDsn': - NetWorkAnnotationModel(amqp_dsn=field_value) - elif self.field_type == 'RedisDsn': - NetWorkAnnotationModel(redis_dsn=field_value) - elif self.field_type == 'MongoDsn': - NetWorkAnnotationModel(mongo_dsn=field_value) - elif self.field_type == 'KafkaDsn': - NetWorkAnnotationModel(kafka_dsn=field_value) - elif self.field_type == 'NatsDsn': - NetWorkAnnotationModel(nats_dsn=field_value) - elif self.field_type == 'MySQLDsn': - NetWorkAnnotationModel(mysql_dsn=field_value) - elif self.field_type == 'MariaDBDsn': - NetWorkAnnotationModel(mariadb_dsn=field_value) - elif self.field_type == 'ClickHouseDsn': - NetWorkAnnotationModel(clickhouse_dsn=field_value) - elif self.field_type == 'EmailStr': - NetWorkAnnotationModel(email_str=field_value) - elif self.field_type == 'NameEmail': - NetWorkAnnotationModel(name_email=field_value) - elif self.field_type == 'IPvAnyAddress': - NetWorkAnnotationModel(ipv_any_address=field_value) - except (ValidationError, ValueError): - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不是正确的{self.field_type}类型') + if field_value: + try: + if self.field_type == 'AnyUrl': + NetWorkAnnotationModel(any_url=field_value) + elif self.field_type == 'AnyHttpUrl': + NetWorkAnnotationModel(any_http_url=field_value) + elif self.field_type == 'HttpUrl': + NetWorkAnnotationModel(http_url=field_value) + elif self.field_type == 'AnyWebsocketUrl': + NetWorkAnnotationModel(any_websocket_url=field_value) + elif self.field_type == 'WebsocketUrl': + NetWorkAnnotationModel(websocket_url=field_value) + elif self.field_type == 'FileUrl': + NetWorkAnnotationModel(file_url=field_value) + elif self.field_type == 'FtpUrl': + NetWorkAnnotationModel(ftp_url=field_value) + elif self.field_type == 'PostgresDsn': + NetWorkAnnotationModel(postgres_dsn=field_value) + elif self.field_type == 'CockroachDsn': + NetWorkAnnotationModel(cockroach_dsn=field_value) + elif self.field_type == 'AmqpDsn': + NetWorkAnnotationModel(amqp_dsn=field_value) + elif self.field_type == 'RedisDsn': + NetWorkAnnotationModel(redis_dsn=field_value) + elif self.field_type == 'MongoDsn': + NetWorkAnnotationModel(mongo_dsn=field_value) + elif self.field_type == 'KafkaDsn': + NetWorkAnnotationModel(kafka_dsn=field_value) + elif self.field_type == 'NatsDsn': + NetWorkAnnotationModel(nats_dsn=field_value) + elif self.field_type == 'MySQLDsn': + NetWorkAnnotationModel(mysql_dsn=field_value) + elif self.field_type == 'MariaDBDsn': + NetWorkAnnotationModel(mariadb_dsn=field_value) + elif self.field_type == 'ClickHouseDsn': + NetWorkAnnotationModel(clickhouse_dsn=field_value) + elif self.field_type == 'EmailStr': + NetWorkAnnotationModel(email_str=field_value) + elif self.field_type == 'NameEmail': + NetWorkAnnotationModel(name_email=field_value) + elif self.field_type == 'IPvAnyAddress': + NetWorkAnnotationModel(ipv_any_address=field_value) + except (ValidationError, ValueError): + raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不是正确的{self.field_type}类型') return func(*args, **kwargs) return wrapper @@ -174,7 +175,7 @@ class NotBlank: @wraps(func) def wrapper(*args, **kwargs): validate_model = args[0] - if isinstance(validate_model, BaseModel): + if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): field_value = getattr(validate_model, self.field_name) if field_value is None or field_value == '' or field_value == [] or field_value == () or field_value == {}: raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不能为空') @@ -202,7 +203,7 @@ class Pattern: @wraps(func) def wrapper(*args, **kwargs): validate_model = args[0] - if isinstance(validate_model, BaseModel): + if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): field_value = getattr(validate_model, self.field_name) if isinstance(field_value, str) and not re.match(self.regexp, field_value): raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}格式不正确') @@ -242,7 +243,7 @@ class Size: @wraps(func) def wrapper(*args, **kwargs): validate_model = args[0] - if isinstance(validate_model, BaseModel): + if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): field_value = getattr(validate_model, self.field_name) if isinstance(field_value, float): if self.gt is not None and field_value <= self.gt: @@ -282,7 +283,7 @@ class Xss: @wraps(func) def wrapper(*args, **kwargs): validate_model = args[0] - if isinstance(validate_model, BaseModel): + if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): field_value = getattr(validate_model, self.field_name) if not StringUtil.is_blank(field_value): pattern = re.compile(self.HTML_PATTERN) -- Gitee From 1f0f35b402689cae84734c138e0406079236d97b Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:51:34 +0800 Subject: [PATCH 041/129] =?UTF-8?q?feat:=20=E5=8F=82=E6=95=B0=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E=E5=92=8C=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/config_controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py index f08dd71..ba7f63c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py @@ -5,6 +5,7 @@ from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.config_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * @@ -28,6 +29,7 @@ async def get_system_config_list(request: Request, config_page_query: ConfigPage @configController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))]) +@ValidateFields(validate_model='add_config') @log_decorator(title='参数管理', business_type=BusinessType.INSERT) async def add_system_config(request: Request, add_config: ConfigModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -48,6 +50,7 @@ async def add_system_config(request: Request, add_config: ConfigModel, query_db: @configController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))]) +@ValidateFields(validate_model='edit_config') @log_decorator(title='参数管理', business_type=BusinessType.UPDATE) async def edit_system_config(request: Request, edit_config: ConfigModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: -- Gitee From 841fbd1ae11121a74925d5ccb9eabf6c9048feb8 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:51:41 +0800 Subject: [PATCH 042/129] =?UTF-8?q?feat:=20=E9=83=A8=E9=97=A8=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E=E5=92=8C=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/dept_controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py index ccfdd64..74e4196 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py @@ -6,6 +6,7 @@ from module_admin.service.dept_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * @@ -38,6 +39,7 @@ async def get_system_dept_list(request: Request, dept_query: DeptQueryModel = De @deptController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) +@ValidateFields(validate_model='add_dept') @log_decorator(title='部门管理', business_type=BusinessType.INSERT) async def add_system_dept(request: Request, add_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -58,6 +60,7 @@ async def add_system_dept(request: Request, add_dept: DeptModel, query_db: Async @deptController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) +@ValidateFields(validate_model='edit_dept') @log_decorator(title='部门管理', business_type=BusinessType.UPDATE) async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: -- Gitee From d5cd7d1ae47852283e0cbb5dca28a50aecf679f2 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:51:50 +0800 Subject: [PATCH 043/129] =?UTF-8?q?feat:=20=E5=AD=97=E5=85=B8=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E=E5=92=8C=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/dict_controller.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py index c999a91..fdfdacb 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py @@ -5,6 +5,7 @@ from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.dict_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * @@ -28,6 +29,7 @@ async def get_system_dict_type_list(request: Request, dict_type_page_query: Dict @dictController.post("/type", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) +@ValidateFields(validate_model='add_dict_type') @log_decorator(title='字典管理', business_type=BusinessType.INSERT) async def add_system_dict_type(request: Request, add_dict_type: DictTypeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -48,6 +50,7 @@ async def add_system_dict_type(request: Request, add_dict_type: DictTypeModel, q @dictController.put("/type", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) +@ValidateFields(validate_model='edit_dict_type') @log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def edit_system_dict_type(request: Request, edit_dict_type: DictTypeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -159,6 +162,7 @@ async def get_system_dict_data_list(request: Request, dict_data_page_query: Dict @dictController.post("/data", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) +@ValidateFields(validate_model='add_dict_data') @log_decorator(title='字典管理', business_type=BusinessType.INSERT) async def add_system_dict_data(request: Request, add_dict_data: DictDataModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -179,6 +183,7 @@ async def add_system_dict_data(request: Request, add_dict_data: DictDataModel, q @dictController.put("/data", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) +@ValidateFields(validate_model='edit_dict_data') @log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def edit_system_dict_data(request: Request, edit_dict_data: DictDataModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: -- Gitee From d12c1c31f34da082f4664b9575fdc65488f80c4a Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:52:00 +0800 Subject: [PATCH 044/129] =?UTF-8?q?feat:=20=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=92=8C=E7=BC=96=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/job_controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py index 1739b67..487f6f9 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py @@ -6,6 +6,7 @@ from module_admin.service.job_service import * from module_admin.service.job_log_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * @@ -29,6 +30,7 @@ async def get_system_job_list(request: Request, job_page_query: JobPageQueryMode @jobController.post("/job", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))]) +@ValidateFields(validate_model='add_job') @log_decorator(title='定时任务管理', business_type=BusinessType.INSERT) async def add_system_job(request: Request, add_job: JobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -49,6 +51,7 @@ async def add_system_job(request: Request, add_job: JobModel, query_db: AsyncSes @jobController.put("/job", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))]) +@ValidateFields(validate_model='edit_job') @log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: -- Gitee From ddfe7c8851ae62970c53f0eb568230c11787e2f2 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:52:09 +0800 Subject: [PATCH 045/129] =?UTF-8?q?feat:=20=E8=8F=9C=E5=8D=95=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E=E5=92=8C=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/menu_controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py index e50eebe..59b7bcf 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py @@ -5,6 +5,7 @@ from module_admin.service.login_service import LoginService from module_admin.service.menu_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * @@ -47,6 +48,7 @@ async def get_system_menu_list(request: Request, menu_query: MenuQueryModel = De @menuController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) +@ValidateFields(validate_model='add_menu') @log_decorator(title='菜单管理', business_type=BusinessType.INSERT) async def add_system_menu(request: Request, add_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -67,6 +69,7 @@ async def add_system_menu(request: Request, add_menu: MenuModel, query_db: Async @menuController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) +@ValidateFields(validate_model='edit_menu') @log_decorator(title='菜单管理', business_type=BusinessType.UPDATE) async def edit_system_menu(request: Request, edit_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: -- Gitee From bfac3ff26e8cd1f454252ab6f904b011a35a777f Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:52:18 +0800 Subject: [PATCH 046/129] =?UTF-8?q?feat:=20=E9=80=9A=E7=9F=A5=E5=85=AC?= =?UTF-8?q?=E5=91=8A=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=92=8C=E7=BC=96=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/notice_controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py index 1b86daa..5844891 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py @@ -5,6 +5,7 @@ from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.notice_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * @@ -27,6 +28,7 @@ async def get_system_notice_list(request: Request, notice_page_query: NoticePage @noticeController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))]) +@ValidateFields(validate_model='add_notice') @log_decorator(title='通知公告管理', business_type=BusinessType.INSERT) async def add_system_notice(request: Request, add_notice: NoticeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -47,6 +49,7 @@ async def add_system_notice(request: Request, add_notice: NoticeModel, query_db: @noticeController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))]) +@ValidateFields(validate_model='edit_notice') @log_decorator(title='通知公告管理', business_type=BusinessType.UPDATE) async def edit_system_notice(request: Request, edit_notice: NoticeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: -- Gitee From 568ed2b9d785ce2e760b1763b5437f3662e040f6 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:52:26 +0800 Subject: [PATCH 047/129] =?UTF-8?q?feat:=20=E8=A7=92=E8=89=B2=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E=E5=92=8C=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/role_controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index a20b25c..7251339 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -8,6 +8,7 @@ from module_admin.service.user_service import UserService, UserRoleQueryModel, U from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * @@ -43,6 +44,7 @@ async def get_system_role_list(request: Request, role_page_query: RolePageQueryM @roleController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))]) +@ValidateFields(validate_model='add_role') @log_decorator(title='角色管理', business_type=BusinessType.INSERT) async def add_system_role(request: Request, add_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -63,6 +65,7 @@ async def add_system_role(request: Request, add_role: AddRoleModel, query_db: As @roleController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@ValidateFields(validate_model='edit_role') @log_decorator(title='角色管理', business_type=BusinessType.UPDATE) async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: -- Gitee From d500e22b2f37bf573cc62eada33ed3ac1646f435 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Jul 2024 12:52:41 +0800 Subject: [PATCH 048/129] =?UTF-8?q?feat:=20=E7=94=A8=E6=88=B7=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97=E6=96=B0=E5=A2=9E=E5=92=8C=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E6=8E=A5=E5=8F=A3=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/user_controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index 96f1a2f..f06daa9 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -8,6 +8,7 @@ from module_admin.service.dept_service import DeptService from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.page_util import PageResponseModel from utils.response_util import * @@ -43,6 +44,7 @@ async def get_system_user_list(request: Request, user_page_query: UserPageQueryM @userController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) +@ValidateFields(validate_model='add_user') @log_decorator(title='用户管理', business_type=BusinessType.INSERT) async def add_system_user(request: Request, add_user: AddUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: @@ -64,6 +66,7 @@ async def add_system_user(request: Request, add_user: AddUserModel, query_db: As @userController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) +@ValidateFields(validate_model='edit_user') @log_decorator(title='用户管理', business_type=BusinessType.UPDATE) async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): try: -- Gitee From 19f34d6a81b16c59c8b77dfc2517280132f17d3f Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sun, 7 Jul 2024 09:09:19 +0800 Subject: [PATCH 049/129] =?UTF-8?q?chore:=20=E5=B0=86validate=5Fannotation?= =?UTF-8?q?=E5=B0=81=E8=A3=85=E4=B8=BApydantic-validation-decorator?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/handle.py | 9 +- .../annotation/validate_annotation.py | 293 ------------------ .../controller/config_controller.py | 2 +- .../controller/dept_controller.py | 2 +- .../controller/dict_controller.py | 2 +- .../module_admin/controller/job_controller.py | 2 +- .../controller/menu_controller.py | 2 +- .../controller/notice_controller.py | 2 +- .../module_admin/controller/post_controler.py | 2 +- .../controller/role_controller.py | 2 +- .../controller/user_controller.py | 2 +- .../module_admin/entity/vo/config_vo.py | 2 +- .../module_admin/entity/vo/dept_vo.py | 4 +- .../module_admin/entity/vo/dict_vo.py | 2 +- .../module_admin/entity/vo/job_vo.py | 2 +- .../module_admin/entity/vo/menu_vo.py | 2 +- .../module_admin/entity/vo/notice_vo.py | 2 +- .../module_admin/entity/vo/post_vo.py | 2 +- .../module_admin/entity/vo/role_vo.py | 2 +- .../module_admin/entity/vo/user_vo.py | 4 +- ruoyi-fastapi-backend/requirements.txt | 1 + 21 files changed, 26 insertions(+), 317 deletions(-) delete mode 100644 ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index accd51e..c5447fe 100644 --- a/ruoyi-fastapi-backend/exceptions/handle.py +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -1,6 +1,7 @@ from fastapi import FastAPI, Request from fastapi.exceptions import HTTPException -from exceptions.exception import AuthException, PermissionException, ModelValidatorException, FieldValidatorException +from pydantic_validation_decorator import FieldValidationError +from exceptions.exception import AuthException, PermissionException, ModelValidatorException from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder @@ -24,9 +25,9 @@ def handle_exception(app: FastAPI): return ResponseUtil.failure(data=exc.data, msg=exc.message) # 自定义模型检验异常 - @app.exception_handler(FieldValidatorException) - async def field_validator_exception_handler(request: Request, exc: FieldValidatorException): - return ResponseUtil.failure(data=exc.data, msg=exc.message) + @app.exception_handler(FieldValidationError) + async def field_validation_error_handler(request: Request, exc: FieldValidationError): + return ResponseUtil.failure(msg=exc.message) # 处理其他http请求异常 @app.exception_handler(HTTPException) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py deleted file mode 100644 index aeb4ff7..0000000 --- a/ruoyi-fastapi-backend/module_admin/annotation/validate_annotation.py +++ /dev/null @@ -1,293 +0,0 @@ -import re -from functools import wraps -from typing import Literal, Optional -from pydantic import ( - BaseModel, - Field, - AnyUrl, - AnyHttpUrl, - HttpUrl, - AnyWebsocketUrl, - WebsocketUrl, - FileUrl, - FtpUrl, - PostgresDsn, - CockroachDsn, - AmqpDsn, - RedisDsn, - MongoDsn, - KafkaDsn, - NatsDsn, - MySQLDsn, - MariaDBDsn, - ClickHouseDsn, - EmailStr, - NameEmail, - IPvAnyAddress, - ValidationError -) -from exceptions.exception import FieldValidatorException -from utils.string_util import StringUtil - - -class NetWorkAnnotationModel(BaseModel): - any_url: Optional[AnyUrl] = Field(default=None, description='接受任何URL类型') - any_http_url: Optional[AnyHttpUrl] = Field(default=None, description='接受任何http或https URL的类型') - http_url: Optional[HttpUrl] = Field(default=None, description='接受任何最大长度2083 & http或https URL的类型') - any_websocket_url: Optional[AnyWebsocketUrl] = Field(default=None, description='接受任何ws或wss URL的类型') - websocket_url: Optional[WebsocketUrl] = Field(default=None, description='接受任何最大长度 2083 & ws或wss URL的类型') - file_url: Optional[FileUrl] = Field(default=None, description='接受任何文件URL的类型') - ftp_url: Optional[FtpUrl] = Field(default=None, description='接受ftp URL的类型') - postgres_dsn: Optional[PostgresDsn] = Field(default=None, description='接受任何Postgres DSN的类型') - cockroach_dsn: Optional[CockroachDsn] = Field(default=None, description='接受任何Cockroach DSN的类型') - amqp_dsn: Optional[AmqpDsn] = Field(default=None, description='接受任何AMQP DSN的类型') - redis_dsn: Optional[RedisDsn] = Field(default=None, description='接受任何Redis DSN的类型') - mongo_dsn: Optional[MongoDsn] = Field(default=None, description='接受任何MongoDB DSN的类型') - kafka_dsn: Optional[KafkaDsn] = Field(default=None, description='接受任何Kafka DSN的类型') - nats_dsn: Optional[NatsDsn] = Field(default=None, description='接受任何NATS DSN的类型') - mysql_dsn: Optional[MySQLDsn] = Field(default=None, description='接受任何MySQL DSN的类型') - mariadb_dsn: Optional[MariaDBDsn] = Field(default=None, description='接受任何MariaDB DSN的类型') - clickhouse_dsn: Optional[ClickHouseDsn] = Field(default=None, description='接受任何ClickHouse DSN的类型') - email_str: Optional[EmailStr] = Field(default=None, description='验证电子邮件地址') - name_email: Optional[NameEmail] = Field(default=None, description='验证RFC 5322指定的名称和电子邮件地址组合') - ipv_any_address: Optional[IPvAnyAddress] = Field(default=None, description='验证IPv4或IPv6地址') - - -class ValidateFields: - """ - 字段校验装饰器 - """ - def __init__(self, validate_model: str, validate_function: str = 'validate_fields'): - """ - 字段校验装饰器 - :param validate_model: 需要校验的pydantic模型在函数中的名称 - :param validate_function: pydantic模型中定义的校验函数名称 - :return: - """ - self.validate_model = validate_model - self.validate_function = validate_function - - def __call__(self, func): - @wraps(func) - async def wrapper(*args, **kwargs): - validate_model = kwargs.get(self.validate_model) - if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.validate_function): - validate_function = getattr(validate_model, self.validate_function) - if validate_function is not None and callable(validate_function): - validate_function() - return await func(*args, **kwargs) - return wrapper - - -class NetWork: - """ - 字段网络类型校验装饰器 - """ - def __init__( - self, - field_name: str, - field_type: Literal['AnyUrl', 'AnyHttpUrl', 'HttpUrl', 'AnyWebsocketUrl', 'WebsocketUrl', 'FileUrl', - 'FtpUrl', 'PostgresDsn', 'CockroachDsn', 'AmqpDsn', 'RedisDsn', 'MongoDsn', 'KafkaDsn', - 'NatsDsn', 'MySQLDsn', 'MariaDBDsn', 'ClickHouseDsn', 'EmailStr', 'NameEmail', - 'IPvAnyAddress'], - message: Optional[str] = None - ): - """ - 字段网络类型校验装饰器 - :param field_name: 需要校验的字段名称 - :param field_type: 需要校验的字段类型 - :param message: 校验失败的提示信息 - :return: - """ - self.field_name = field_name - self.field_type = field_type - self.message = message - - def __call__(self, func): - @wraps(func) - def wrapper(*args, **kwargs): - validate_model = args[0] - if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): - field_value = getattr(validate_model, self.field_name) - if field_value: - try: - if self.field_type == 'AnyUrl': - NetWorkAnnotationModel(any_url=field_value) - elif self.field_type == 'AnyHttpUrl': - NetWorkAnnotationModel(any_http_url=field_value) - elif self.field_type == 'HttpUrl': - NetWorkAnnotationModel(http_url=field_value) - elif self.field_type == 'AnyWebsocketUrl': - NetWorkAnnotationModel(any_websocket_url=field_value) - elif self.field_type == 'WebsocketUrl': - NetWorkAnnotationModel(websocket_url=field_value) - elif self.field_type == 'FileUrl': - NetWorkAnnotationModel(file_url=field_value) - elif self.field_type == 'FtpUrl': - NetWorkAnnotationModel(ftp_url=field_value) - elif self.field_type == 'PostgresDsn': - NetWorkAnnotationModel(postgres_dsn=field_value) - elif self.field_type == 'CockroachDsn': - NetWorkAnnotationModel(cockroach_dsn=field_value) - elif self.field_type == 'AmqpDsn': - NetWorkAnnotationModel(amqp_dsn=field_value) - elif self.field_type == 'RedisDsn': - NetWorkAnnotationModel(redis_dsn=field_value) - elif self.field_type == 'MongoDsn': - NetWorkAnnotationModel(mongo_dsn=field_value) - elif self.field_type == 'KafkaDsn': - NetWorkAnnotationModel(kafka_dsn=field_value) - elif self.field_type == 'NatsDsn': - NetWorkAnnotationModel(nats_dsn=field_value) - elif self.field_type == 'MySQLDsn': - NetWorkAnnotationModel(mysql_dsn=field_value) - elif self.field_type == 'MariaDBDsn': - NetWorkAnnotationModel(mariadb_dsn=field_value) - elif self.field_type == 'ClickHouseDsn': - NetWorkAnnotationModel(clickhouse_dsn=field_value) - elif self.field_type == 'EmailStr': - NetWorkAnnotationModel(email_str=field_value) - elif self.field_type == 'NameEmail': - NetWorkAnnotationModel(name_email=field_value) - elif self.field_type == 'IPvAnyAddress': - NetWorkAnnotationModel(ipv_any_address=field_value) - except (ValidationError, ValueError): - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不是正确的{self.field_type}类型') - return func(*args, **kwargs) - return wrapper - - -class NotBlank: - """ - 字段非空校验装饰器 - """ - def __init__(self, field_name: str, message: Optional[str] = None): - """ - 字段非空校验装饰器 - :param field_name: 需要校验的字段名称 - :param message: 校验失败的提示信息 - :return: - """ - self.field_name = field_name - self.message = message - - def __call__(self, func): - @wraps(func) - def wrapper(*args, **kwargs): - validate_model = args[0] - if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): - field_value = getattr(validate_model, self.field_name) - if field_value is None or field_value == '' or field_value == [] or field_value == () or field_value == {}: - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不能为空') - return func(*args, **kwargs) - return wrapper - - -class Pattern: - """ - 字段正则校验装饰器 - """ - def __init__(self, field_name: str, regexp: str, message: Optional[str] = None): - """ - 字段正则校验装饰器 - :param field_name: 需要校验的字段名称 - :param regexp: 正则表达式 - :param message: 校验失败的提示信息 - :return: - """ - self.field_name = field_name - self.regexp = regexp - self.message = message - - def __call__(self, func): - @wraps(func) - def wrapper(*args, **kwargs): - validate_model = args[0] - if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): - field_value = getattr(validate_model, self.field_name) - if isinstance(field_value, str) and not re.match(self.regexp, field_value): - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}格式不正确') - return func(*args, **kwargs) - return wrapper - - -class Size: - """ - 字段大小校验装饰器 - """ - def __init__(self, field_name: str, gt: Optional[float] = None, ge: Optional[float] = None, - lt: Optional[float] = None, le: Optional[float] = None, min_length: Optional[int] = 0, - max_length: Optional[int] = None, message: Optional[str] = None): - """ - 字段大小校验装饰器 - :param field_name: 需要校验的字段名称 - :param gt: 数字型字段值必须要大于gt - :param ge: 数字型字段值必须要大于等于ge - :param lt: 数字型字段值必须要小于ge - :param le: 数字型字段值必须要小于等于ge - :param min_length: 字符串型字段长度不能小于min_length - :param max_length: 字符串型字段长度不能大于max_length - :param message: 校验失败的提示信息 - :return: - """ - self.field_name = field_name - self.gt = gt - self.ge = ge - self.lt = lt - self.le = le - self.min_length = min_length if min_length >= 0 else 0 - self.max_length = max_length - self.message = message - - def __call__(self, func): - @wraps(func) - def wrapper(*args, **kwargs): - validate_model = args[0] - if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): - field_value = getattr(validate_model, self.field_name) - if isinstance(field_value, float): - if self.gt is not None and field_value <= self.gt: - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须大于{self.gt}') - elif self.ge is not None and field_value < self.ge: - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须大于等于{self.ge}') - elif self.lt is not None and field_value >= self.lt: - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须小于{self.lt}') - elif self.le is not None and field_value > self.le: - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}必须小于等于{self.le}') - elif isinstance(field_value, str): - if len(field_value) < self.min_length: - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}长度不能小于{self.min_length}') - elif self.max_length is not None and len(field_value) > self.max_length: - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}长度不能大于{self.max_length}') - return func(*args, **kwargs) - return wrapper - - -class Xss: - """ - 字段Xss校验装饰器 - """ - HTML_PATTERN = '<(\S*?)[^>]*>.*?|<.*? />' - - def __init__(self, field_name: str, message: Optional[str] = None): - """ - 字段Xss校验装饰器 - :param field_name: 需要校验的字段名称 - :param message: 校验失败的提示信息 - :return: - """ - self.field_name = field_name - self.message = message - - def __call__(self, func): - @wraps(func) - def wrapper(*args, **kwargs): - validate_model = args[0] - if isinstance(validate_model, BaseModel) and hasattr(validate_model, self.field_name): - field_value = getattr(validate_model, self.field_name) - if not StringUtil.is_blank(field_value): - pattern = re.compile(self.HTML_PATTERN) - if pattern.search(field_value): - raise FieldValidatorException(message=self.message if self.message else f'{self.field_name}不能包含脚本字符') - return func(*args, **kwargs) - return wrapper diff --git a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py index ba7f63c..31e28e9 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py @@ -1,11 +1,11 @@ from fastapi import APIRouter from fastapi import Depends +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.config_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py index 74e4196..5d8208f 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py @@ -1,12 +1,12 @@ from fastapi import APIRouter, Request from fastapi import Depends +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.dept_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py index fdfdacb..ce508cf 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py @@ -1,11 +1,11 @@ from fastapi import APIRouter from fastapi import Depends +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.dict_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py index 487f6f9..f3d536b 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py @@ -1,12 +1,12 @@ from fastapi import APIRouter from fastapi import Depends +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.job_service import * from module_admin.service.job_log_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py index 59b7bcf..ddda0ea 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py @@ -1,11 +1,11 @@ from fastapi import APIRouter, Request from fastapi import Depends +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from module_admin.service.login_service import LoginService from module_admin.service.menu_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py index 5844891..9395bca 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py @@ -1,11 +1,11 @@ from fastapi import APIRouter, Request from fastapi import Depends +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.notice_service import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py index 1049ccb..97cd459 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py @@ -1,12 +1,12 @@ from fastapi import APIRouter, Request from fastapi import Depends +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.post_service import * from module_admin.entity.vo.post_vo import * from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index 7251339..a27eb91 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -1,5 +1,6 @@ from fastapi import APIRouter, Request from fastapi import Depends +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.role_service import * @@ -8,7 +9,6 @@ from module_admin.service.user_service import UserService, UserRoleQueryModel, U from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.response_util import * from utils.log_util import * diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index f06daa9..8c651a6 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -1,5 +1,6 @@ from fastapi import APIRouter, Request from fastapi import Depends, File, Query +from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from config.env import UploadConfig from module_admin.service.login_service import LoginService @@ -8,7 +9,6 @@ from module_admin.service.dept_service import DeptService from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator -from module_admin.annotation.validate_annotation import ValidateFields from config.enums import BusinessType from utils.page_util import PageResponseModel from utils.response_util import * diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py index 7dd7a5f..c749190 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py @@ -1,9 +1,9 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import NotBlank, Size from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form -from module_admin.annotation.validate_annotation import NotBlank, Size class ConfigModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py index c55b186..f91d820 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py @@ -1,9 +1,9 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import Network, NotBlank, Size from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query -from module_admin.annotation.validate_annotation import NetWork, NotBlank, Size class DeptModel(BaseModel): @@ -40,7 +40,7 @@ class DeptModel(BaseModel): def get_phone(self): return self.phone - @NetWork(field_name='email', field_type='EmailStr', message='邮箱格式不正确') + @Network(field_name='email', field_type='EmailStr', message='邮箱格式不正确') @Size(field_name='email', min_length=0, max_length=50, message='邮箱长度不能超过50个字符') def get_email(self): return self.email diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py index 7a303c1..3c24554 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py @@ -1,9 +1,9 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import NotBlank, Pattern, Size from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form -from module_admin.annotation.validate_annotation import NotBlank, Pattern, Size class DictTypeModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py index c3efb7f..f39cc21 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py @@ -1,9 +1,9 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import NotBlank, Size from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form -from module_admin.annotation.validate_annotation import NotBlank, Size class JobModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py index 7175c74..224015c 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py @@ -1,9 +1,9 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import NotBlank, Size from datetime import datetime from typing import Union, Optional, List, Literal from module_admin.annotation.pydantic_annotation import as_query -from module_admin.annotation.validate_annotation import NotBlank, Size class MenuModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py index d95a6dc..75ef99c 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py @@ -1,9 +1,9 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import NotBlank, Size, Xss from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form -from module_admin.annotation.validate_annotation import NotBlank, Size, Xss class NoticeModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py index c2056c8..68dd079 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py @@ -1,9 +1,9 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import NotBlank, Size from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form -from module_admin.annotation.validate_annotation import NotBlank, Size class PostModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py index 439ff8b..ab809bc 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py @@ -1,9 +1,9 @@ from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import NotBlank, Size from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.annotation.pydantic_annotation import as_query, as_form -from module_admin.annotation.validate_annotation import NotBlank, Size class RoleModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py index 6c47258..3613913 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py @@ -1,13 +1,13 @@ import re from pydantic import BaseModel, Field, ConfigDict, model_validator from pydantic.alias_generators import to_camel +from pydantic_validation_decorator import Network, NotBlank, Size, Xss from typing import Union, Optional, List, Literal from datetime import datetime from module_admin.entity.vo.role_vo import RoleModel from module_admin.entity.vo.dept_vo import DeptModel from module_admin.entity.vo.post_vo import PostModel from module_admin.annotation.pydantic_annotation import as_query, as_form -from module_admin.annotation.validate_annotation import NetWork, NotBlank, Size, Xss from exceptions.exception import ModelValidatorException @@ -72,7 +72,7 @@ class UserModel(BaseModel): def get_nick_name(self): return self.nick_name - @NetWork(field_name='email', field_type='EmailStr', message='邮箱格式不正确') + @Network(field_name='email', field_type='EmailStr', message='邮箱格式不正确') @Size(field_name='email', min_length=0, max_length=50, message='邮箱长度不能超过50个字符') def get_email(self): return self.email diff --git a/ruoyi-fastapi-backend/requirements.txt b/ruoyi-fastapi-backend/requirements.txt index 292ca2f..976dbb9 100644 --- a/ruoyi-fastapi-backend/requirements.txt +++ b/ruoyi-fastapi-backend/requirements.txt @@ -8,6 +8,7 @@ pandas==2.1.4 passlib[bcrypt]==1.7.4 Pillow==10.2.0 psutil==5.9.7 +pydantic-validation-decorator==0.1.2 PyMySQL==1.1.0 python-jose[cryptography]==3.3.0 redis==5.0.1 -- Gitee From 82c61753e3e19d8bab8dda4ba2f8e6cd386e133a Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sun, 7 Jul 2024 09:46:29 +0800 Subject: [PATCH 050/129] =?UTF-8?q?style:=20=E5=88=A0=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E7=9A=84=E8=87=AA=E5=AE=9A=E4=B9=89=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/exception.py | 10 ---------- ruoyi-fastapi-backend/exceptions/handle.py | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/ruoyi-fastapi-backend/exceptions/exception.py b/ruoyi-fastapi-backend/exceptions/exception.py index 281bb64..28c39a6 100644 --- a/ruoyi-fastapi-backend/exceptions/exception.py +++ b/ruoyi-fastapi-backend/exceptions/exception.py @@ -36,13 +36,3 @@ class ModelValidatorException(Exception): def __init__(self, data: str = None, message: str = None): self.data = data self.message = message - - -class FieldValidatorException(Exception): - """ - 自定义字段校验异常FieldValidatorException - """ - - def __init__(self, data: str = None, message: str = None): - self.data = data - self.message = message diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index c5447fe..d394542 100644 --- a/ruoyi-fastapi-backend/exceptions/handle.py +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -24,7 +24,7 @@ def handle_exception(app: FastAPI): async def model_validator_exception_handler(request: Request, exc: ModelValidatorException): return ResponseUtil.failure(data=exc.data, msg=exc.message) - # 自定义模型检验异常 + # 自定义字段检验异常 @app.exception_handler(FieldValidationError) async def field_validation_error_handler(request: Request, exc: FieldValidationError): return ResponseUtil.failure(msg=exc.message) -- Gitee From 3684d5a703c283016132d9213eb3919449ecf70b Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sun, 7 Jul 2024 13:06:16 +0800 Subject: [PATCH 051/129] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=AD=97=E5=85=B8=E6=97=B6=E4=BF=AE=E6=94=B9=E5=AD=97?= =?UTF-8?q?=E5=85=B8=E7=B1=BB=E5=9E=8B=E5=BC=82=E5=B8=B8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/service/dict_service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/service/dict_service.py b/ruoyi-fastapi-backend/module_admin/service/dict_service.py index efcd3b7..b07a465 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dict_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dict_service.py @@ -67,8 +67,8 @@ class DictTypeService: return CrudResponseModel(**result) try: if dict_type_info.dict_type != page_object.dict_type: - query_dict_data = await DictDataModel(dictType=dict_type_info.dict_type) - dict_data_list = await DictDataDao.get_dict_data_list(query_db, query_dict_data) + query_dict_data = DictDataPageQueryModel(dictType=dict_type_info.dict_type) + dict_data_list = await DictDataDao.get_dict_data_list(query_db, query_dict_data, is_page=False) for dict_data in dict_data_list: edit_dict_data = DictDataModel(dictCode=dict_data.dict_code, dictType=page_object.dict_type, updateBy=page_object.update_by).model_dump(exclude_unset=True) await DictDataDao.edit_dict_data_dao(query_db, edit_dict_data) -- Gitee From e9c4f295ce7905cd195033f74c27d77e54be7afe Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sun, 7 Jul 2024 13:07:48 +0800 Subject: [PATCH 052/129] =?UTF-8?q?perf:=20=E7=BC=96=E8=BE=91=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=97=B6=E6=8E=A5=E5=8F=A3=E8=AF=B7=E6=B1=82=E4=BD=93?= =?UTF-8?q?=E4=B8=AD=E5=88=A0=E9=99=A4password?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-frontend/src/views/system/user/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-fastapi-frontend/src/views/system/user/index.vue b/ruoyi-fastapi-frontend/src/views/system/user/index.vue index 5cd9936..5dd15f6 100644 --- a/ruoyi-fastapi-frontend/src/views/system/user/index.vue +++ b/ruoyi-fastapi-frontend/src/views/system/user/index.vue @@ -583,7 +583,7 @@ function handleUpdate(row) { form.value.roleIds = response.roleIds; open.value = true; title.value = "修改用户"; - form.password = ""; + form.value.password = undefined; }); }; /** 提交按钮 */ -- Gitee From 09f9dd2784f7ab68d25bba5deace86fd383f2ea4 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 8 Jul 2024 16:47:17 +0800 Subject: [PATCH 053/129] =?UTF-8?q?perf:=20=E5=8F=82=E6=95=B0=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/config/constant.py | 4 + .../module_admin/service/config_service.py | 73 ++++++++++++------- 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/ruoyi-fastapi-backend/config/constant.py b/ruoyi-fastapi-backend/config/constant.py index 552d717..5f94546 100644 --- a/ruoyi-fastapi-backend/config/constant.py +++ b/ruoyi-fastapi-backend/config/constant.py @@ -4,12 +4,16 @@ class CommonConstant: WWW: www主域 HTTP: http请求 HTTPS: https请求 + YES: 是否为系统默认(是) + NO: 是否为系统默认(否) UNIQUE: 校验是否唯一的返回标识(是) NOT_UNIQUE: 校验是否唯一的返回标识(否) """ WWW = 'www.' HTTP = 'http://' HTTPS = 'https://' + YES = 'Y' + NO = 'N' UNIQUE = True NOT_UNIQUE = False diff --git a/ruoyi-fastapi-backend/module_admin/service/config_service.py b/ruoyi-fastapi-backend/module_admin/service/config_service.py index e470060..fd269e8 100644 --- a/ruoyi-fastapi-backend/module_admin/service/config_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/config_service.py @@ -1,4 +1,5 @@ from fastapi import Request +from config.constant import CommonConstant from config.env import RedisInitKeyConfig from module_admin.dao.config_dao import * from module_admin.entity.vo.common_vo import CrudResponseModel @@ -38,8 +39,7 @@ class ConfigService: await redis.delete(*keys) config_all = await ConfigDao.get_config_list(query_db, ConfigPageQueryModel(**dict()), is_page=False) for config_obj in config_all: - if config_obj.get('configType') == 'Y': - await redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_obj.get('configKey')}", config_obj.get('configValue')) + await redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_obj.get('configKey')}", config_obj.get('configValue')) @classmethod async def query_config_list_from_cache_services(cls, redis, config_key: str): @@ -53,6 +53,20 @@ class ConfigService: return result + @classmethod + async def check_config_key_unique_services(cls, query_db: AsyncSession, page_object: ConfigModel): + """ + 校验参数键名是否唯一service + :param query_db: orm对象 + :param page_object: 参数配置对象 + :return: 校验结果 + """ + config_id = -1 if page_object.config_id is None else page_object.config_id + config = await ConfigDao.get_config_detail_by_info(query_db, ConfigModel(configKey=page_object.config_key)) + if config and config.config_id != config_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_config_services(cls, request: Request, query_db: AsyncSession, page_object: ConfigModel): """ @@ -62,14 +76,13 @@ class ConfigService: :param page_object: 新增参数配置对象 :return: 新增参数配置校验结果 """ - config = await ConfigDao.get_config_detail_by_info(query_db, ConfigModel(configKey=page_object.config_key)) - if config: - result = dict(is_success=False, message='参数键名已存在') + if not await cls.check_config_key_unique_services(query_db, page_object): + result = dict(is_success=False, message=f'新增参数{page_object.config_name}失败,参数键名已存在') else: try: await ConfigDao.add_config_dao(query_db, page_object) await query_db.commit() - await cls.init_cache_sys_config_services(query_db, request.app.state.redis) + await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{page_object.config_key}", page_object.config_value) result = dict(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() @@ -87,21 +100,21 @@ class ConfigService: :return: 编辑参数配置校验结果 """ edit_config = page_object.model_dump(exclude_unset=True) - config_info = await cls.config_detail_services(query_db, edit_config.get('config_id')) - if config_info: - if config_info.config_key != page_object.config_key or config_info.config_value != page_object.config_value: - config = await ConfigDao.get_config_detail_by_info(query_db, page_object) - if config: - result = dict(is_success=False, message='参数配置已存在') - return CrudResponseModel(**result) - try: - await ConfigDao.edit_config_dao(query_db, edit_config) - await query_db.commit() - await cls.init_cache_sys_config_services(query_db, request.app.state.redis) - result = dict(is_success=True, message='更新成功') - except Exception as e: - await query_db.rollback() - raise e + config_info = await cls.config_detail_services(query_db, page_object.config_id) + if config_info.config_id: + if not await cls.check_config_key_unique_services(query_db, page_object): + result = dict(is_success=False, message=f'修改参数{page_object.config_name}失败,参数键名已存在') + else: + try: + await ConfigDao.edit_config_dao(query_db, edit_config) + await query_db.commit() + if config_info.config_key != page_object.config_key: + await request.app.state.redis.delete(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_info.config_key}") + await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{page_object.config_key}", page_object.config_value) + result = dict(is_success=True, message='更新成功') + except Exception as e: + await query_db.rollback() + raise e else: result = dict(is_success=False, message='参数配置不存在') @@ -119,16 +132,23 @@ class ConfigService: if page_object.config_ids.split(','): config_id_list = page_object.config_ids.split(',') try: + delete_config_key_list = [] for config_id in config_id_list: - await ConfigDao.delete_config_dao(query_db, ConfigModel(configId=config_id)) + config_info = await cls.config_detail_services(query_db, int(config_id)) + if config_info.config_type == CommonConstant.YES: + return CrudResponseModel(is_success=False, message=f'内置参数{config_info.config_key}不能删除') + else: + await ConfigDao.delete_config_dao(query_db, ConfigModel(configId=int(config_id))) + delete_config_key_list.append(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_info.config_key}") await query_db.commit() - await cls.init_cache_sys_config_services(query_db, request.app.state.redis) + if delete_config_key_list: + await request.app.state.redis.delete(*delete_config_key_list) result = dict(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入字典数据id为空') + result = dict(is_success=False, message='传入参数配置id为空') return CrudResponseModel(**result) @classmethod @@ -140,7 +160,10 @@ class ConfigService: :return: 参数配置id对应的信息 """ config = await ConfigDao.get_config_detail_by_id(query_db, config_id=config_id) - result = ConfigModel(**CamelCaseUtil.transform_result(config)) + if config: + result = ConfigModel(**CamelCaseUtil.transform_result(config)) + else: + result = ConfigModel(**dict()) return result -- Gitee From 2fef16e58bf2bac591683133517dcadb2d3cf74d Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Tue, 9 Jul 2024 16:25:13 +0800 Subject: [PATCH 054/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E5=A4=84=E7=90=86=E8=87=AA=E5=AE=9A=E4=B9=89=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=BC=82=E5=B8=B8=E5=8F=8A=E5=85=B6=E4=BB=96=E5=BC=82?= =?UTF-8?q?=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/exception.py | 10 ++++++++++ ruoyi-fastapi-backend/exceptions/handle.py | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/exceptions/exception.py b/ruoyi-fastapi-backend/exceptions/exception.py index 28c39a6..0a94948 100644 --- a/ruoyi-fastapi-backend/exceptions/exception.py +++ b/ruoyi-fastapi-backend/exceptions/exception.py @@ -28,6 +28,16 @@ class PermissionException(Exception): self.message = message +class ServiceException(Exception): + """ + 自定义服务异常ServiceException + """ + + def __init__(self, data: str = None, message: str = None): + self.data = data + self.message = message + + class ModelValidatorException(Exception): """ 自定义模型校验异常ModelValidatorException diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index d394542..b4ad02b 100644 --- a/ruoyi-fastapi-backend/exceptions/handle.py +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -1,7 +1,8 @@ from fastapi import FastAPI, Request from fastapi.exceptions import HTTPException from pydantic_validation_decorator import FieldValidationError -from exceptions.exception import AuthException, PermissionException, ModelValidatorException +from exceptions.exception import AuthException, PermissionException, ServiceException, ModelValidatorException +from utils.log_util import logger from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder @@ -19,14 +20,22 @@ def handle_exception(app: FastAPI): async def permission_exception_handler(request: Request, exc: PermissionException): return ResponseUtil.forbidden(data=exc.data, msg=exc.message) + # 自定义服务异常 + @app.exception_handler(ServiceException) + async def service_exception_handler(request: Request, exc: ServiceException): + logger.warning(exc.message) + return ResponseUtil.failure(data=exc.data, msg=exc.message) + # 自定义模型检验异常 @app.exception_handler(ModelValidatorException) async def model_validator_exception_handler(request: Request, exc: ModelValidatorException): + logger.warning(exc.message) return ResponseUtil.failure(data=exc.data, msg=exc.message) # 自定义字段检验异常 @app.exception_handler(FieldValidationError) async def field_validation_error_handler(request: Request, exc: FieldValidationError): + logger.warning(exc.message) return ResponseUtil.failure(msg=exc.message) # 处理其他http请求异常 @@ -36,3 +45,9 @@ def handle_exception(app: FastAPI): content=jsonable_encoder({"code": exc.status_code, "msg": exc.detail}), status_code=exc.status_code ) + + # 处理其他异常 + @app.exception_handler(Exception) + async def exception_handler(request: Request, exc: Exception): + logger.exception(exc) + return ResponseUtil.error(msg=str(exc)) -- Gitee From 2b19022e292b6f35e25ef8983b8714f4d59e740f Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Tue, 9 Jul 2024 16:25:27 +0800 Subject: [PATCH 055/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/config_controller.py | 126 ++++++------------ .../module_admin/service/config_service.py | 29 ++-- 2 files changed, 55 insertions(+), 100 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py index 31e28e9..3c26783 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py @@ -18,121 +18,81 @@ configController = APIRouter(prefix='/system/config', dependencies=[Depends(Logi @configController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:list'))]) async def get_system_config_list(request: Request, config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - # 获取分页数据 - config_page_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=config_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + config_page_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=config_page_query_result) @configController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))]) @ValidateFields(validate_model='add_config') @log_decorator(title='参数管理', business_type=BusinessType.INSERT) async def add_system_config(request: Request, add_config: ConfigModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_config.create_by = current_user.user.user_name - add_config.create_time = datetime.now() - add_config.update_by = current_user.user.user_name - add_config.update_time = datetime.now() - add_config_result = await ConfigService.add_config_services(request, query_db, add_config) - if add_config_result.is_success: - logger.info(add_config_result.message) - return ResponseUtil.success(msg=add_config_result.message) - else: - logger.warning(add_config_result.message) - return ResponseUtil.failure(msg=add_config_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_config.create_by = current_user.user.user_name + add_config.create_time = datetime.now() + add_config.update_by = current_user.user.user_name + add_config.update_time = datetime.now() + add_config_result = await ConfigService.add_config_services(request, query_db, add_config) + logger.info(add_config_result.message) + + return ResponseUtil.success(msg=add_config_result.message) @configController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))]) @ValidateFields(validate_model='edit_config') @log_decorator(title='参数管理', business_type=BusinessType.UPDATE) async def edit_system_config(request: Request, edit_config: ConfigModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_config.update_by = current_user.user.user_name - edit_config.update_time = datetime.now() - edit_config_result = await ConfigService.edit_config_services(request, query_db, edit_config) - if edit_config_result.is_success: - logger.info(edit_config_result.message) - return ResponseUtil.success(msg=edit_config_result.message) - else: - logger.warning(edit_config_result.message) - return ResponseUtil.failure(msg=edit_config_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_config.update_by = current_user.user.user_name + edit_config.update_time = datetime.now() + edit_config_result = await ConfigService.edit_config_services(request, query_db, edit_config) + logger.info(edit_config_result.message) + + return ResponseUtil.success(msg=edit_config_result.message) @configController.delete("/refreshCache", dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) @log_decorator(title='参数管理', business_type=BusinessType.UPDATE) async def refresh_system_config(request: Request, query_db: AsyncSession = Depends(get_db)): - try: - refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db) - if refresh_config_result.is_success: - logger.info(refresh_config_result.message) - return ResponseUtil.success(msg=refresh_config_result.message) - else: - logger.warning(refresh_config_result.message) - return ResponseUtil.failure(msg=refresh_config_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db) + logger.info(refresh_config_result.message) + + return ResponseUtil.success(msg=refresh_config_result.message) @configController.delete("/{config_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) @log_decorator(title='参数管理', business_type=BusinessType.DELETE) async def delete_system_config(request: Request, config_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_config = DeleteConfigModel(configIds=config_ids) - delete_config_result = await ConfigService.delete_config_services(request, query_db, delete_config) - if delete_config_result.is_success: - logger.info(delete_config_result.message) - return ResponseUtil.success(msg=delete_config_result.message) - else: - logger.warning(delete_config_result.message) - return ResponseUtil.failure(msg=delete_config_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_config = DeleteConfigModel(configIds=config_ids) + delete_config_result = await ConfigService.delete_config_services(request, query_db, delete_config) + logger.info(delete_config_result.message) + + return ResponseUtil.success(msg=delete_config_result.message) @configController.get("/{config_id}", response_model=ConfigModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:query'))]) async def query_detail_system_config(request: Request, config_id: int, query_db: AsyncSession = Depends(get_db)): - try: - config_detail_result = await ConfigService.config_detail_services(query_db, config_id) - logger.info(f'获取config_id为{config_id}的信息成功') - return ResponseUtil.success(data=config_detail_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + config_detail_result = await ConfigService.config_detail_services(query_db, config_id) + logger.info(f'获取config_id为{config_id}的信息成功') + + return ResponseUtil.success(data=config_detail_result) @configController.get("/configKey/{config_key}") async def query_system_config(request: Request, config_key: str): - try: - # 获取全量数据 - config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key) - logger.info('获取成功') - return ResponseUtil.success(msg=config_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key) + logger.info('获取成功') + + return ResponseUtil.success(msg=config_query_result) @configController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))]) @log_decorator(title='参数管理', business_type=BusinessType.EXPORT) async def export_system_config_list(request: Request, config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): - try: - # 获取全量数据 - config_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=False) - config_export_result = await ConfigService.export_config_list_services(config_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(config_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + config_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=False) + config_export_result = await ConfigService.export_config_list_services(config_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(config_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/service/config_service.py b/ruoyi-fastapi-backend/module_admin/service/config_service.py index fd269e8..6759a8b 100644 --- a/ruoyi-fastapi-backend/module_admin/service/config_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/config_service.py @@ -1,8 +1,9 @@ from fastapi import Request -from config.constant import CommonConstant -from config.env import RedisInitKeyConfig from module_admin.dao.config_dao import * from module_admin.entity.vo.common_vo import CrudResponseModel +from config.constant import CommonConstant +from config.env import RedisInitKeyConfig +from exceptions.exception import ServiceException from utils.common_util import export_list2excel, CamelCaseUtil @@ -77,19 +78,17 @@ class ConfigService: :return: 新增参数配置校验结果 """ if not await cls.check_config_key_unique_services(query_db, page_object): - result = dict(is_success=False, message=f'新增参数{page_object.config_name}失败,参数键名已存在') + raise ServiceException(message=f'新增参数{page_object.config_name}失败,参数键名已存在') else: try: await ConfigDao.add_config_dao(query_db, page_object) await query_db.commit() await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{page_object.config_key}", page_object.config_value) - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def edit_config_services(cls, request: Request, query_db: AsyncSession, page_object: ConfigModel): """ @@ -103,7 +102,7 @@ class ConfigService: config_info = await cls.config_detail_services(query_db, page_object.config_id) if config_info.config_id: if not await cls.check_config_key_unique_services(query_db, page_object): - result = dict(is_success=False, message=f'修改参数{page_object.config_name}失败,参数键名已存在') + raise ServiceException(message=f'修改参数{page_object.config_name}失败,参数键名已存在') else: try: await ConfigDao.edit_config_dao(query_db, edit_config) @@ -111,14 +110,12 @@ class ConfigService: if config_info.config_key != page_object.config_key: await request.app.state.redis.delete(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_info.config_key}") await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{page_object.config_key}", page_object.config_value) - result = dict(is_success=True, message='更新成功') + return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='参数配置不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='参数配置不存在') @classmethod async def delete_config_services(cls, request: Request, query_db: AsyncSession, page_object: DeleteConfigModel): @@ -136,20 +133,19 @@ class ConfigService: for config_id in config_id_list: config_info = await cls.config_detail_services(query_db, int(config_id)) if config_info.config_type == CommonConstant.YES: - return CrudResponseModel(is_success=False, message=f'内置参数{config_info.config_key}不能删除') + raise ServiceException(message=f'内置参数{config_info.config_key}不能删除') else: await ConfigDao.delete_config_dao(query_db, ConfigModel(configId=int(config_id))) delete_config_key_list.append(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_info.config_key}") await query_db.commit() if delete_config_key_list: await request.app.state.redis.delete(*delete_config_key_list) - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入参数配置id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入参数配置id为空') @classmethod async def config_detail_services(cls, query_db: AsyncSession, config_id: int): @@ -209,6 +205,5 @@ class ConfigService: :return: 刷新字典缓存校验结果 """ await cls.init_cache_sys_config_services(query_db, request.app.state.redis) - result = dict(is_success=True, message='刷新成功') - return CrudResponseModel(**result) + return CrudResponseModel(is_success=True, message='刷新成功') -- Gitee From 1eff840afa1a9b65ef4b50c487c949f653a91454 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Tue, 9 Jul 2024 17:07:33 +0800 Subject: [PATCH 056/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/user_controller.py | 352 ++++++++---------- .../module_admin/dao/user_dao.py | 6 +- .../module_admin/service/user_service.py | 142 +++++-- 3 files changed, 253 insertions(+), 247 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index 8c651a6..cbe510c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -22,155 +22,133 @@ userController = APIRouter(prefix='/system/user', dependencies=[Depends(LoginSer @userController.get("/deptTree", dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]) async def get_system_dept_tree(request: Request, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): - try: - dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql) - logger.info('获取成功') - return ResponseUtil.success(data=dept_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql) + logger.info('获取成功') + + return ResponseUtil.success(data=dept_query_result) @userController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]) async def get_system_user_list(request: Request, user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): - try: - # 获取分页数据 - user_page_query_result = await UserService.get_user_list_services(query_db, user_page_query, data_scope_sql, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=user_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + user_page_query_result = await UserService.get_user_list_services(query_db, user_page_query, data_scope_sql, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=user_page_query_result) @userController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) @ValidateFields(validate_model='add_user') @log_decorator(title='用户管理', business_type=BusinessType.INSERT) async def add_system_user(request: Request, add_user: AddUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_user.password = PwdUtil.get_password_hash(add_user.password) - add_user.create_by = current_user.user.user_name - add_user.create_time = datetime.now() - add_user.update_by = current_user.user.user_name - add_user.update_time = datetime.now() - add_user_result = await UserService.add_user_services(query_db, add_user) - if add_user_result.is_success: - logger.info(add_user_result.message) - return ResponseUtil.success(msg=add_user_result.message) - else: - logger.warning(add_user_result.message) - return ResponseUtil.failure(msg=add_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_user.password = PwdUtil.get_password_hash(add_user.password) + add_user.create_by = current_user.user.user_name + add_user.create_time = datetime.now() + add_user.update_by = current_user.user.user_name + add_user.update_time = datetime.now() + add_user_result = await UserService.add_user_services(query_db, add_user) + logger.info(add_user_result.message) + + return ResponseUtil.success(msg=add_user_result.message) @userController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @ValidateFields(validate_model='edit_user') @log_decorator(title='用户管理', business_type=BusinessType.UPDATE) -async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_user.update_by = current_user.user.user_name - edit_user.update_time = datetime.now() - edit_user_result = await UserService.edit_user_services(query_db, edit_user) - if edit_user_result.is_success: - logger.info(edit_user_result.message) - return ResponseUtil.success(msg=edit_user_result.message) - else: - logger.warning(edit_user_result.message) - return ResponseUtil.failure(msg=edit_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): + await UserService.check_user_allowed_services(edit_user) + if not current_user.user.admin: + await UserService.check_user_data_scope_services(query_db, edit_user.user_id, data_scope_sql) + edit_user.update_by = current_user.user.user_name + edit_user.update_time = datetime.now() + edit_user_result = await UserService.edit_user_services(query_db, edit_user) + logger.info(edit_user_result.message) + + return ResponseUtil.success(msg=edit_user_result.message) @userController.delete("/{user_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))]) @log_decorator(title='用户管理', business_type=BusinessType.DELETE) -async def delete_system_user(request: Request, user_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - delete_user = DeleteUserModel( - userIds=user_ids, - updateBy=current_user.user.user_name, - updateTime=datetime.now() - ) - delete_user_result = await UserService.delete_user_services(query_db, delete_user) - if delete_user_result.is_success: - logger.info(delete_user_result.message) - return ResponseUtil.success(msg=delete_user_result.message) - else: - logger.warning(delete_user_result.message) - return ResponseUtil.failure(msg=delete_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def delete_system_user(request: Request, user_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): + user_id_list = user_ids.split(',') + if current_user.user.user_id in user_id_list: + logger.warning('当前登录用户不能删除') + + return ResponseUtil.failure(msg='当前登录用户不能删除') + for user_id in user_id_list: + if not current_user.user.admin: + await UserService.check_user_allowed_services(UserModel(userId=int(user_id))) + await UserService.check_user_data_scope_services(query_db, int(user_id), data_scope_sql) + delete_user = DeleteUserModel( + userIds=user_ids, + updateBy=current_user.user.user_name, + updateTime=datetime.now() + ) + delete_user_result = await UserService.delete_user_services(query_db, delete_user) + logger.info(delete_user_result.message) + + return ResponseUtil.success(msg=delete_user_result.message) @userController.put("/resetPwd", dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))]) @log_decorator(title='用户管理', business_type=BusinessType.UPDATE) -async def reset_system_user_pwd(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_user.password = PwdUtil.get_password_hash(edit_user.password) - edit_user.update_by = current_user.user.user_name - edit_user.update_time = datetime.now() - edit_user.type = 'pwd' - edit_user_result = await UserService.edit_user_services(query_db, edit_user) - if edit_user_result.is_success: - logger.info(edit_user_result.message) - return ResponseUtil.success(msg=edit_user_result.message) - else: - logger.warning(edit_user_result.message) - return ResponseUtil.failure(msg=edit_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def reset_system_user_pwd(request: Request, reset_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): + await UserService.check_user_allowed_services(reset_user) + if not current_user.user.admin: + await UserService.check_user_data_scope_services(query_db, reset_user.user_id, data_scope_sql) + edit_user = EditUserModel( + userId=reset_user.user_id, + password=PwdUtil.get_password_hash(reset_user.password), + updateBy=current_user.user.user_name, + updateTime=datetime.now(), + type='pwd' + ) + edit_user_result = await UserService.edit_user_services(query_db, edit_user) + logger.info(edit_user_result.message) + + return ResponseUtil.success(msg=edit_user_result.message) @userController.put("/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @log_decorator(title='用户管理', business_type=BusinessType.UPDATE) -async def change_system_user_status(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_user.update_by = current_user.user.user_name - edit_user.update_time = datetime.now() - edit_user.type = 'status' - edit_user_result = await UserService.edit_user_services(query_db, edit_user) - if edit_user_result.is_success: - logger.info(edit_user_result.message) - return ResponseUtil.success(msg=edit_user_result.message) - else: - logger.warning(edit_user_result.message) - return ResponseUtil.failure(msg=edit_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def change_system_user_status(request: Request, change_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): + await UserService.check_user_allowed_services(change_user) + if not current_user.user.admin: + await UserService.check_user_data_scope_services(query_db, change_user.user_id, data_scope_sql) + edit_user = EditUserModel( + userId=change_user.user_id, + status=change_user.status, + updateBy=current_user.user.user_name, + updateTime=datetime.now(), + type='status' + ) + edit_user_result = await UserService.edit_user_services(query_db, edit_user) + logger.info(edit_user_result.message) + + return ResponseUtil.success(msg=edit_user_result.message) @userController.get("/profile", response_model=UserProfileModel) async def query_detail_system_user(request: Request, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - profile_user_result = await UserService.user_profile_services(query_db, current_user.user.user_id) - logger.info(f'获取user_id为{current_user.user.user_id}的信息成功') - return ResponseUtil.success(model_content=profile_user_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + profile_user_result = await UserService.user_profile_services(query_db, current_user.user.user_id) + logger.info(f'获取user_id为{current_user.user.user_id}的信息成功') + + return ResponseUtil.success(model_content=profile_user_result) @userController.get("/{user_id}", response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]) @userController.get("/", response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]) async def query_detail_system_user(request: Request, user_id: Optional[Union[int, str]] = '', query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - detail_user_result = await UserService.user_detail_services(query_db, user_id) - logger.info(f'获取user_id为{user_id}的信息成功') - return ResponseUtil.success(model_content=detail_user_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + detail_user_result = await UserService.user_detail_services(query_db, user_id) + logger.info(f'获取user_id为{user_id}的信息成功') + + return ResponseUtil.success(model_content=detail_user_result) @userController.post("/profile/avatar") @log_decorator(title='个人信息', business_type=BusinessType.UPDATE) async def change_system_user_profile_avatar(request: Request, avatarfile: bytes = File(), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: + if avatarfile: relative_path = f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}' dir_path = os.path.join(UploadConfig.UPLOAD_PATH, relative_path) try: @@ -189,134 +167,94 @@ async def change_system_user_profile_avatar(request: Request, avatarfile: bytes type='avatar' ) edit_user_result = await UserService.edit_user_services(query_db, edit_user) - if edit_user_result.is_success: - logger.info(edit_user_result.message) - return ResponseUtil.success(dict_content={'imgUrl': edit_user.avatar}, msg=edit_user_result.message) - else: - logger.warning(edit_user_result.message) - return ResponseUtil.failure(msg=edit_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + logger.info(edit_user_result.message) + + return ResponseUtil.success(dict_content={'imgUrl': edit_user.avatar}, msg=edit_user_result.message) + return ResponseUtil.failure(msg='上传图片异常,请联系管理员') @userController.put("/profile") @log_decorator(title='个人信息', business_type=BusinessType.UPDATE) async def change_system_user_profile_info(request: Request, user_info: UserInfoModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_user = EditUserModel( - **user_info.model_dump( - exclude_unset=True, - by_alias=True, - exclude={'role_ids', 'post_ids'} - ), - userId=current_user.user.user_id, - userName=current_user.user.user_name, - updateBy=current_user.user.user_name, - updateTime=datetime.now(), - roleIds=current_user.user.role_ids.split(',') if current_user.user.role_ids else [], - postIds=current_user.user.post_ids.split(',') if current_user.user.post_ids else [], - role=current_user.user.role - ) - edit_user_result = await UserService.edit_user_services(query_db, edit_user) - if edit_user_result.is_success: - logger.info(edit_user_result.message) - return ResponseUtil.success(msg=edit_user_result.message) - else: - logger.warning(edit_user_result.message) - return ResponseUtil.failure(msg=edit_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_user = EditUserModel( + **user_info.model_dump( + exclude_unset=True, + by_alias=True, + exclude={'role_ids', 'post_ids'} + ), + userId=current_user.user.user_id, + userName=current_user.user.user_name, + updateBy=current_user.user.user_name, + updateTime=datetime.now(), + roleIds=current_user.user.role_ids.split(',') if current_user.user.role_ids else [], + postIds=current_user.user.post_ids.split(',') if current_user.user.post_ids else [], + role=current_user.user.role + ) + edit_user_result = await UserService.edit_user_services(query_db, edit_user) + logger.info(edit_user_result.message) + + return ResponseUtil.success(msg=edit_user_result.message) @userController.put("/profile/updatePwd") @log_decorator(title='个人信息', business_type=BusinessType.UPDATE) async def reset_system_user_password(request: Request, reset_password: ResetPasswordModel = Depends(ResetPasswordModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - reset_user = ResetUserModel( - userId=current_user.user.user_id, - oldPassword=reset_password.old_password, - password=PwdUtil.get_password_hash(reset_password.new_password), - updateBy=current_user.user.user_name, - updateTime=datetime.now() - ) - reset_user_result = await UserService.reset_user_services(query_db, reset_user) - if reset_user_result.is_success: - logger.info(reset_user_result.message) - return ResponseUtil.success(msg=reset_user_result.message) - else: - logger.warning(reset_user_result.message) - return ResponseUtil.failure(msg=reset_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + reset_user = ResetUserModel( + userId=current_user.user.user_id, + oldPassword=reset_password.old_password, + password=PwdUtil.get_password_hash(reset_password.new_password), + updateBy=current_user.user.user_name, + updateTime=datetime.now() + ) + reset_user_result = await UserService.reset_user_services(query_db, reset_user) + logger.info(reset_user_result.message) + + return ResponseUtil.success(msg=reset_user_result.message) @userController.post("/importData", dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) @log_decorator(title='用户管理', business_type=BusinessType.IMPORT) async def batch_import_system_user(request: Request, file: UploadFile = File(...), update_support: bool = Query(alias='updateSupport'), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - batch_import_result = await UserService.batch_import_user_services(query_db, file, update_support, current_user) - if batch_import_result.is_success: - logger.info(batch_import_result.message) - return ResponseUtil.success(msg=batch_import_result.message) - else: - logger.warning(batch_import_result.message) - return ResponseUtil.failure(msg=batch_import_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + batch_import_result = await UserService.batch_import_user_services(query_db, file, update_support, current_user) + logger.info(batch_import_result.message) + + return ResponseUtil.success(msg=batch_import_result.message) @userController.post("/importTemplate", dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) async def export_system_user_template(request: Request, query_db: AsyncSession = Depends(get_db)): - try: - user_import_template_result = await UserService.get_user_import_template_services() - logger.info('获取成功') - return ResponseUtil.streaming(data=bytes2file_response(user_import_template_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + user_import_template_result = await UserService.get_user_import_template_services() + logger.info('获取成功') + + return ResponseUtil.streaming(data=bytes2file_response(user_import_template_result)) @userController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:user:export'))]) @log_decorator(title='用户管理', business_type=BusinessType.EXPORT) async def export_system_user_list(request: Request, user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): - try: - # 获取全量数据 - user_query_result = await UserService.get_user_list_services(query_db, user_page_query, data_scope_sql, is_page=False) - user_export_result = await UserService.export_user_list_services(user_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(user_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + user_query_result = await UserService.get_user_list_services(query_db, user_page_query, data_scope_sql, is_page=False) + user_export_result = await UserService.export_user_list_services(user_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(user_export_result)) @userController.get("/authRole/{user_id}", response_model=UserRoleResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]) async def get_system_allocated_role_list(request: Request, user_id: int, query_db: AsyncSession = Depends(get_db)): - try: - user_role_query = UserRoleQueryModel(userId=user_id) - user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services(query_db, user_role_query) - logger.info('获取成功') - return ResponseUtil.success(model_content=user_role_allocated_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + user_role_query = UserRoleQueryModel(userId=user_id) + user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services(query_db, user_role_query) + logger.info('获取成功') + + return ResponseUtil.success(model_content=user_role_allocated_query_result) @userController.put("/authRole", response_model=UserRoleResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @log_decorator(title='用户管理', business_type=BusinessType.GRANT) -async def update_system_role_user(request: Request, user_id: int = Query(alias='userId'), role_ids: str = Query(alias='roleIds'), query_db: AsyncSession = Depends(get_db)): - try: - add_user_role_result = await UserService.add_user_role_services(query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids)) - if add_user_role_result.is_success: - logger.info(add_user_role_result.message) - return ResponseUtil.success(msg=add_user_role_result.message) - else: - logger.warning(add_user_role_result.message) - return ResponseUtil.failure(msg=add_user_role_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def update_system_role_user(request: Request, user_id: int = Query(alias='userId'), role_ids: str = Query(alias='roleIds'), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): + if not current_user.user.admin: + await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql) + add_user_role_result = await UserService.add_user_role_services(query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids)) + logger.info(add_user_role_result.message) + + return ResponseUtil.success(msg=add_user_role_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py index 5a8a7c4..76e23a4 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py @@ -42,7 +42,10 @@ class UserDao: """ query_user_info = (await db.execute( select(SysUser) - .where(SysUser.del_flag == '0', SysUser.user_name == user.user_name) + .where(SysUser.del_flag == '0', + SysUser.user_name == user.user_name if user.user_name else True, + SysUser.phonenumber == user.phonenumber if user.phonenumber else True, + SysUser.email == user.email if user.email else True) .order_by(desc(SysUser.create_time)) .distinct() )).scalars().first() @@ -190,6 +193,7 @@ class UserDao: or_(SysUser.dept_id == query_object.dept_id, SysUser.dept_id.in_( select(SysDept.dept_id).where(func.find_in_set(query_object.dept_id, SysDept.ancestors)) )) if query_object.dept_id else True, + SysUser.user_id == query_object.user_id if query_object.user_id is not None else True, SysUser.user_name.like(f'%{query_object.user_name}%') if query_object.user_name else True, SysUser.nick_name.like(f'%{query_object.nick_name}%') if query_object.nick_name else True, SysUser.email.like(f'%{query_object.email}%') if query_object.email else True, diff --git a/ruoyi-fastapi-backend/module_admin/service/user_service.py b/ruoyi-fastapi-backend/module_admin/service/user_service.py index d1132de..4e9ab2a 100644 --- a/ruoyi-fastapi-backend/module_admin/service/user_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/user_service.py @@ -3,6 +3,8 @@ from module_admin.service.role_service import RoleService from module_admin.service.post_service import PostService, PostPageQueryModel from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.user_dao import * +from config.constant import CommonConstant +from exceptions.exception import ServiceException from utils.page_util import PageResponseModel from utils.pwd_util import * from utils.common_util import * @@ -38,6 +40,75 @@ class UserService: return user_list_result + @classmethod + async def check_user_allowed_services(cls, check_user: UserModel): + """ + 校验用户是否允许操作service + :param check_user: 用户信息 + :return: 校验结果 + """ + if check_user.admin: + raise ServiceException(message='不允许操作超级管理员用户') + else: + return CrudResponseModel(is_success=True, message='校验通过') + + @classmethod + async def check_user_data_scope_services(cls, query_db: AsyncSession, user_id: int, data_scope_sql: str): + """ + 校验用户数据权限service + :param query_db: orm对象 + :param user_id: 用户id + :param data_scope_sql: 数据权限对应的查询sql语句 + :return: 校验结果 + """ + users = await UserDao.get_user_list(query_db, UserPageQueryModel(userId=user_id), data_scope_sql, is_page=False) + if users: + return CrudResponseModel(is_success=True, message='校验通过') + else: + raise ServiceException(message='没有权限访问用户数据') + + @classmethod + async def check_user_name_unique_services(cls, query_db: AsyncSession, page_object: UserModel): + """ + 校验用户名是否唯一service + :param query_db: orm对象 + :param page_object: 用户对象 + :return: 校验结果 + """ + user_id = -1 if page_object.user_id is None else page_object.user_id + user = await UserDao.get_user_by_info(query_db, UserModel(userName=page_object.user_name)) + if user and user.user_id != user_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + + @classmethod + async def check_phonenumber_unique_services(cls, query_db: AsyncSession, page_object: UserModel): + """ + 校验用户手机号是否唯一service + :param query_db: orm对象 + :param page_object: 用户对象 + :return: 校验结果 + """ + user_id = -1 if page_object.user_id is None else page_object.user_id + user = await UserDao.get_user_by_info(query_db, UserModel(phonenumber=page_object.phonenumber)) + if user and user.user_id != user_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + + @classmethod + async def check_email_unique_services(cls, query_db: AsyncSession, page_object: UserModel): + """ + 校验用户邮箱是否唯一service + :param query_db: orm对象 + :param page_object: 用户对象 + :return: 校验结果 + """ + user_id = -1 if page_object.user_id is None else page_object.user_id + user = await UserDao.get_user_by_info(query_db, UserModel(email=page_object.email)) + if user and user.user_id != user_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_user_services(cls, query_db: AsyncSession, page_object: AddUserModel): """ @@ -47,9 +118,12 @@ class UserService: :return: 新增用户校验结果 """ add_user = UserModel(**page_object.model_dump(by_alias=True)) - user = await UserDao.get_user_by_info(query_db, UserModel(userName=page_object.user_name)) - if user: - result = dict(is_success=False, message='用户名已存在') + if not await cls.check_user_name_unique_services(query_db, page_object): + raise ServiceException(message=f'新增用户{page_object.user_name}失败,登录账号已存在') + elif page_object.phonenumber and not await cls.check_phonenumber_unique_services(query_db, page_object): + raise ServiceException(message=f'新增用户{page_object.user_name}失败,手机号码已存在') + elif page_object.email and not await cls.check_email_unique_services(query_db, page_object): + raise ServiceException(message=f'新增用户{page_object.user_name}失败,邮箱账号已存在') else: try: add_result = await UserDao.add_user_dao(query_db, add_user) @@ -61,13 +135,11 @@ class UserService: for post in page_object.post_ids: await UserDao.add_user_post_dao(query_db, UserPostModel(userId=user_id, postId=post)) await query_db.commit() - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def edit_user_services(cls, query_db: AsyncSession, page_object: EditUserModel): """ @@ -84,12 +156,14 @@ class UserService: if page_object.type == 'status' or page_object.type == 'avatar' or page_object.type == 'pwd': del edit_user['type'] user_info = await cls.user_detail_services(query_db, edit_user.get('user_id')) - if user_info: - if page_object.type != 'status' and page_object.type != 'avatar' and page_object.type == 'pwd' and user_info.data.user_name != page_object.user_name: - user = await UserDao.get_user_by_info(query_db, UserModel(userName=page_object.user_name)) - if user: - result = dict(is_success=False, message='用户名已存在') - return CrudResponseModel(**result) + if user_info.data and user_info.data.user_id: + if page_object.type != 'status' and page_object.type != 'avatar' and page_object.type != 'pwd': + if not await cls.check_user_name_unique_services(query_db, page_object): + raise ServiceException(message=f'修改用户{page_object.user_name}失败,登录账号已存在') + elif page_object.phonenumber and not await cls.check_phonenumber_unique_services(query_db, page_object): + raise ServiceException(message=f'修改用户{page_object.user_name}失败,手机号码已存在') + elif page_object.email and not await cls.check_email_unique_services(query_db, page_object): + raise ServiceException(message=f'修改用户{page_object.user_name}失败,邮箱账号已存在') try: await UserDao.edit_user_dao(query_db, edit_user) if page_object.type != 'status' and page_object.type != 'avatar' and page_object.type != 'pwd': @@ -102,14 +176,12 @@ class UserService: for post in page_object.post_ids: await UserDao.add_user_post_dao(query_db, UserPostModel(userId=page_object.user_id, postId=post)) await query_db.commit() - result = dict(is_success=True, message='更新成功') + return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='用户不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='用户不存在') @classmethod async def delete_user_services(cls, query_db: AsyncSession, page_object: DeleteUserModel): @@ -128,13 +200,12 @@ class UserService: await UserDao.delete_user_post_dao(query_db, UserPostModel(**user_id_dict)) await UserDao.delete_user_dao(query_db, UserModel(**user_id_dict)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入用户id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入用户id为空') @classmethod async def user_detail_services(cls, query_db: AsyncSession, user_id: Union[int, str]): @@ -210,8 +281,9 @@ class UserService: if page_object.old_password: user = (await UserDao.get_user_detail_by_id(query_db, user_id=page_object.user_id)).get('user_basic_info') if not PwdUtil.verify_password(page_object.old_password, user.password): - result = dict(is_success=False, message='旧密码不正确') - return CrudResponseModel(**result) + raise ServiceException(message='修改密码失败,旧密码错误') + elif PwdUtil.verify_password(page_object.password, user.password): + raise ServiceException(message='新密码不能与旧密码相同') else: del reset_user['old_password'] if page_object.sms_code and page_object.session_id: @@ -220,13 +292,11 @@ class UserService: try: await UserDao.edit_user_dao(query_db, reset_user) await query_db.commit() - result = dict(is_success=True, message='重置成功') + return CrudResponseModel(is_success=True, message='重置成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def batch_import_user_services(cls, query_db: AsyncSession, file: UploadFile, update_support: bool, current_user: CurrentUserModel): """ @@ -300,13 +370,11 @@ class UserService: else: await UserDao.add_user_dao(query_db, add_user) await query_db.commit() - result = dict(is_success=True, message='\n'.join(add_error_result)) + return CrudResponseModel(is_success=True, message='\n'.join(add_error_result)) except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @staticmethod async def get_user_import_template_services(): """ @@ -410,7 +478,7 @@ class UserService: else: await UserDao.add_user_role_dao(query_db, UserRoleModel(userId=page_object.user_id, roleId=role_id)) await query_db.commit() - result = dict(is_success=True, message='分配成功') + return CrudResponseModel(is_success=True, message='分配成功') except Exception as e: await query_db.rollback() raise e @@ -418,7 +486,7 @@ class UserService: try: await UserDao.delete_user_role_by_user_and_role_dao(query_db, UserRoleModel(userId=page_object.user_id)) await query_db.commit() - result = dict(is_success=True, message='分配成功') + return CrudResponseModel(is_success=True, message='分配成功') except Exception as e: await query_db.rollback() raise e @@ -432,14 +500,12 @@ class UserService: else: await UserDao.add_user_role_dao(query_db, UserRoleModel(userId=user_id, roleId=page_object.role_id)) await query_db.commit() - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='不满足新增条件') - - return CrudResponseModel(**result) + raise ServiceException(message='不满足新增条件') @classmethod async def delete_user_role_services(cls, query_db: AsyncSession, page_object: CrudUserRoleModel): @@ -454,7 +520,7 @@ class UserService: try: await UserDao.delete_user_role_by_user_and_role_dao(query_db, UserRoleModel(userId=page_object.user_id, roleId=page_object.role_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e @@ -464,16 +530,14 @@ class UserService: for user_id in user_id_list: await UserDao.delete_user_role_by_user_and_role_dao(query_db, UserRoleModel(userId=user_id, roleId=page_object.role_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='不满足删除条件') + raise ServiceException(message='不满足删除条件') else: - result = dict(is_success=False, message='传入用户角色关联信息为空') - - return CrudResponseModel(**result) + raise ServiceException(message='传入用户角色关联信息为空') @classmethod async def detail_user_role_services(cls, query_db: AsyncSession, page_object: UserRoleModel): -- Gitee From da54a7e5f58177b074a240d003ec8d2ae303dc64 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Tue, 9 Jul 2024 21:03:05 +0800 Subject: [PATCH 057/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E5=85=AC=E5=91=8A=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97?= =?UTF-8?q?service=E5=B1=82=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/notice_controller.py | 83 +++++++------------ .../module_admin/dao/notice_dao.py | 6 +- .../module_admin/service/notice_service.py | 65 +++++++++------ 3 files changed, 69 insertions(+), 85 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py index 9395bca..7e75306 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py @@ -17,79 +17,52 @@ noticeController = APIRouter(prefix='/system/notice', dependencies=[Depends(Logi @noticeController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:list'))]) async def get_system_notice_list(request: Request, notice_page_query: NoticePageQueryModel = Depends(NoticePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - # 获取分页数据 - notice_page_query_result = await NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=notice_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + notice_page_query_result = await NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=notice_page_query_result) @noticeController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))]) @ValidateFields(validate_model='add_notice') @log_decorator(title='通知公告管理', business_type=BusinessType.INSERT) async def add_system_notice(request: Request, add_notice: NoticeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_notice.create_by = current_user.user.user_name - add_notice.create_time = datetime.now() - add_notice.update_by = current_user.user.user_name - add_notice.update_time = datetime.now() - add_notice_result = await NoticeService.add_notice_services(query_db, add_notice) - if add_notice_result.is_success: - logger.info(add_notice_result.message) - return ResponseUtil.success(msg=add_notice_result.message) - else: - logger.warning(add_notice_result.message) - return ResponseUtil.failure(msg=add_notice_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_notice.create_by = current_user.user.user_name + add_notice.create_time = datetime.now() + add_notice.update_by = current_user.user.user_name + add_notice.update_time = datetime.now() + add_notice_result = await NoticeService.add_notice_services(query_db, add_notice) + logger.info(add_notice_result.message) + + return ResponseUtil.success(msg=add_notice_result.message) @noticeController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))]) @ValidateFields(validate_model='edit_notice') @log_decorator(title='通知公告管理', business_type=BusinessType.UPDATE) async def edit_system_notice(request: Request, edit_notice: NoticeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_notice.update_by = current_user.user.user_name - edit_notice.update_time = datetime.now() - edit_notice_result = await NoticeService.edit_notice_services(query_db, edit_notice) - if edit_notice_result.is_success: - logger.info(edit_notice_result.message) - return ResponseUtil.success(msg=edit_notice_result.message) - else: - logger.warning(edit_notice_result.message) - return ResponseUtil.failure(msg=edit_notice_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_notice.update_by = current_user.user.user_name + edit_notice.update_time = datetime.now() + edit_notice_result = await NoticeService.edit_notice_services(query_db, edit_notice) + logger.info(edit_notice_result.message) + + return ResponseUtil.success(msg=edit_notice_result.message) @noticeController.delete("/{notice_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))]) @log_decorator(title='通知公告管理', business_type=BusinessType.DELETE) async def delete_system_notice(request: Request, notice_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_notice = DeleteNoticeModel(noticeIds=notice_ids) - delete_notice_result = await NoticeService.delete_notice_services(query_db, delete_notice) - if delete_notice_result.is_success: - logger.info(delete_notice_result.message) - return ResponseUtil.success(msg=delete_notice_result.message) - else: - logger.warning(delete_notice_result.message) - return ResponseUtil.failure(msg=delete_notice_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_notice = DeleteNoticeModel(noticeIds=notice_ids) + delete_notice_result = await NoticeService.delete_notice_services(query_db, delete_notice) + logger.info(delete_notice_result.message) + + return ResponseUtil.success(msg=delete_notice_result.message) @noticeController.get("/{notice_id}", response_model=NoticeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:query'))]) async def query_detail_system_post(request: Request, notice_id: int, query_db: AsyncSession = Depends(get_db)): - try: - notice_detail_result = await NoticeService.notice_detail_services(query_db, notice_id) - logger.info(f'获取notice_id为{notice_id}的信息成功') - return ResponseUtil.success(data=notice_detail_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + notice_detail_result = await NoticeService.notice_detail_services(query_db, notice_id) + logger.info(f'获取notice_id为{notice_id}的信息成功') + + return ResponseUtil.success(data=notice_detail_result) diff --git a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py index fd1846f..d680aa7 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py @@ -36,9 +36,9 @@ class NoticeDao: """ notice_info = (await db.execute( select(SysNotice) - .where(SysNotice.notice_title == notice.notice_title if notice.notice_title else True, - SysNotice.notice_type == notice.notice_type if notice.notice_type else True, - SysNotice.notice_content == notice.notice_content if notice.notice_content else True) + .where(SysNotice.notice_title == notice.notice_title, + SysNotice.notice_type == notice.notice_type, + SysNotice.notice_content == notice.notice_content) )).scalars().first() return notice_info diff --git a/ruoyi-fastapi-backend/module_admin/service/notice_service.py b/ruoyi-fastapi-backend/module_admin/service/notice_service.py index 573fc39..1926ed7 100644 --- a/ruoyi-fastapi-backend/module_admin/service/notice_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/notice_service.py @@ -1,5 +1,7 @@ from module_admin.dao.notice_dao import * from module_admin.entity.vo.common_vo import CrudResponseModel +from config.constant import CommonConstant +from exceptions.exception import ServiceException from utils.common_util import export_list2excel, CamelCaseUtil @@ -21,6 +23,20 @@ class NoticeService: return notice_list_result + @classmethod + async def check_notice_unique_services(cls, query_db: AsyncSession, page_object: NoticeModel): + """ + 校验通知公告是否存在service + :param query_db: orm对象 + :param page_object: 通知公告对象 + :return: 校验结果 + """ + notice_id = -1 if page_object.notice_id is None else page_object.notice_id + notice = await NoticeDao.get_notice_detail_by_info(query_db, page_object) + if notice and notice.notice_id != notice_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_notice_services(cls, query_db: AsyncSession, page_object: NoticeModel): """ @@ -29,20 +45,17 @@ class NoticeService: :param page_object: 新增通知公告对象 :return: 新增通知公告校验结果 """ - notice = await NoticeDao.get_notice_detail_by_info(query_db, page_object) - if notice: - result = dict(is_success=False, message='通知公告已存在') + if not await cls.check_notice_unique_services(query_db, page_object): + raise ServiceException(message=f'新增通知公告{page_object.notice_title}失败,通知公告已存在') else: try: await NoticeDao.add_notice_dao(query_db, page_object) await query_db.commit() - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def edit_notice_services(cls, query_db: AsyncSession, page_object: NoticeModel): """ @@ -52,24 +65,20 @@ class NoticeService: :return: 编辑通知公告校验结果 """ edit_notice = page_object.model_dump(exclude_unset=True) - notice_info = await cls.notice_detail_services(query_db, edit_notice.get('notice_id')) - if notice_info: - if notice_info.notice_title != page_object.notice_title or notice_info.notice_type != page_object.notice_type or notice_info.notice_content != page_object.notice_content: - notice = await NoticeDao.get_notice_detail_by_info(query_db, page_object) - if notice: - result = dict(is_success=False, message='通知公告已存在') - return CrudResponseModel(**result) - try: - await NoticeDao.edit_notice_dao(query_db, edit_notice) - await query_db.commit() - result = dict(is_success=True, message='更新成功') - except Exception as e: - await query_db.rollback() - raise e + notice_info = await cls.notice_detail_services(query_db, page_object.notice_id) + if notice_info.notice_id: + if not await cls.check_notice_unique_services(query_db, page_object): + raise ServiceException(message=f'修改通知公告{page_object.notice_title}失败,通知公告已存在') + else: + try: + await NoticeDao.edit_notice_dao(query_db, edit_notice) + await query_db.commit() + return CrudResponseModel(is_success=True, message='更新成功') + except Exception as e: + await query_db.rollback() + raise e else: - result = dict(is_success=False, message='通知公告不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='通知公告不存在') @classmethod async def delete_notice_services(cls, query_db: AsyncSession, page_object: DeleteNoticeModel): @@ -85,13 +94,12 @@ class NoticeService: for notice_id in notice_id_list: await NoticeDao.delete_notice_dao(query_db, NoticeModel(noticeId=notice_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入通知公告id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入通知公告id为空') @classmethod async def notice_detail_services(cls, query_db: AsyncSession, notice_id: int): @@ -102,6 +110,9 @@ class NoticeService: :return: 通知公告id对应的信息 """ notice = await NoticeDao.get_notice_detail_by_id(query_db, notice_id=notice_id) - result = NoticeModel(**CamelCaseUtil.transform_result(notice)) + if notice: + result = NoticeModel(**CamelCaseUtil.transform_result(notice)) + else: + result = NoticeModel(**dict()) return result -- Gitee From e3efca9648722ac875b72c107282fc86daa6597c Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Tue, 9 Jul 2024 21:17:50 +0800 Subject: [PATCH 058/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/post_controler.py | 98 +++++++------------ .../module_admin/dao/post_dao.py | 19 +++- .../module_admin/service/post_service.py | 86 +++++++++++----- 3 files changed, 111 insertions(+), 92 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py index 97cd459..299d900 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py @@ -19,93 +19,63 @@ postController = APIRouter(prefix='/system/post', dependencies=[Depends(LoginSer @postController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:list'))]) async def get_system_post_list(request: Request, post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - # 获取分页数据 - post_page_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=post_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + post_page_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=post_page_query_result) @postController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))]) @ValidateFields(validate_model='add_post') @log_decorator(title='岗位管理', business_type=BusinessType.INSERT) async def add_system_post(request: Request, add_post: PostModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_post.create_by = current_user.user.user_name - add_post.create_time = datetime.now() - add_post.update_by = current_user.user.user_name - add_post.update_time = datetime.now() - add_post_result = await PostService.add_post_services(query_db, add_post) - if add_post_result.is_success: - logger.info(add_post_result.message) - return ResponseUtil.success(msg=add_post_result.message) - else: - logger.warning(add_post_result.message) - return ResponseUtil.failure(msg=add_post_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_post.create_by = current_user.user.user_name + add_post.create_time = datetime.now() + add_post.update_by = current_user.user.user_name + add_post.update_time = datetime.now() + add_post_result = await PostService.add_post_services(query_db, add_post) + logger.info(add_post_result.message) + + return ResponseUtil.success(msg=add_post_result.message) @postController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))]) @ValidateFields(validate_model='edit_post') @log_decorator(title='岗位管理', business_type=BusinessType.UPDATE) async def edit_system_post(request: Request, edit_post: PostModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_post.update_by = current_user.user.user_name - edit_post.update_time = datetime.now() - edit_post_result = await PostService.edit_post_services(query_db, edit_post) - if edit_post_result.is_success: - logger.info(edit_post_result.message) - return ResponseUtil.success(msg=edit_post_result.message) - else: - logger.warning(edit_post_result.message) - return ResponseUtil.failure(msg=edit_post_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_post.update_by = current_user.user.user_name + edit_post.update_time = datetime.now() + edit_post_result = await PostService.edit_post_services(query_db, edit_post) + logger.info(edit_post_result.message) + + return ResponseUtil.success(msg=edit_post_result.message) @postController.delete("/{post_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))]) @log_decorator(title='岗位管理', business_type=BusinessType.DELETE) async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_post = DeletePostModel(postIds=post_ids) - delete_post_result = await PostService.delete_post_services(query_db, delete_post) - if delete_post_result.is_success: - logger.info(delete_post_result.message) - return ResponseUtil.success(msg=delete_post_result.message) - else: - logger.warning(delete_post_result.message) - return ResponseUtil.failure(msg=delete_post_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_post = DeletePostModel(postIds=post_ids) + delete_post_result = await PostService.delete_post_services(query_db, delete_post) + logger.info(delete_post_result.message) + + return ResponseUtil.success(msg=delete_post_result.message) @postController.get("/{post_id}", response_model=PostModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:query'))]) async def query_detail_system_post(request: Request, post_id: int, query_db: AsyncSession = Depends(get_db)): - try: - post_detail_result = await PostService.post_detail_services(query_db, post_id) - logger.info(f'获取post_id为{post_id}的信息成功') - return ResponseUtil.success(data=post_detail_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + post_detail_result = await PostService.post_detail_services(query_db, post_id) + logger.info(f'获取post_id为{post_id}的信息成功') + + return ResponseUtil.success(data=post_detail_result) @postController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:post:export'))]) @log_decorator(title='岗位管理', business_type=BusinessType.EXPORT) async def export_system_post_list(request: Request, post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): - try: - # 获取全量数据 - post_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=False) - post_export_result = await PostService.export_post_list_services(post_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(post_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + post_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=False) + post_export_result = await PostService.export_post_list_services(post_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(post_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py index a1945ed..6478012 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py @@ -1,6 +1,7 @@ -from sqlalchemy import select, update, delete +from sqlalchemy import select, update, delete, func from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.post_do import SysPost +from module_admin.entity.do.user_do import SysUserPost from module_admin.entity.vo.post_vo import * from utils.page_util import PageUtil @@ -116,3 +117,19 @@ class PostDao: delete(SysPost) .where(SysPost.post_id.in_([post.post_id])) ) + + @classmethod + async def count_user_post_dao(cls, db: AsyncSession, post_id: int): + """ + 根据岗位id查询岗位关联的用户数量 + :param db: orm对象 + :param post_id: 岗位id + :return: 岗位关联的用户数量 + """ + user_post_count = (await db.execute( + select(func.count('*')) + .select_from(SysUserPost) + .where(SysUserPost.post_id == post_id) + )).scalar() + + return user_post_count diff --git a/ruoyi-fastapi-backend/module_admin/service/post_service.py b/ruoyi-fastapi-backend/module_admin/service/post_service.py index 13882ab..b9a088c 100644 --- a/ruoyi-fastapi-backend/module_admin/service/post_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/post_service.py @@ -1,5 +1,7 @@ from module_admin.dao.post_dao import * from module_admin.entity.vo.common_vo import CrudResponseModel +from config.constant import CommonConstant +from exceptions.exception import ServiceException from utils.common_util import export_list2excel, CamelCaseUtil @@ -20,6 +22,34 @@ class PostService: return post_list_result + @classmethod + async def check_post_name_unique_services(cls, query_db: AsyncSession, page_object: PostModel): + """ + 检查岗位名称是否唯一service + :param query_db: orm对象 + :param page_object: 岗位对象 + :return: 校验结果 + """ + post_id = -1 if page_object.post_id is None else page_object.post_id + post = await PostDao.get_post_detail_by_info(query_db, PostModel(postName=page_object.post_name)) + if post and post.post_id != post_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + + @classmethod + async def check_post_code_unique_services(cls, query_db: AsyncSession, page_object: PostModel): + """ + 检查岗位编码是否唯一service + :param query_db: orm对象 + :param page_object: 岗位对象 + :return: 校验结果 + """ + post_id = -1 if page_object.post_id is None else page_object.post_id + post = await PostDao.get_post_detail_by_info(query_db, PostModel(postCode=page_object.post_code)) + if post and post.post_id != post_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_post_services(cls, query_db: AsyncSession, page_object: PostModel): """ @@ -28,20 +58,19 @@ class PostService: :param page_object: 新增岗位对象 :return: 新增岗位校验结果 """ - post = await PostDao.get_post_detail_by_info(query_db, PostModel(postName=page_object.post_name)) - if post: - result = dict(is_success=False, message='岗位名称已存在') + if not await cls.check_post_name_unique_services(query_db, page_object): + raise ServiceException(message=f'新增岗位{page_object.post_name}失败,岗位名称已存在') + elif not await cls.check_post_code_unique_services(query_db, page_object): + raise ServiceException(message=f'新增岗位{page_object.post_name}失败,岗位编码已存在') else: try: await PostDao.add_post_dao(query_db, page_object) await query_db.commit() - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def edit_post_services(cls, query_db: AsyncSession, page_object: PostModel): """ @@ -51,24 +80,22 @@ class PostService: :return: 编辑岗位校验结果 """ edit_post = page_object.model_dump(exclude_unset=True) - post_info = await cls.post_detail_services(query_db, edit_post.get('post_id')) - if post_info: - if post_info.post_name != page_object.post_name: - post = await PostDao.get_post_detail_by_info(query_db, PostModel(postName=page_object.post_name)) - if post: - result = dict(is_success=False, message='岗位名称已存在') - return CrudResponseModel(**result) - try: - await PostDao.edit_post_dao(query_db, edit_post) - await query_db.commit() - result = dict(is_success=True, message='更新成功') - except Exception as e: - await query_db.rollback() - raise e + post_info = await cls.post_detail_services(query_db, page_object.post_id) + if post_info.post_id: + if not await cls.check_post_name_unique_services(query_db, page_object): + raise ServiceException(message=f'修改岗位{page_object.post_name}失败,岗位名称已存在') + elif not await cls.check_post_code_unique_services(query_db, page_object): + raise ServiceException(message=f'修改岗位{page_object.post_name}失败,岗位编码已存在') + else: + try: + await PostDao.edit_post_dao(query_db, edit_post) + await query_db.commit() + return CrudResponseModel(is_success=True, message='更新成功') + except Exception as e: + await query_db.rollback() + raise e else: - result = dict(is_success=False, message='岗位不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='岗位不存在') @classmethod async def delete_post_services(cls, query_db: AsyncSession, page_object: DeletePostModel): @@ -82,15 +109,17 @@ class PostService: post_id_list = page_object.post_ids.split(',') try: for post_id in post_id_list: + post = await cls.post_detail_services(query_db, int(post_id)) + if (await PostDao.count_user_post_dao(query_db, int(post_id))) > 0: + raise ServiceException(message=f'{post.post_name}已分配,不能删除') await PostDao.delete_post_dao(query_db, PostModel(postId=post_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入岗位id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入岗位id为空') @classmethod async def post_detail_services(cls, query_db: AsyncSession, post_id: int): @@ -101,7 +130,10 @@ class PostService: :return: 岗位id对应的信息 """ post = await PostDao.get_post_detail_by_id(query_db, post_id=post_id) - result = PostModel(**CamelCaseUtil.transform_result(post)) + if post: + result = PostModel(**CamelCaseUtil.transform_result(post)) + else: + result = PostModel(**dict()) return result -- Gitee From 4a17ffbebe131568c48baab84f044e258c1befdf Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 10:33:44 +0800 Subject: [PATCH 059/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=AD=97?= =?UTF-8?q?=E5=85=B8=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/dict_controller.py | 235 ++++++------------ .../module_admin/dao/dict_dao.py | 24 +- .../module_admin/service/dict_service.py | 163 +++++++----- 3 files changed, 201 insertions(+), 221 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py index ce508cf..7c7a6b3 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py @@ -18,226 +18,153 @@ dictController = APIRouter(prefix='/system/dict', dependencies=[Depends(LoginSer @dictController.get("/type/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]) async def get_system_dict_type_list(request: Request, dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - # 获取分页数据 - dict_type_page_query_result = await DictTypeService.get_dict_type_list_services(query_db, dict_type_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=dict_type_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + dict_type_page_query_result = await DictTypeService.get_dict_type_list_services(query_db, dict_type_page_query, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=dict_type_page_query_result) @dictController.post("/type", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) @ValidateFields(validate_model='add_dict_type') @log_decorator(title='字典管理', business_type=BusinessType.INSERT) async def add_system_dict_type(request: Request, add_dict_type: DictTypeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_dict_type.create_by = current_user.user.user_name - add_dict_type.create_time = datetime.now() - add_dict_type.update_by = current_user.user.user_name - add_dict_type.update_time = datetime.now() - add_dict_type_result = await DictTypeService.add_dict_type_services(request, query_db, add_dict_type) - if add_dict_type_result.is_success: - logger.info(add_dict_type_result.message) - return ResponseUtil.success(msg=add_dict_type_result.message) - else: - logger.warning(add_dict_type_result.message) - return ResponseUtil.failure(msg=add_dict_type_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_dict_type.create_by = current_user.user.user_name + add_dict_type.create_time = datetime.now() + add_dict_type.update_by = current_user.user.user_name + add_dict_type.update_time = datetime.now() + add_dict_type_result = await DictTypeService.add_dict_type_services(request, query_db, add_dict_type) + logger.info(add_dict_type_result.message) + + return ResponseUtil.success(msg=add_dict_type_result.message) @dictController.put("/type", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) @ValidateFields(validate_model='edit_dict_type') @log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def edit_system_dict_type(request: Request, edit_dict_type: DictTypeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_dict_type.update_by = current_user.user.user_name - edit_dict_type.update_time = datetime.now() - edit_dict_type_result = await DictTypeService.edit_dict_type_services(request, query_db, edit_dict_type) - if edit_dict_type_result.is_success: - logger.info(edit_dict_type_result.message) - return ResponseUtil.success(msg=edit_dict_type_result.message) - else: - logger.warning(edit_dict_type_result.message) - return ResponseUtil.failure(msg=edit_dict_type_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_dict_type.update_by = current_user.user.user_name + edit_dict_type.update_time = datetime.now() + edit_dict_type_result = await DictTypeService.edit_dict_type_services(request, query_db, edit_dict_type) + logger.info(edit_dict_type_result.message) + + return ResponseUtil.success(msg=edit_dict_type_result.message) @dictController.delete("/type/refreshCache", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends(get_db)): - try: - refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db) - if refresh_dict_result.is_success: - logger.info(refresh_dict_result.message) - return ResponseUtil.success(msg=refresh_dict_result.message) - else: - logger.warning(refresh_dict_result.message) - return ResponseUtil.failure(msg=refresh_dict_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db) + logger.info(refresh_dict_result.message) + + return ResponseUtil.success(msg=refresh_dict_result.message) @dictController.delete("/type/{dict_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @log_decorator(title='字典管理', business_type=BusinessType.DELETE) async def delete_system_dict_type(request: Request, dict_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids) - delete_dict_type_result = await DictTypeService.delete_dict_type_services(request, query_db, delete_dict_type) - if delete_dict_type_result.is_success: - logger.info(delete_dict_type_result.message) - return ResponseUtil.success(msg=delete_dict_type_result.message) - else: - logger.warning(delete_dict_type_result.message) - return ResponseUtil.failure(msg=delete_dict_type_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids) + delete_dict_type_result = await DictTypeService.delete_dict_type_services(request, query_db, delete_dict_type) + logger.info(delete_dict_type_result.message) + + return ResponseUtil.success(msg=delete_dict_type_result.message) @dictController.get("/type/optionselect", response_model=List[DictTypeModel]) async def query_system_dict_type_options(request: Request, query_db: AsyncSession = Depends(get_db)): - try: - dict_type_query_result = await DictTypeService.get_dict_type_list_services(query_db, DictTypePageQueryModel(**dict()), is_page=False) - logger.info(f'获取成功') - return ResponseUtil.success(data=dict_type_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + dict_type_query_result = await DictTypeService.get_dict_type_list_services(query_db, DictTypePageQueryModel(**dict()), is_page=False) + logger.info(f'获取成功') + + return ResponseUtil.success(data=dict_type_query_result) @dictController.get("/type/{dict_id}", response_model=DictTypeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))]) async def query_detail_system_dict_type(request: Request, dict_id: int, query_db: AsyncSession = Depends(get_db)): - try: - dict_type_detail_result = await DictTypeService.dict_type_detail_services(query_db, dict_id) - logger.info(f'获取dict_id为{dict_id}的信息成功') - return ResponseUtil.success(data=dict_type_detail_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + dict_type_detail_result = await DictTypeService.dict_type_detail_services(query_db, dict_id) + logger.info(f'获取dict_id为{dict_id}的信息成功') + + return ResponseUtil.success(data=dict_type_detail_result) @dictController.post("/type/export", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) @log_decorator(title='字典管理', business_type=BusinessType.EXPORT) async def export_system_dict_type_list(request: Request, dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): - try: - # 获取全量数据 - dict_type_query_result = await DictTypeService.get_dict_type_list_services(query_db, dict_type_page_query, is_page=False) - dict_type_export_result = await DictTypeService.export_dict_type_list_services(dict_type_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(dict_type_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + dict_type_query_result = await DictTypeService.get_dict_type_list_services(query_db, dict_type_page_query, is_page=False) + dict_type_export_result = await DictTypeService.export_dict_type_list_services(dict_type_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(dict_type_export_result)) @dictController.get("/data/type/{dict_type}") async def query_system_dict_type_data(request: Request, dict_type: str, query_db: AsyncSession = Depends(get_db)): - try: - # 获取全量数据 - dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type) - logger.info('获取成功') - return ResponseUtil.success(data=dict_data_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type) + logger.info('获取成功') + + return ResponseUtil.success(data=dict_data_query_result) @dictController.get("/data/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]) async def get_system_dict_data_list(request: Request, dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - # 获取分页数据 - dict_data_page_query_result = await DictDataService.get_dict_data_list_services(query_db, dict_data_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=dict_data_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + dict_data_page_query_result = await DictDataService.get_dict_data_list_services(query_db, dict_data_page_query, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=dict_data_page_query_result) @dictController.post("/data", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) @ValidateFields(validate_model='add_dict_data') @log_decorator(title='字典管理', business_type=BusinessType.INSERT) async def add_system_dict_data(request: Request, add_dict_data: DictDataModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_dict_data.create_by = current_user.user.user_name - add_dict_data.create_time = datetime.now() - add_dict_data.update_by = current_user.user.user_name - add_dict_data.update_time = datetime.now() - add_dict_data_result = await DictDataService.add_dict_data_services(request, query_db, add_dict_data) - if add_dict_data_result.is_success: - logger.info(add_dict_data_result.message) - return ResponseUtil.success(msg=add_dict_data_result.message) - else: - logger.warning(add_dict_data_result.message) - return ResponseUtil.failure(msg=add_dict_data_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_dict_data.create_by = current_user.user.user_name + add_dict_data.create_time = datetime.now() + add_dict_data.update_by = current_user.user.user_name + add_dict_data.update_time = datetime.now() + add_dict_data_result = await DictDataService.add_dict_data_services(request, query_db, add_dict_data) + logger.info(add_dict_data_result.message) + + return ResponseUtil.success(msg=add_dict_data_result.message) @dictController.put("/data", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) @ValidateFields(validate_model='edit_dict_data') @log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def edit_system_dict_data(request: Request, edit_dict_data: DictDataModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_dict_data.update_by = current_user.user.user_name - edit_dict_data.update_time = datetime.now() - edit_dict_data_result = await DictDataService.edit_dict_data_services(request, query_db, edit_dict_data) - if edit_dict_data_result.is_success: - logger.info(edit_dict_data_result.message) - return ResponseUtil.success(msg=edit_dict_data_result.message) - else: - logger.warning(edit_dict_data_result.message) - return ResponseUtil.failure(msg=edit_dict_data_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_dict_data.update_by = current_user.user.user_name + edit_dict_data.update_time = datetime.now() + edit_dict_data_result = await DictDataService.edit_dict_data_services(request, query_db, edit_dict_data) + logger.info(edit_dict_data_result.message) + + return ResponseUtil.success(msg=edit_dict_data_result.message) @dictController.delete("/data/{dict_codes}", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @log_decorator(title='字典管理', business_type=BusinessType.DELETE) async def delete_system_dict_data(request: Request, dict_codes: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes) - delete_dict_data_result = await DictDataService.delete_dict_data_services(request, query_db, delete_dict_data) - if delete_dict_data_result.is_success: - logger.info(delete_dict_data_result.message) - return ResponseUtil.success(msg=delete_dict_data_result.message) - else: - logger.warning(delete_dict_data_result.message) - return ResponseUtil.failure(msg=delete_dict_data_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes) + delete_dict_data_result = await DictDataService.delete_dict_data_services(request, query_db, delete_dict_data) + logger.info(delete_dict_data_result.message) + + return ResponseUtil.success(msg=delete_dict_data_result.message) @dictController.get("/data/{dict_code}", response_model=DictDataModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))]) async def query_detail_system_dict_data(request: Request, dict_code: int, query_db: AsyncSession = Depends(get_db)): - try: - detail_dict_data_result = await DictDataService.dict_data_detail_services(query_db, dict_code) - logger.info(f'获取dict_code为{dict_code}的信息成功') - return ResponseUtil.success(data=detail_dict_data_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + detail_dict_data_result = await DictDataService.dict_data_detail_services(query_db, dict_code) + logger.info(f'获取dict_code为{dict_code}的信息成功') + + return ResponseUtil.success(data=detail_dict_data_result) @dictController.post("/data/export", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) @log_decorator(title='字典管理', business_type=BusinessType.EXPORT) async def export_system_dict_data_list(request: Request, dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): - try: - # 获取全量数据 - dict_data_query_result = await DictDataService.get_dict_data_list_services(query_db, dict_data_page_query, is_page=False) - dict_data_export_result = await DictDataService.export_dict_data_list_services(dict_data_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(dict_data_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + dict_data_query_result = await DictDataService.get_dict_data_list_services(query_db, dict_data_page_query, is_page=False) + dict_data_export_result = await DictDataService.export_dict_data_list_services(dict_data_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(dict_data_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py index 603d347..3342f6b 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py @@ -1,4 +1,4 @@ -from sqlalchemy import select, update, delete, and_ +from sqlalchemy import select, update, delete, and_, func from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.dict_do import SysDictType, SysDictData from module_admin.entity.vo.dict_vo import * @@ -149,9 +149,9 @@ class DictDataDao: """ dict_data_info = (await db.execute( select(SysDictData) - .where(SysDictData.dict_type == dict_data.dict_type if dict_data.dict_type else True, - SysDictData.dict_label == dict_data.dict_label if dict_data.dict_label else True, - SysDictData.dict_value == dict_data.dict_value if dict_data.dict_value else True) + .where(SysDictData.dict_type == dict_data.dict_type, + SysDictData.dict_label == dict_data.dict_label, + SysDictData.dict_value == dict_data.dict_value) )).scalars().first() return dict_data_info @@ -233,3 +233,19 @@ class DictDataDao: delete(SysDictData) .where(SysDictData.dict_code.in_([dict_data.dict_code])) ) + + @classmethod + async def count_dict_data_dao(cls, db: AsyncSession, dict_type: str): + """ + 根据字典类型查询字典类型关联的字典数据数量 + :param db: orm对象 + :param dict_type: 字典类型 + :return: 字典类型关联的字典数据数量 + """ + dict_data_count = (await db.execute( + select(func.count('*')) + .select_from(SysDictData) + .where(SysDictData.dict_type == dict_type) + )).scalar() + + return dict_data_count diff --git a/ruoyi-fastapi-backend/module_admin/service/dict_service.py b/ruoyi-fastapi-backend/module_admin/service/dict_service.py index b07a465..9d373ae 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dict_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dict_service.py @@ -1,8 +1,10 @@ from fastapi import Request import json -from config.env import RedisInitKeyConfig from module_admin.dao.dict_dao import * from module_admin.entity.vo.common_vo import CrudResponseModel +from config.constant import CommonConstant +from config.env import RedisInitKeyConfig +from exceptions.exception import ServiceException from utils.common_util import export_list2excel, CamelCaseUtil @@ -24,6 +26,20 @@ class DictTypeService: return dict_type_list_result + @classmethod + async def check_dict_type_unique_services(cls, query_db: AsyncSession, page_object: DictTypeModel): + """ + 校验字典类型称是否唯一service + :param query_db: orm对象 + :param page_object: 字典类型对象 + :return: 校验结果 + """ + dict_id = -1 if page_object.dict_id is None else page_object.dict_id + dict_type = await DictTypeDao.get_dict_type_detail_by_info(query_db, DictTypeModel(dictType=page_object.dict_type)) + if dict_type and dict_type.dict_id != dict_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_dict_type_services(cls, request: Request, query_db: AsyncSession, page_object: DictTypeModel): """ @@ -33,14 +49,13 @@ class DictTypeService: :param page_object: 新增岗位对象 :return: 新增字典类型校验结果 """ - dict_type = await DictTypeDao.get_dict_type_detail_by_info(query_db, DictTypeModel(dictType=page_object.dict_type)) - if dict_type: - result = dict(is_success=False, message='字典类型已存在') + if not await cls.check_dict_type_unique_services(query_db, page_object): + raise ServiceException(message=f'新增字典{page_object.dict_name}失败,字典类型已存在') else: try: await DictTypeDao.add_dict_type_dao(query_db, page_object) await query_db.commit() - await DictDataService.init_cache_sys_dict_services(query_db, request.app.state.redis) + await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", '') result = dict(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() @@ -58,31 +73,29 @@ class DictTypeService: :return: 编辑字典类型校验结果 """ edit_dict_type = page_object.model_dump(exclude_unset=True) - dict_type_info = await cls.dict_type_detail_services(query_db, edit_dict_type.get('dict_id')) - if dict_type_info: - if dict_type_info.dict_type != page_object.dict_type or dict_type_info.dict_name != page_object.dict_name: - dict_type = await DictTypeDao.get_dict_type_detail_by_info(query_db, DictTypeModel(dictType=page_object.dict_type)) - if dict_type: - result = dict(is_success=False, message='字典类型已存在') - return CrudResponseModel(**result) - try: - if dict_type_info.dict_type != page_object.dict_type: + dict_type_info = await cls.dict_type_detail_services(query_db, page_object.dict_id) + if dict_type_info.dict_id: + if not await cls.check_dict_type_unique_services(query_db, page_object): + raise ServiceException(message=f'修改字典{page_object.dict_name}失败,字典类型已存在') + else: + try: query_dict_data = DictDataPageQueryModel(dictType=dict_type_info.dict_type) dict_data_list = await DictDataDao.get_dict_data_list(query_db, query_dict_data, is_page=False) - for dict_data in dict_data_list: - edit_dict_data = DictDataModel(dictCode=dict_data.dict_code, dictType=page_object.dict_type, updateBy=page_object.update_by).model_dump(exclude_unset=True) - await DictDataDao.edit_dict_data_dao(query_db, edit_dict_data) - await DictTypeDao.edit_dict_type_dao(query_db, edit_dict_type) - await query_db.commit() - await DictDataService.init_cache_sys_dict_services(query_db, request.app.state.redis) - result = dict(is_success=True, message='更新成功') - except Exception as e: - await query_db.rollback() - raise e + if dict_type_info.dict_type != page_object.dict_type: + for dict_data in dict_data_list: + edit_dict_data = DictDataModel(dictCode=dict_data.dict_code, dictType=page_object.dict_type, updateBy=page_object.update_by).model_dump(exclude_unset=True) + await DictDataDao.edit_dict_data_dao(query_db, edit_dict_data) + await DictTypeDao.edit_dict_type_dao(query_db, edit_dict_type) + await query_db.commit() + if dict_type_info.dict_type != page_object.dict_type: + dict_data = [CamelCaseUtil.transform_result(row) for row in dict_data_list if row] + await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", json.dumps(dict_data, ensure_ascii=False, default=str)) + return CrudResponseModel(is_success=True, message='更新成功') + except Exception as e: + await query_db.rollback() + raise e else: - result = dict(is_success=False, message='字典类型不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='字典类型不存在') @classmethod async def delete_dict_type_services(cls, request: Request, query_db: AsyncSession, page_object: DeleteDictTypeModel): @@ -96,17 +109,22 @@ class DictTypeService: if page_object.dict_ids.split(','): dict_id_list = page_object.dict_ids.split(',') try: + delete_dict_type_list = [] for dict_id in dict_id_list: - await DictTypeDao.delete_dict_type_dao(query_db, DictTypeModel(dictId=dict_id)) + dict_type_into = await cls.dict_type_detail_services(query_db, int(dict_id)) + if (await DictDataDao.count_dict_data_dao(query_db, dict_type_into.dict_type)) > 0: + raise ServiceException(message=f'{dict_type_into.dict_name}已分配,不能删除') + await DictTypeDao.delete_dict_type_dao(query_db, DictTypeModel(dictId=int(dict_id))) + delete_dict_type_list.append(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{dict_type_into.dict_type}") await query_db.commit() - await DictDataService.init_cache_sys_dict_services(query_db, request.app.state.redis) - result = dict(is_success=True, message='删除成功') + if delete_dict_type_list: + await request.app.state.redis.delete(*delete_dict_type_list) + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入字典类型id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入字典类型id为空') @classmethod async def dict_type_detail_services(cls, query_db: AsyncSession, dict_id: int): @@ -117,7 +135,10 @@ class DictTypeService: :return: 字典类型id对应的信息 """ dict_type = await DictTypeDao.get_dict_type_detail_by_id(query_db, dict_id=dict_id) - result = DictTypeModel(**CamelCaseUtil.transform_result(dict_type)) + if dict_type: + result = DictTypeModel(**CamelCaseUtil.transform_result(dict_type)) + else: + result = DictTypeModel(**dict()) return result @@ -232,6 +253,20 @@ class DictDataService: return CamelCaseUtil.transform_result(result) + @classmethod + async def check_dict_data_unique_services(cls, query_db: AsyncSession, page_object: DictDataModel): + """ + 校验字典数据是否唯一service + :param query_db: orm对象 + :param page_object: 字典数据对象 + :return: 校验结果 + """ + dict_code = -1 if page_object.dict_code is None else page_object.dict_code + dict_data = await DictDataDao.get_dict_data_detail_by_info(query_db, page_object) + if dict_data and dict_data.dict_code != dict_code: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_dict_data_services(cls, request: Request, query_db: AsyncSession, page_object: DictDataModel): """ @@ -241,21 +276,19 @@ class DictDataService: :param page_object: 新增岗位对象 :return: 新增字典数据校验结果 """ - dict_data = await DictDataDao.get_dict_data_detail_by_info(query_db, page_object) - if dict_data: - result = dict(is_success=False, message='字典数据已存在') + if not await cls.check_dict_data_unique_services(query_db, page_object): + raise ServiceException(message=f'新增字典数据{page_object.dict_label}失败,{page_object.dict_type}下已存在该字典数据') else: try: await DictDataDao.add_dict_data_dao(query_db, page_object) await query_db.commit() - await cls.init_cache_sys_dict_services(query_db, request.app.state.redis) - result = dict(is_success=True, message='新增成功') + dict_data_list = await cls.query_dict_data_list_services(query_db, page_object.dict_type) + await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str)) + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def edit_dict_data_services(cls, request: Request, query_db: AsyncSession, page_object: DictDataModel): """ @@ -266,25 +299,22 @@ class DictDataService: :return: 编辑字典数据校验结果 """ edit_data_type = page_object.model_dump(exclude_unset=True) - dict_data_info = await cls.dict_data_detail_services(query_db, edit_data_type.get('dict_code')) - if dict_data_info: - if dict_data_info.dict_type != page_object.dict_type or dict_data_info.dict_label != page_object.dict_label or dict_data_info.dict_value != page_object.dict_value: - dict_data = await DictDataDao.get_dict_data_detail_by_info(query_db, page_object) - if dict_data: - result = dict(is_success=False, message='字典数据已存在') - return CrudResponseModel(**result) - try: - await DictDataDao.edit_dict_data_dao(query_db, edit_data_type) - await query_db.commit() - await cls.init_cache_sys_dict_services(query_db, request.app.state.redis) - result = dict(is_success=True, message='更新成功') - except Exception as e: - await query_db.rollback() - raise e + dict_data_info = await cls.dict_data_detail_services(query_db, page_object.dict_code) + if dict_data_info.dict_code: + if not await cls.check_dict_data_unique_services(query_db, page_object): + raise ServiceException(message=f'新增字典数据{page_object.dict_label}失败,{page_object.dict_type}下已存在该字典数据') + else: + try: + await DictDataDao.edit_dict_data_dao(query_db, edit_data_type) + await query_db.commit() + dict_data_list = await cls.query_dict_data_list_services(query_db, page_object.dict_type) + await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str)) + return CrudResponseModel(is_success=True, message='更新成功') + except Exception as e: + await query_db.rollback() + raise e else: - result = dict(is_success=False, message='字典数据不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='字典数据不存在') @classmethod async def delete_dict_data_services(cls, request: Request, query_db: AsyncSession, page_object: DeleteDictDataModel): @@ -298,17 +328,21 @@ class DictDataService: if page_object.dict_codes.split(','): dict_code_list = page_object.dict_codes.split(',') try: + delete_dict_type_list = [] for dict_code in dict_code_list: + dict_data = await cls.dict_data_detail_services(query_db, int(dict_code)) await DictDataDao.delete_dict_data_dao(query_db, DictDataModel(dictCode=dict_code)) + delete_dict_type_list.append(dict_data.dict_type) await query_db.commit() - await cls.init_cache_sys_dict_services(query_db, request.app.state.redis) - result = dict(is_success=True, message='删除成功') + for dict_type in list(set(delete_dict_type_list)): + dict_data_list = await cls.query_dict_data_list_services(query_db, dict_type) + await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{dict_type}", json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str)) + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入字典数据id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入字典数据id为空') @classmethod async def dict_data_detail_services(cls, query_db: AsyncSession, dict_code: int): @@ -319,7 +353,10 @@ class DictDataService: :return: 字典数据id对应的信息 """ dict_data = await DictDataDao.get_dict_data_detail_by_id(query_db, dict_code=dict_code) - result = DictDataModel(**CamelCaseUtil.transform_result(dict_data)) + if dict_data: + result = DictDataModel(**CamelCaseUtil.transform_result(dict_data)) + else: + result = DictDataModel(**dict()) return result -- Gitee From 013ea257314db315c1a6a3928bcfac37839dc582 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 11:08:07 +0800 Subject: [PATCH 060/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/menu_controller.py | 103 ++++++------------ .../module_admin/dao/menu_dao.py | 34 +++++- .../module_admin/service/menu_service.py | 76 ++++++++----- ruoyi-fastapi-backend/utils/string_util.py | 12 ++ 4 files changed, 129 insertions(+), 96 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py index ddda0ea..3baa142 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py @@ -16,100 +16,67 @@ menuController = APIRouter(prefix='/system/menu', dependencies=[Depends(LoginSer @menuController.get("/treeselect") async def get_system_menu_tree(request: Request, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - menu_query_result = await MenuService.get_menu_tree_services(query_db, current_user) - logger.info('获取成功') - return ResponseUtil.success(data=menu_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + menu_query_result = await MenuService.get_menu_tree_services(query_db, current_user) + logger.info('获取成功') + + return ResponseUtil.success(data=menu_query_result) @menuController.get("/roleMenuTreeselect/{role_id}") async def get_system_role_menu_tree(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - role_menu_query_result = await MenuService.get_role_menu_tree_services(query_db, role_id, current_user) - logger.info('获取成功') - return ResponseUtil.success(model_content=role_menu_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + role_menu_query_result = await MenuService.get_role_menu_tree_services(query_db, role_id, current_user) + logger.info('获取成功') + + return ResponseUtil.success(model_content=role_menu_query_result) @menuController.get("/list", response_model=List[MenuModel], dependencies=[Depends(CheckUserInterfaceAuth('system:menu:list'))]) async def get_system_menu_list(request: Request, menu_query: MenuQueryModel = Depends(MenuQueryModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - menu_query_result = await MenuService.get_menu_list_services(query_db, menu_query, current_user) - logger.info('获取成功') - return ResponseUtil.success(data=menu_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + menu_query_result = await MenuService.get_menu_list_services(query_db, menu_query, current_user) + logger.info('获取成功') + + return ResponseUtil.success(data=menu_query_result) @menuController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) @ValidateFields(validate_model='add_menu') @log_decorator(title='菜单管理', business_type=BusinessType.INSERT) async def add_system_menu(request: Request, add_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_menu.create_by = current_user.user.user_name - add_menu.create_time = datetime.now() - add_menu.update_by = current_user.user.user_name - add_menu.update_time = datetime.now() - add_menu_result = await MenuService.add_menu_services(query_db, add_menu) - if add_menu_result.is_success: - logger.info(add_menu_result.message) - return ResponseUtil.success(msg=add_menu_result.message) - else: - logger.warning(add_menu_result.message) - return ResponseUtil.failure(msg=add_menu_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_menu.create_by = current_user.user.user_name + add_menu.create_time = datetime.now() + add_menu.update_by = current_user.user.user_name + add_menu.update_time = datetime.now() + add_menu_result = await MenuService.add_menu_services(query_db, add_menu) + logger.info(add_menu_result.message) + + return ResponseUtil.success(msg=add_menu_result.message) @menuController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) @ValidateFields(validate_model='edit_menu') @log_decorator(title='菜单管理', business_type=BusinessType.UPDATE) async def edit_system_menu(request: Request, edit_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_menu.update_by = current_user.user.user_name - edit_menu.update_time = datetime.now() - edit_menu_result = await MenuService.edit_menu_services(query_db, edit_menu) - if edit_menu_result.is_success: - logger.info(edit_menu_result.message) - return ResponseUtil.success(msg=edit_menu_result.message) - else: - logger.warning(edit_menu_result.message) - return ResponseUtil.failure(msg=edit_menu_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_menu.update_by = current_user.user.user_name + edit_menu.update_time = datetime.now() + edit_menu_result = await MenuService.edit_menu_services(query_db, edit_menu) + logger.info(edit_menu_result.message) + + return ResponseUtil.success(msg=edit_menu_result.message) @menuController.delete("/{menu_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) @log_decorator(title='菜单管理', business_type=BusinessType.DELETE) async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_menu = DeleteMenuModel(menuIds=menu_ids) - delete_menu_result = await MenuService.delete_menu_services(query_db, delete_menu) - if delete_menu_result.is_success: - logger.info(delete_menu_result.message) - return ResponseUtil.success(msg=delete_menu_result.message) - else: - logger.warning(delete_menu_result.message) - return ResponseUtil.failure(msg=delete_menu_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_menu = DeleteMenuModel(menuIds=menu_ids) + delete_menu_result = await MenuService.delete_menu_services(query_db, delete_menu) + logger.info(delete_menu_result.message) + + return ResponseUtil.success(msg=delete_menu_result.message) @menuController.get("/{menu_id}", response_model=MenuModel, dependencies=[Depends(CheckUserInterfaceAuth('system:menu:query'))]) async def query_detail_system_menu(request: Request, menu_id: int, query_db: AsyncSession = Depends(get_db)): - try: - menu_detail_result = await MenuService.menu_detail_services(query_db, menu_id) - logger.info(f'获取menu_id为{menu_id}的信息成功') - return ResponseUtil.success(data=menu_detail_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + menu_detail_result = await MenuService.menu_detail_services(query_db, menu_id) + logger.info(f'获取menu_id为{menu_id}的信息成功') + + return ResponseUtil.success(data=menu_detail_result) diff --git a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py index b600dfa..522022c 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py @@ -1,4 +1,4 @@ -from sqlalchemy import select, update, delete, and_ +from sqlalchemy import select, update, delete, and_, func from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.menu_do import SysMenu from module_admin.entity.do.user_do import SysUser, SysUserRole @@ -156,3 +156,35 @@ class MenuDao: delete(SysMenu) .where(SysMenu.menu_id.in_([menu.menu_id])) ) + + @classmethod + async def has_child_by_menu_id_dao(cls, db: AsyncSession, menu_id: int): + """ + 根据菜单id查询菜单关联子菜单的数量 + :param db: orm对象 + :param menu_id: 菜单id + :return: 菜单关联子菜单的数量 + """ + menu_count = (await db.execute( + select(func.count('*')) + .select_from(SysMenu) + .where(SysMenu.menu_id == menu_id) + )).scalar() + + return menu_count + + @classmethod + async def check_menu_exist_role_dao(cls, db: AsyncSession, menu_id: int): + """ + 根据菜单id查询菜单关联角色数量 + :param db: orm对象 + :param menu_id: 菜单id + :return: 菜单关联角色数量 + """ + role_count = (await db.execute( + select(func.count('*')) + .select_from(SysRoleMenu) + .where(SysRoleMenu.menu_id == menu_id) + )).scalar() + + return role_count diff --git a/ruoyi-fastapi-backend/module_admin/service/menu_service.py b/ruoyi-fastapi-backend/module_admin/service/menu_service.py index 5f89c90..4769311 100644 --- a/ruoyi-fastapi-backend/module_admin/service/menu_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/menu_service.py @@ -3,7 +3,10 @@ from module_admin.entity.vo.role_vo import RoleMenuQueryModel from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.role_dao import RoleDao from module_admin.dao.menu_dao import * +from config.constant import CommonConstant, MenuConstant +from exceptions.exception import ServiceException from utils.common_util import CamelCaseUtil +from utils.string_util import StringUtil class MenuService: @@ -57,6 +60,20 @@ class MenuService: return CamelCaseUtil.transform_result(menu_list_result) + @classmethod + async def check_menu_name_unique_services(cls, query_db: AsyncSession, page_object: MenuModel): + """ + 校验菜单名称是否唯一service + :param query_db: orm对象 + :param page_object: 菜单对象 + :return: 校验结果 + """ + menu_id = -1 if page_object.menu_id is None else page_object.menu_id + menu = await MenuDao.get_menu_detail_by_info(query_db, MenuModel(menuName=page_object.menu_name)) + if menu and menu.menu_id != menu_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_menu_services(cls, query_db: AsyncSession, page_object: MenuModel): """ @@ -65,20 +82,19 @@ class MenuService: :param page_object: 新增菜单对象 :return: 新增菜单校验结果 """ - menu = await MenuDao.get_menu_detail_by_info(query_db, MenuModel(parentId=page_object.parent_id, menuName=page_object.menu_name, menuType=page_object.menu_type)) - if menu: - result = dict(is_success=False, message='同一目录下不允许存在同名同类型的菜单') + if not await cls.check_menu_name_unique_services(query_db, page_object): + raise ServiceException(message=f'新增菜单{page_object.post_name}失败,菜单名称已存在') + elif page_object.is_frame == MenuConstant.YES_FRAME and not StringUtil.is_http(page_object.path): + raise ServiceException(message=f'新增菜单{page_object.post_name}失败,地址必须以http(s)://开头') else: try: await MenuDao.add_menu_dao(query_db, page_object) await query_db.commit() - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def edit_menu_services(cls, query_db: AsyncSession, page_object: MenuModel): """ @@ -88,24 +104,24 @@ class MenuService: :return: 编辑菜单校验结果 """ edit_menu = page_object.model_dump(exclude_unset=True) - menu_info = await cls.menu_detail_services(query_db, edit_menu.get('menu_id')) - if menu_info: - if menu_info.parent_id != page_object.parent_id or menu_info.menu_name != page_object.menu_name or menu_info.menu_type != page_object.menu_type: - menu = await MenuDao.get_menu_detail_by_info(query_db, MenuModel(parentId=page_object.parent_id, menuName=page_object.menu_name, menuType=page_object.menu_type)) - if menu: - result = dict(is_success=False, message='同一目录下不允许存在同名同类型的菜单') - return CrudResponseModel(**result) - try: - await MenuDao.edit_menu_dao(query_db, edit_menu) - await query_db.commit() - result = dict(is_success=True, message='更新成功') - except Exception as e: - await query_db.rollback() - raise e + menu_info = await cls.menu_detail_services(query_db, page_object.menu_id) + if menu_info.menu_id: + if not await cls.check_menu_name_unique_services(query_db, page_object): + raise ServiceException(message=f'修改菜单{page_object.post_name}失败,菜单名称已存在') + elif page_object.is_frame == MenuConstant.YES_FRAME and not StringUtil.is_http(page_object.path): + raise ServiceException(message=f'修改菜单{page_object.post_name}失败,地址必须以http(s)://开头') + elif page_object.menu_id == page_object.parent_id: + raise ServiceException(message=f'修改菜单{page_object.post_name}失败,上级菜单不能选择自己') + else: + try: + await MenuDao.edit_menu_dao(query_db, edit_menu) + await query_db.commit() + return CrudResponseModel(is_success=True, message='更新成功') + except Exception as e: + await query_db.rollback() + raise e else: - result = dict(is_success=False, message='菜单不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='菜单不存在') @classmethod async def delete_menu_services(cls, query_db: AsyncSession, page_object: DeleteMenuModel): @@ -119,15 +135,18 @@ class MenuService: menu_id_list = page_object.menu_ids.split(',') try: for menu_id in menu_id_list: + if (await MenuDao.has_child_by_menu_id_dao(query_db, int(menu_id))) > 0: + raise ServiceException(message='存在子菜单,不允许删除') + elif (await MenuDao.check_menu_exist_role_dao(query_db, int(menu_id))) > 0: + raise ServiceException(message='菜单已分配,不允许删除') await MenuDao.delete_menu_dao(query_db, MenuModel(menuId=menu_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入菜单id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入菜单id为空') @classmethod async def menu_detail_services(cls, query_db: AsyncSession, menu_id: int): @@ -138,7 +157,10 @@ class MenuService: :return: 菜单id对应的信息 """ menu = await MenuDao.get_menu_detail_by_id(query_db, menu_id=menu_id) - result = MenuModel(**CamelCaseUtil.transform_result(menu)) + if menu: + result = MenuModel(**CamelCaseUtil.transform_result(menu)) + else: + result = MenuModel(**dict()) return result diff --git a/ruoyi-fastapi-backend/utils/string_util.py b/ruoyi-fastapi-backend/utils/string_util.py index a03fd6b..738e0ac 100644 --- a/ruoyi-fastapi-backend/utils/string_util.py +++ b/ruoyi-fastapi-backend/utils/string_util.py @@ -1,3 +1,6 @@ +from config.constant import CommonConstant + + class StringUtil: """ 字符串工具类 @@ -29,3 +32,12 @@ class StringUtil: :return: 校验结果 """ return string is None or len(string) == 0 + + @classmethod + def is_http(cls, link: str): + """ + 判断是否为http(s)://开头 + :param link: 链接 + :return: 是否为http(s)://开头 + """ + return link.startswith(CommonConstant.HTTP) or link.startswith(CommonConstant.HTTPS) -- Gitee From 1bd4bba2f5c90b4f7d314ccd84ba44bce11a1a2d Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 17:11:03 +0800 Subject: [PATCH 061/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/role_controller.py | 274 ++++++++---------- .../controller/user_controller.py | 4 +- .../module_admin/dao/dept_dao.py | 2 +- .../module_admin/dao/role_dao.py | 53 +++- .../module_admin/dao/user_dao.py | 32 +- .../module_admin/entity/vo/role_vo.py | 2 +- .../module_admin/service/role_service.py | 147 ++++++---- 7 files changed, 275 insertions(+), 239 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index a27eb91..1dd4d16 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -21,216 +21,170 @@ roleController = APIRouter(prefix='/system/role', dependencies=[Depends(LoginSer @roleController.get("/deptTree/{role_id}", dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]) async def get_system_role_dept_tree(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): - try: - dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql) - role_dept_query_result = await RoleService.get_role_dept_tree_services(query_db, role_id) - role_dept_query_result.depts = dept_query_result - logger.info('获取成功') - return ResponseUtil.success(model_content=role_dept_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql) + role_dept_query_result = await RoleService.get_role_dept_tree_services(query_db, role_id) + role_dept_query_result.depts = dept_query_result + logger.info('获取成功') + + return ResponseUtil.success(model_content=role_dept_query_result) @roleController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]) -async def get_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - role_page_query_result = await RoleService.get_role_list_services(query_db, role_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=role_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def get_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('role_query.columns'))): + role_page_query_result = await RoleService.get_role_list_services(query_db, role_page_query, data_scope_sql, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=role_page_query_result) @roleController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))]) @ValidateFields(validate_model='add_role') @log_decorator(title='角色管理', business_type=BusinessType.INSERT) async def add_system_role(request: Request, add_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_role.create_by = current_user.user.user_name - add_role.create_time = datetime.now() - add_role.update_by = current_user.user.user_name - add_role.update_time = datetime.now() - add_role_result = await RoleService.add_role_services(query_db, add_role) - if add_role_result.is_success: - logger.info(add_role_result.message) - return ResponseUtil.success(msg=add_role_result.message) - else: - logger.warning(add_role_result.message) - return ResponseUtil.failure(msg=add_role_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_role.create_by = current_user.user.user_name + add_role.create_time = datetime.now() + add_role.update_by = current_user.user.user_name + add_role.update_time = datetime.now() + add_role_result = await RoleService.add_role_services(query_db, add_role) + logger.info(add_role_result.message) + + return ResponseUtil.success(msg=add_role_result.message) @roleController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @ValidateFields(validate_model='edit_role') @log_decorator(title='角色管理', business_type=BusinessType.UPDATE) -async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_role.update_by = current_user.user.user_name - edit_role.update_time = datetime.now() - edit_role_result = await RoleService.edit_role_services(query_db, edit_role) - if edit_role_result.is_success: - logger.info(edit_role_result.message) - return ResponseUtil.success(msg=edit_role_result.message) - else: - logger.warning(edit_role_result.message) - return ResponseUtil.failure(msg=edit_role_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): + await RoleService.check_role_allowed_services(edit_role) + if not current_user.user.admin: + await RoleService.check_role_data_scope_services(query_db, edit_role.role_id, data_scope_sql) + edit_role.update_by = current_user.user.user_name + edit_role.update_time = datetime.now() + edit_role_result = await RoleService.edit_role_services(query_db, edit_role) + logger.info(edit_role_result.message) + + return ResponseUtil.success(msg=edit_role_result.message) @roleController.put("/dataScope", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) -async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - role_data_scope.update_by = current_user.user.user_name - role_data_scope.update_time = datetime.now() - role_data_scope_result = await RoleService.role_datascope_services(query_db, role_data_scope) - if role_data_scope_result.is_success: - logger.info(role_data_scope_result.message) - return ResponseUtil.success(msg=role_data_scope_result.message) - else: - logger.warning(role_data_scope_result.message) - return ResponseUtil.failure(msg=role_data_scope_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): + await RoleService.check_role_allowed_services(role_data_scope) + if not current_user.user.admin: + await RoleService.check_role_data_scope_services(query_db, role_data_scope.role_id, data_scope_sql) + edit_role = AddRoleModel( + roleId=role_data_scope.role_id, + dataScope=role_data_scope.data_scope, + deptIds=role_data_scope.dept_ids, + deptCheckStrictly=role_data_scope.dept_check_strictly, + updateBy=current_user.user.user_name, + updateTime=datetime.now() + ) + role_data_scope_result = await RoleService.role_datascope_services(query_db, edit_role) + logger.info(role_data_scope_result.message) + + return ResponseUtil.success(msg=role_data_scope_result.message) @roleController.delete("/{role_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))]) @log_decorator(title='角色管理', business_type=BusinessType.DELETE) -async def delete_system_role(request: Request, role_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - delete_role = DeleteRoleModel( - roleIds=role_ids, - updateBy=current_user.user.user_name, - updateTime=datetime.now() - ) - delete_role_result = await RoleService.delete_role_services(query_db, delete_role) - if delete_role_result.is_success: - logger.info(delete_role_result.message) - return ResponseUtil.success(msg=delete_role_result.message) - else: - logger.warning(delete_role_result.message) - return ResponseUtil.failure(msg=delete_role_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def delete_system_role(request: Request, role_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): + role_id_list = role_ids.split(',') + for role_id in role_id_list: + await RoleService.check_role_allowed_services(RoleModel(roleId=int(role_id))) + if not current_user.user.admin: + await RoleService.check_role_data_scope_services(query_db, int(role_id), data_scope_sql) + delete_role = DeleteRoleModel( + roleIds=role_ids, + updateBy=current_user.user.user_name, + updateTime=datetime.now() + ) + delete_role_result = await RoleService.delete_role_services(query_db, delete_role) + logger.info(delete_role_result.message) + + return ResponseUtil.success(msg=delete_role_result.message) @roleController.get("/{role_id}", response_model=RoleModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]) -async def query_detail_system_role(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db)): - try: - role_detail_result = await RoleService.role_detail_services(query_db, role_id) - logger.info(f'获取role_id为{role_id}的信息成功') - return ResponseUtil.success(data=role_detail_result.model_dump(by_alias=True)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def query_detail_system_role(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): + if not current_user.user.admin: + await RoleService.check_role_data_scope_services(query_db, role_id, data_scope_sql) + role_detail_result = await RoleService.role_detail_services(query_db, role_id) + logger.info(f'获取role_id为{role_id}的信息成功') + + return ResponseUtil.success(data=role_detail_result.model_dump(by_alias=True)) @roleController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))]) @log_decorator(title='角色管理', business_type=BusinessType.EXPORT) -async def export_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): - try: - # 获取全量数据 - role_query_result = await RoleService.get_role_list_services(query_db, role_page_query, is_page=False) - role_export_result = await RoleService.export_role_list_services(role_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(role_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def export_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('role_query'))): + # 获取全量数据 + role_query_result = await RoleService.get_role_list_services(query_db, role_page_query, data_scope_sql, is_page=False) + role_export_result = await RoleService.export_role_list_services(role_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(role_export_result)) @roleController.put("/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.UPDATE) -async def reset_system_role_status(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_role.update_by = current_user.user.user_name - edit_role.update_time = datetime.now() - edit_role.type = 'status' - edit_role_result = await RoleService.edit_role_services(query_db, edit_role) - if edit_role_result.is_success: - logger.info(edit_role_result.message) - return ResponseUtil.success(msg=edit_role_result.message) - else: - logger.warning(edit_role_result.message) - return ResponseUtil.failure(msg=edit_role_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def reset_system_role_status(request: Request, change_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): + await RoleService.check_role_allowed_services(change_role) + if not current_user.user.admin: + await RoleService.check_role_data_scope_services(query_db, change_role.role_id, data_scope_sql) + edit_role = AddRoleModel( + roleId=change_role.role_id, + status=change_role.status, + updateBy=current_user.user.user_name, + updateTime=datetime.now(), + type='status' + ) + edit_role_result = await RoleService.edit_role_services(query_db, edit_role) + logger.info(edit_role_result.message) + + return ResponseUtil.success(msg=edit_role_result.message) @roleController.get("/authUser/allocatedList", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]) -async def get_system_allocated_user_list(request: Request, user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services(query_db, user_role, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=role_user_allocated_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def get_system_allocated_user_list(request: Request, user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): + role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services(query_db, user_role, data_scope_sql, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=role_user_allocated_page_query_result) @roleController.get("/authUser/unallocatedList", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]) -async def get_system_unallocated_user_list(request: Request, user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services(query_db, user_role, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=role_user_unallocated_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def get_system_unallocated_user_list(request: Request, user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): + role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services(query_db, user_role, data_scope_sql, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=role_user_unallocated_page_query_result) @roleController.put("/authUser/selectAll", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) -async def add_system_role_user(request: Request, add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user) - if add_role_user_result.is_success: - logger.info(add_role_user_result.message) - return ResponseUtil.success(msg=add_role_user_result.message) - else: - logger.warning(add_role_user_result.message) - return ResponseUtil.failure(msg=add_role_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def add_system_role_user(request: Request, add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): + if not current_user.user.admin: + await RoleService.check_role_data_scope_services(query_db, add_role_user.role_id, data_scope_sql) + add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user) + logger.info(add_role_user_result.message) + + return ResponseUtil.success(msg=add_role_user_result.message) @roleController.put("/authUser/cancel", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) async def cancel_system_role_user(request: Request, cancel_user_role: CrudUserRoleModel, query_db: AsyncSession = Depends(get_db)): - try: - cancel_user_role_result = await UserService.delete_user_role_services(query_db, cancel_user_role) - if cancel_user_role_result.is_success: - logger.info(cancel_user_role_result.message) - return ResponseUtil.success(msg=cancel_user_role_result.message) - else: - logger.warning(cancel_user_role_result.message) - return ResponseUtil.failure(msg=cancel_user_role_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + cancel_user_role_result = await UserService.delete_user_role_services(query_db, cancel_user_role) + logger.info(cancel_user_role_result.message) + + return ResponseUtil.success(msg=cancel_user_role_result.message) @roleController.put("/authUser/cancelAll", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) async def batch_cancel_system_role_user(request: Request, batch_cancel_user_role: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - batch_cancel_user_role_result = await UserService.delete_user_role_services(query_db, batch_cancel_user_role) - if batch_cancel_user_role_result.is_success: - logger.info(batch_cancel_user_role_result.message) - return ResponseUtil.success(msg=batch_cancel_user_role_result.message) - else: - logger.warning(batch_cancel_user_role_result.message) - return ResponseUtil.failure(msg=batch_cancel_user_role_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + batch_cancel_user_role_result = await UserService.delete_user_role_services(query_db, batch_cancel_user_role) + logger.info(batch_cancel_user_role_result.message) + + return ResponseUtil.success(msg=batch_cancel_user_role_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index cbe510c..c79c1cb 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -76,9 +76,9 @@ async def delete_system_user(request: Request, user_ids: str, query_db: AsyncSes return ResponseUtil.failure(msg='当前登录用户不能删除') for user_id in user_id_list: + await UserService.check_user_allowed_services(UserModel(userId=int(user_id))) if not current_user.user.admin: - await UserService.check_user_allowed_services(UserModel(userId=int(user_id))) - await UserService.check_user_data_scope_services(query_db, int(user_id), data_scope_sql) + await UserService.check_user_data_scope_services(query_db, int(user_id), data_scope_sql) delete_user = DeleteUserModel( userIds=user_ids, updateBy=current_user.user.user_name, diff --git a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py index e15278b..44a2f20 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py @@ -1,4 +1,4 @@ -from sqlalchemy import select, update, delete +from sqlalchemy import select, update, delete, or_, func from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.dept_do import SysDept from module_admin.entity.do.role_do import SysRoleDept diff --git a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py index 1d5a1fa..b65b4a1 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py @@ -1,5 +1,6 @@ -from sqlalchemy import select, update, delete, desc, func +from sqlalchemy import select, update, delete, desc, and_, or_, func from sqlalchemy.ext.asyncio import AsyncSession +from module_admin.entity.do.user_do import SysUser, SysUserRole from module_admin.entity.do.role_do import SysRole, SysRoleMenu, SysRoleDept from module_admin.entity.do.dept_do import SysDept from module_admin.entity.vo.role_vo import * @@ -96,15 +97,19 @@ class RoleDao: return role_info @classmethod - async def get_role_list(cls, db: AsyncSession, query_object: RolePageQueryModel, is_page: bool = False): + async def get_role_list(cls, db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False): """ 根据查询参数获取角色列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param data_scope_sql: 数据权限对应的查询sql语句 :param is_page: 是否开启分页 :return: 角色列表信息对象 """ - query = select(SysRole) \ + role_query = (select(SysRole, SysUser.user_id, SysDept.dept_id) + .join(SysUserRole, SysUserRole.role_id == SysRole.role_id, isouter=True) + .join(SysUser, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) .where(SysRole.del_flag == '0', SysRole.role_name.like(f'%{query_object.role_name}%') if query_object.role_name else True, SysRole.role_key.like(f'%{query_object.role_key}%') if query_object.role_key else True, @@ -112,9 +117,12 @@ class RoleDao: SysRole.create_time.between( datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True) \ - .order_by(SysRole.role_sort) \ - .distinct() + if query_object.begin_time and query_object.end_time else True) + .order_by(SysRole.role_sort)).subquery() + query = select(SysRole) \ + .select_from(role_query) \ + .join(SysRole, SysRole.role_id == role_query.columns.role_id) \ + .where(eval(data_scope_sql)).distinct() role_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return role_list @@ -201,18 +209,23 @@ class RoleDao: ) @classmethod - async def get_role_dept_dao(cls, db: AsyncSession, role_id: int): + async def get_role_dept_dao(cls, db: AsyncSession, role: RoleModel): """ 根据角色id获取角色部门关联列表信息 :param db: orm对象 - :param role_id: 角色id + :param role: 角色对象 :return: 角色部门关联列表信息 """ role_dept_query_all = (await db.execute( - select(SysRoleDept) - .where(SysRoleDept.role_id == role_id, - ~select(SysDept).where(func.find_in_set(SysRoleDept.dept_id, SysDept.ancestors)).exists()) - .distinct() + select(SysDept) + .join(SysRoleDept, SysRoleDept.dept_id == SysDept.dept_id) + .where(SysRoleDept.role_id == role.role_id, + ~SysDept.dept_id.in_( + select(SysDept.parent_id) + .select_from(SysDept) + .join(SysRoleDept, and_(SysRoleDept.dept_id == SysDept.dept_id, SysRoleDept.role_id == role.role_id)) + ) if role.dept_check_strictly else True) + .order_by(SysDept.parent_id, SysDept.order_num) )).scalars().all() return role_dept_query_all @@ -240,3 +253,19 @@ class RoleDao: delete(SysRoleDept) .where(SysRoleDept.role_id.in_([role_dept.role_id])) ) + + @classmethod + async def count_user_role_dao(cls, db: AsyncSession, role_id: int): + """ + 根据角色id查询角色关联用户数量 + :param db: orm对象 + :param role_id: 角色id + :return: 角色关联用户数量 + """ + user_count = (await db.execute( + select(func.count('*')) + .select_from(SysUserRole) + .where(SysUserRole.role_id == role_id) + )).scalar() + + return user_count diff --git a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py index 76e23a4..f75deac 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py @@ -277,46 +277,56 @@ class UserDao: return allocated_role_list @classmethod - async def get_user_role_allocated_list_by_role_id(cls, db: AsyncSession, query_object: UserRolePageQueryModel, - is_page: bool = False): + async def get_user_role_allocated_list_by_role_id(cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False): """ 根据角色id获取已分配的用户列表信息 :param db: orm对象 :param query_object: 用户角色查询对象 + :param data_scope_sql: 数据权限对应的查询sql语句 :param is_page: 是否开启分页 :return: 角色已分配的用户列表信息 """ query = select(SysUser) \ + .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) \ + .join(SysUserRole, SysUserRole.user_id == SysUser.user_id, isouter=True) \ + .join(SysRole, SysRole.role_id == SysUserRole.role_id, isouter=True) \ .where(SysUser.del_flag == '0', - SysUser.user_id != 1, SysUser.user_name == query_object.user_name if query_object.user_name else True, SysUser.phonenumber == query_object.phonenumber if query_object.phonenumber else True, - SysUser.user_id.in_( - select(SysUserRole.user_id).where(SysUserRole.role_id == query_object.role_id) - )) \ + SysRole.role_id == query_object.role_id, + eval(data_scope_sql)) \ .distinct() allocated_user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return allocated_user_list @classmethod - async def get_user_role_unallocated_list_by_role_id(cls, db: AsyncSession, query_object: UserRolePageQueryModel, - is_page: bool = False): + async def get_user_role_unallocated_list_by_role_id(cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False): """ 根据角色id获取未分配的用户列表信息 :param db: orm对象 :param query_object: 用户角色查询对象 + :param data_scope_sql: 数据权限对应的查询sql语句 :param is_page: 是否开启分页 :return: 角色未分配的用户列表信息 """ query = select(SysUser) \ + .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) \ + .join(SysUserRole, SysUserRole.user_id == SysUser.user_id, isouter=True) \ + .join(SysRole, SysRole.role_id == SysUserRole.role_id, isouter=True) \ .where(SysUser.del_flag == '0', - SysUser.user_id != 1, SysUser.user_name == query_object.user_name if query_object.user_name else True, SysUser.phonenumber == query_object.phonenumber if query_object.phonenumber else True, + or_(SysRole.role_id != query_object.role_id, SysRole.role_id is None), ~SysUser.user_id.in_( - select(SysUserRole.user_id).where(SysUserRole.role_id == query_object.role_id) - )) \ + select(SysUser.user_id) + .select_from(SysUser) + .join(SysUserRole, + and_(SysUserRole.user_id == SysUser.user_id, + SysUserRole.role_id == query_object.role_id) + ) + ), + eval(data_scope_sql)) \ .distinct() unallocated_user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py index ab809bc..aa69c3f 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py @@ -16,7 +16,7 @@ class RoleModel(BaseModel): role_name: Optional[str] = Field(default=None, description='角色名称') role_key: Optional[str] = Field(default=None, description='角色权限字符串') role_sort: Optional[int] = Field(default=None, description='显示顺序') - data_scope: Optional[Literal['1', '2', '3', '4']] = Field(default=None, description='数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)') + data_scope: Optional[Literal['1', '2', '3', '4', '5']] = Field(default=None, description='数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限)') menu_check_strictly: Optional[Union[int, bool]] = Field(default=None, description='菜单树选择项是否关联显示') dept_check_strictly: Optional[Union[int, bool]] = Field(default=None, description='部门树选择项是否关联显示') status: Optional[Literal['0', '1']] = Field(default=None, description='角色状态(0正常 1停用)') diff --git a/ruoyi-fastapi-backend/module_admin/service/role_service.py b/ruoyi-fastapi-backend/module_admin/service/role_service.py index 745d3db..aa0a54d 100644 --- a/ruoyi-fastapi-backend/module_admin/service/role_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/role_service.py @@ -2,6 +2,8 @@ from module_admin.entity.vo.user_vo import UserInfoModel, UserRolePageQueryModel from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.user_dao import UserDao from module_admin.dao.role_dao import * +from config.constant import CommonConstant +from exceptions.exception import ServiceException from utils.page_util import PageResponseModel from utils.common_util import export_list2excel, CamelCaseUtil @@ -30,7 +32,8 @@ class RoleService: :param role_id: 角色id :return: 当前角色id的部门树信息对象 """ - role_dept_list = await RoleDao.get_role_dept_dao(query_db, role_id) + role = await cls.role_detail_services(query_db, role_id) + role_dept_list = await RoleDao.get_role_dept_dao(query_db, role) checked_keys = [row.dept_id for row in role_dept_list] result = RoleDeptQueryModel( checkedKeys=checked_keys @@ -39,18 +42,74 @@ class RoleService: return result @classmethod - async def get_role_list_services(cls, query_db: AsyncSession, query_object: RolePageQueryModel, is_page: bool = False): + async def get_role_list_services(cls, query_db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False): """ 获取角色列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param data_scope_sql: 数据权限对应的查询sql语句 :param is_page: 是否开启分页 :return: 角色列表信息对象 """ - role_list_result = await RoleDao.get_role_list(query_db, query_object, is_page) + role_list_result = await RoleDao.get_role_list(query_db, query_object, data_scope_sql, is_page) return role_list_result + @classmethod + async def check_role_allowed_services(cls, check_role: RoleModel): + """ + 校验角色是否允许操作service + :param check_role: 角色信息 + :return: 校验结果 + """ + if check_role.admin: + raise ServiceException(message='不允许操作超级管理员角色') + else: + return CrudResponseModel(is_success=True, message='校验通过') + + @classmethod + async def check_role_data_scope_services(cls, query_db: AsyncSession, role_id: int, data_scope_sql: str): + """ + 校验角色是否有数据权限service + :param query_db: orm对象 + :param role_id: 角色id + :param data_scope_sql: 数据权限对应的查询sql语句 + :return: 校验结果 + """ + roles = await RoleDao.get_role_list(query_db, RolePageQueryModel(roleId=role_id), data_scope_sql, is_page=False) + if roles: + return CrudResponseModel(is_success=True, message='校验通过') + else: + raise ServiceException(message='没有权限访问角色数据') + + @classmethod + async def check_role_name_unique_services(cls, query_db: AsyncSession, page_object: RoleModel): + """ + 校验角色名称是否唯一service + :param query_db: orm对象 + :param page_object: 角色对象 + :return: 校验结果 + """ + role_id = -1 if page_object.role_id is None else page_object.role_id + role = await RoleDao.get_role_by_info(query_db, RoleModel(roleName=page_object.role_name)) + if role and role.role_id != role_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + + @classmethod + async def check_role_key_unique_services(cls, query_db: AsyncSession, page_object: RoleModel): + """ + 校验角色权限字符是否唯一service + :param query_db: orm对象 + :param page_object: 角色对象 + :return: 校验结果 + """ + role_id = -1 if page_object.role_id is None else page_object.role_id + role = await RoleDao.get_role_by_info(query_db, RoleModel(roleKey=page_object.role_key)) + if role and role.role_id != role_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_role_services(cls, query_db: AsyncSession, page_object: AddRoleModel): """ @@ -60,12 +119,10 @@ class RoleService: :return: 新增角色校验结果 """ add_role = RoleModel(**page_object.model_dump(by_alias=True)) - role_name = await RoleDao.get_role_by_info(query_db, RoleModel(roleName=page_object.role_name)) - role_key = await RoleDao.get_role_by_info(query_db, RoleModel(roleKey=page_object.role_key)) - if role_name: - result = dict(is_success=False, message='角色名称已存在') - elif role_key: - result = dict(is_success=False, message='权限字符已存在') + if not await cls.check_role_name_unique_services(query_db, page_object): + raise ServiceException(message=f'新增角色{page_object.post_name}失败,角色名称已存在') + elif not await cls.check_role_key_unique_services(query_db, page_object): + raise ServiceException(message=f'新增角色{page_object.post_name}失败,角色权限已存在') else: try: add_result = await RoleDao.add_role_dao(query_db, add_role) @@ -74,13 +131,11 @@ class RoleService: for menu in page_object.menu_ids: await RoleDao.add_role_menu_dao(query_db, RoleMenuModel(roleId=role_id, menuId=menu)) await query_db.commit() - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def edit_role_services(cls, query_db: AsyncSession, page_object: AddRoleModel): """ @@ -96,16 +151,11 @@ class RoleService: del edit_role['type'] role_info = await cls.role_detail_services(query_db, edit_role.get('role_id')) if role_info: - if page_object.type != 'status' and role_info.role_name != page_object.role_name: - role_name = await RoleDao.get_role_by_info(query_db, RoleModel(roleName=page_object.role_name)) - if role_name: - result = dict(is_success=False, message='角色名称已存在') - return CrudResponseModel(**result) - elif page_object.type != 'status' and role_info.role_key != page_object.role_key: - role_key = await RoleDao.get_role_by_info(query_db, RoleModel(roleKey=page_object.role_key)) - if role_key: - result = dict(is_success=False, message='权限字符已存在') - return CrudResponseModel(**result) + if page_object.type != 'status': + if not await cls.check_role_name_unique_services(query_db, page_object): + raise ServiceException(message=f'修改角色{page_object.post_name}失败,角色名称已存在') + elif not await cls.check_role_key_unique_services(query_db, page_object): + raise ServiceException(message=f'修改角色{page_object.post_name}失败,角色权限已存在') try: await RoleDao.edit_role_dao(query_db, edit_role) if page_object.type != 'status': @@ -114,14 +164,12 @@ class RoleService: for menu in page_object.menu_ids: await RoleDao.add_role_menu_dao(query_db, RoleMenuModel(roleId=page_object.role_id, menuId=menu)) await query_db.commit() - result = dict(is_success=True, message='更新成功') + return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='角色不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='角色不存在') @classmethod async def role_datascope_services(cls, query_db: AsyncSession, page_object: AddRoleModel): @@ -131,20 +179,9 @@ class RoleService: :param page_object: 角色数据权限对象 :return: 分配角色数据权限结果 """ - edit_role = page_object.model_dump(exclude_unset=True, exclude={'admin'}) - del edit_role['dept_ids'] - role_info = await cls.role_detail_services(query_db, edit_role.get('role_id')) - if role_info: - if role_info.role_name != page_object.role_name: - role_name = await RoleDao.get_role_by_info(query_db, RoleModel(roleName=page_object.role_name)) - if role_name: - result = dict(is_success=False, message='角色名称已存在') - return CrudResponseModel(**result) - elif role_info.role_key != page_object.role_key: - role_key = await RoleDao.get_role_by_info(query_db, RoleModel(roleKey=page_object.role_key)) - if role_key: - result = dict(is_success=False, message='权限字符已存在') - return CrudResponseModel(**result) + edit_role = page_object.model_dump(exclude_unset=True, exclude={'admin', 'dept_ids'}) + role_info = await cls.role_detail_services(query_db, page_object.role_id) + if role_info.role_id: try: await RoleDao.edit_role_dao(query_db, edit_role) await RoleDao.delete_role_dept_dao(query_db, RoleDeptModel(roleId=page_object.role_id)) @@ -152,14 +189,12 @@ class RoleService: for dept in page_object.dept_ids: await RoleDao.add_role_dept_dao(query_db, RoleDeptModel(roleId=page_object.role_id, deptId=dept)) await query_db.commit() - result = dict(is_success=True, message='分配成功') + return CrudResponseModel(is_success=True, message='分配成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='角色不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='角色不存在') @classmethod async def delete_role_services(cls, query_db: AsyncSession, page_object: DeleteRoleModel): @@ -173,17 +208,20 @@ class RoleService: role_id_list = page_object.role_ids.split(',') try: for role_id in role_id_list: + role = await cls.role_detail_services(query_db, int(role_id)) + if (await RoleDao.count_user_role_dao(query_db, int(role_id))) > 0: + raise ServiceException(message=f'角色{role.role_name}已分配,不能删除') role_id_dict = dict(roleId=role_id, updateBy=page_object.update_by, updateTime=page_object.update_time) await RoleDao.delete_role_menu_dao(query_db, RoleMenuModel(**role_id_dict)) + await RoleDao.delete_role_dept_dao(query_db, RoleDeptModel(**role_id_dict)) await RoleDao.delete_role_dao(query_db, RoleModel(**role_id_dict)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入角色id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入角色id为空') @classmethod async def role_detail_services(cls, query_db: AsyncSession, role_id: int): @@ -194,7 +232,10 @@ class RoleService: :return: 角色id对应的信息 """ role = await RoleDao.get_role_detail_by_id(query_db, role_id=role_id) - result = RoleModel(**CamelCaseUtil.transform_result(role)) + if role: + result = RoleModel(**CamelCaseUtil.transform_result(role)) + else: + result = RoleModel(**dict()) return result @@ -232,15 +273,16 @@ class RoleService: return binary_data @classmethod - async def get_role_user_allocated_list_services(cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, is_page: bool = False): + async def get_role_user_allocated_list_services(cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False): """ 根据角色id获取已分配用户列表 :param query_db: orm对象 :param page_object: 用户关联角色对象 + :param data_scope_sql: 数据权限对应的查询sql语句 :param is_page: 是否开启分页 :return: 已分配用户列表 """ - query_user_list = await UserDao.get_user_role_allocated_list_by_role_id(query_db, page_object, is_page) + query_user_list = await UserDao.get_user_role_allocated_list_by_role_id(query_db, page_object, data_scope_sql, is_page) allocated_list = PageResponseModel( **{ **query_user_list.model_dump(by_alias=True), @@ -251,15 +293,16 @@ class RoleService: return allocated_list @classmethod - async def get_role_user_unallocated_list_services(cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, is_page: bool = False): + async def get_role_user_unallocated_list_services(cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False): """ 根据角色id获取未分配用户列表 :param query_db: orm对象 :param page_object: 用户关联角色对象 + :param data_scope_sql: 数据权限对应的查询sql语句 :param is_page: 是否开启分页 :return: 未分配用户列表 """ - query_user_list = await UserDao.get_user_role_unallocated_list_by_role_id(query_db, page_object, is_page) + query_user_list = await UserDao.get_user_role_unallocated_list_by_role_id(query_db, page_object, data_scope_sql, is_page) unallocated_list = PageResponseModel( **{ **query_user_list.model_dump(by_alias=True), -- Gitee From 55babcee4c1e8dd937875905124e18828ec83df0 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 20:47:51 +0800 Subject: [PATCH 062/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=9B=91=E6=8E=A7=E6=A8=A1=E5=9D=97=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/server_controller.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/server_controller.py b/ruoyi-fastapi-backend/module_admin/controller/server_controller.py index c21db20..86c970a 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/server_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/server_controller.py @@ -12,11 +12,8 @@ serverController = APIRouter(prefix='/monitor/server', dependencies=[Depends(Log @serverController.get("", response_model=ServerMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:server:list'))]) async def get_monitor_server_info(request: Request): - try: - # 获取全量数据 - server_info_query_result = await ServerService.get_server_monitor_info() - logger.info('获取成功') - return ResponseUtil.success(data=server_info_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + server_info_query_result = await ServerService.get_server_monitor_info() + logger.info('获取成功') + + return ResponseUtil.success(data=server_info_query_result) -- Gitee From 4d31fe7a92c47738f7054fcc872e7e887eb38568 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 20:50:39 +0800 Subject: [PATCH 063/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=9C=A8?= =?UTF-8?q?=E7=BA=BF=E7=94=A8=E6=88=B7=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/online_controller.py | 30 +++++++------------ .../module_admin/service/online_service.py | 6 ++-- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py index 71531ea..be9669c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py @@ -16,28 +16,18 @@ onlineController = APIRouter(prefix='/monitor/online', dependencies=[Depends(Log @onlineController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:list'))]) async def get_monitor_online_list(request: Request, online_page_query: OnlineQueryModel = Depends(OnlineQueryModel.as_query)): - try: - # 获取全量数据 - online_query_result = await OnlineService.get_online_list_services(request, online_page_query) - logger.info('获取成功') - return ResponseUtil.success(model_content=PageResponseModel(rows=online_query_result, total=len(online_query_result))) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + online_query_result = await OnlineService.get_online_list_services(request, online_page_query) + logger.info('获取成功') + + return ResponseUtil.success(model_content=PageResponseModel(rows=online_query_result, total=len(online_query_result))) @onlineController.delete("/{token_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))]) @log_decorator(title='在线用户', business_type=BusinessType.FORCE) async def delete_monitor_online(request: Request, token_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_online = DeleteOnlineModel(tokenIds=token_ids) - delete_online_result = await OnlineService.delete_online_services(request, delete_online) - if delete_online_result.is_success: - logger.info(delete_online_result.message) - return ResponseUtil.success(msg=delete_online_result.message) - else: - logger.warning(delete_online_result.message) - return ResponseUtil.failure(msg=delete_online_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_online = DeleteOnlineModel(tokenIds=token_ids) + delete_online_result = await OnlineService.delete_online_services(request, delete_online) + logger.info(delete_online_result.message) + + return ResponseUtil.success(msg=delete_online_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/service/online_service.py b/ruoyi-fastapi-backend/module_admin/service/online_service.py index 968aacb..2b679f9 100644 --- a/ruoyi-fastapi-backend/module_admin/service/online_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/online_service.py @@ -3,6 +3,7 @@ from jose import jwt from config.env import JwtConfig, RedisInitKeyConfig from module_admin.entity.vo.online_vo import * from module_admin.entity.vo.common_vo import CrudResponseModel +from exceptions.exception import ServiceException from utils.common_util import CamelCaseUtil @@ -65,7 +66,6 @@ class OnlineService: token_id_list = page_object.token_ids.split(',') for token_id in token_id_list: await request.app.state.redis.delete(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{token_id}") - result = dict(is_success=True, message='强退成功') + return CrudResponseModel(is_success=True, message='强退成功') else: - result = dict(is_success=False, message='传入session_id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入session_id为空') -- Gitee From 98784826541af5b08f7f88fe524c527782c7d7f2 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:00:25 +0800 Subject: [PATCH 064/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E5=A4=84=E7=90=86=E8=87=AA=E5=AE=9A=E4=B9=89=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/handle.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index b4ad02b..2b18687 100644 --- a/ruoyi-fastapi-backend/exceptions/handle.py +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -1,7 +1,7 @@ from fastapi import FastAPI, Request from fastapi.exceptions import HTTPException from pydantic_validation_decorator import FieldValidationError -from exceptions.exception import AuthException, PermissionException, ServiceException, ModelValidatorException +from exceptions.exception import AuthException, LoginException, PermissionException, ServiceException, ModelValidatorException from utils.log_util import logger from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder @@ -15,6 +15,11 @@ def handle_exception(app: FastAPI): async def auth_exception_handler(request: Request, exc: AuthException): return ResponseUtil.unauthorized(data=exc.data, msg=exc.message) + # 自定义登录检验异常 + @app.exception_handler(LoginException) + async def login_exception_handler(request: Request, exc: LoginException): + return ResponseUtil.failure(data=exc.data, msg=exc.message) + # 自定义权限检验异常 @app.exception_handler(PermissionException) async def permission_exception_handler(request: Request, exc: PermissionException): -- Gitee From 0737adb389f5447175b87ba6f34efc0cd0f9a0b2 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:00:43 +0800 Subject: [PATCH 065/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E6=A8=A1=E5=9D=97service=E5=B1=82=E5=8F=8A=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/login_controller.py | 119 +++++++----------- .../module_admin/service/login_service.py | 14 +-- 2 files changed, 53 insertions(+), 80 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py index 4861ca4..7c769a1 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py @@ -25,80 +25,60 @@ async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = D loginInfo=form_data.login_info, captchaEnabled=captcha_enabled ) - try: - result = await LoginService.authenticate_user(request, query_db, user) - except LoginException as e: - return ResponseUtil.failure(msg=e.message) - try: - access_token_expires = timedelta(minutes=JwtConfig.jwt_expire_minutes) - session_id = str(uuid.uuid4()) - access_token = await LoginService.create_access_token( - data={ - "user_id": str(result[0].user_id), - "user_name": result[0].user_name, - "dept_name": result[1].dept_name if result[1] else None, - "session_id": session_id, - "login_info": user.login_info - }, - expires_delta=access_token_expires - ) - if AppConfig.app_same_time_login: - await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", access_token, - ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) - else: - # 此方法可实现同一账号同一时间只能登录一次 - await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{result[0].user_id}", access_token, - ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) - await UserService.edit_user_services(query_db, EditUserModel(userId=result[0].user_id, loginDate=datetime.now(), type='status')) - logger.info('登录成功') - # 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug - request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False - request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False - if request_from_swagger or request_from_redoc: - return {'access_token': access_token, 'token_type': 'Bearer'} - return ResponseUtil.success( - msg='登录成功', - dict_content={'token': access_token} - ) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + result = await LoginService.authenticate_user(request, query_db, user) + access_token_expires = timedelta(minutes=JwtConfig.jwt_expire_minutes) + session_id = str(uuid.uuid4()) + access_token = await LoginService.create_access_token( + data={ + "user_id": str(result[0].user_id), + "user_name": result[0].user_name, + "dept_name": result[1].dept_name if result[1] else None, + "session_id": session_id, + "login_info": user.login_info + }, + expires_delta=access_token_expires + ) + if AppConfig.app_same_time_login: + await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", access_token, + ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) + else: + # 此方法可实现同一账号同一时间只能登录一次 + await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{result[0].user_id}", access_token, + ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) + await UserService.edit_user_services(query_db, EditUserModel(userId=result[0].user_id, loginDate=datetime.now(), type='status')) + logger.info('登录成功') + # 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug + request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False + request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False + if request_from_swagger or request_from_redoc: + return {'access_token': access_token, 'token_type': 'Bearer'} + return ResponseUtil.success( + msg='登录成功', + dict_content={'token': access_token} + ) @loginController.get("/getInfo", response_model=CurrentUserModel) async def get_login_user_info(request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - logger.info('获取成功') - return ResponseUtil.success(model_content=current_user) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + logger.info('获取成功') + + return ResponseUtil.success(model_content=current_user) @loginController.get("/getRouters") async def get_login_user_routers(request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user), query_db: AsyncSession = Depends(get_db)): - try: - logger.info('获取成功') - user_routers = await LoginService.get_current_user_routers(current_user.user.user_id, query_db) - return ResponseUtil.success(data=user_routers) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + logger.info('获取成功') + user_routers = await LoginService.get_current_user_routers(current_user.user.user_id, query_db) + + return ResponseUtil.success(data=user_routers) @loginController.post("/register", response_model=CrudResponseModel) async def register_user(request: Request, user_register: UserRegister, query_db: AsyncSession = Depends(get_db)): - try: - user_register_result = await LoginService.register_user_services(request, query_db, user_register) - if user_register_result.is_success: - logger.info(user_register_result.message) - return ResponseUtil.success(data=user_register_result, msg=user_register_result.message) - else: - logger.warning(user_register_result.message) - return ResponseUtil.failure(msg=user_register_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + user_register_result = await LoginService.register_user_services(request, query_db, user_register) + logger.info(user_register_result.message) + + return ResponseUtil.success(data=user_register_result, msg=user_register_result.message) # @loginController.post("/getSmsCode", response_model=SmsCode) @@ -133,12 +113,9 @@ async def register_user(request: Request, user_register: UserRegister, query_db: @loginController.post("/logout") async def logout(request: Request, token: Optional[str] = Depends(oauth2_scheme)): - try: - payload = jwt.decode(token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False}) - session_id: str = payload.get("session_id") - await LoginService.logout_services(request, session_id) - logger.info('退出成功') - return ResponseUtil.success(msg="退出成功") - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + payload = jwt.decode(token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False}) + session_id: str = payload.get("session_id") + await LoginService.logout_services(request, session_id) + logger.info('退出成功') + + return ResponseUtil.success(msg="退出成功") diff --git a/ruoyi-fastapi-backend/module_admin/service/login_service.py b/ruoyi-fastapi-backend/module_admin/service/login_service.py index 358d840..f4a96b3 100644 --- a/ruoyi-fastapi-backend/module_admin/service/login_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/login_service.py @@ -9,7 +9,7 @@ from module_admin.service.user_service import * from module_admin.entity.vo.login_vo import * from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.login_dao import * -from exceptions.exception import LoginException, AuthException +from exceptions.exception import LoginException, AuthException, ServiceException from config.constant import CommonConstant, MenuConstant from config.env import AppConfig, JwtConfig, RedisInitKeyConfig from config.get_db import get_db @@ -344,11 +344,9 @@ class LoginService: captcha_value = await request.app.state.redis.get( f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{user_register.uuid}") if not captcha_value: - logger.warning("验证码已失效") - return CrudResponseModel(is_success=False, message='验证码已失效') + raise ServiceException(message='验证码已失效') elif user_register.code != str(captcha_value): - logger.warning("验证码错误") - return CrudResponseModel(is_success=False, message='验证码错误') + raise ServiceException(message='验证码错误') add_user = AddUserModel( userName=user_register.username, nickName=user_register.username, @@ -357,11 +355,9 @@ class LoginService: result = await UserService.add_user_services(query_db, add_user) return result else: - result = dict(is_success=False, message='注册程序已关闭,禁止注册') + raise ServiceException(message='注册程序已关闭,禁止注册') else: - result = dict(is_success=False, message='两次输入的密码不一致') - - return CrudResponseModel(**result) + raise ServiceException(message='两次输入的密码不一致') @classmethod async def get_sms_code_services(cls, request: Request, query_db: AsyncSession, user: ResetUserModel): -- Gitee From 95b0cdebfb1c23721dc0f002f89533fa08da4307 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:02:40 +0800 Subject: [PATCH 066/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81=E6=A8=A1=E5=9D=97=E5=BC=82=E5=B8=B8=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/captcha_controller.py | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py b/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py index 9d245cc..3ad1543 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py @@ -13,19 +13,16 @@ captchaController = APIRouter() @captchaController.get("/captchaImage") async def get_captcha_image(request: Request): - try: - captcha_enabled = True if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") == 'true' else False - register_enabled = True if await request.app.state.redis.get( - f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.registerUser") == 'true' else False - session_id = str(uuid.uuid4()) - captcha_result = await CaptchaService.create_captcha_image_service() - image = captcha_result[0] - computed_result = captcha_result[1] - await request.app.state.redis.set(f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{session_id}", computed_result, ex=timedelta(minutes=2)) - logger.info(f'编号为{session_id}的会话获取图片验证码成功') - return ResponseUtil.success( - model_content=CaptchaCode(captchaEnabled=captcha_enabled, registerEnabled=register_enabled, img=image, uuid=session_id) - ) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + captcha_enabled = True if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") == 'true' else False + register_enabled = True if await request.app.state.redis.get( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.registerUser") == 'true' else False + session_id = str(uuid.uuid4()) + captcha_result = await CaptchaService.create_captcha_image_service() + image = captcha_result[0] + computed_result = captcha_result[1] + await request.app.state.redis.set(f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{session_id}", computed_result, ex=timedelta(minutes=2)) + logger.info(f'编号为{session_id}的会话获取图片验证码成功') + + return ResponseUtil.success( + model_content=CaptchaCode(captchaEnabled=captcha_enabled, registerEnabled=register_enabled, img=image, uuid=session_id) + ) -- Gitee From bbd4a4cd95e573d82de2ac3c0177962377f14e65 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:08:55 +0800 Subject: [PATCH 067/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/log_controller.py | 137 ++++++------------ .../module_admin/service/log_service.py | 36 ++--- 2 files changed, 58 insertions(+), 115 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py index 715567b..59bce15 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py @@ -17,134 +17,87 @@ logController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService. @logController.get("/operlog/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:list'))]) async def get_system_operation_log_list(request: Request, operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - # 获取分页数据 - operation_log_page_query_result = await OperationLogService.get_operation_log_list_services(query_db, operation_log_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=operation_log_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + operation_log_page_query_result = await OperationLogService.get_operation_log_list_services(query_db, operation_log_page_query, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=operation_log_page_query_result) @logController.delete("/operlog/clean", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) @log_decorator(title='操作日志管理', business_type=BusinessType.CLEAN) async def clear_system_operation_log(request: Request, query_db: AsyncSession = Depends(get_db)): - try: - clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db) - if clear_operation_log_result.is_success: - logger.info(clear_operation_log_result.message) - return ResponseUtil.success(msg=clear_operation_log_result.message) - else: - logger.warning(clear_operation_log_result.message) - return ResponseUtil.failure(msg=clear_operation_log_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db) + logger.info(clear_operation_log_result.message) + + return ResponseUtil.success(msg=clear_operation_log_result.message) @logController.delete("/operlog/{oper_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) @log_decorator(title='操作日志管理', business_type=BusinessType.DELETE) async def delete_system_operation_log(request: Request, oper_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_operation_log = DeleteOperLogModel(operIds=oper_ids) - delete_operation_log_result = await OperationLogService.delete_operation_log_services(query_db, delete_operation_log) - if delete_operation_log_result.is_success: - logger.info(delete_operation_log_result.message) - return ResponseUtil.success(msg=delete_operation_log_result.message) - else: - logger.warning(delete_operation_log_result.message) - return ResponseUtil.failure(msg=delete_operation_log_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_operation_log = DeleteOperLogModel(operIds=oper_ids) + delete_operation_log_result = await OperationLogService.delete_operation_log_services(query_db, delete_operation_log) + logger.info(delete_operation_log_result.message) + + return ResponseUtil.success(msg=delete_operation_log_result.message) @logController.post("/operlog/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))]) @log_decorator(title='操作日志管理', business_type=BusinessType.EXPORT) async def export_system_operation_log_list(request: Request, operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): - try: - # 获取全量数据 - operation_log_query_result = await OperationLogService.get_operation_log_list_services(query_db, operation_log_page_query, is_page=False) - operation_log_export_result = await OperationLogService.export_operation_log_list_services(request, operation_log_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + operation_log_query_result = await OperationLogService.get_operation_log_list_services(query_db, operation_log_page_query, is_page=False) + operation_log_export_result = await OperationLogService.export_operation_log_list_services(request, operation_log_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result)) @logController.get("/logininfor/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:list'))]) async def get_system_login_log_list(request: Request, login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): - try: - # 获取分页数据 - login_log_page_query_result = await LoginLogService.get_login_log_list_services(query_db, login_log_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=login_log_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + login_log_page_query_result = await LoginLogService.get_login_log_list_services(query_db, login_log_page_query, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=login_log_page_query_result) @logController.delete("/logininfor/clean", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) @log_decorator(title='登录日志管理', business_type=BusinessType.CLEAN) async def clear_system_login_log(request: Request, query_db: AsyncSession = Depends(get_db)): - try: - clear_login_log_result = await LoginLogService.clear_login_log_services(query_db) - if clear_login_log_result.is_success: - logger.info(clear_login_log_result.message) - return ResponseUtil.success(msg=clear_login_log_result.message) - else: - logger.warning(clear_login_log_result.message) - return ResponseUtil.failure(msg=clear_login_log_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + clear_login_log_result = await LoginLogService.clear_login_log_services(query_db) + logger.info(clear_login_log_result.message) + + return ResponseUtil.success(msg=clear_login_log_result.message) @logController.delete("/logininfor/{info_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) @log_decorator(title='登录日志管理', business_type=BusinessType.DELETE) async def delete_system_login_log(request: Request, info_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_login_log = DeleteLoginLogModel(infoIds=info_ids) - delete_login_log_result = await LoginLogService.delete_login_log_services(query_db, delete_login_log) - if delete_login_log_result.is_success: - logger.info(delete_login_log_result.message) - return ResponseUtil.success(msg=delete_login_log_result.message) - else: - logger.warning(delete_login_log_result.message) - return ResponseUtil.failure(msg=delete_login_log_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_login_log = DeleteLoginLogModel(infoIds=info_ids) + delete_login_log_result = await LoginLogService.delete_login_log_services(query_db, delete_login_log) + logger.info(delete_login_log_result.message) + + return ResponseUtil.success(msg=delete_login_log_result.message) @logController.get("/logininfor/unlock/{user_name}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:unlock'))]) @log_decorator(title='登录日志管理', business_type=BusinessType.OTHER) async def clear_system_login_log(request: Request, user_name: str, query_db: AsyncSession = Depends(get_db)): - try: - unlock_user = UnlockUser(userName=user_name) - unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user) - if unlock_user_result.is_success: - logger.info(unlock_user_result.message) - return ResponseUtil.success(msg=unlock_user_result.message) - else: - logger.warning(unlock_user_result.message) - return ResponseUtil.failure(msg=unlock_user_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + unlock_user = UnlockUser(userName=user_name) + unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user) + logger.info(unlock_user_result.message) + + return ResponseUtil.success(msg=unlock_user_result.message) @logController.post("/logininfor/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))]) @log_decorator(title='登录日志管理', business_type=BusinessType.EXPORT) async def export_system_login_log_list(request: Request, login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): - try: - # 获取全量数据 - login_log_query_result = await LoginLogService.get_login_log_list_services(query_db, login_log_page_query, is_page=False) - login_log_export_result = await LoginLogService.export_login_log_list_services(login_log_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(login_log_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + login_log_query_result = await LoginLogService.get_login_log_list_services(query_db, login_log_page_query, is_page=False) + login_log_export_result = await LoginLogService.export_login_log_list_services(login_log_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(login_log_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/service/log_service.py b/ruoyi-fastapi-backend/module_admin/service/log_service.py index 4e15d2c..51b57c2 100644 --- a/ruoyi-fastapi-backend/module_admin/service/log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/log_service.py @@ -1,6 +1,7 @@ from module_admin.dao.log_dao import * from module_admin.service.dict_service import Request, DictDataService from module_admin.entity.vo.common_vo import CrudResponseModel +from exceptions.exception import ServiceException from utils.common_util import export_list2excel, CamelCaseUtil @@ -33,12 +34,10 @@ class OperationLogService: try: await OperationLogDao.add_operation_log_dao(query_db, page_object) await query_db.commit() - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() - result = dict(is_success=False, message=str(e)) - - return CrudResponseModel(**result) + raise e @classmethod async def delete_operation_log_services(cls, query_db: AsyncSession, page_object: DeleteOperLogModel): @@ -54,13 +53,12 @@ class OperationLogService: for oper_id in oper_id_list: await OperationLogDao.delete_operation_log_dao(query_db, OperLogModel(operId=oper_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入操作日志id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入操作日志id为空') @classmethod async def clear_operation_log_services(cls, query_db: AsyncSession): @@ -72,13 +70,11 @@ class OperationLogService: try: await OperationLogDao.clear_operation_log_dao(query_db) await query_db.commit() - result = dict(is_success=True, message='清除成功') + return CrudResponseModel(is_success=True, message='清除成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def export_operation_log_list_services(cls, request: Request, operation_log_list: List): """ @@ -155,12 +151,10 @@ class LoginLogService: try: await LoginLogDao.add_login_log_dao(query_db, page_object) await query_db.commit() - result = dict(is_success=True, message='新增成功') + return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() - result = dict(is_success=False, message=str(e)) - - return CrudResponseModel(**result) + raise e @classmethod async def delete_login_log_services(cls, query_db: AsyncSession, page_object: DeleteLoginLogModel): @@ -176,13 +170,12 @@ class LoginLogService: for info_id in info_id_list: await LoginLogDao.delete_login_log_dao(query_db, LogininforModel(infoId=info_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入登录日志id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入登录日志id为空') @classmethod async def clear_login_log_services(cls, query_db: AsyncSession): @@ -194,22 +187,19 @@ class LoginLogService: try: await LoginLogDao.clear_login_log_dao(query_db) await query_db.commit() - result = dict(is_success=True, message='清除成功') + return CrudResponseModel(is_success=True, message='清除成功') except Exception as e: await query_db.rollback() raise e - return CrudResponseModel(**result) - @classmethod async def unlock_user_services(cls, request: Request, unlock_user: UnlockUser): locked_user = await request.app.state.redis.get(f"account_lock:{unlock_user.user_name}") if locked_user: await request.app.state.redis.delete(f"account_lock:{unlock_user.user_name}") - result = dict(is_success=True, message='解锁成功') + return CrudResponseModel(is_success=True, message='解锁成功') else: - result = dict(is_success=False, message='该用户未锁定') - return CrudResponseModel(**result) + raise ServiceException(message='该用户未锁定') @staticmethod async def export_login_log_list_services(login_log_list: List): -- Gitee From f255595b304a7ab904c0ce6bf85eddba4568096d Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:14:41 +0800 Subject: [PATCH 068/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E6=A8=A1=E5=9D=97service=E5=B1=82=E5=8F=8A=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/common_controller.py | 45 +++++-------------- .../module_admin/service/common_service.py | 21 ++++----- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/common_controller.py b/ruoyi-fastapi-backend/module_admin/controller/common_controller.py index 5744f70..dc93030 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/common_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/common_controller.py @@ -10,44 +10,23 @@ commonController = APIRouter(prefix='/common', dependencies=[Depends(LoginServic @commonController.post("/upload") async def common_upload(request: Request, file: UploadFile = File(...)): - try: - upload_result = await CommonService.upload_service(request, file) - if upload_result.is_success: - logger.info('上传成功') - return ResponseUtil.success(model_content=upload_result.result) - else: - logger.warning('上传失败') - return ResponseUtil.failure(msg=upload_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + upload_result = await CommonService.upload_service(request, file) + logger.info('上传成功') + + return ResponseUtil.success(model_content=upload_result.result) @commonController.get("/download") async def common_download(request: Request, background_tasks: BackgroundTasks, file_name: str = Query(alias='fileName'), delete: bool = Query()): - try: - download_result = await CommonService.download_services(background_tasks, file_name, delete) - if download_result.is_success: - logger.info(download_result.message) - return ResponseUtil.streaming(data=download_result.result) - else: - logger.warning(download_result.message) - return ResponseUtil.failure(msg=download_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + download_result = await CommonService.download_services(background_tasks, file_name, delete) + logger.info(download_result.message) + + return ResponseUtil.streaming(data=download_result.result) @commonController.get("/download/resource") async def common_download(request: Request, resource: str = Query()): - try: - download_resource_result = await CommonService.download_resource_services(resource) - if download_resource_result.is_success: - logger.info(download_resource_result.message) - return ResponseUtil.streaming(data=download_resource_result.result) - else: - logger.warning(download_resource_result.message) - return ResponseUtil.failure(msg=download_resource_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + download_resource_result = await CommonService.download_resource_services(resource) + logger.info(download_resource_result.message) + + return ResponseUtil.streaming(data=download_resource_result.result) diff --git a/ruoyi-fastapi-backend/module_admin/service/common_service.py b/ruoyi-fastapi-backend/module_admin/service/common_service.py index 883f18c..105f351 100644 --- a/ruoyi-fastapi-backend/module_admin/service/common_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/common_service.py @@ -4,6 +4,7 @@ from fastapi import UploadFile from datetime import datetime from config.env import UploadConfig from module_admin.entity.vo.common_vo import * +from exceptions.exception import ServiceException from utils.upload_util import UploadUtil @@ -21,7 +22,7 @@ class CommonService: :return: 上传结果 """ if not UploadUtil.check_file_extension(file): - result = dict(is_success=False, message='文件类型不合法') + raise ServiceException(message='文件类型不合法') else: relative_path = f'upload/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}' dir_path = os.path.join(UploadConfig.UPLOAD_PATH, relative_path) @@ -36,7 +37,7 @@ class CommonService: for chunk in iter(lambda: file.file.read(1024 * 1024 * 10), b''): f.write(chunk) - result = dict( + return CrudResponseModel( is_success=True, result=UploadResponseModel( fileName=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{filename}', @@ -47,8 +48,6 @@ class CommonService: message='上传成功' ) - return CrudResponseModel(**result) - @classmethod async def download_services(cls, background_tasks: BackgroundTasks, file_name, delete: bool): """ @@ -60,14 +59,13 @@ class CommonService: """ filepath = os.path.join(UploadConfig.DOWNLOAD_PATH, file_name) if '..' in file_name: - result = dict(is_success=False, message='文件名称不合法') + raise ServiceException(message='文件名称不合法') elif not UploadUtil.check_file_exists(filepath): - result = dict(is_success=False, message='文件不存在') + raise ServiceException(message='文件不存在') else: - result = dict(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功') if delete: background_tasks.add_task(UploadUtil.delete_file, filepath) - return CrudResponseModel(**result) + return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功') @classmethod async def download_resource_services(cls, resource: str): @@ -79,9 +77,8 @@ class CommonService: filepath = os.path.join(resource.replace(UploadConfig.UPLOAD_PREFIX, UploadConfig.UPLOAD_PATH)) filename = resource.rsplit("/", 1)[-1] if '..' in filename or not UploadUtil.check_file_timestamp(filename) or not UploadUtil.check_file_machine(filename) or not UploadUtil.check_file_random_code(filename): - result = dict(is_success=False, message='文件名称不合法') + raise ServiceException(message='文件名称不合法') elif not UploadUtil.check_file_exists(filepath): - result = dict(is_success=False, message='文件不存在') + raise ServiceException(message='文件不存在') else: - result = dict(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功') - return CrudResponseModel(**result) + return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功') -- Gitee From 51bed591d43cb1c92461dcb151d2775d9823ca50 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:21:22 +0800 Subject: [PATCH 069/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=BC=93?= =?UTF-8?q?=E5=AD=98=E7=9B=91=E6=8E=A7=E5=8F=8A=E7=BC=93=E5=AD=98=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E6=A8=A1=E5=9D=97service=E5=B1=82=E5=8F=8A=E5=BC=82?= =?UTF-8?q?=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/cache_controller.py | 88 +++++++------------ .../module_admin/service/cache_service.py | 9 +- 2 files changed, 35 insertions(+), 62 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py b/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py index 74b1a25..459c8c6 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py @@ -12,83 +12,59 @@ cacheController = APIRouter(prefix='/monitor/cache', dependencies=[Depends(Login @cacheController.get("", response_model=CacheMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) async def get_monitor_cache_info(request: Request): - try: - # 获取全量数据 - cache_info_query_result = await CacheService.get_cache_monitor_statistical_info_services(request) - logger.info('获取成功') - return ResponseUtil.success(data=cache_info_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + cache_info_query_result = await CacheService.get_cache_monitor_statistical_info_services(request) + logger.info('获取成功') + + return ResponseUtil.success(data=cache_info_query_result) @cacheController.get("/getNames", response_model=List[CacheInfoModel], dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) async def get_monitor_cache_name(request: Request): - try: - # 获取全量数据 - cache_name_list_result = await CacheService.get_cache_monitor_cache_name_services() - logger.info('获取成功') - return ResponseUtil.success(data=cache_name_list_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + cache_name_list_result = await CacheService.get_cache_monitor_cache_name_services() + logger.info('获取成功') + + return ResponseUtil.success(data=cache_name_list_result) @cacheController.get("/getKeys/{cache_name}", response_model=List[str], dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) async def get_monitor_cache_key(request: Request, cache_name: str): - try: - # 获取全量数据 - cache_key_list_result = await CacheService.get_cache_monitor_cache_key_services(request, cache_name) - logger.info('获取成功') - return ResponseUtil.success(data=cache_key_list_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + cache_key_list_result = await CacheService.get_cache_monitor_cache_key_services(request, cache_name) + logger.info('获取成功') + + return ResponseUtil.success(data=cache_key_list_result) @cacheController.get("/getValue/{cache_name}/{cache_key}", response_model=CacheInfoModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) async def get_monitor_cache_value(request: Request, cache_name: str, cache_key: str): - try: - # 获取全量数据 - cache_value_list_result = await CacheService.get_cache_monitor_cache_value_services(request, cache_name, cache_key) - logger.info('获取成功') - return ResponseUtil.success(data=cache_value_list_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + cache_value_list_result = await CacheService.get_cache_monitor_cache_value_services(request, cache_name, cache_key) + logger.info('获取成功') + + return ResponseUtil.success(data=cache_value_list_result) @cacheController.delete("/clearCacheName/{cache_name}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) async def clear_monitor_cache_name(request: Request, cache_name: str): - try: - clear_cache_name_result = await CacheService.clear_cache_monitor_cache_name_services(request, cache_name) - if clear_cache_name_result.is_success: - logger.info(clear_cache_name_result.message) - return ResponseUtil.success(msg=clear_cache_name_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + clear_cache_name_result = await CacheService.clear_cache_monitor_cache_name_services(request, cache_name) + logger.info(clear_cache_name_result.message) + + return ResponseUtil.success(msg=clear_cache_name_result.message) @cacheController.delete("/clearCacheKey/{cache_key}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) async def clear_monitor_cache_key(request: Request, cache_key: str): - try: - clear_cache_key_result = await CacheService.clear_cache_monitor_cache_key_services(request, cache_key) - if clear_cache_key_result.is_success: - logger.info(clear_cache_key_result.message) - return ResponseUtil.success(msg=clear_cache_key_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + clear_cache_key_result = await CacheService.clear_cache_monitor_cache_key_services(request, cache_key) + logger.info(clear_cache_key_result.message) + + return ResponseUtil.success(msg=clear_cache_key_result.message) @cacheController.delete("/clearCacheAll", dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) async def clear_monitor_cache_all(request: Request): - try: - clear_cache_all_result = await CacheService.clear_cache_monitor_all_services(request) - if clear_cache_all_result.is_success: - logger.info(clear_cache_all_result.message) - return ResponseUtil.success(msg=clear_cache_all_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + clear_cache_all_result = await CacheService.clear_cache_monitor_all_services(request) + logger.info(clear_cache_all_result.message) + + return ResponseUtil.success(msg=clear_cache_all_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/service/cache_service.py b/ruoyi-fastapi-backend/module_admin/service/cache_service.py index 960b9cd..06000d1 100644 --- a/ruoyi-fastapi-backend/module_admin/service/cache_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/cache_service.py @@ -87,9 +87,8 @@ class CacheService: cache_keys = await request.app.state.redis.keys(f"{cache_name}*") if cache_keys: await request.app.state.redis.delete(*cache_keys) - result = dict(is_success=True, message=f"{cache_name}对应键值清除成功") - return CrudResponseModel(**result) + return CrudResponseModel(is_success=True, message=f"{cache_name}对应键值清除成功") @classmethod async def clear_cache_monitor_cache_key_services(cls, request: Request, cache_key: str): @@ -102,9 +101,8 @@ class CacheService: cache_keys = await request.app.state.redis.keys(f"*{cache_key}") if cache_keys: await request.app.state.redis.delete(*cache_keys) - result = dict(is_success=True, message=f"{cache_key}清除成功") - return CrudResponseModel(**result) + return CrudResponseModel(is_success=True, message=f"{cache_key}清除成功") @classmethod async def clear_cache_monitor_all_services(cls, request: Request): @@ -117,8 +115,7 @@ class CacheService: if cache_keys: await request.app.state.redis.delete(*cache_keys) - result = dict(is_success=True, message="所有缓存清除成功") await RedisUtil.init_sys_dict(request.app.state.redis) await RedisUtil.init_sys_config(request.app.state.redis) - return CrudResponseModel(**result) + return CrudResponseModel(is_success=True, message="所有缓存清除成功") -- Gitee From 36f45b2c267993b6b577031e70d95a3197779289 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:24:00 +0800 Subject: [PATCH 070/129] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=8D=87?= =?UTF-8?q?=E7=BA=A7axios=E5=88=B0=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=90=8E=E8=A1=A8=E5=8D=95=E6=95=B0=E6=8D=AE=E9=9C=80=E6=89=8B?= =?UTF-8?q?=E5=8A=A8=E6=8C=87=E5=AE=9AContent-Type=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-frontend/src/api/login.js | 3 ++- ruoyi-fastapi-frontend/src/api/system/user.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ruoyi-fastapi-frontend/src/api/login.js b/ruoyi-fastapi-frontend/src/api/login.js index d3a8e0b..8f6699b 100644 --- a/ruoyi-fastapi-frontend/src/api/login.js +++ b/ruoyi-fastapi-frontend/src/api/login.js @@ -11,7 +11,8 @@ export function login(username, password, code, uuid) { url: '/login', headers: { isToken: false, - repeatSubmit: false + repeatSubmit: false, + 'Content-Type': 'application/x-www-form-urlencoded' }, method: 'post', data: data diff --git a/ruoyi-fastapi-frontend/src/api/system/user.js b/ruoyi-fastapi-frontend/src/api/system/user.js index f2f76ef..9b0211a 100644 --- a/ruoyi-fastapi-frontend/src/api/system/user.js +++ b/ruoyi-fastapi-frontend/src/api/system/user.js @@ -105,6 +105,7 @@ export function uploadAvatar(data) { return request({ url: '/system/user/profile/avatar', method: 'post', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, data: data }) } -- Gitee From 0ee473fd070cab9ff8f4aaa7474c0c96fb3e102d Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:29:50 +0800 Subject: [PATCH 071/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=8E=A5=E5=8F=A3dao=E5=B1=82=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/dao/dept_dao.py | 4 ++-- .../module_admin/dao/menu_dao.py | 2 +- .../module_admin/dao/role_dao.py | 18 +++++++++++++----- .../module_admin/service/menu_service.py | 3 ++- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py index 44a2f20..d470692 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py @@ -88,14 +88,14 @@ class DeptDao: dept_result = (await db.execute( select(SysDept) .where(SysDept.dept_id != dept_info.dept_id, - SysDept.parent_id != dept_info.dept_id, + ~SysDept.dept_id.in_(select(SysDept.dept_id).where(func.find_in_set(dept_info.dept_id, SysDept.ancestors))), SysDept.del_flag == '0', SysDept.status == '0', eval(data_scope_sql)) .order_by(SysDept.order_num) .distinct() )).scalars().all() - return list_format_datetime(dept_result) + return dept_result @classmethod async def get_children_dept(cls, db: AsyncSession, dept_id: int): diff --git a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py index 522022c..dfa9ca2 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py @@ -168,7 +168,7 @@ class MenuDao: menu_count = (await db.execute( select(func.count('*')) .select_from(SysMenu) - .where(SysMenu.menu_id == menu_id) + .where(SysMenu.parent_id == menu_id) )).scalar() return menu_count diff --git a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py index b65b4a1..5706128 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py @@ -3,6 +3,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.user_do import SysUser, SysUserRole from module_admin.entity.do.role_do import SysRole, SysRoleMenu, SysRoleDept from module_admin.entity.do.dept_do import SysDept +from module_admin.entity.do.menu_do import SysMenu from module_admin.entity.vo.role_vo import * from utils.page_util import PageUtil from datetime import datetime, time @@ -169,17 +170,24 @@ class RoleDao: ) @classmethod - async def get_role_menu_dao(cls, db: AsyncSession, role_id: int): + async def get_role_menu_dao(cls, db: AsyncSession, role: RoleModel): """ 根据角色id获取角色菜单关联列表信息 :param db: orm对象 - :param role_id: 角色id + :param role: 角色对象 :return: 角色菜单关联列表信息 """ role_menu_query_all = (await db.execute( - select(SysRoleMenu) - .where(SysRoleMenu.role_id == role_id) - .distinct() + select(SysMenu) + .join(SysRoleMenu, SysRoleMenu.menu_id == SysMenu.menu_id) + .where(SysRoleMenu.role_id == role.role_id, + ~SysMenu.menu_id.in_( + select(SysMenu.parent_id) + .select_from(SysMenu) + .join(SysRoleMenu, + and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysRoleMenu.role_id == role.role_id)) + ) if role.menu_check_strictly else True) + .order_by(SysMenu.parent_id, SysMenu.order_num) )).scalars().all() return role_menu_query_all diff --git a/ruoyi-fastapi-backend/module_admin/service/menu_service.py b/ruoyi-fastapi-backend/module_admin/service/menu_service.py index 4769311..e68d3f6 100644 --- a/ruoyi-fastapi-backend/module_admin/service/menu_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/menu_service.py @@ -38,7 +38,8 @@ class MenuService: """ menu_list_result = await MenuDao.get_menu_list_for_tree(query_db, current_user.user.user_id, current_user.user.role) menu_tree_result = cls.list_to_tree(menu_list_result) - role_menu_list = await RoleDao.get_role_menu_dao(query_db, role_id) + role = await RoleDao.get_role_detail_by_id(query_db, role_id) + role_menu_list = await RoleDao.get_role_menu_dao(query_db, role) checked_keys = [row.menu_id for row in role_menu_list] result = RoleMenuQueryModel( menus=menu_tree_result, -- Gitee From f87ae9a25b23a8844b0bbcbeb7fbcfe6bc6e82cb Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Wed, 10 Jul 2024 21:30:11 +0800 Subject: [PATCH 072/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=9D=83=E9=99=90=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/aspect/data_scope.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py b/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py index 598170e..f097907 100644 --- a/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py +++ b/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py @@ -24,13 +24,13 @@ class GetDataScope: if self.query_alias == '' or max_data_scope == 1 or user_id == 1: param_sql = '1 == 1' elif max_data_scope == 2: - param_sql = f"{self.query_alias}.{self.dept_alias}.in_(select(SysRoleDept.dept_id).where(SysRoleDept.role_id == {max_role_id})) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 1" + param_sql = f"{self.query_alias}.{self.dept_alias}.in_(select(SysRoleDept.dept_id).where(SysRoleDept.role_id == {max_role_id})) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0" elif max_data_scope == 3: - param_sql = f"{self.query_alias}.{self.dept_alias} == {dept_id} if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 1" + param_sql = f"{self.query_alias}.{self.dept_alias} == {dept_id} if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0" elif max_data_scope == 4: - param_sql = f"{self.query_alias}.{self.dept_alias}.in_(select(SysDept.dept_id).where(or_(SysDept.dept_id == {dept_id}, func.find_in_set({dept_id}, SysDept.ancestors)))) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 1" + param_sql = f"{self.query_alias}.{self.dept_alias}.in_(select(SysDept.dept_id).where(or_(SysDept.dept_id == {dept_id}, func.find_in_set({dept_id}, SysDept.ancestors)))) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0" elif max_data_scope == 5: - param_sql = f"{self.query_alias}.{self.user_alias} == {user_id} if hasattr({self.query_alias}, '{self.user_alias}') else 1 == 1" + param_sql = f"{self.query_alias}.{self.user_alias} == {user_id} if hasattr({self.query_alias}, '{self.user_alias}') else 1 == 0" else: param_sql = '1 == 0' -- Gitee From cd260fbcdafd841b0c987ccfd9421ce8a94be73f Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 11 Jul 2024 16:36:04 +0800 Subject: [PATCH 073/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E9=97=A8=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/config/constant.py | 4 + .../controller/dept_controller.py | 112 +++++----- .../module_admin/dao/dept_dao.py | 137 +++++++++---- .../module_admin/service/dept_service.py | 191 +++++++++++------- 4 files changed, 260 insertions(+), 184 deletions(-) diff --git a/ruoyi-fastapi-backend/config/constant.py b/ruoyi-fastapi-backend/config/constant.py index 5f94546..fb860f7 100644 --- a/ruoyi-fastapi-backend/config/constant.py +++ b/ruoyi-fastapi-backend/config/constant.py @@ -6,6 +6,8 @@ class CommonConstant: HTTPS: https请求 YES: 是否为系统默认(是) NO: 是否为系统默认(否) + DEPT_NORMAL: 部门正常状态 + DEPT_DISABLE: 部门停用状态 UNIQUE: 校验是否唯一的返回标识(是) NOT_UNIQUE: 校验是否唯一的返回标识(否) """ @@ -14,6 +16,8 @@ class CommonConstant: HTTPS = 'https://' YES = 'Y' NO = 'N' + DEPT_NORMAL = '0' + DEPT_DISABLE = '1' UNIQUE = True NOT_UNIQUE = False diff --git a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py index 5d8208f..fe927c7 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py @@ -17,92 +17,70 @@ deptController = APIRouter(prefix='/system/dept', dependencies=[Depends(LoginSer @deptController.get("/list/exclude/{dept_id}", response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))]) async def get_system_dept_tree_for_edit_option(request: Request, dept_id: int, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): - try: - dept_query = DeptModel(deptId=dept_id) - dept_query_result = await DeptService.get_dept_for_edit_option_services(query_db, dept_query, data_scope_sql) - logger.info('获取成功') - return ResponseUtil.success(data=dept_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + dept_query = DeptModel(deptId=dept_id) + dept_query_result = await DeptService.get_dept_for_edit_option_services(query_db, dept_query, data_scope_sql) + logger.info('获取成功') + + return ResponseUtil.success(data=dept_query_result) @deptController.get("/list", response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))]) async def get_system_dept_list(request: Request, dept_query: DeptQueryModel = Depends(DeptQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): - try: - dept_query_result = await DeptService.get_dept_list_services(query_db, dept_query, data_scope_sql) - logger.info('获取成功') - return ResponseUtil.success(data=dept_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + dept_query_result = await DeptService.get_dept_list_services(query_db, dept_query, data_scope_sql) + logger.info('获取成功') + + return ResponseUtil.success(data=dept_query_result) @deptController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) @ValidateFields(validate_model='add_dept') @log_decorator(title='部门管理', business_type=BusinessType.INSERT) async def add_system_dept(request: Request, add_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - add_dept.create_by = current_user.user.user_name - add_dept.create_time = datetime.now() - add_dept.update_by = current_user.user.user_name - add_dept.update_time = datetime.now() - add_dept_result = await DeptService.add_dept_services(query_db, add_dept) - if add_dept_result.is_success: - logger.info(add_dept_result.message) - return ResponseUtil.success(data=add_dept_result) - else: - logger.warning(add_dept_result.message) - return ResponseUtil.failure(msg=add_dept_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_dept.create_by = current_user.user.user_name + add_dept.create_time = datetime.now() + add_dept.update_by = current_user.user.user_name + add_dept.update_time = datetime.now() + add_dept_result = await DeptService.add_dept_services(query_db, add_dept) + logger.info(add_dept_result.message) + + return ResponseUtil.success(data=add_dept_result) @deptController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) @ValidateFields(validate_model='edit_dept') @log_decorator(title='部门管理', business_type=BusinessType.UPDATE) -async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - edit_dept.update_by = current_user.user.user_name - edit_dept.update_time = datetime.now() - edit_dept_result = await DeptService.edit_dept_services(query_db, edit_dept) - if edit_dept_result.is_success: - logger.info(edit_dept_result.message) - return ResponseUtil.success(msg=edit_dept_result.message) - else: - logger.warning(edit_dept_result.message) - return ResponseUtil.failure(msg=edit_dept_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): + if not current_user.user.admin: + await DeptService.check_dept_data_scope_services(query_db, edit_dept.dept_id, data_scope_sql) + edit_dept.update_by = current_user.user.user_name + edit_dept.update_time = datetime.now() + edit_dept_result = await DeptService.edit_dept_services(query_db, edit_dept) + logger.info(edit_dept_result.message) + + return ResponseUtil.success(msg=edit_dept_result.message) @deptController.delete("/{dept_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) @log_decorator(title='部门管理', business_type=BusinessType.DELETE) -async def delete_system_dept(request: Request, dept_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - try: - delete_dept = DeleteDeptModel(deptIds=dept_ids) - delete_dept.update_by = current_user.user.user_name - delete_dept.update_time = datetime.now() - delete_dept_result = await DeptService.delete_dept_services(query_db, delete_dept) - if delete_dept_result.is_success: - logger.info(delete_dept_result.message) - return ResponseUtil.success(msg=delete_dept_result.message) - else: - logger.warning(delete_dept_result.message) - return ResponseUtil.failure(msg=delete_dept_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def delete_system_dept(request: Request, dept_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): + dept_id_list = dept_ids.split(',') + for dept_id in dept_id_list: + if not current_user.user.admin: + await DeptService.check_dept_data_scope_services(query_db, int(dept_id), data_scope_sql) + delete_dept = DeleteDeptModel(deptIds=dept_ids) + delete_dept.update_by = current_user.user.user_name + delete_dept.update_time = datetime.now() + delete_dept_result = await DeptService.delete_dept_services(query_db, delete_dept) + logger.info(delete_dept_result.message) + + return ResponseUtil.success(msg=delete_dept_result.message) @deptController.get("/{dept_id}", response_model=DeptModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dept:query'))]) -async def query_detail_system_dept(request: Request, dept_id: int, query_db: AsyncSession = Depends(get_db)): - try: - detail_dept_result = await DeptService.dept_detail_services(query_db, dept_id) - logger.info(f'获取dept_id为{dept_id}的信息成功') - return ResponseUtil.success(data=detail_dept_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) +async def query_detail_system_dept(request: Request, dept_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): + if not current_user.user.admin: + await DeptService.check_dept_data_scope_services(query_db, dept_id, data_scope_sql) + detail_dept_result = await DeptService.dept_detail_services(query_db, dept_id) + logger.info(f'获取dept_id为{dept_id}的信息成功') + + return ResponseUtil.success(data=detail_dept_result) diff --git a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py index d470692..7dfc8a1 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py @@ -1,9 +1,10 @@ -from sqlalchemy import select, update, delete, or_, func +from sqlalchemy import select, update, delete, or_, func, bindparam from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.util import immutabledict from module_admin.entity.do.dept_do import SysDept +from module_admin.entity.do.user_do import SysUser from module_admin.entity.do.role_do import SysRoleDept from module_admin.entity.vo.dept_vo import * -from utils.time_format_util import list_format_datetime class DeptDao: @@ -21,25 +22,7 @@ class DeptDao: """ dept_info = (await db.execute( select(SysDept) - .where(SysDept.dept_id == dept_id, - SysDept.status == '0', - SysDept.del_flag == '0') - )).scalars().first() - - return dept_info - - @classmethod - async def get_dept_by_id_for_list(cls, db: AsyncSession, dept_id: int): - """ - 用于获取部门列表的工具方法 - :param db: orm对象 - :param dept_id: 部门id - :return: 部门id对应的信息对象 - """ - dept_info = (await db.execute( - select(SysDept) - .where(SysDept.dept_id == dept_id, - SysDept.del_flag == '0') + .where(SysDept.dept_id == dept_id) )).scalars().first() return dept_info @@ -98,7 +81,7 @@ class DeptDao: return dept_result @classmethod - async def get_children_dept(cls, db: AsyncSession, dept_id: int): + async def get_children_dept_dao(cls, db: AsyncSession, dept_id: int): """ 根据部门id查询当前部门的子部门列表信息 :param db: orm对象 @@ -107,25 +90,10 @@ class DeptDao: """ dept_result = (await db.execute( select(SysDept) - .where(SysDept.parent_id == dept_id, - SysDept.del_flag == '0') + .where(func.find_in_set(dept_id, SysDept.ancestors)) )).scalars().all() - return list_format_datetime(dept_result) - - @classmethod - async def get_dept_all_ancestors(cls, db: AsyncSession): - """ - 获取所有部门的ancestors信息 - :param db: orm对象 - :return: ancestors信息列表 - """ - ancestors = (await db.execute( - select(SysDept.ancestors) - .where(SysDept.del_flag == '0') - )).scalars().all() - - return ancestors + return dept_result @classmethod async def get_dept_list_for_tree(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str): @@ -196,6 +164,43 @@ class DeptDao: [dept] ) + @classmethod + async def update_dept_children_dao(cls, db: AsyncSession, update_dept: List): + """ + 更新子部门信息 + :param db: orm对象 + :param update_dept: 需要更新的部门列表 + :return: + """ + await db.execute( + update(SysDept) + .where(SysDept.dept_id == bindparam('dept_id')) + .values( + { + 'dept_id': bindparam('dept_id'), + 'ancestors': bindparam('ancestors'), + } + ), + update_dept, + execution_options=immutabledict( + {"synchronize_session": None} + ) + ) + + @classmethod + async def update_dept_status_normal_dao(cls, db: AsyncSession, dept_id_list: List): + """ + 批量更新部门状态为正常 + :param db: orm对象 + :param dept_id_list: 部门id列表 + :return: + """ + await db.execute( + update(SysDept) + .where(SysDept.dept_id.in_(dept_id_list)) + .values(status='0') + ) + @classmethod async def delete_dept_dao(cls, db: AsyncSession, dept: DeptModel): """ @@ -209,3 +214,57 @@ class DeptDao: .where(SysDept.dept_id == dept.dept_id) .values(del_flag='2', update_by=dept.update_by, update_time=dept.update_time) ) + + @classmethod + async def count_normal_children_dept_dao(cls, db: AsyncSession, dept_id: int): + """ + 根据部门id查询查询所有子部门(正常状态)的数量 + :param db: orm对象 + :param dept_id: 部门id + :return: 所有子部门(正常状态)的数量 + """ + normal_children_dept_count = (await db.execute( + select(func.count('*')) + .select_from(SysDept) + .where( + SysDept.status == '0', + SysDept.del_flag == '0', + func.find_in_set(dept_id, SysDept.ancestors) + ) + )).scalar() + + return normal_children_dept_count + + @classmethod + async def count_children_dept_dao(cls, db: AsyncSession, dept_id: int): + """ + 根据部门id查询查询所有子部门(所有状态)的数量 + :param db: orm对象 + :param dept_id: 部门id + :return: 所有子部门(所有状态)的数量 + """ + children_dept_count = (await db.execute( + select(func.count('*')) + .select_from(SysDept) + .where(SysDept.del_flag == '0', + SysDept.parent_id == dept_id) + .limit(1) + )).scalar() + + return children_dept_count + + @classmethod + async def count_dept_user_dao(cls, db: AsyncSession, dept_id: int): + """ + 根据部门id查询查询部门下的用户数量 + :param db: orm对象 + :param dept_id: 部门id + :return: 部门下的用户数量 + """ + dept_user_count = (await db.execute( + select(func.count('*')) + .select_from(SysUser) + .where(SysUser.dept_id == dept_id, SysUser.del_flag == '0') + )).scalar() + + return dept_user_count diff --git a/ruoyi-fastapi-backend/module_admin/service/dept_service.py b/ruoyi-fastapi-backend/module_admin/service/dept_service.py index 5d67412..1a84c6e 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dept_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dept_service.py @@ -1,5 +1,7 @@ from module_admin.dao.dept_dao import * from module_admin.entity.vo.common_vo import CrudResponseModel +from config.constant import CommonConstant +from exceptions.exception import ServiceException from utils.common_util import CamelCaseUtil @@ -49,6 +51,35 @@ class DeptService: return CamelCaseUtil.transform_result(dept_list_result) + @classmethod + async def check_dept_data_scope_services(cls, query_db: AsyncSession, dept_id: int, data_scope_sql: str): + """ + 校验部门是否有数据权限service + :param query_db: orm对象 + :param dept_id: 部门id + :param data_scope_sql: 数据权限对应的查询sql语句 + :return: 校验结果 + """ + depts = await DeptDao.get_dept_list(query_db, DeptModel(deptId=dept_id), data_scope_sql) + if depts: + return CrudResponseModel(is_success=True, message='校验通过') + else: + raise ServiceException(message='没有权限访问部门数据') + + @classmethod + async def check_dept_name_unique_services(cls, query_db: AsyncSession, page_object: DeptModel): + """ + 校验部门名称是否唯一service + :param query_db: orm对象 + :param page_object: 部门对象 + :return: 校验结果 + """ + dept_id = -1 if page_object.dept_id is None else page_object.dept_id + dept = await DeptDao.get_dept_detail_by_info(query_db, DeptModel(deptName=page_object.dept_name, parentId=page_object.parent_id)) + if dept and dept.dept_id != dept_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_dept_services(cls, query_db: AsyncSession, page_object: DeptModel): """ @@ -57,25 +88,19 @@ class DeptService: :param page_object: 新增部门对象 :return: 新增部门校验结果 """ + if not await cls.check_dept_name_unique_services(query_db, page_object): + raise ServiceException(message=f'新增部门{page_object.dept_name}失败,部门名称已存在') parent_info = await DeptDao.get_dept_by_id(query_db, page_object.parent_id) - if parent_info: - page_object.ancestors = f'{parent_info.ancestors},{page_object.parent_id}' - else: - page_object.ancestors = '0' - dept = await DeptDao.get_dept_detail_by_info(query_db, DeptModel(parentId=page_object.parent_id, - deptName=page_object.dept_name)) - if dept: - result = dict(is_success=False, message='同一部门下不允许存在同名的部门') - else: - try: - await DeptDao.add_dept_dao(query_db, page_object) - await query_db.commit() - result = dict(is_success=True, message='新增成功') - except Exception as e: - await query_db.rollback() - raise e - - return CrudResponseModel(**result) + if parent_info.status != CommonConstant.DEPT_NORMAL: + raise ServiceException(message=f'部门{parent_info.dept_name}停用,不允许新增') + page_object.ancestors = f'{parent_info.ancestors},{page_object.parent_id}' + try: + await DeptDao.add_dept_dao(query_db, page_object) + await query_db.commit() + return CrudResponseModel(is_success=True, message='新增成功') + except Exception as e: + await query_db.rollback() + raise e @classmethod async def edit_dept_services(cls, query_db: AsyncSession, page_object: DeptModel): @@ -85,37 +110,29 @@ class DeptService: :param page_object: 编辑部门对象 :return: 编辑部门校验结果 """ - parent_info = await DeptDao.get_dept_by_id(query_db, page_object.parent_id) - if parent_info: - page_object.ancestors = f'{parent_info.ancestors},{page_object.parent_id}' - else: - page_object.ancestors = '0' - edit_dept = page_object.model_dump(exclude_unset=True) - dept_info = await cls.dept_detail_services(query_db, edit_dept.get('dept_id')) - if dept_info: - if dept_info.parent_id != page_object.parent_id or dept_info.dept_name != page_object.dept_name: - dept = await DeptDao.get_dept_detail_by_info(query_db, DeptModel(parentId=page_object.parent_id, - deptName=page_object.dept_name)) - if dept: - result = dict(is_success=False, message='同一部门下不允许存在同名的部门') - return CrudResponseModel(**result) - try: - await DeptDao.edit_dept_dao(query_db, edit_dept) - await cls.update_children_info(query_db, DeptModel(deptId=page_object.dept_id, - ancestors=page_object.ancestors, - updateBy=page_object.update_by, - updateTime=page_object.update_time - ) - ) - await query_db.commit() - result = dict(is_success=True, message='更新成功') - except Exception as e: - await query_db.rollback() - raise e - else: - result = dict(is_success=False, message='部门不存在') - - return CrudResponseModel(**result) + if not await cls.check_dept_name_unique_services(query_db, page_object): + raise ServiceException(message=f'修改部门{page_object.dept_name}失败,部门名称已存在') + elif page_object.dept_id == page_object.parent_id: + raise ServiceException(message=f'修改部门{page_object.dept_name}失败,上级部门不能是自己') + elif page_object.status == CommonConstant.DEPT_DISABLE and (await DeptDao.count_normal_children_dept_dao(query_db, page_object.dept_id)) > 0: + raise ServiceException(message=f'修改部门{page_object.dept_name}失败,该部门包含未停用的子部门') + new_parent_dept = await DeptDao.get_dept_by_id(query_db, page_object.parent_id) + old_dept = await DeptDao.get_dept_by_id(query_db, page_object.dept_id) + try: + if new_parent_dept and old_dept: + new_ancestors = f'{new_parent_dept.ancestors},{new_parent_dept.dept_id}' + old_ancestors = old_dept.ancestors + page_object.ancestors = new_ancestors + await cls.update_dept_children(query_db, page_object.dept_id, new_ancestors, old_ancestors) + edit_dept = page_object.model_dump(exclude_unset=True) + await DeptDao.edit_dept_dao(query_db, edit_dept) + if page_object.status == CommonConstant.DEPT_NORMAL and page_object.ancestors and page_object.ancestors != 0: + await cls.update_parent_dept_status_normal(query_db, page_object) + await query_db.commit() + return CrudResponseModel(is_success=True, message='更新成功') + except Exception as e: + await query_db.rollback() + raise e @classmethod async def delete_dept_services(cls, query_db: AsyncSession, page_object: DeleteDeptModel): @@ -127,24 +144,21 @@ class DeptService: """ if page_object.dept_ids.split(','): dept_id_list = page_object.dept_ids.split(',') - ancestors = await DeptDao.get_dept_all_ancestors(query_db) try: for dept_id in dept_id_list: - for ancestor in ancestors: - if dept_id in ancestor[0]: - result = dict(is_success=False, message='该部门下有子部门,不允许删除') - - return CrudResponseModel(**result) + if (await DeptDao.count_children_dept_dao(query_db, int(dept_id))) > 0: + raise ServiceException(message='存在下级部门,不允许删除') + elif (await DeptDao.count_dept_user_dao(query_db, int(dept_id))) > 0: + raise ServiceException(message='部门存在用户,不允许删除') await DeptDao.delete_dept_dao(query_db, DeptModel(deptId=dept_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入部门id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入部门id为空') @classmethod async def dept_detail_services(cls, query_db: AsyncSession, dept_id: int): @@ -155,7 +169,10 @@ class DeptService: :return: 部门id对应的信息 """ dept = await DeptDao.get_dept_detail_by_id(query_db, dept_id=dept_id) - result = DeptModel(**CamelCaseUtil.transform_result(dept)) + if dept: + result = DeptModel(**CamelCaseUtil.transform_result(dept)) + else: + result = DeptModel(**dict()) return result @@ -189,26 +206,44 @@ class DeptService: return container @classmethod - async def update_children_info(cls, query_db, page_object): + async def replace_first(cls, original_str: str, old_str: str, new_str: str): + """ + 工具方法:替换字符串 + :param original_str: 需要替换的原始字符串 + :param old_str: 用于匹配的字符串 + :param new_str: 替换的字符串 + :return: 替换后的字符串 """ - 工具方法:递归更新子部门信息 + if original_str.startswith(old_str): + return original_str.replace(old_str, new_str, 1) + else: + return original_str + + @classmethod + async def update_parent_dept_status_normal(cls, query_db: AsyncSession, dept: DeptModel): + """ + 更新父部门状态为正常 :param query_db: orm对象 - :param page_object: 编辑部门对象 + :param dept: 部门对象 + :return: + """ + dept_id_list = dept.ancestors.split(',') + await DeptDao.update_dept_status_normal_dao(query_db, dept_id_list) + + @classmethod + async def update_dept_children(cls, query_db: AsyncSession, dept_id: int, new_ancestors: str, old_ancestors: str): + """ + 更新子部门信息 + :param query_db: orm对象 + :param dept_id: 部门id + :param new_ancestors: 新的祖先 + :param old_ancestors: 旧的祖先 :return: """ - children_info = await DeptDao.get_children_dept(query_db, page_object.dept_id) - if children_info: - for child in children_info: - child.ancestors = f'{page_object.ancestors},{page_object.dept_id}' - await DeptDao.edit_dept_dao(query_db, - dict(dept_id=child.dept_id, - ancestors=child.ancestors, - update_by=page_object.update_by, - update_time=page_object.update_time - ) - ) - await cls.update_children_info(query_db, DeptModel(dept_id=child.dept_id, - ancestors=child.ancestors, - update_by=page_object.update_by, - update_time=page_object.update_time - )) + children = await DeptDao.get_children_dept_dao(query_db, dept_id) + update_children = [] + for child in children: + child_ancestors = await cls.replace_first(child.ancestors, old_ancestors, new_ancestors) + update_children.append({'dept_id': child.dept_id, 'ancestors': child_ancestors}) + if children: + await DeptDao.update_dept_children_dao(query_db, update_children) -- Gitee From 0dfc201990133b3d23ff3286bb36bdabd843c6c7 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 11 Jul 2024 16:36:28 +0800 Subject: [PATCH 074/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=A7=92?= =?UTF-8?q?=E8=89=B2=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/role_controller.py | 28 +++++++++---------- .../module_admin/dao/role_dao.py | 18 ++++++------ .../module_admin/service/role_service.py | 15 +++++----- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index 1dd4d16..3c35a4a 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -30,7 +30,7 @@ async def get_system_role_dept_tree(request: Request, role_id: int, query_db: As @roleController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]) -async def get_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('role_query.columns'))): +async def get_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): role_page_query_result = await RoleService.get_role_list_services(query_db, role_page_query, data_scope_sql, is_page=True) logger.info('获取成功') @@ -54,10 +54,10 @@ async def add_system_role(request: Request, add_role: AddRoleModel, query_db: As @roleController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @ValidateFields(validate_model='edit_role') @log_decorator(title='角色管理', business_type=BusinessType.UPDATE) -async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): +async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): await RoleService.check_role_allowed_services(edit_role) if not current_user.user.admin: - await RoleService.check_role_data_scope_services(query_db, edit_role.role_id, data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, str(edit_role.role_id), data_scope_sql) edit_role.update_by = current_user.user.user_name edit_role.update_time = datetime.now() edit_role_result = await RoleService.edit_role_services(query_db, edit_role) @@ -68,10 +68,10 @@ async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: @roleController.put("/dataScope", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) -async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): +async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): await RoleService.check_role_allowed_services(role_data_scope) if not current_user.user.admin: - await RoleService.check_role_data_scope_services(query_db, role_data_scope.role_id, data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, str(role_data_scope.role_id), data_scope_sql) edit_role = AddRoleModel( roleId=role_data_scope.role_id, dataScope=role_data_scope.data_scope, @@ -88,12 +88,12 @@ async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleM @roleController.delete("/{role_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))]) @log_decorator(title='角色管理', business_type=BusinessType.DELETE) -async def delete_system_role(request: Request, role_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): +async def delete_system_role(request: Request, role_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): role_id_list = role_ids.split(',') for role_id in role_id_list: await RoleService.check_role_allowed_services(RoleModel(roleId=int(role_id))) if not current_user.user.admin: - await RoleService.check_role_data_scope_services(query_db, int(role_id), data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, role_id, data_scope_sql) delete_role = DeleteRoleModel( roleIds=role_ids, updateBy=current_user.user.user_name, @@ -106,9 +106,9 @@ async def delete_system_role(request: Request, role_ids: str, query_db: AsyncSes @roleController.get("/{role_id}", response_model=RoleModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]) -async def query_detail_system_role(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): +async def query_detail_system_role(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): if not current_user.user.admin: - await RoleService.check_role_data_scope_services(query_db, role_id, data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, str(role_id), data_scope_sql) role_detail_result = await RoleService.role_detail_services(query_db, role_id) logger.info(f'获取role_id为{role_id}的信息成功') @@ -117,7 +117,7 @@ async def query_detail_system_role(request: Request, role_id: int, query_db: Asy @roleController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))]) @log_decorator(title='角色管理', business_type=BusinessType.EXPORT) -async def export_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('role_query'))): +async def export_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): # 获取全量数据 role_query_result = await RoleService.get_role_list_services(query_db, role_page_query, data_scope_sql, is_page=False) role_export_result = await RoleService.export_role_list_services(role_query_result) @@ -128,10 +128,10 @@ async def export_system_role_list(request: Request, role_page_query: RolePageQue @roleController.put("/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.UPDATE) -async def reset_system_role_status(request: Request, change_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): +async def reset_system_role_status(request: Request, change_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): await RoleService.check_role_allowed_services(change_role) if not current_user.user.admin: - await RoleService.check_role_data_scope_services(query_db, change_role.role_id, data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, str(change_role.role_id), data_scope_sql) edit_role = AddRoleModel( roleId=change_role.role_id, status=change_role.status, @@ -163,9 +163,9 @@ async def get_system_unallocated_user_list(request: Request, user_role: UserRole @roleController.put("/authUser/selectAll", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) -async def add_system_role_user(request: Request, add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('role_query'))): +async def add_system_role_user(request: Request, add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): if not current_user.user.admin: - await RoleService.check_role_data_scope_services(query_db, add_role_user.role_id, data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, str(add_role_user.role_id), data_scope_sql) add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user) logger.info(add_role_user_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py index 5706128..36fb89c 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py @@ -107,10 +107,10 @@ class RoleDao: :param is_page: 是否开启分页 :return: 角色列表信息对象 """ - role_query = (select(SysRole, SysUser.user_id, SysDept.dept_id) - .join(SysUserRole, SysUserRole.role_id == SysRole.role_id, isouter=True) - .join(SysUser, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) + query = select(SysRole) \ + .join(SysUserRole, SysUserRole.role_id == SysRole.role_id, isouter=True) \ + .join(SysUser, SysUser.user_id == SysUserRole.user_id, isouter=True) \ + .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) \ .where(SysRole.del_flag == '0', SysRole.role_name.like(f'%{query_object.role_name}%') if query_object.role_name else True, SysRole.role_key.like(f'%{query_object.role_key}%') if query_object.role_key else True, @@ -118,12 +118,10 @@ class RoleDao: SysRole.create_time.between( datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True) - .order_by(SysRole.role_sort)).subquery() - query = select(SysRole) \ - .select_from(role_query) \ - .join(SysRole, SysRole.role_id == role_query.columns.role_id) \ - .where(eval(data_scope_sql)).distinct() + if query_object.begin_time and query_object.end_time else True, + eval(data_scope_sql)) \ + .order_by(SysRole.role_sort) \ + .distinct() role_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return role_list diff --git a/ruoyi-fastapi-backend/module_admin/service/role_service.py b/ruoyi-fastapi-backend/module_admin/service/role_service.py index aa0a54d..890f23a 100644 --- a/ruoyi-fastapi-backend/module_admin/service/role_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/role_service.py @@ -68,19 +68,20 @@ class RoleService: return CrudResponseModel(is_success=True, message='校验通过') @classmethod - async def check_role_data_scope_services(cls, query_db: AsyncSession, role_id: int, data_scope_sql: str): + async def check_role_data_scope_services(cls, query_db: AsyncSession, role_ids: str, data_scope_sql: str): """ 校验角色是否有数据权限service :param query_db: orm对象 - :param role_id: 角色id + :param role_ids: 角色id :param data_scope_sql: 数据权限对应的查询sql语句 :return: 校验结果 """ - roles = await RoleDao.get_role_list(query_db, RolePageQueryModel(roleId=role_id), data_scope_sql, is_page=False) - if roles: - return CrudResponseModel(is_success=True, message='校验通过') - else: - raise ServiceException(message='没有权限访问角色数据') + for role_id in role_ids.split(','): + roles = await RoleDao.get_role_list(query_db, RolePageQueryModel(roleId=int(role_id)), data_scope_sql, is_page=False) + if roles: + return CrudResponseModel(is_success=True, message='校验通过') + else: + raise ServiceException(message='没有权限访问角色数据') @classmethod async def check_role_name_unique_services(cls, query_db: AsyncSession, page_object: RoleModel): -- Gitee From 47d5697653f351ebfe1d7153b0c9e4aff8c50806 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 11 Jul 2024 16:47:23 +0800 Subject: [PATCH 075/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=85=A8?= =?UTF-8?q?=E5=B1=80=E5=A4=84=E7=90=86=E8=87=AA=E5=AE=9A=E4=B9=89=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/exception.py | 10 ++++++++++ ruoyi-fastapi-backend/exceptions/handle.py | 8 +++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/exceptions/exception.py b/ruoyi-fastapi-backend/exceptions/exception.py index 0a94948..b86f50d 100644 --- a/ruoyi-fastapi-backend/exceptions/exception.py +++ b/ruoyi-fastapi-backend/exceptions/exception.py @@ -38,6 +38,16 @@ class ServiceException(Exception): self.message = message +class ServiceWarning(Exception): + """ + 自定义服务警告ServiceWarning + """ + + def __init__(self, data: str = None, message: str = None): + self.data = data + self.message = message + + class ModelValidatorException(Exception): """ 自定义模型校验异常ModelValidatorException diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index 2b18687..5895586 100644 --- a/ruoyi-fastapi-backend/exceptions/handle.py +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -1,7 +1,7 @@ from fastapi import FastAPI, Request from fastapi.exceptions import HTTPException from pydantic_validation_decorator import FieldValidationError -from exceptions.exception import AuthException, LoginException, PermissionException, ServiceException, ModelValidatorException +from exceptions.exception import AuthException, LoginException, PermissionException, ServiceException, ServiceWarning, ModelValidatorException from utils.log_util import logger from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder @@ -28,6 +28,12 @@ def handle_exception(app: FastAPI): # 自定义服务异常 @app.exception_handler(ServiceException) async def service_exception_handler(request: Request, exc: ServiceException): + logger.warning(exc.message) + return ResponseUtil.error(data=exc.data, msg=exc.message) + + # 自定义服务警告 + @app.exception_handler(ServiceWarning) + async def service_warning_handler(request: Request, exc: ServiceWarning): logger.warning(exc.message) return ResponseUtil.failure(data=exc.data, msg=exc.message) -- Gitee From d0eafb1e098852908728d04620e28eb4e6dddaaa Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 11 Jul 2024 17:17:56 +0800 Subject: [PATCH 076/129] =?UTF-8?q?feat:=20=E9=83=A8=E9=97=A8=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E5=92=8C=E8=8F=9C=E5=8D=95=E7=AE=A1=E7=90=86service?= =?UTF-8?q?=E5=B1=82=E5=BC=95=E5=85=A5ServiceWarning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/service/dept_service.py | 6 +++--- ruoyi-fastapi-backend/module_admin/service/menu_service.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/service/dept_service.py b/ruoyi-fastapi-backend/module_admin/service/dept_service.py index 1a84c6e..85685a2 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dept_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dept_service.py @@ -1,7 +1,7 @@ from module_admin.dao.dept_dao import * from module_admin.entity.vo.common_vo import CrudResponseModel from config.constant import CommonConstant -from exceptions.exception import ServiceException +from exceptions.exception import ServiceException, ServiceWarning from utils.common_util import CamelCaseUtil @@ -147,9 +147,9 @@ class DeptService: try: for dept_id in dept_id_list: if (await DeptDao.count_children_dept_dao(query_db, int(dept_id))) > 0: - raise ServiceException(message='存在下级部门,不允许删除') + raise ServiceWarning(message='存在下级部门,不允许删除') elif (await DeptDao.count_dept_user_dao(query_db, int(dept_id))) > 0: - raise ServiceException(message='部门存在用户,不允许删除') + raise ServiceWarning(message='部门存在用户,不允许删除') await DeptDao.delete_dept_dao(query_db, DeptModel(deptId=dept_id)) await query_db.commit() diff --git a/ruoyi-fastapi-backend/module_admin/service/menu_service.py b/ruoyi-fastapi-backend/module_admin/service/menu_service.py index e68d3f6..3935495 100644 --- a/ruoyi-fastapi-backend/module_admin/service/menu_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/menu_service.py @@ -4,7 +4,7 @@ from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.role_dao import RoleDao from module_admin.dao.menu_dao import * from config.constant import CommonConstant, MenuConstant -from exceptions.exception import ServiceException +from exceptions.exception import ServiceException, ServiceWarning from utils.common_util import CamelCaseUtil from utils.string_util import StringUtil @@ -137,9 +137,9 @@ class MenuService: try: for menu_id in menu_id_list: if (await MenuDao.has_child_by_menu_id_dao(query_db, int(menu_id))) > 0: - raise ServiceException(message='存在子菜单,不允许删除') + raise ServiceWarning(message='存在子菜单,不允许删除') elif (await MenuDao.check_menu_exist_role_dao(query_db, int(menu_id))) > 0: - raise ServiceException(message='菜单已分配,不允许删除') + raise ServiceWarning(message='菜单已分配,不允许删除') await MenuDao.delete_menu_dao(query_db, MenuModel(menuId=menu_id)) await query_db.commit() return CrudResponseModel(is_success=True, message='删除成功') -- Gitee From 449b7581d8ae7e80a69c2cee50519247d3a721d3 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 11 Jul 2024 21:38:44 +0800 Subject: [PATCH 077/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E6=95=B0=E6=8D=AE=E6=9D=83=E9=99=90=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/user_controller.py | 41 +++++++++++++++---- .../module_admin/service/user_service.py | 24 ++++++++--- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index c79c1cb..28bea7c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -5,6 +5,7 @@ from config.get_db import get_db from config.env import UploadConfig from module_admin.service.login_service import LoginService from module_admin.service.user_service import * +from module_admin.service.role_service import RoleService from module_admin.service.dept_service import DeptService from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope @@ -40,7 +41,13 @@ async def get_system_user_list(request: Request, user_page_query: UserPageQueryM @userController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) @ValidateFields(validate_model='add_user') @log_decorator(title='用户管理', business_type=BusinessType.INSERT) -async def add_system_user(request: Request, add_user: AddUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_user(request: Request, add_user: AddUserModel, query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + dept_data_scope_sql: str = Depends(GetDataScope('SysDept')), + role_data_scope_sql: str = Depends(GetDataScope('SysDept'))): + if not current_user.user.admin: + await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, ','.join(add_user.role_ids), role_data_scope_sql) add_user.password = PwdUtil.get_password_hash(add_user.password) add_user.create_by = current_user.user.user_name add_user.create_time = datetime.now() @@ -55,10 +62,16 @@ async def add_system_user(request: Request, add_user: AddUserModel, query_db: As @userController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @ValidateFields(validate_model='edit_user') @log_decorator(title='用户管理', business_type=BusinessType.UPDATE) -async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): +async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + user_data_scope_sql: str = Depends(GetDataScope('SysUser')), + dept_data_scope_sql: str = Depends(GetDataScope('SysDept')), + role_data_scope_sql: str = Depends(GetDataScope('SysDept'))): await UserService.check_user_allowed_services(edit_user) if not current_user.user.admin: - await UserService.check_user_data_scope_services(query_db, edit_user.user_id, data_scope_sql) + await UserService.check_user_data_scope_services(query_db, edit_user.user_id, user_data_scope_sql) + await DeptService.check_dept_data_scope_services(query_db, edit_user.dept_id, dept_data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, ','.join(edit_user.role_ids), role_data_scope_sql) edit_user.update_by = current_user.user.user_name edit_user.update_time = datetime.now() edit_user_result = await UserService.edit_user_services(query_db, edit_user) @@ -138,7 +151,9 @@ async def query_detail_system_user(request: Request, query_db: AsyncSession = De @userController.get("/{user_id}", response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]) @userController.get("/", response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]) -async def query_detail_system_user(request: Request, user_id: Optional[Union[int, str]] = '', query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def query_detail_system_user(request: Request, user_id: Optional[Union[int, str]] = '', query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): + if user_id and not current_user.user.admin: + await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql) detail_user_result = await UserService.user_detail_services(query_db, user_id) logger.info(f'获取user_id为{user_id}的信息成功') @@ -214,8 +229,13 @@ async def reset_system_user_password(request: Request, reset_password: ResetPass @userController.post("/importData", dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) @log_decorator(title='用户管理', business_type=BusinessType.IMPORT) -async def batch_import_system_user(request: Request, file: UploadFile = File(...), update_support: bool = Query(alias='updateSupport'), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): - batch_import_result = await UserService.batch_import_user_services(query_db, file, update_support, current_user) +async def batch_import_system_user(request: Request, file: UploadFile = File(...), + update_support: bool = Query(alias='updateSupport'), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + user_data_scope_sql: str = Depends(GetDataScope('SysUser')), + dept_data_scope_sql: str = Depends(GetDataScope('SysDept'))): + batch_import_result = await UserService.batch_import_user_services(request, query_db, file, update_support, current_user, user_data_scope_sql, dept_data_scope_sql) logger.info(batch_import_result.message) return ResponseUtil.success(msg=batch_import_result.message) @@ -251,9 +271,14 @@ async def get_system_allocated_role_list(request: Request, user_id: int, query_d @userController.put("/authRole", response_model=UserRoleResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @log_decorator(title='用户管理', business_type=BusinessType.GRANT) -async def update_system_role_user(request: Request, user_id: int = Query(alias='userId'), role_ids: str = Query(alias='roleIds'), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): +async def update_system_role_user(request: Request, user_id: int = Query(alias='userId'), role_ids: str = Query(alias='roleIds'), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + user_data_scope_sql: str = Depends(GetDataScope('SysUser')), + role_data_scope_sql: str = Depends(GetDataScope('SysDept'))): if not current_user.user.admin: - await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql) + await UserService.check_user_data_scope_services(query_db, user_id, user_data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, role_ids, role_data_scope_sql) add_user_role_result = await UserService.add_user_role_services(query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids)) logger.info(add_user_role_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/service/user_service.py b/ruoyi-fastapi-backend/module_admin/service/user_service.py index 4e9ab2a..720480d 100644 --- a/ruoyi-fastapi-backend/module_admin/service/user_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/user_service.py @@ -1,6 +1,8 @@ -from fastapi import UploadFile +from fastapi import Request, UploadFile from module_admin.service.role_service import RoleService +from module_admin.service.dept_service import DeptService from module_admin.service.post_service import PostService, PostPageQueryModel +from module_admin.service.config_service import ConfigService from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.user_dao import * from config.constant import CommonConstant @@ -298,13 +300,16 @@ class UserService: raise e @classmethod - async def batch_import_user_services(cls, query_db: AsyncSession, file: UploadFile, update_support: bool, current_user: CurrentUserModel): + async def batch_import_user_services(cls, request: Request, query_db: AsyncSession, file: UploadFile, update_support: bool, current_user: CurrentUserModel, user_data_scope_sql: str, dept_data_scope_sql: str): """ 批量导入用户service + :param request: Request对象 :param query_db: orm对象 :param file: 用户导入文件对象 :param update_support: 用户存在时是否更新 :param current_user: 当前用户对象 + :param user_data_scope_sql: 用户数据权限sql + :param dept_data_scope_sql: 部门数据权限sql :return: 批量导入用户结果 """ header_dict = { @@ -338,7 +343,7 @@ class UserService: add_user = UserModel( deptId=row['dept_id'], userName=row['user_name'], - password=PwdUtil.get_password_hash('123456'), + password=PwdUtil.get_password_hash(await ConfigService.query_config_list_from_cache_services(request.app.state.redis, 'sys.user.initPassword')), nickName=row['nick_name'], email=row['email'], phonenumber=str(row['phonenumber']), @@ -352,7 +357,7 @@ class UserService: user_info = await UserDao.get_user_by_info(query_db, UserModel(userName=row['user_name'])) if user_info: if update_support: - edit_user = UserModel( + edit_user_model = UserModel( userId=user_info.user_id, deptId=row['dept_id'], userName=row['user_name'], @@ -363,11 +368,20 @@ class UserService: status=row['status'], updateBy=current_user.user.user_name, updateTime=datetime.now() - ).model_dump(exclude_unset=True) + ) + edit_user_model.validate_fields() + await cls.check_user_allowed_services(edit_user_model) + if not current_user.user.admin: + await cls.check_user_data_scope_services(query_db, edit_user_model.user_id, user_data_scope_sql) + await DeptService.check_dept_data_scope_services(query_db, edit_user_model.dept_id, dept_data_scope_sql) + edit_user = edit_user_model.model_dump(exclude_unset=True) await UserDao.edit_user_dao(query_db, edit_user) else: add_error_result.append(f"{count}.用户账号{row['user_name']}已存在") else: + add_user.validate_fields() + if not current_user.user.admin: + await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql) await UserDao.add_user_dao(query_db, add_user) await query_db.commit() return CrudResponseModel(is_success=True, message='\n'.join(add_error_result)) -- Gitee From 5ae234714f9ddc64d30ba84e22eaead8896cac3d Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 11 Jul 2024 22:24:17 +0800 Subject: [PATCH 078/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Eruff=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/ruff.toml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 ruoyi-fastapi-backend/ruff.toml diff --git a/ruoyi-fastapi-backend/ruff.toml b/ruoyi-fastapi-backend/ruff.toml new file mode 100644 index 0000000..ea95368 --- /dev/null +++ b/ruoyi-fastapi-backend/ruff.toml @@ -0,0 +1,4 @@ +line-length = 120 + +[format] +quote-style = "single" \ No newline at end of file -- Gitee From 40a8c7346170d3ed8763275973ed6fe546d2bff8 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Thu, 11 Jul 2024 22:24:58 +0800 Subject: [PATCH 079/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E7=94=A8=E6=88=B7=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/user_controller.py | 267 ++++++--- .../module_admin/dao/user_dao.py | 522 +++++++++++------- .../module_admin/entity/vo/user_vo.py | 38 +- .../module_admin/service/user_service.py | 193 ++++--- 4 files changed, 669 insertions(+), 351 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index 28bea7c..2ee6e70 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -1,50 +1,86 @@ -from fastapi import APIRouter, Request -from fastapi import Depends, File, Query +import os +from datetime import datetime +from fastapi import APIRouter, Depends, File, Query, Request, UploadFile +from sqlalchemy.ext.asyncio import AsyncSession +from typing import Optional, Union from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from config.env import UploadConfig +from module_admin.annotation.log_annotation import log_decorator +from module_admin.aspect.data_scope import GetDataScope +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.dept_vo import DeptModel +from module_admin.entity.vo.user_vo import ( + AddUserModel, + CrudUserRoleModel, + CurrentUserModel, + DeleteUserModel, + EditUserModel, + ResetPasswordModel, + ResetUserModel, + UserDetailModel, + UserInfoModel, + UserModel, + UserPageQueryModel, + UserProfileModel, + UserRoleQueryModel, + UserRoleResponseModel, +) from module_admin.service.login_service import LoginService -from module_admin.service.user_service import * +from module_admin.service.user_service import UserService from module_admin.service.role_service import RoleService from module_admin.service.dept_service import DeptService -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.aspect.data_scope import GetDataScope -from module_admin.annotation.log_annotation import log_decorator from config.enums import BusinessType -from utils.page_util import PageResponseModel -from utils.response_util import * -from utils.log_util import * from utils.common_util import bytes2file_response +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.pwd_util import PwdUtil +from utils.response_util import ResponseUtil from utils.upload_util import UploadUtil userController = APIRouter(prefix='/system/user', dependencies=[Depends(LoginService.get_current_user)]) -@userController.get("/deptTree", dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]) -async def get_system_dept_tree(request: Request, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +@userController.get('/deptTree', dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]) +async def get_system_dept_tree( + request: Request, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept')) +): dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql) logger.info('获取成功') return ResponseUtil.success(data=dept_query_result) -@userController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]) -async def get_system_user_list(request: Request, user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): +@userController.get( + '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))] +) +async def get_system_user_list( + request: Request, + user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysUser')), +): # 获取分页数据 - user_page_query_result = await UserService.get_user_list_services(query_db, user_page_query, data_scope_sql, is_page=True) + user_page_query_result = await UserService.get_user_list_services( + query_db, user_page_query, data_scope_sql, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=user_page_query_result) -@userController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) +@userController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) @ValidateFields(validate_model='add_user') @log_decorator(title='用户管理', business_type=BusinessType.INSERT) -async def add_system_user(request: Request, add_user: AddUserModel, query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), - dept_data_scope_sql: str = Depends(GetDataScope('SysDept')), - role_data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def add_system_user( + request: Request, + add_user: AddUserModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + dept_data_scope_sql: str = Depends(GetDataScope('SysDept')), + role_data_scope_sql: str = Depends(GetDataScope('SysDept')), +): if not current_user.user.admin: await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql) await RoleService.check_role_data_scope_services(query_db, ','.join(add_user.role_ids), role_data_scope_sql) @@ -59,14 +95,18 @@ async def add_system_user(request: Request, add_user: AddUserModel, query_db: As return ResponseUtil.success(msg=add_user_result.message) -@userController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) +@userController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @ValidateFields(validate_model='edit_user') @log_decorator(title='用户管理', business_type=BusinessType.UPDATE) -async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), - user_data_scope_sql: str = Depends(GetDataScope('SysUser')), - dept_data_scope_sql: str = Depends(GetDataScope('SysDept')), - role_data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def edit_system_user( + request: Request, + edit_user: EditUserModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + user_data_scope_sql: str = Depends(GetDataScope('SysUser')), + dept_data_scope_sql: str = Depends(GetDataScope('SysDept')), + role_data_scope_sql: str = Depends(GetDataScope('SysDept')), +): await UserService.check_user_allowed_services(edit_user) if not current_user.user.admin: await UserService.check_user_data_scope_services(query_db, edit_user.user_id, user_data_scope_sql) @@ -80,9 +120,15 @@ async def edit_system_user(request: Request, edit_user: EditUserModel, query_db: return ResponseUtil.success(msg=edit_user_result.message) -@userController.delete("/{user_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))]) +@userController.delete('/{user_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))]) @log_decorator(title='用户管理', business_type=BusinessType.DELETE) -async def delete_system_user(request: Request, user_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): +async def delete_system_user( + request: Request, + user_ids: str, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysUser')), +): user_id_list = user_ids.split(',') if current_user.user.user_id in user_id_list: logger.warning('当前登录用户不能删除') @@ -92,20 +138,22 @@ async def delete_system_user(request: Request, user_ids: str, query_db: AsyncSes await UserService.check_user_allowed_services(UserModel(userId=int(user_id))) if not current_user.user.admin: await UserService.check_user_data_scope_services(query_db, int(user_id), data_scope_sql) - delete_user = DeleteUserModel( - userIds=user_ids, - updateBy=current_user.user.user_name, - updateTime=datetime.now() - ) + delete_user = DeleteUserModel(userIds=user_ids, updateBy=current_user.user.user_name, updateTime=datetime.now()) delete_user_result = await UserService.delete_user_services(query_db, delete_user) logger.info(delete_user_result.message) return ResponseUtil.success(msg=delete_user_result.message) -@userController.put("/resetPwd", dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))]) +@userController.put('/resetPwd', dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))]) @log_decorator(title='用户管理', business_type=BusinessType.UPDATE) -async def reset_system_user_pwd(request: Request, reset_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): +async def reset_system_user_pwd( + request: Request, + reset_user: EditUserModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysUser')), +): await UserService.check_user_allowed_services(reset_user) if not current_user.user.admin: await UserService.check_user_data_scope_services(query_db, reset_user.user_id, data_scope_sql) @@ -114,7 +162,7 @@ async def reset_system_user_pwd(request: Request, reset_user: EditUserModel, que password=PwdUtil.get_password_hash(reset_user.password), updateBy=current_user.user.user_name, updateTime=datetime.now(), - type='pwd' + type='pwd', ) edit_user_result = await UserService.edit_user_services(query_db, edit_user) logger.info(edit_user_result.message) @@ -122,9 +170,15 @@ async def reset_system_user_pwd(request: Request, reset_user: EditUserModel, que return ResponseUtil.success(msg=edit_user_result.message) -@userController.put("/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) +@userController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @log_decorator(title='用户管理', business_type=BusinessType.UPDATE) -async def change_system_user_status(request: Request, change_user: EditUserModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): +async def change_system_user_status( + request: Request, + change_user: EditUserModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysUser')), +): await UserService.check_user_allowed_services(change_user) if not current_user.user.admin: await UserService.check_user_data_scope_services(query_db, change_user.user_id, data_scope_sql) @@ -133,7 +187,7 @@ async def change_system_user_status(request: Request, change_user: EditUserModel status=change_user.status, updateBy=current_user.user.user_name, updateTime=datetime.now(), - type='status' + type='status', ) edit_user_result = await UserService.edit_user_services(query_db, edit_user) logger.info(edit_user_result.message) @@ -141,17 +195,31 @@ async def change_system_user_status(request: Request, change_user: EditUserModel return ResponseUtil.success(msg=edit_user_result.message) -@userController.get("/profile", response_model=UserProfileModel) -async def query_detail_system_user(request: Request, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +@userController.get('/profile', response_model=UserProfileModel) +async def query_detail_system_user_profile( + request: Request, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): profile_user_result = await UserService.user_profile_services(query_db, current_user.user.user_id) logger.info(f'获取user_id为{current_user.user.user_id}的信息成功') return ResponseUtil.success(model_content=profile_user_result) -@userController.get("/{user_id}", response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]) -@userController.get("/", response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]) -async def query_detail_system_user(request: Request, user_id: Optional[Union[int, str]] = '', query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysUser'))): +@userController.get( + '/{user_id}', response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))] +) +@userController.get( + '/', response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))] +) +async def query_detail_system_user( + request: Request, + user_id: Optional[Union[int, str]] = '', + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysUser')), +): if user_id and not current_user.user.admin: await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql) detail_user_result = await UserService.user_detail_services(query_db, user_id) @@ -160,11 +228,18 @@ async def query_detail_system_user(request: Request, user_id: Optional[Union[int return ResponseUtil.success(model_content=detail_user_result) -@userController.post("/profile/avatar") +@userController.post('/profile/avatar') @log_decorator(title='个人信息', business_type=BusinessType.UPDATE) -async def change_system_user_profile_avatar(request: Request, avatarfile: bytes = File(), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def change_system_user_profile_avatar( + request: Request, + avatarfile: bytes = File(), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): if avatarfile: - relative_path = f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}' + relative_path = ( + f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}' + ) dir_path = os.path.join(UploadConfig.UPLOAD_PATH, relative_path) try: os.makedirs(dir_path) @@ -179,7 +254,7 @@ async def change_system_user_profile_avatar(request: Request, avatarfile: bytes avatar=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{avatar_name}', updateBy=current_user.user.user_name, updateTime=datetime.now(), - type='avatar' + type='avatar', ) edit_user_result = await UserService.edit_user_services(query_db, edit_user) logger.info(edit_user_result.message) @@ -188,22 +263,23 @@ async def change_system_user_profile_avatar(request: Request, avatarfile: bytes return ResponseUtil.failure(msg='上传图片异常,请联系管理员') -@userController.put("/profile") +@userController.put('/profile') @log_decorator(title='个人信息', business_type=BusinessType.UPDATE) -async def change_system_user_profile_info(request: Request, user_info: UserInfoModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def change_system_user_profile_info( + request: Request, + user_info: UserInfoModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): edit_user = EditUserModel( - **user_info.model_dump( - exclude_unset=True, - by_alias=True, - exclude={'role_ids', 'post_ids'} - ), + **user_info.model_dump(exclude_unset=True, by_alias=True, exclude={'role_ids', 'post_ids'}), userId=current_user.user.user_id, userName=current_user.user.user_name, updateBy=current_user.user.user_name, updateTime=datetime.now(), roleIds=current_user.user.role_ids.split(',') if current_user.user.role_ids else [], postIds=current_user.user.post_ids.split(',') if current_user.user.post_ids else [], - role=current_user.user.role + role=current_user.user.role, ) edit_user_result = await UserService.edit_user_services(query_db, edit_user) logger.info(edit_user_result.message) @@ -211,15 +287,20 @@ async def change_system_user_profile_info(request: Request, user_info: UserInfoM return ResponseUtil.success(msg=edit_user_result.message) -@userController.put("/profile/updatePwd") +@userController.put('/profile/updatePwd') @log_decorator(title='个人信息', business_type=BusinessType.UPDATE) -async def reset_system_user_password(request: Request, reset_password: ResetPasswordModel = Depends(ResetPasswordModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def reset_system_user_password( + request: Request, + reset_password: ResetPasswordModel = Depends(ResetPasswordModel.as_query), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): reset_user = ResetUserModel( userId=current_user.user.user_id, oldPassword=reset_password.old_password, password=PwdUtil.get_password_hash(reset_password.new_password), updateBy=current_user.user.user_name, - updateTime=datetime.now() + updateTime=datetime.now(), ) reset_user_result = await UserService.reset_user_services(query_db, reset_user) logger.info(reset_user_result.message) @@ -227,21 +308,26 @@ async def reset_system_user_password(request: Request, reset_password: ResetPass return ResponseUtil.success(msg=reset_user_result.message) -@userController.post("/importData", dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) +@userController.post('/importData', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) @log_decorator(title='用户管理', business_type=BusinessType.IMPORT) -async def batch_import_system_user(request: Request, file: UploadFile = File(...), - update_support: bool = Query(alias='updateSupport'), - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), - user_data_scope_sql: str = Depends(GetDataScope('SysUser')), - dept_data_scope_sql: str = Depends(GetDataScope('SysDept'))): - batch_import_result = await UserService.batch_import_user_services(request, query_db, file, update_support, current_user, user_data_scope_sql, dept_data_scope_sql) +async def batch_import_system_user( + request: Request, + file: UploadFile = File(...), + update_support: bool = Query(alias='updateSupport'), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + user_data_scope_sql: str = Depends(GetDataScope('SysUser')), + dept_data_scope_sql: str = Depends(GetDataScope('SysDept')), +): + batch_import_result = await UserService.batch_import_user_services( + request, query_db, file, update_support, current_user, user_data_scope_sql, dept_data_scope_sql + ) logger.info(batch_import_result.message) return ResponseUtil.success(msg=batch_import_result.message) -@userController.post("/importTemplate", dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) +@userController.post('/importTemplate', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) async def export_system_user_template(request: Request, query_db: AsyncSession = Depends(get_db)): user_import_template_result = await UserService.get_user_import_template_services() logger.info('获取成功') @@ -249,37 +335,60 @@ async def export_system_user_template(request: Request, query_db: AsyncSession = return ResponseUtil.streaming(data=bytes2file_response(user_import_template_result)) -@userController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:user:export'))]) +@userController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:user:export'))]) @log_decorator(title='用户管理', business_type=BusinessType.EXPORT) -async def export_system_user_list(request: Request, user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): +async def export_system_user_list( + request: Request, + user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysUser')), +): # 获取全量数据 - user_query_result = await UserService.get_user_list_services(query_db, user_page_query, data_scope_sql, is_page=False) + user_query_result = await UserService.get_user_list_services( + query_db, user_page_query, data_scope_sql, is_page=False + ) user_export_result = await UserService.export_user_list_services(user_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(user_export_result)) -@userController.get("/authRole/{user_id}", response_model=UserRoleResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]) +@userController.get( + '/authRole/{user_id}', + response_model=UserRoleResponseModel, + dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))], +) async def get_system_allocated_role_list(request: Request, user_id: int, query_db: AsyncSession = Depends(get_db)): user_role_query = UserRoleQueryModel(userId=user_id) - user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services(query_db, user_role_query) + user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services( + query_db, user_role_query + ) logger.info('获取成功') return ResponseUtil.success(model_content=user_role_allocated_query_result) -@userController.put("/authRole", response_model=UserRoleResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) +@userController.put( + '/authRole', + response_model=UserRoleResponseModel, + dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))], +) @log_decorator(title='用户管理', business_type=BusinessType.GRANT) -async def update_system_role_user(request: Request, user_id: int = Query(alias='userId'), role_ids: str = Query(alias='roleIds'), - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), - user_data_scope_sql: str = Depends(GetDataScope('SysUser')), - role_data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def update_system_role_user( + request: Request, + user_id: int = Query(alias='userId'), + role_ids: str = Query(alias='roleIds'), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + user_data_scope_sql: str = Depends(GetDataScope('SysUser')), + role_data_scope_sql: str = Depends(GetDataScope('SysDept')), +): if not current_user.user.admin: await UserService.check_user_data_scope_services(query_db, user_id, user_data_scope_sql) await RoleService.check_role_data_scope_services(query_db, role_ids, role_data_scope_sql) - add_user_role_result = await UserService.add_user_role_services(query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids)) + add_user_role_result = await UserService.add_user_role_services( + query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids) + ) logger.info(add_user_role_result.message) return ResponseUtil.success(msg=add_user_role_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py index f75deac..05e47bc 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py @@ -1,13 +1,20 @@ -from sqlalchemy import select, update, delete, and_, or_, desc, func +from datetime import datetime, time +from sqlalchemy import and_, delete, desc, func, or_, select, update from sqlalchemy.ext.asyncio import AsyncSession -from module_admin.entity.do.user_do import SysUser, SysUserRole, SysUserPost -from module_admin.entity.do.role_do import SysRole, SysRoleDept, SysRoleMenu from module_admin.entity.do.dept_do import SysDept -from module_admin.entity.do.post_do import SysPost from module_admin.entity.do.menu_do import SysMenu -from module_admin.entity.vo.user_vo import * +from module_admin.entity.do.post_do import SysPost +from module_admin.entity.do.role_do import SysRole, SysRoleDept, SysRoleMenu # noqa: F401 +from module_admin.entity.do.user_do import SysUser, SysUserPost, SysUserRole +from module_admin.entity.vo.user_vo import ( + UserModel, + UserPageQueryModel, + UserPostModel, + UserRoleModel, + UserRolePageQueryModel, + UserRoleQueryModel, +) from utils.page_util import PageUtil -from datetime import datetime, time class UserDao: @@ -23,12 +30,18 @@ class UserDao: :param user_name: 用户名 :return: 当前用户名的用户信息对象 """ - query_user_info = (await db.execute( - select(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_name == user_name) - .order_by(desc(SysUser.create_time)) - .distinct() - )).scalars().first() + query_user_info = ( + ( + await db.execute( + select(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_name == user_name) + .order_by(desc(SysUser.create_time)) + .distinct() + ) + ) + .scalars() + .first() + ) return query_user_info @@ -40,15 +53,23 @@ class UserDao: :param user: 用户参数 :return: 当前用户参数的用户信息对象 """ - query_user_info = (await db.execute( - select(SysUser) - .where(SysUser.del_flag == '0', - SysUser.user_name == user.user_name if user.user_name else True, - SysUser.phonenumber == user.phonenumber if user.phonenumber else True, - SysUser.email == user.email if user.email else True) - .order_by(desc(SysUser.create_time)) - .distinct() - )).scalars().first() + query_user_info = ( + ( + await db.execute( + select(SysUser) + .where( + SysUser.del_flag == '0', + SysUser.user_name == user.user_name if user.user_name else True, + SysUser.phonenumber == user.phonenumber if user.phonenumber else True, + SysUser.email == user.email if user.email else True, + ) + .order_by(desc(SysUser.create_time)) + .distinct() + ) + ) + .scalars() + .first() + ) return query_user_info @@ -60,62 +81,100 @@ class UserDao: :param user_id: 用户id :return: 当前user_id的用户信息对象 """ - query_user_basic_info = (await db.execute( - select(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) - .distinct() - )).scalars().first() - query_user_dept_info = (await db.execute( - select(SysDept) - .select_from(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0')) - .distinct() - )).scalars().first() - query_user_role_info = (await db.execute( - select(SysRole) - .select_from(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0')) - .distinct() - )).scalars().all() - query_user_post_info = (await db.execute( - select(SysPost) - .select_from(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserPost, SysUser.user_id == SysUserPost.user_id, isouter=True) - .join(SysPost, and_(SysUserPost.post_id == SysPost.post_id, SysPost.status == '0')) - .distinct() - )).scalars().all() - role_id_list = [item.role_id for item in query_user_role_info] - if 1 in role_id_list: - query_user_menu_info = (await db.execute( - select(SysMenu) - .where(SysMenu.status == '0') + query_user_basic_info = ( + ( + await db.execute( + select(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) .distinct() - )).scalars().all() - else: - query_user_menu_info = (await db.execute( - select(SysMenu) + ) + ) + .scalars() + .first() + ) + query_user_dept_info = ( + ( + await db.execute( + select(SysDept) + .select_from(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) + .join( + SysDept, + and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0'), + ) + .distinct() + ) + ) + .scalars() + .first() + ) + query_user_role_info = ( + ( + await db.execute( + select(SysRole) .select_from(SysUser) .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, - and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), - isouter=True) - .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) - .order_by(SysMenu.order_num) + .join( + SysRole, + and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), + ) + .distinct() + ) + ) + .scalars() + .all() + ) + query_user_post_info = ( + ( + await db.execute( + select(SysPost) + .select_from(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserPost, SysUser.user_id == SysUserPost.user_id, isouter=True) + .join(SysPost, and_(SysUserPost.post_id == SysPost.post_id, SysPost.status == '0')) .distinct() - )).scalars().all() + ) + ) + .scalars() + .all() + ) + role_id_list = [item.role_id for item in query_user_role_info] + if 1 in role_id_list: + query_user_menu_info = ( + (await db.execute(select(SysMenu).where(SysMenu.status == '0').distinct())).scalars().all() + ) + else: + query_user_menu_info = ( + ( + await db.execute( + select(SysMenu) + .select_from(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join( + SysRole, + and_( + SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0' + ), + isouter=True, + ) + .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) + .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) + .order_by(SysMenu.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) results = dict( user_basic_info=query_user_basic_info, user_dept_info=query_user_dept_info, user_role_info=query_user_role_info, user_post_info=query_user_post_info, - user_menu_info=query_user_menu_info + user_menu_info=query_user_menu_info, ) return results @@ -128,58 +187,92 @@ class UserDao: :param user_id: 用户id :return: 当前user_id的用户信息对象 """ - query_user_basic_info = (await db.execute( - select(SysUser) - .where(SysUser.del_flag == '0', SysUser.user_id == user_id) - .distinct() - )).scalars().first() - query_user_dept_info = (await db.execute( - select(SysDept) - .select_from(SysUser) - .where(SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0')) - .distinct() - )).scalars().first() - query_user_role_info = (await db.execute( - select(SysRole) - .select_from(SysUser) - .where(SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0')) - .distinct() - )).scalars().all() - query_user_post_info = (await db.execute( - select(SysPost) - .select_from(SysUser) - .where(SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserPost, SysUser.user_id == SysUserPost.user_id, isouter=True) - .join(SysPost, and_(SysUserPost.post_id == SysPost.post_id, SysPost.status == '0')) - .distinct() - )).scalars().all() - query_user_menu_info = (await db.execute( - select(SysMenu) - .select_from(SysUser) - .where(SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), - isouter=True) - .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) - .distinct() - )).scalars().all() + query_user_basic_info = ( + (await db.execute(select(SysUser).where(SysUser.del_flag == '0', SysUser.user_id == user_id).distinct())) + .scalars() + .first() + ) + query_user_dept_info = ( + ( + await db.execute( + select(SysDept) + .select_from(SysUser) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) + .join( + SysDept, + and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0'), + ) + .distinct() + ) + ) + .scalars() + .first() + ) + query_user_role_info = ( + ( + await db.execute( + select(SysRole) + .select_from(SysUser) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join( + SysRole, + and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), + ) + .distinct() + ) + ) + .scalars() + .all() + ) + query_user_post_info = ( + ( + await db.execute( + select(SysPost) + .select_from(SysUser) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserPost, SysUser.user_id == SysUserPost.user_id, isouter=True) + .join(SysPost, and_(SysUserPost.post_id == SysPost.post_id, SysPost.status == '0')) + .distinct() + ) + ) + .scalars() + .all() + ) + query_user_menu_info = ( + ( + await db.execute( + select(SysMenu) + .select_from(SysUser) + .where(SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join( + SysRole, + and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), + isouter=True, + ) + .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) + .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) + .distinct() + ) + ) + .scalars() + .all() + ) results = dict( user_basic_info=query_user_basic_info, user_dept_info=query_user_dept_info, user_role_info=query_user_role_info, user_post_info=query_user_post_info, - user_menu_info=query_user_menu_info + user_menu_info=query_user_menu_info, ) return results @classmethod - async def get_user_list(cls, db: AsyncSession, query_object: UserPageQueryModel, data_scope_sql: str, - is_page: bool = False): + async def get_user_list( + cls, db: AsyncSession, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False + ): """ 根据查询参数获取用户列表信息 :param db: orm对象 @@ -188,27 +281,40 @@ class UserDao: :param is_page: 是否开启分页 :return: 用户列表信息对象 """ - query = select(SysUser, SysDept) \ - .where(SysUser.del_flag == '0', - or_(SysUser.dept_id == query_object.dept_id, SysUser.dept_id.in_( - select(SysDept.dept_id).where(func.find_in_set(query_object.dept_id, SysDept.ancestors)) - )) if query_object.dept_id else True, - SysUser.user_id == query_object.user_id if query_object.user_id is not None else True, - SysUser.user_name.like(f'%{query_object.user_name}%') if query_object.user_name else True, - SysUser.nick_name.like(f'%{query_object.nick_name}%') if query_object.nick_name else True, - SysUser.email.like(f'%{query_object.email}%') if query_object.email else True, - SysUser.phonenumber.like(f'%{query_object.phonenumber}%') if query_object.phonenumber else True, - SysUser.status == query_object.status if query_object.status else True, - SysUser.sex == query_object.sex if query_object.sex else True, - SysUser.create_time.between( - datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), - datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True, - eval(data_scope_sql) - ) \ - .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0'), - isouter=True) \ + query = ( + select(SysUser, SysDept) + .where( + SysUser.del_flag == '0', + or_( + SysUser.dept_id == query_object.dept_id, + SysUser.dept_id.in_( + select(SysDept.dept_id).where(func.find_in_set(query_object.dept_id, SysDept.ancestors)) + ), + ) + if query_object.dept_id + else True, + SysUser.user_id == query_object.user_id if query_object.user_id is not None else True, + SysUser.user_name.like(f'%{query_object.user_name}%') if query_object.user_name else True, + SysUser.nick_name.like(f'%{query_object.nick_name}%') if query_object.nick_name else True, + SysUser.email.like(f'%{query_object.email}%') if query_object.email else True, + SysUser.phonenumber.like(f'%{query_object.phonenumber}%') if query_object.phonenumber else True, + SysUser.status == query_object.status if query_object.status else True, + SysUser.sex == query_object.sex if query_object.sex else True, + SysUser.create_time.between( + datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), + datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)), + ) + if query_object.begin_time and query_object.end_time + else True, + eval(data_scope_sql), + ) + .join( + SysDept, + and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0'), + isouter=True, + ) .distinct() + ) user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return user_list @@ -235,10 +341,7 @@ class UserDao: :param user: 需要更新的用户字典 :return: 编辑校验结果 """ - await db.execute( - update(SysUser), - [user] - ) + await db.execute(update(SysUser), [user]) @classmethod async def delete_user_dao(cls, db: AsyncSession, user: UserModel): @@ -250,8 +353,8 @@ class UserDao: """ await db.execute( update(SysUser) - .where(SysUser.user_id == user.user_id) - .values(del_flag='2', update_by=user.update_by, update_time=user.update_time) + .where(SysUser.user_id == user.user_id) + .values(del_flag='2', update_by=user.update_by, update_time=user.update_time) ) @classmethod @@ -262,22 +365,32 @@ class UserDao: :param query_object: 用户角色查询对象 :return: 用户已分配的角色列表信息 """ - allocated_role_list = (await db.execute( - select(SysRole) - .where(SysRole.del_flag == '0', - SysRole.role_id != 1, - SysRole.role_name == query_object.role_name if query_object.role_name else True, - SysRole.role_key == query_object.role_key if query_object.role_key else True, - SysRole.role_id.in_( - select(SysUserRole.role_id).where(SysUserRole.user_id == query_object.user_id) - )) - .distinct() - )).scalars().all() + allocated_role_list = ( + ( + await db.execute( + select(SysRole) + .where( + SysRole.del_flag == '0', + SysRole.role_id != 1, + SysRole.role_name == query_object.role_name if query_object.role_name else True, + SysRole.role_key == query_object.role_key if query_object.role_key else True, + SysRole.role_id.in_( + select(SysUserRole.role_id).where(SysUserRole.user_id == query_object.user_id) + ), + ) + .distinct() + ) + ) + .scalars() + .all() + ) return allocated_role_list @classmethod - async def get_user_role_allocated_list_by_role_id(cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False): + async def get_user_role_allocated_list_by_role_id( + cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False + ): """ 根据角色id获取已分配的用户列表信息 :param db: orm对象 @@ -286,22 +399,28 @@ class UserDao: :param is_page: 是否开启分页 :return: 角色已分配的用户列表信息 """ - query = select(SysUser) \ - .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) \ - .join(SysUserRole, SysUserRole.user_id == SysUser.user_id, isouter=True) \ - .join(SysRole, SysRole.role_id == SysUserRole.role_id, isouter=True) \ - .where(SysUser.del_flag == '0', - SysUser.user_name == query_object.user_name if query_object.user_name else True, - SysUser.phonenumber == query_object.phonenumber if query_object.phonenumber else True, - SysRole.role_id == query_object.role_id, - eval(data_scope_sql)) \ + query = ( + select(SysUser) + .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) + .join(SysUserRole, SysUserRole.user_id == SysUser.user_id, isouter=True) + .join(SysRole, SysRole.role_id == SysUserRole.role_id, isouter=True) + .where( + SysUser.del_flag == '0', + SysUser.user_name == query_object.user_name if query_object.user_name else True, + SysUser.phonenumber == query_object.phonenumber if query_object.phonenumber else True, + SysRole.role_id == query_object.role_id, + eval(data_scope_sql), + ) .distinct() + ) allocated_user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return allocated_user_list @classmethod - async def get_user_role_unallocated_list_by_role_id(cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False): + async def get_user_role_unallocated_list_by_role_id( + cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False + ): """ 根据角色id获取未分配的用户列表信息 :param db: orm对象 @@ -310,26 +429,31 @@ class UserDao: :param is_page: 是否开启分页 :return: 角色未分配的用户列表信息 """ - query = select(SysUser) \ - .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) \ - .join(SysUserRole, SysUserRole.user_id == SysUser.user_id, isouter=True) \ - .join(SysRole, SysRole.role_id == SysUserRole.role_id, isouter=True) \ - .where(SysUser.del_flag == '0', - SysUser.user_name == query_object.user_name if query_object.user_name else True, - SysUser.phonenumber == query_object.phonenumber if query_object.phonenumber else True, - or_(SysRole.role_id != query_object.role_id, SysRole.role_id is None), - ~SysUser.user_id.in_( - select(SysUser.user_id) - .select_from(SysUser) - .join(SysUserRole, - and_(SysUserRole.user_id == SysUser.user_id, - SysUserRole.role_id == query_object.role_id) - ) - ), - eval(data_scope_sql)) \ + query = ( + select(SysUser) + .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) + .join(SysUserRole, SysUserRole.user_id == SysUser.user_id, isouter=True) + .join(SysRole, SysRole.role_id == SysUserRole.role_id, isouter=True) + .where( + SysUser.del_flag == '0', + SysUser.user_name == query_object.user_name if query_object.user_name else True, + SysUser.phonenumber == query_object.phonenumber if query_object.phonenumber else True, + or_(SysRole.role_id != query_object.role_id, SysRole.role_id is None), + ~SysUser.user_id.in_( + select(SysUser.user_id) + .select_from(SysUser) + .join( + SysUserRole, + and_(SysUserRole.user_id == SysUser.user_id, SysUserRole.role_id == query_object.role_id), + ) + ), + eval(data_scope_sql), + ) .distinct() - unallocated_user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, - is_page) + ) + unallocated_user_list = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return unallocated_user_list @@ -352,10 +476,7 @@ class UserDao: :param user_role: 用户角色关联对象 :return: """ - await db.execute( - delete(SysUserRole) - .where(SysUserRole.user_id.in_([user_role.user_id])) - ) + await db.execute(delete(SysUserRole).where(SysUserRole.user_id.in_([user_role.user_id]))) @classmethod async def delete_user_role_by_user_and_role_dao(cls, db: AsyncSession, user_role: UserRoleModel): @@ -366,9 +487,10 @@ class UserDao: :return: """ await db.execute( - delete(SysUserRole) - .where(SysUserRole.user_id.in_([user_role.user_id]), - SysUserRole.role_id == user_role.role_id if user_role.role_id else True) + delete(SysUserRole).where( + SysUserRole.user_id.in_([user_role.user_id]), + SysUserRole.role_id == user_role.role_id if user_role.role_id else True, + ) ) @classmethod @@ -379,11 +501,17 @@ class UserDao: :param user_role: 用户角色关联对象 :return: 用户角色关联信息 """ - user_role_info = (await db.execute( - select(SysUserRole) - .where(SysUserRole.user_id == user_role.user_id, SysUserRole.role_id == user_role.role_id) - .distinct() - )).scalars().first() + user_role_info = ( + ( + await db.execute( + select(SysUserRole) + .where(SysUserRole.user_id == user_role.user_id, SysUserRole.role_id == user_role.role_id) + .distinct() + ) + ) + .scalars() + .first() + ) return user_role_info @@ -406,17 +534,17 @@ class UserDao: :param user_post: 用户岗位关联对象 :return: """ - await db.execute( - delete(SysUserPost) - .where(SysUserPost.user_id.in_([user_post.user_id])) - ) + await db.execute(delete(SysUserPost).where(SysUserPost.user_id.in_([user_post.user_id]))) @classmethod async def get_user_dept_info(cls, db: AsyncSession, dept_id: int): - dept_basic_info = (await db.execute( - select(SysDept) - .where(SysDept.dept_id == dept_id, - SysDept.status == '0', - SysDept.del_flag == '0') - )).scalars().first() + dept_basic_info = ( + ( + await db.execute( + select(SysDept).where(SysDept.dept_id == dept_id, SysDept.status == '0', SysDept.del_flag == '0') + ) + ) + .scalars() + .first() + ) return dept_basic_info diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py index 3613913..67a1d14 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py @@ -1,20 +1,21 @@ import re -from pydantic import BaseModel, Field, ConfigDict, model_validator +from datetime import datetime +from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel from pydantic_validation_decorator import Network, NotBlank, Size, Xss -from typing import Union, Optional, List, Literal -from datetime import datetime -from module_admin.entity.vo.role_vo import RoleModel +from typing import List, Literal, Optional, Union +from exceptions.exception import ModelValidatorException +from module_admin.annotation.pydantic_annotation import as_form, as_query from module_admin.entity.vo.dept_vo import DeptModel from module_admin.entity.vo.post_vo import PostModel -from module_admin.annotation.pydantic_annotation import as_query, as_form -from exceptions.exception import ModelValidatorException +from module_admin.entity.vo.role_vo import RoleModel class TokenData(BaseModel): """ token解析结果 """ + user_id: Union[int, None] = Field(default=None, description='用户ID') @@ -22,6 +23,7 @@ class UserModel(BaseModel): """ 用户表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) user_id: Optional[int] = Field(default=None, description='用户ID') @@ -47,11 +49,11 @@ class UserModel(BaseModel): @model_validator(mode='after') def check_password(self) -> 'UserModel': - pattern = r'''^[^<>"'|\\]+$''' + pattern = r"""^[^<>"'|\\]+$""" if self.password is None or re.match(pattern, self.password): return self else: - raise ModelValidatorException(message="密码不能包含非法字符:< > \" ' \\ |") + raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |') @model_validator(mode='after') def check_admin(self) -> 'UserModel': @@ -92,6 +94,7 @@ class UserRoleModel(BaseModel): """ 用户和角色关联表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) user_id: Optional[int] = Field(default=None, description='用户ID') @@ -102,6 +105,7 @@ class UserPostModel(BaseModel): """ 用户与岗位关联表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) user_id: Optional[int] = Field(default=None, description='用户ID') @@ -127,6 +131,7 @@ class UserDetailModel(BaseModel): """ 获取用户详情信息响应模型 """ + model_config = ConfigDict(alias_generator=to_camel) data: Optional[Union[UserInfoModel, None]] = Field(default=None, description='用户信息') @@ -140,6 +145,7 @@ class UserProfileModel(BaseModel): """ 获取个人信息响应模型 """ + model_config = ConfigDict(alias_generator=to_camel) data: Union[UserInfoModel, None] = Field(description='用户信息') @@ -151,6 +157,7 @@ class UserQueryModel(UserModel): """ 用户管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -161,6 +168,7 @@ class UserPageQueryModel(UserQueryModel): """ 用户管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -169,6 +177,7 @@ class AddUserModel(UserModel): """ 新增用户模型 """ + role_ids: Optional[List] = Field(default=[], description='角色ID信息') post_ids: Optional[List] = Field(default=[], description='岗位ID信息') type: Optional[str] = Field(default=None, description='操作类型') @@ -178,6 +187,7 @@ class EditUserModel(AddUserModel): """ 编辑用户模型 """ + role: Optional[List] = Field(default=[], description='角色信息') @@ -186,6 +196,7 @@ class ResetPasswordModel(BaseModel): """ 重置密码模型 """ + model_config = ConfigDict(alias_generator=to_camel) old_password: Optional[str] = Field(default=None, description='旧密码') @@ -193,17 +204,18 @@ class ResetPasswordModel(BaseModel): @model_validator(mode='after') def check_new_password(self) -> 'ResetPasswordModel': - pattern = r'''^[^<>"'|\\]+$''' + pattern = r"""^[^<>"'|\\]+$""" if self.new_password is None or re.match(pattern, self.new_password): return self else: - raise ModelValidatorException(message="密码不能包含非法字符:< > \" ' \\ |") + raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |') class ResetUserModel(UserModel): """ 重置用户密码模型 """ + old_password: Optional[str] = Field(default=None, description='旧密码') sms_code: Optional[str] = Field(default=None, description='验证码') session_id: Optional[str] = Field(default=None, description='会话id') @@ -213,6 +225,7 @@ class DeleteUserModel(BaseModel): """ 删除用户模型 """ + model_config = ConfigDict(alias_generator=to_camel) user_ids: str = Field(description='需要删除的用户ID') @@ -224,6 +237,7 @@ class UserRoleQueryModel(UserModel): """ 用户角色关联管理不分页查询模型 """ + role_id: Optional[int] = Field(default=None, description='角色ID') @@ -232,6 +246,7 @@ class UserRolePageQueryModel(UserRoleQueryModel): """ 用户角色关联管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -240,6 +255,7 @@ class SelectedRoleModel(RoleModel): """ 是否选择角色模型 """ + flag: Optional[bool] = Field(default=False, description='选择标识') @@ -247,6 +263,7 @@ class UserRoleResponseModel(BaseModel): """ 用户角色关联管理列表返回模型 """ + model_config = ConfigDict(alias_generator=to_camel) roles: List[Union[SelectedRoleModel, None]] = Field(default=[], description='角色信息') @@ -258,6 +275,7 @@ class CrudUserRoleModel(BaseModel): """ 新增、删除用户关联角色及角色关联用户模型 """ + model_config = ConfigDict(alias_generator=to_camel) user_id: Optional[int] = Field(default=None, description='用户ID') diff --git a/ruoyi-fastapi-backend/module_admin/service/user_service.py b/ruoyi-fastapi-backend/module_admin/service/user_service.py index 720480d..37d9dac 100644 --- a/ruoyi-fastapi-backend/module_admin/service/user_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/user_service.py @@ -1,15 +1,39 @@ +import io +import pandas as pd +from datetime import datetime from fastapi import Request, UploadFile -from module_admin.service.role_service import RoleService -from module_admin.service.dept_service import DeptService -from module_admin.service.post_service import PostService, PostPageQueryModel -from module_admin.service.config_service import ConfigService -from module_admin.entity.vo.common_vo import CrudResponseModel -from module_admin.dao.user_dao import * +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List, Union from config.constant import CommonConstant from exceptions.exception import ServiceException +from module_admin.dao.user_dao import UserDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.post_vo import PostPageQueryModel +from module_admin.entity.vo.user_vo import ( + AddUserModel, + CrudUserRoleModel, + CurrentUserModel, + DeleteUserModel, + EditUserModel, + ResetUserModel, + SelectedRoleModel, + UserDetailModel, + UserInfoModel, + UserModel, + UserPageQueryModel, + UserPostModel, + UserProfileModel, + UserRoleModel, + UserRoleQueryModel, + UserRoleResponseModel, +) +from module_admin.service.config_service import ConfigService +from module_admin.service.dept_service import DeptService +from module_admin.service.post_service import PostService +from module_admin.service.role_service import RoleService +from utils.common_util import CamelCaseUtil, export_list2excel, get_excel_template from utils.page_util import PageResponseModel -from utils.pwd_util import * -from utils.common_util import * +from utils.pwd_util import PwdUtil class UserService: @@ -18,7 +42,9 @@ class UserService: """ @classmethod - async def get_user_list_services(cls, query_db: AsyncSession, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False): + async def get_user_list_services( + cls, query_db: AsyncSession, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False + ): """ 获取用户列表信息service :param query_db: orm对象 @@ -32,7 +58,7 @@ class UserService: user_list_result = PageResponseModel( **{ **query_result.model_dump(by_alias=True), - 'rows': [{**row[0], 'dept': row[1]} for row in query_result.rows] + 'rows': [{**row[0], 'dept': row[1]} for row in query_result.rows], } ) else: @@ -173,10 +199,14 @@ class UserService: await UserDao.delete_user_post_dao(query_db, UserPostModel(userId=page_object.user_id)) if page_object.role_ids: for role in page_object.role_ids: - await UserDao.add_user_role_dao(query_db, UserRoleModel(userId=page_object.user_id, roleId=role)) + await UserDao.add_user_role_dao( + query_db, UserRoleModel(userId=page_object.user_id, roleId=role) + ) if page_object.post_ids: for post in page_object.post_ids: - await UserDao.add_user_post_dao(query_db, UserPostModel(userId=page_object.user_id, postId=post)) + await UserDao.add_user_post_dao( + query_db, UserPostModel(userId=page_object.user_id, postId=post) + ) await query_db.commit() return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: @@ -197,7 +227,9 @@ class UserService: user_id_list = page_object.user_ids.split(',') try: for user_id in user_id_list: - user_id_dict = dict(userId=user_id, updateBy=page_object.update_by, updateTime=page_object.update_time) + user_id_dict = dict( + userId=user_id, updateBy=page_object.update_by, updateTime=page_object.update_time + ) await UserDao.delete_user_role_dao(query_db, UserRoleModel(**user_id_dict)) await UserDao.delete_user_post_dao(query_db, UserPostModel(**user_id_dict)) await UserDao.delete_user_dao(query_db, UserModel(**user_id_dict)) @@ -232,18 +264,15 @@ class UserService: postIds=post_ids, roleIds=role_ids, dept=CamelCaseUtil.transform_result(query_user.get('user_dept_info')), - role=CamelCaseUtil.transform_result(query_user.get('user_role_info')) + role=CamelCaseUtil.transform_result(query_user.get('user_role_info')), ), postIds=post_ids_list, posts=posts, roleIds=role_ids_list, - roles=roles + roles=roles, ) - return UserDetailModel( - posts=posts, - roles=roles - ) + return UserDetailModel(posts=posts, roles=roles) @classmethod async def user_profile_services(cls, query_db: AsyncSession, user_id: int): @@ -265,10 +294,10 @@ class UserService: postIds=post_ids, roleIds=role_ids, dept=CamelCaseUtil.transform_result(query_user.get('user_dept_info')), - role=CamelCaseUtil.transform_result(query_user.get('user_role_info')) + role=CamelCaseUtil.transform_result(query_user.get('user_role_info')), ), postGroup=post_group, - roleGroup=role_group + roleGroup=role_group, ) @classmethod @@ -300,7 +329,16 @@ class UserService: raise e @classmethod - async def batch_import_user_services(cls, request: Request, query_db: AsyncSession, file: UploadFile, update_support: bool, current_user: CurrentUserModel, user_data_scope_sql: str, dept_data_scope_sql: str): + async def batch_import_user_services( + cls, + request: Request, + query_db: AsyncSession, + file: UploadFile, + update_support: bool, + current_user: CurrentUserModel, + user_data_scope_sql: str, + dept_data_scope_sql: str, + ): """ 批量导入用户service :param request: Request对象 @@ -313,13 +351,13 @@ class UserService: :return: 批量导入用户结果 """ header_dict = { - "部门编号": "dept_id", - "登录名称": "user_name", - "用户名称": "nick_name", - "用户邮箱": "email", - "手机号码": "phonenumber", - "用户性别": "sex", - "帐号状态": "status" + '部门编号': 'dept_id', + '登录名称': 'user_name', + '用户名称': 'nick_name', + '用户邮箱': 'email', + '手机号码': 'phonenumber', + '用户性别': 'sex', + '帐号状态': 'status', } contents = await file.read() df = pd.read_excel(io.BytesIO(contents)) @@ -343,7 +381,11 @@ class UserService: add_user = UserModel( deptId=row['dept_id'], userName=row['user_name'], - password=PwdUtil.get_password_hash(await ConfigService.query_config_list_from_cache_services(request.app.state.redis, 'sys.user.initPassword')), + password=PwdUtil.get_password_hash( + await ConfigService.query_config_list_from_cache_services( + request.app.state.redis, 'sys.user.initPassword' + ) + ), nickName=row['nick_name'], email=row['email'], phonenumber=str(row['phonenumber']), @@ -352,7 +394,7 @@ class UserService: createBy=current_user.user.user_name, createTime=datetime.now(), updateBy=current_user.user.user_name, - updateTime=datetime.now() + updateTime=datetime.now(), ) user_info = await UserDao.get_user_by_info(query_db, UserModel(userName=row['user_name'])) if user_info: @@ -367,13 +409,17 @@ class UserService: sex=row['sex'], status=row['status'], updateBy=current_user.user.user_name, - updateTime=datetime.now() + updateTime=datetime.now(), ) edit_user_model.validate_fields() await cls.check_user_allowed_services(edit_user_model) if not current_user.user.admin: - await cls.check_user_data_scope_services(query_db, edit_user_model.user_id, user_data_scope_sql) - await DeptService.check_dept_data_scope_services(query_db, edit_user_model.dept_id, dept_data_scope_sql) + await cls.check_user_data_scope_services( + query_db, edit_user_model.user_id, user_data_scope_sql + ) + await DeptService.check_dept_data_scope_services( + query_db, edit_user_model.dept_id, dept_data_scope_sql + ) edit_user = edit_user_model.model_dump(exclude_unset=True) await UserDao.edit_user_dao(query_db, edit_user) else: @@ -381,7 +427,9 @@ class UserService: else: add_user.validate_fields() if not current_user.user.admin: - await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql) + await DeptService.check_dept_data_scope_services( + query_db, add_user.dept_id, dept_data_scope_sql + ) await UserDao.add_user_dao(query_db, add_user) await query_db.commit() return CrudResponseModel(is_success=True, message='\n'.join(add_error_result)) @@ -395,10 +443,12 @@ class UserService: 获取用户导入模板service :return: 用户导入模板excel的二进制数据 """ - header_list = ["部门编号", "登录名称", "用户名称", "用户邮箱", "手机号码", "用户性别", "帐号状态"] - selector_header_list = ["用户性别", "帐号状态"] - option_list = [{"用户性别": ["男", "女", "未知"]}, {"帐号状态": ["正常", "停用"]}] - binary_data = get_excel_template(header_list=header_list, selector_header_list=selector_header_list, option_list=option_list) + header_list = ['部门编号', '登录名称', '用户名称', '用户邮箱', '手机号码', '用户性别', '帐号状态'] + selector_header_list = ['用户性别', '帐号状态'] + option_list = [{'用户性别': ['男', '女', '未知']}, {'帐号状态': ['正常', '停用']}] + binary_data = get_excel_template( + header_list=header_list, selector_header_list=selector_header_list, option_list=option_list + ) return binary_data @@ -411,19 +461,19 @@ class UserService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "userId": "用户编号", - "userName": "用户名称", - "nickName": "用户昵称", - "deptName": "部门", - "email": "邮箱地址", - "phonenumber": "手机号码", - "sex": "性别", - "status": "状态", - "createBy": "创建者", - "createTime": "创建时间", - "updateBy": "更新者", - "updateTime": "更新时间", - "remark": "备注", + 'userId': '用户编号', + 'userName': '用户名称', + 'nickName': '用户昵称', + 'deptName': '部门', + 'email': '邮箱地址', + 'phonenumber': '手机号码', + 'sex': '性别', + 'status': '状态', + 'createBy': '创建者', + 'createTime': '创建时间', + 'updateBy': '更新者', + 'updateTime': '更新时间', + 'remark': '备注', } data = user_list @@ -439,7 +489,9 @@ class UserService: item['sex'] = '女' else: item['sex'] = '未知' - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data @@ -460,17 +512,16 @@ class UserService: postIds=post_ids, roleIds=role_ids, dept=CamelCaseUtil.transform_result(query_user.get('user_dept_info')), - role=CamelCaseUtil.transform_result(query_user.get('user_role_info')) + role=CamelCaseUtil.transform_result(query_user.get('user_role_info')), ) - query_role_list = [SelectedRoleModel(**row) for row in await RoleService.get_role_select_option_services(query_db)] + query_role_list = [ + SelectedRoleModel(**row) for row in await RoleService.get_role_select_option_services(query_db) + ] for model_a in query_role_list: for model_b in user.role: if model_a.role_id == model_b.role_id: model_a.flag = True - result = UserRoleResponseModel( - roles=query_role_list, - user=user - ) + result = UserRoleResponseModel(roles=query_role_list, user=user) return result @@ -486,11 +537,15 @@ class UserService: role_id_list = page_object.role_ids.split(',') try: for role_id in role_id_list: - user_role = await cls.detail_user_role_services(query_db, UserRoleModel(userId=page_object.user_id, roleId=role_id)) + user_role = await cls.detail_user_role_services( + query_db, UserRoleModel(userId=page_object.user_id, roleId=role_id) + ) if user_role: continue else: - await UserDao.add_user_role_dao(query_db, UserRoleModel(userId=page_object.user_id, roleId=role_id)) + await UserDao.add_user_role_dao( + query_db, UserRoleModel(userId=page_object.user_id, roleId=role_id) + ) await query_db.commit() return CrudResponseModel(is_success=True, message='分配成功') except Exception as e: @@ -508,11 +563,15 @@ class UserService: user_id_list = page_object.user_ids.split(',') try: for user_id in user_id_list: - user_role = await cls.detail_user_role_services(query_db, UserRoleModel(userId=user_id, roleId=page_object.role_id)) + user_role = await cls.detail_user_role_services( + query_db, UserRoleModel(userId=user_id, roleId=page_object.role_id) + ) if user_role: continue else: - await UserDao.add_user_role_dao(query_db, UserRoleModel(userId=user_id, roleId=page_object.role_id)) + await UserDao.add_user_role_dao( + query_db, UserRoleModel(userId=user_id, roleId=page_object.role_id) + ) await query_db.commit() return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: @@ -532,7 +591,9 @@ class UserService: if (page_object.user_id and page_object.role_id) or (page_object.user_ids and page_object.role_id): if page_object.user_id and page_object.role_id: try: - await UserDao.delete_user_role_by_user_and_role_dao(query_db, UserRoleModel(userId=page_object.user_id, roleId=page_object.role_id)) + await UserDao.delete_user_role_by_user_and_role_dao( + query_db, UserRoleModel(userId=page_object.user_id, roleId=page_object.role_id) + ) await query_db.commit() return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: @@ -542,7 +603,9 @@ class UserService: user_id_list = page_object.user_ids.split(',') try: for user_id in user_id_list: - await UserDao.delete_user_role_by_user_and_role_dao(query_db, UserRoleModel(userId=user_id, roleId=page_object.role_id)) + await UserDao.delete_user_role_by_user_and_role_dao( + query_db, UserRoleModel(userId=user_id, roleId=page_object.role_id) + ) await query_db.commit() return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: -- Gitee From bd242c95f737d0c7fe08d6347face91bd320bfc2 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 09:35:26 +0800 Subject: [PATCH 080/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E7=99=BB=E5=BD=95=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/login_controller.py | 99 ++++--- .../module_admin/dao/login_dao.py | 18 +- .../module_admin/entity/vo/login_vo.py | 14 +- .../module_admin/service/login_service.py | 257 +++++++++++------- 4 files changed, 241 insertions(+), 147 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py index 7c769a1..b8b3133 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py @@ -1,79 +1,104 @@ -from fastapi import APIRouter -from module_admin.service.login_service import * -from module_admin.entity.vo.login_vo import * -from module_admin.dao.login_dao import * -from module_admin.annotation.log_annotation import log_decorator -from config.env import JwtConfig, RedisInitKeyConfig +import uuid +from datetime import datetime, timedelta +from fastapi import APIRouter, Depends, Request +from jose import jwt +from sqlalchemy.ext.asyncio import AsyncSession +from typing import Optional from config.enums import BusinessType +from config.env import AppConfig, JwtConfig, RedisInitKeyConfig +from config.get_db import get_db +from module_admin.annotation.log_annotation import log_decorator +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.login_vo import UserLogin, UserRegister, Token +from module_admin.entity.vo.user_vo import CurrentUserModel, EditUserModel +from module_admin.service.login_service import CustomOAuth2PasswordRequestForm, LoginService, oauth2_scheme +from module_admin.service.user_service import UserService +from utils.log_util import logger from utils.response_util import ResponseUtil -from utils.log_util import * -from datetime import timedelta loginController = APIRouter() -@loginController.post("/login", response_model=Token) +@loginController.post('/login', response_model=Token) @log_decorator(title='用户登录', business_type=BusinessType.OTHER, log_type='login') -async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = Depends(), query_db: AsyncSession = Depends(get_db)): - captcha_enabled = True if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") == 'true' else False +async def login( + request: Request, form_data: CustomOAuth2PasswordRequestForm = Depends(), query_db: AsyncSession = Depends(get_db) +): + captcha_enabled = ( + True + if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") + == 'true' + else False + ) user = UserLogin( userName=form_data.username, password=form_data.password, code=form_data.code, uuid=form_data.uuid, loginInfo=form_data.login_info, - captchaEnabled=captcha_enabled + captchaEnabled=captcha_enabled, ) result = await LoginService.authenticate_user(request, query_db, user) access_token_expires = timedelta(minutes=JwtConfig.jwt_expire_minutes) session_id = str(uuid.uuid4()) access_token = await LoginService.create_access_token( data={ - "user_id": str(result[0].user_id), - "user_name": result[0].user_name, - "dept_name": result[1].dept_name if result[1] else None, - "session_id": session_id, - "login_info": user.login_info + 'user_id': str(result[0].user_id), + 'user_name': result[0].user_name, + 'dept_name': result[1].dept_name if result[1] else None, + 'session_id': session_id, + 'login_info': user.login_info, }, - expires_delta=access_token_expires + expires_delta=access_token_expires, ) if AppConfig.app_same_time_login: - await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", access_token, - ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", + access_token, + ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes), + ) else: # 此方法可实现同一账号同一时间只能登录一次 - await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{result[0].user_id}", access_token, - ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) - await UserService.edit_user_services(query_db, EditUserModel(userId=result[0].user_id, loginDate=datetime.now(), type='status')) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{result[0].user_id}", + access_token, + ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes), + ) + await UserService.edit_user_services( + query_db, EditUserModel(userId=result[0].user_id, loginDate=datetime.now(), type='status') + ) logger.info('登录成功') # 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False if request_from_swagger or request_from_redoc: return {'access_token': access_token, 'token_type': 'Bearer'} - return ResponseUtil.success( - msg='登录成功', - dict_content={'token': access_token} - ) + return ResponseUtil.success(msg='登录成功', dict_content={'token': access_token}) -@loginController.get("/getInfo", response_model=CurrentUserModel) -async def get_login_user_info(request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +@loginController.get('/getInfo', response_model=CurrentUserModel) +async def get_login_user_info( + request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user) +): logger.info('获取成功') return ResponseUtil.success(model_content=current_user) -@loginController.get("/getRouters") -async def get_login_user_routers(request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user), query_db: AsyncSession = Depends(get_db)): +@loginController.get('/getRouters') +async def get_login_user_routers( + request: Request, + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + query_db: AsyncSession = Depends(get_db), +): logger.info('获取成功') user_routers = await LoginService.get_current_user_routers(current_user.user.user_id, query_db) return ResponseUtil.success(data=user_routers) -@loginController.post("/register", response_model=CrudResponseModel) +@loginController.post('/register', response_model=CrudResponseModel) async def register_user(request: Request, user_register: UserRegister, query_db: AsyncSession = Depends(get_db)): user_register_result = await LoginService.register_user_services(request, query_db, user_register) logger.info(user_register_result.message) @@ -111,11 +136,13 @@ async def register_user(request: Request, user_register: UserRegister, query_db: # return ResponseUtil.error(msg=str(e)) -@loginController.post("/logout") +@loginController.post('/logout') async def logout(request: Request, token: Optional[str] = Depends(oauth2_scheme)): - payload = jwt.decode(token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False}) - session_id: str = payload.get("session_id") + payload = jwt.decode( + token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False} + ) + session_id: str = payload.get('session_id') await LoginService.logout_services(request, session_id) logger.info('退出成功') - return ResponseUtil.success(msg="退出成功") + return ResponseUtil.success(msg='退出成功') diff --git a/ruoyi-fastapi-backend/module_admin/dao/login_dao.py b/ruoyi-fastapi-backend/module_admin/dao/login_dao.py index baa77ab..9bafa65 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/login_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/login_dao.py @@ -1,7 +1,7 @@ -from sqlalchemy import select, and_ +from sqlalchemy import and_, select from sqlalchemy.ext.asyncio import AsyncSession -from module_admin.entity.do.user_do import SysUser from module_admin.entity.do.dept_do import SysDept +from module_admin.entity.do.user_do import SysUser async def login_by_account(db: AsyncSession, user_name: str): @@ -11,11 +11,17 @@ async def login_by_account(db: AsyncSession, user_name: str): :param user_name: 用户名 :return: 用户对象 """ - user = (await db.execute( - select(SysUser, SysDept) + user = ( + await db.execute( + select(SysUser, SysDept) .where(SysUser.user_name == user_name, SysUser.del_flag == '0') - .join(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0'), isouter=True) + .join( + SysDept, + and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == '0', SysDept.del_flag == '0'), + isouter=True, + ) .distinct() - )).first() + ) + ).first() return user diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py index c3ee684..fbd6e07 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py @@ -1,7 +1,7 @@ import re from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel -from typing import Optional, List, Union +from typing import List, Optional, Union from exceptions.exception import ModelValidatorException from module_admin.entity.vo.menu_vo import MenuModel @@ -28,11 +28,11 @@ class UserRegister(BaseModel): @model_validator(mode='after') def check_password(self) -> 'UserRegister': - pattern = r'''^[^<>"'|\\]+$''' + pattern = r"""^[^<>"'|\\]+$""" if self.password is None or re.match(pattern, self.password): return self else: - raise ModelValidatorException(message="密码不能包含非法字符:< > \" ' \\ |") + raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |') class Token(BaseModel): @@ -75,9 +75,13 @@ class RouterModel(BaseModel): name: Optional[str] = Field(default=None, description='路由名称') path: Optional[str] = Field(default=None, description='路由地址') hidden: Optional[bool] = Field(default=None, description='是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现') - redirect: Optional[str] = Field(default=None, description='重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击') + redirect: Optional[str] = Field( + default=None, description='重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击' + ) component: Optional[str] = Field(default=None, description='组件地址') query: Optional[str] = Field(default=None, description='路由参数:如 {"id": 1, "name": "ry"}') - always_show: Optional[bool] = Field(default=None, description='当你一个路由下面的children声明的路由大于1个时,自动会变成嵌套的模式--如组件页面') + always_show: Optional[bool] = Field( + default=None, description='当你一个路由下面的children声明的路由大于1个时,自动会变成嵌套的模式--如组件页面' + ) meta: Optional[MetaModel] = Field(default=None, description='其他元素') children: Optional[Union[List['RouterModel'], None]] = Field(default=None, description='子路由') diff --git a/ruoyi-fastapi-backend/module_admin/service/login_service.py b/ruoyi-fastapi-backend/module_admin/service/login_service.py index f4a96b3..ddf792a 100644 --- a/ruoyi-fastapi-backend/module_admin/service/login_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/login_service.py @@ -1,24 +1,28 @@ -from fastapi import Request, Form -from fastapi import Depends -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jose import JWTError, jwt import random import uuid -from datetime import timedelta -from module_admin.service.user_service import * -from module_admin.entity.vo.login_vo import * -from module_admin.entity.vo.common_vo import CrudResponseModel -from module_admin.dao.login_dao import * -from exceptions.exception import LoginException, AuthException, ServiceException +from datetime import datetime, timedelta +from fastapi import Depends, Form, Request +from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm +from jose import JWTError, jwt +from sqlalchemy.ext.asyncio import AsyncSession +from typing import Dict, List, Optional, Union from config.constant import CommonConstant, MenuConstant from config.env import AppConfig, JwtConfig, RedisInitKeyConfig from config.get_db import get_db +from exceptions.exception import LoginException, AuthException, ServiceException +from module_admin.dao.login_dao import login_by_account +from module_admin.dao.user_dao import UserDao +from module_admin.entity.do.menu_do import SysMenu +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.login_vo import MenuTreeModel, MetaModel, RouterModel, SmsCode, UserLogin, UserRegister +from module_admin.entity.vo.user_vo import AddUserModel, CurrentUserModel, ResetUserModel, TokenData, UserInfoModel +from module_admin.service.user_service import UserService from utils.common_util import CamelCaseUtil -from utils.pwd_util import * -from utils.response_util import * -from utils.message_util import * +from utils.log_util import logger +from utils.message_util import message_service +from utils.pwd_util import PwdUtil -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login") +oauth2_scheme = OAuth2PasswordBearer(tokenUrl='login') class CustomOAuth2PasswordRequestForm(OAuth2PasswordRequestForm): @@ -27,19 +31,25 @@ class CustomOAuth2PasswordRequestForm(OAuth2PasswordRequestForm): """ def __init__( - self, - grant_type: str = Form(default=None, regex="password"), - username: str = Form(), - password: str = Form(), - scope: str = Form(default=""), - client_id: Optional[str] = Form(default=None), - client_secret: Optional[str] = Form(default=None), - code: Optional[str] = Form(default=""), - uuid: Optional[str] = Form(default=""), - login_info: Optional[Dict[str, str]] = Form(default=None) + self, + grant_type: str = Form(default=None, regex='password'), + username: str = Form(), + password: str = Form(), + scope: str = Form(default=''), + client_id: Optional[str] = Form(default=None), + client_secret: Optional[str] = Form(default=None), + code: Optional[str] = Form(default=''), + uuid: Optional[str] = Form(default=''), + login_info: Optional[Dict[str, str]] = Form(default=None), ): - super().__init__(grant_type=grant_type, username=username, password=password, - scope=scope, client_id=client_id, client_secret=client_secret) + super().__init__( + grant_type=grant_type, + username=username, + password=password, + scope=scope, + client_id=client_id, + client_secret=client_secret, + ) self.code = code self.uuid = uuid self.login_info = login_info @@ -61,47 +71,61 @@ class LoginService: """ await cls.__check_login_ip(request) account_lock = await request.app.state.redis.get( - f"{RedisInitKeyConfig.ACCOUNT_LOCK.get('key')}:{login_user.user_name}") + f"{RedisInitKeyConfig.ACCOUNT_LOCK.get('key')}:{login_user.user_name}" + ) if login_user.user_name == account_lock: - logger.warning("账号已锁定,请稍后再试") - raise LoginException(data="", message="账号已锁定,请稍后再试") + logger.warning('账号已锁定,请稍后再试') + raise LoginException(data='', message='账号已锁定,请稍后再试') # 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug - request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False - request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False + request_from_swagger = ( + request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False + ) + request_from_redoc = ( + request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False + ) # 判断是否开启验证码,开启则验证,否则不验证(dev模式下来自API文档的登录请求不检验) - if not login_user.captcha_enabled or ((request_from_swagger or request_from_redoc) and AppConfig.app_env == 'dev'): + if not login_user.captcha_enabled or ( + (request_from_swagger or request_from_redoc) and AppConfig.app_env == 'dev' + ): pass else: await cls.__check_login_captcha(request, login_user) user = await login_by_account(query_db, login_user.user_name) if not user: - logger.warning("用户不存在") - raise LoginException(data="", message="用户不存在") + logger.warning('用户不存在') + raise LoginException(data='', message='用户不存在') if not PwdUtil.verify_password(login_user.password, user[0].password): cache_password_error_count = await request.app.state.redis.get( - f"{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.get('key')}:{login_user.user_name}") + f"{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.get('key')}:{login_user.user_name}" + ) password_error_counted = 0 if cache_password_error_count: password_error_counted = cache_password_error_count password_error_count = int(password_error_counted) + 1 await request.app.state.redis.set( - f"{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.get('key')}:{login_user.user_name}", password_error_count, - ex=timedelta(minutes=10)) + f"{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.get('key')}:{login_user.user_name}", + password_error_count, + ex=timedelta(minutes=10), + ) if password_error_count > 5: await request.app.state.redis.delete( - f"{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.get('key')}:{login_user.user_name}") + f"{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.get('key')}:{login_user.user_name}" + ) await request.app.state.redis.set( - f"{RedisInitKeyConfig.ACCOUNT_LOCK.get('key')}:{login_user.user_name}", login_user.user_name, - ex=timedelta(minutes=10)) - logger.warning("10分钟内密码已输错超过5次,账号已锁定,请10分钟后再试") - raise LoginException(data="", message="10分钟内密码已输错超过5次,账号已锁定,请10分钟后再试") - logger.warning("密码错误") - raise LoginException(data="", message="密码错误") + f"{RedisInitKeyConfig.ACCOUNT_LOCK.get('key')}:{login_user.user_name}", + login_user.user_name, + ex=timedelta(minutes=10), + ) + logger.warning('10分钟内密码已输错超过5次,账号已锁定,请10分钟后再试') + raise LoginException(data='', message='10分钟内密码已输错超过5次,账号已锁定,请10分钟后再试') + logger.warning('密码错误') + raise LoginException(data='', message='密码错误') if user[0].status == '1': - logger.warning("用户已停用") - raise LoginException(data="", message="用户已停用") + logger.warning('用户已停用') + raise LoginException(data='', message='用户已停用') await request.app.state.redis.delete( - f"{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.get('key')}:{login_user.user_name}") + f"{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.get('key')}:{login_user.user_name}" + ) return user @classmethod @@ -112,11 +136,12 @@ class LoginService: :return: 校验结果 """ black_ip_value = await request.app.state.redis.get( - f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.login.blackIPList") + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.login.blackIPList" + ) black_ip_list = black_ip_value.split(',') if black_ip_value else [] if request.headers.get('X-Forwarded-For') in black_ip_list: - logger.warning("当前IP禁止登录") - raise LoginException(data="", message="当前IP禁止登录") + logger.warning('当前IP禁止登录') + raise LoginException(data='', message='当前IP禁止登录') return True @classmethod @@ -128,13 +153,14 @@ class LoginService: :return: 校验结果 """ captcha_value = await request.app.state.redis.get( - f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{login_user.uuid}") + f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{login_user.uuid}" + ) if not captcha_value: - logger.warning("验证码已失效") - raise LoginException(data="", message="验证码已失效") + logger.warning('验证码已失效') + raise LoginException(data='', message='验证码已失效') if login_user.code != str(captcha_value): - logger.warning("验证码错误") - raise LoginException(data="", message="验证码错误") + logger.warning('验证码错误') + raise LoginException(data='', message='验证码错误') return True @classmethod @@ -150,13 +176,14 @@ class LoginService: expire = datetime.utcnow() + expires_delta else: expire = datetime.utcnow() + timedelta(minutes=30) - to_encode.update({"exp": expire}) + to_encode.update({'exp': expire}) encoded_jwt = jwt.encode(to_encode, JwtConfig.jwt_secret_key, algorithm=JwtConfig.jwt_algorithm) return encoded_jwt @classmethod - async def get_current_user(cls, request: Request = Request, token: str = Depends(oauth2_scheme), - query_db: AsyncSession = Depends(get_db)): + async def get_current_user( + cls, request: Request = Request, token: str = Depends(oauth2_scheme), query_db: AsyncSession = Depends(get_db) + ): """ 根据token获取当前用户信息 :param request: Request对象 @@ -172,31 +199,41 @@ class LoginService: if token.startswith('Bearer'): token = token.split(' ')[1] payload = jwt.decode(token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm]) - user_id: str = payload.get("user_id") - session_id: str = payload.get("session_id") + user_id: str = payload.get('user_id') + session_id: str = payload.get('session_id') if user_id is None: - logger.warning("用户token不合法") - raise AuthException(data="", message="用户token不合法") + logger.warning('用户token不合法') + raise AuthException(data='', message='用户token不合法') token_data = TokenData(user_id=int(user_id)) except JWTError: - logger.warning("用户token已失效,请重新登录") - raise AuthException(data="", message="用户token已失效,请重新登录") + logger.warning('用户token已失效,请重新登录') + raise AuthException(data='', message='用户token已失效,请重新登录') query_user = await UserDao.get_user_by_id(query_db, user_id=token_data.user_id) if query_user.get('user_basic_info') is None: - logger.warning("用户token不合法") - raise AuthException(data="", message="用户token不合法") + logger.warning('用户token不合法') + raise AuthException(data='', message='用户token不合法') if AppConfig.app_same_time_login: - redis_token = await request.app.state.redis.get(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}") + redis_token = await request.app.state.redis.get( + f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}" + ) else: # 此方法可实现同一账号同一时间只能登录一次 - redis_token = await request.app.state.redis.get(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{query_user.get('user_basic_info').user_id}") + redis_token = await request.app.state.redis.get( + f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{query_user.get('user_basic_info').user_id}" + ) if token == redis_token: if AppConfig.app_same_time_login: - await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", redis_token, - ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", + redis_token, + ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes), + ) else: - await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{query_user.get('user_basic_info').user_id}", redis_token, - ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{query_user.get('user_basic_info').user_id}", + redis_token, + ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes), + ) role_id_list = [item.role_id for item in query_user.get('user_role_info')] if 1 in role_id_list: @@ -215,13 +252,13 @@ class LoginService: postIds=post_ids, roleIds=role_ids, dept=CamelCaseUtil.transform_result(query_user.get('user_dept_info')), - role=CamelCaseUtil.transform_result(query_user.get('user_role_info')) - ) + role=CamelCaseUtil.transform_result(query_user.get('user_role_info')), + ), ) return current_user else: - logger.warning("用户token已失效,请重新登录") - raise AuthException(data="", message="用户token已失效,请重新登录") + logger.warning('用户token已失效,请重新登录') + raise AuthException(data='', message='用户token已失效,请重新登录') @classmethod async def get_current_user_routers(cls, user_id: int, query_db: AsyncSession): @@ -232,7 +269,14 @@ class LoginService: :return: 当前用户路由信息对象 """ query_user = await UserDao.get_user_by_id(query_db, user_id=user_id) - user_router_menu = sorted([row for row in query_user.get('user_menu_info') if row.menu_type in [MenuConstant.TYPE_DIR, MenuConstant.TYPE_MENU]], key=lambda x: x.order_num) + user_router_menu = sorted( + [ + row + for row in query_user.get('user_menu_info') + if row.menu_type in [MenuConstant.TYPE_DIR, MenuConstant.TYPE_MENU] + ], + key=lambda x: x.order_num, + ) menus = cls.__generate_menus(0, user_router_menu) user_router = cls.__generate_user_router_menu(menus) return [router.model_dump(exclude_unset=True, by_alias=True) for router in user_router] @@ -275,8 +319,8 @@ class LoginService: title=permission.menu_name, icon=permission.icon, noCache=True if permission.is_cache == 1 else False, - link=permission.path if RouterUtil.is_http(permission.path) else None - ) + link=permission.path if RouterUtil.is_http(permission.path) else None, + ), ) c_menus = permission.children if c_menus and permission.menu_type == MenuConstant.TYPE_DIR: @@ -294,17 +338,14 @@ class LoginService: title=permission.menu_name, icon=permission.icon, noCache=True if permission.is_cache == 1 else False, - link=permission.path if RouterUtil.is_http(permission.path) else None + link=permission.path if RouterUtil.is_http(permission.path) else None, ), - query=permission.query + query=permission.query, ) children_list.append(children) router.children = children_list elif permission.parent_id == 0 and RouterUtil.is_inner_link(permission): - router.meta = MetaModel( - title=permission.menu_name, - icon=permission.icon - ) + router.meta = MetaModel(title=permission.menu_name, icon=permission.icon) router.path = '/' children_list: List[RouterModel] = [] router_path = RouterUtil.inner_link_replace_each(permission.path) @@ -315,8 +356,8 @@ class LoginService: meta=MetaModel( title=permission.menu_name, icon=permission.icon, - link=permission.path if RouterUtil.is_http(permission.path) else None - ) + link=permission.path if RouterUtil.is_http(permission.path) else None, + ), ) children_list.append(children) router.children = children_list @@ -334,15 +375,26 @@ class LoginService: :param user_register: 注册用户对象 :return: 注册结果 """ - register_enabled = True if await request.app.state.redis.get( - f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.registerUser") == 'true' else False - captcha_enabled = True if await request.app.state.redis.get( - f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") == 'true' else False + register_enabled = ( + True + if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.registerUser") + == 'true' + else False + ) + captcha_enabled = ( + True + if await request.app.state.redis.get( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled" + ) + == 'true' + else False + ) if user_register.password == user_register.confirm_password: if register_enabled: if captcha_enabled: captcha_value = await request.app.state.redis.get( - f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{user_register.uuid}") + f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{user_register.uuid}" + ) if not captcha_value: raise ServiceException(message='验证码已失效') elif user_register.code != str(captcha_value): @@ -350,7 +402,7 @@ class LoginService: add_user = AddUserModel( userName=user_register.username, nickName=user_register.username, - password=PwdUtil.get_password_hash(user_register.password) + password=PwdUtil.get_password_hash(user_register.password), ) result = await UserService.add_user_services(query_db, add_user) return result @@ -369,15 +421,17 @@ class LoginService: :return: 短信验证码对象 """ redis_sms_result = await request.app.state.redis.get( - f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{user.session_id}") + f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{user.session_id}" + ) if redis_sms_result: return SmsCode(**dict(is_success=False, sms_code='', session_id='', message='短信验证码仍在有效期内')) is_user = await UserDao.get_user_by_name(query_db, user.user_name) if is_user: sms_code = str(random.randint(100000, 999999)) session_id = str(uuid.uuid4()) - await request.app.state.redis.set(f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{session_id}", sms_code, - ex=timedelta(minutes=2)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{session_id}", sms_code, ex=timedelta(minutes=2) + ) # 此处模拟调用短信服务 message_service(sms_code) @@ -395,7 +449,8 @@ class LoginService: :return: 重置结果 """ redis_sms_result = await request.app.state.redis.get( - f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{forget_user.session_id}") + f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{forget_user.session_id}" + ) if forget_user.sms_code == redis_sms_result: forget_user.password = PwdUtil.get_password_hash(forget_user.password) forget_user.user_id = (await UserDao.get_user_by_name(query_db, forget_user.user_name)).user_id @@ -484,7 +539,9 @@ class RouterUtil: :param menu: 菜单数对象 :return: 是否为菜单内部跳转 """ - return menu.parent_id == 0 and menu.menu_type == MenuConstant.TYPE_MENU and menu.is_frame == MenuConstant.NO_FRAME + return ( + menu.parent_id == 0 and menu.menu_type == MenuConstant.TYPE_MENU and menu.is_frame == MenuConstant.NO_FRAME + ) @classmethod def is_inner_link(cls, menu: MenuTreeModel): @@ -520,8 +577,8 @@ class RouterUtil: :param path: 内链域名 :return: 替换后的内链域名 """ - old_values = [CommonConstant.HTTP, CommonConstant.HTTPS, CommonConstant.WWW, ".", ":"] - new_values = ["", "", "", "/", "/"] + old_values = [CommonConstant.HTTP, CommonConstant.HTTPS, CommonConstant.WWW, '.', ':'] + new_values = ['', '', '', '/', '/'] for old, new in zip(old_values, new_values): path = path.replace(old, new) return path -- Gitee From 4a7c9367d4c9a65f4343c5c62b3e2804da153b20 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 09:35:55 +0800 Subject: [PATCH 081/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E8=A7=92=E8=89=B2=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/role_controller.py | 214 ++++++++++++----- .../module_admin/dao/role_dao.py | 226 +++++++++++------- .../module_admin/entity/do/role_do.py | 13 +- .../module_admin/entity/vo/role_vo.py | 20 +- .../module_admin/service/role_service.py | 89 ++++--- 5 files changed, 373 insertions(+), 189 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index 3c35a4a..d764414 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -1,46 +1,69 @@ -from fastapi import APIRouter, Request -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, CurrentUserModel -from module_admin.service.role_service import * -from module_admin.service.dept_service import DeptService, DeptModel -from module_admin.service.user_service import UserService, UserRoleQueryModel, UserRolePageQueryModel, CrudUserRoleModel -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * -from utils.page_util import PageResponseModel +from module_admin.aspect.data_scope import GetDataScope +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.dept_vo import DeptModel +from module_admin.entity.vo.role_vo import AddRoleModel, DeleteRoleModel, RoleModel, RolePageQueryModel +from module_admin.entity.vo.user_vo import CrudUserRoleModel, CurrentUserModel, UserRolePageQueryModel +from module_admin.service.dept_service import DeptService +from module_admin.service.login_service import LoginService +from module_admin.service.role_service import RoleService +from module_admin.service.user_service import UserService from utils.common_util import bytes2file_response +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.response_util import ResponseUtil roleController = APIRouter(prefix='/system/role', dependencies=[Depends(LoginService.get_current_user)]) -@roleController.get("/deptTree/{role_id}", dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]) -async def get_system_role_dept_tree(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +@roleController.get('/deptTree/{role_id}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]) +async def get_system_role_dept_tree( + request: Request, + role_id: int, + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql) role_dept_query_result = await RoleService.get_role_dept_tree_services(query_db, role_id) role_dept_query_result.depts = dept_query_result logger.info('获取成功') return ResponseUtil.success(model_content=role_dept_query_result) - - -@roleController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]) -async def get_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): - role_page_query_result = await RoleService.get_role_list_services(query_db, role_page_query, data_scope_sql, is_page=True) + + +@roleController.get( + '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))] +) +async def get_system_role_list( + request: Request, + role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): + role_page_query_result = await RoleService.get_role_list_services( + query_db, role_page_query, data_scope_sql, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=role_page_query_result) - - -@roleController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))]) + + +@roleController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))]) @ValidateFields(validate_model='add_role') @log_decorator(title='角色管理', business_type=BusinessType.INSERT) -async def add_system_role(request: Request, add_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_role( + request: Request, + add_role: AddRoleModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_role.create_by = current_user.user.user_name add_role.create_time = datetime.now() add_role.update_by = current_user.user.user_name @@ -49,12 +72,18 @@ async def add_system_role(request: Request, add_role: AddRoleModel, query_db: As logger.info(add_role_result.message) return ResponseUtil.success(msg=add_role_result.message) - - -@roleController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) + + +@roleController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @ValidateFields(validate_model='edit_role') @log_decorator(title='角色管理', business_type=BusinessType.UPDATE) -async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def edit_system_role( + request: Request, + edit_role: AddRoleModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): await RoleService.check_role_allowed_services(edit_role) if not current_user.user.admin: await RoleService.check_role_data_scope_services(query_db, str(edit_role.role_id), data_scope_sql) @@ -66,9 +95,15 @@ async def edit_system_role(request: Request, edit_role: AddRoleModel, query_db: return ResponseUtil.success(msg=edit_role_result.message) -@roleController.put("/dataScope", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@roleController.put('/dataScope', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) -async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def edit_system_role_datascope( + request: Request, + role_data_scope: AddRoleModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): await RoleService.check_role_allowed_services(role_data_scope) if not current_user.user.admin: await RoleService.check_role_data_scope_services(query_db, str(role_data_scope.role_id), data_scope_sql) @@ -78,35 +113,45 @@ async def edit_system_role_datascope(request: Request, role_data_scope: AddRoleM deptIds=role_data_scope.dept_ids, deptCheckStrictly=role_data_scope.dept_check_strictly, updateBy=current_user.user.user_name, - updateTime=datetime.now() + updateTime=datetime.now(), ) role_data_scope_result = await RoleService.role_datascope_services(query_db, edit_role) logger.info(role_data_scope_result.message) return ResponseUtil.success(msg=role_data_scope_result.message) - - -@roleController.delete("/{role_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))]) + + +@roleController.delete('/{role_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))]) @log_decorator(title='角色管理', business_type=BusinessType.DELETE) -async def delete_system_role(request: Request, role_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def delete_system_role( + request: Request, + role_ids: str, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): role_id_list = role_ids.split(',') for role_id in role_id_list: await RoleService.check_role_allowed_services(RoleModel(roleId=int(role_id))) if not current_user.user.admin: await RoleService.check_role_data_scope_services(query_db, role_id, data_scope_sql) - delete_role = DeleteRoleModel( - roleIds=role_ids, - updateBy=current_user.user.user_name, - updateTime=datetime.now() - ) + delete_role = DeleteRoleModel(roleIds=role_ids, updateBy=current_user.user.user_name, updateTime=datetime.now()) delete_role_result = await RoleService.delete_role_services(query_db, delete_role) logger.info(delete_role_result.message) return ResponseUtil.success(msg=delete_role_result.message) - - -@roleController.get("/{role_id}", response_model=RoleModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]) -async def query_detail_system_role(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): + + +@roleController.get( + '/{role_id}', response_model=RoleModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))] +) +async def query_detail_system_role( + request: Request, + role_id: int, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): if not current_user.user.admin: await RoleService.check_role_data_scope_services(query_db, str(role_id), data_scope_sql) role_detail_result = await RoleService.role_detail_services(query_db, role_id) @@ -115,20 +160,33 @@ async def query_detail_system_role(request: Request, role_id: int, query_db: Asy return ResponseUtil.success(data=role_detail_result.model_dump(by_alias=True)) -@roleController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))]) +@roleController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))]) @log_decorator(title='角色管理', business_type=BusinessType.EXPORT) -async def export_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def export_system_role_list( + request: Request, + role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): # 获取全量数据 - role_query_result = await RoleService.get_role_list_services(query_db, role_page_query, data_scope_sql, is_page=False) + role_query_result = await RoleService.get_role_list_services( + query_db, role_page_query, data_scope_sql, is_page=False + ) role_export_result = await RoleService.export_role_list_services(role_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(role_export_result)) -@roleController.put("/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@roleController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.UPDATE) -async def reset_system_role_status(request: Request, change_role: AddRoleModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def reset_system_role_status( + request: Request, + change_role: AddRoleModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): await RoleService.check_role_allowed_services(change_role) if not current_user.user.admin: await RoleService.check_role_data_scope_services(query_db, str(change_role.role_id), data_scope_sql) @@ -137,7 +195,7 @@ async def reset_system_role_status(request: Request, change_role: AddRoleModel, status=change_role.status, updateBy=current_user.user.user_name, updateTime=datetime.now(), - type='status' + type='status', ) edit_role_result = await RoleService.edit_role_services(query_db, edit_role) logger.info(edit_role_result.message) @@ -145,25 +203,53 @@ async def reset_system_role_status(request: Request, change_role: AddRoleModel, return ResponseUtil.success(msg=edit_role_result.message) -@roleController.get("/authUser/allocatedList", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]) -async def get_system_allocated_user_list(request: Request, user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): - role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services(query_db, user_role, data_scope_sql, is_page=True) +@roleController.get( + '/authUser/allocatedList', + response_model=PageResponseModel, + dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))], +) +async def get_system_allocated_user_list( + request: Request, + user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysUser')), +): + role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services( + query_db, user_role, data_scope_sql, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=role_user_allocated_page_query_result) -@roleController.get("/authUser/unallocatedList", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]) -async def get_system_unallocated_user_list(request: Request, user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): - role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services(query_db, user_role, data_scope_sql, is_page=True) +@roleController.get( + '/authUser/unallocatedList', + response_model=PageResponseModel, + dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))], +) +async def get_system_unallocated_user_list( + request: Request, + user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysUser')), +): + role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services( + query_db, user_role, data_scope_sql, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=role_user_unallocated_page_query_result) -@roleController.put("/authUser/selectAll", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@roleController.put('/authUser/selectAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) -async def add_system_role_user(request: Request, add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def add_system_role_user( + request: Request, + add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): if not current_user.user.admin: await RoleService.check_role_data_scope_services(query_db, str(add_role_user.role_id), data_scope_sql) add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user) @@ -172,18 +258,24 @@ async def add_system_role_user(request: Request, add_role_user: CrudUserRoleMode return ResponseUtil.success(msg=add_role_user_result.message) -@roleController.put("/authUser/cancel", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@roleController.put('/authUser/cancel', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) -async def cancel_system_role_user(request: Request, cancel_user_role: CrudUserRoleModel, query_db: AsyncSession = Depends(get_db)): +async def cancel_system_role_user( + request: Request, cancel_user_role: CrudUserRoleModel, query_db: AsyncSession = Depends(get_db) +): cancel_user_role_result = await UserService.delete_user_role_services(query_db, cancel_user_role) logger.info(cancel_user_role_result.message) return ResponseUtil.success(msg=cancel_user_role_result.message) -@roleController.put("/authUser/cancelAll", dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@roleController.put('/authUser/cancelAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @log_decorator(title='角色管理', business_type=BusinessType.GRANT) -async def batch_cancel_system_role_user(request: Request, batch_cancel_user_role: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), query_db: AsyncSession = Depends(get_db)): +async def batch_cancel_system_role_user( + request: Request, + batch_cancel_user_role: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), + query_db: AsyncSession = Depends(get_db), +): batch_cancel_user_role_result = await UserService.delete_user_role_services(query_db, batch_cancel_user_role) logger.info(batch_cancel_user_role_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py index 36fb89c..30352e8 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py @@ -1,12 +1,12 @@ -from sqlalchemy import select, update, delete, desc, and_, or_, func +from datetime import datetime, time +from sqlalchemy import and_, delete, desc, func, or_, select, update # noqa: F401 from sqlalchemy.ext.asyncio import AsyncSession -from module_admin.entity.do.user_do import SysUser, SysUserRole -from module_admin.entity.do.role_do import SysRole, SysRoleMenu, SysRoleDept from module_admin.entity.do.dept_do import SysDept from module_admin.entity.do.menu_do import SysMenu -from module_admin.entity.vo.role_vo import * +from module_admin.entity.do.role_do import SysRole, SysRoleMenu, SysRoleDept +from module_admin.entity.do.user_do import SysUser, SysUserRole +from module_admin.entity.vo.role_vo import RoleDeptModel, RoleMenuModel, RoleModel, RolePageQueryModel from utils.page_util import PageUtil -from datetime import datetime, time class RoleDao: @@ -22,12 +22,18 @@ class RoleDao: :param role_name: 角色名 :return: 当前角色名的角色信息对象 """ - query_role_info = (await db.execute( - select(SysRole) - .where(SysRole.status == '0', SysRole.del_flag == '0', SysRole.role_name == role_name) - .order_by(desc(SysRole.create_time)) - .distinct() - )).scalars().first() + query_role_info = ( + ( + await db.execute( + select(SysRole) + .where(SysRole.status == '0', SysRole.del_flag == '0', SysRole.role_name == role_name) + .order_by(desc(SysRole.create_time)) + .distinct() + ) + ) + .scalars() + .first() + ) return query_role_info @@ -39,14 +45,22 @@ class RoleDao: :param role: 角色参数 :return: 当前角色参数的角色信息对象 """ - query_role_info = (await db.execute( - select(SysRole) - .where(SysRole.del_flag == '0', - SysRole.role_name == role.role_name if role.role_name else True, - SysRole.role_key == role.role_key if role.role_key else True) - .order_by(desc(SysRole.create_time)) - .distinct() - )).scalars().first() + query_role_info = ( + ( + await db.execute( + select(SysRole) + .where( + SysRole.del_flag == '0', + SysRole.role_name == role.role_name if role.role_name else True, + SysRole.role_key == role.role_key if role.role_key else True, + ) + .order_by(desc(SysRole.create_time)) + .distinct() + ) + ) + .scalars() + .first() + ) return query_role_info @@ -58,12 +72,15 @@ class RoleDao: :param role_id: 角色id :return: 当前角色id的角色信息对象 """ - role_info = (await db.execute( - select(SysRole) - .where(SysRole.role_id == role_id, - SysRole.status == '0', - SysRole.del_flag == '0') - )).scalars().first() + role_info = ( + ( + await db.execute( + select(SysRole).where(SysRole.role_id == role_id, SysRole.status == '0', SysRole.del_flag == '0') + ) + ) + .scalars() + .first() + ) return role_info @@ -75,11 +92,11 @@ class RoleDao: :param role_id: 角色id :return: 当前role_id的角色信息对象 """ - query_role_info = (await db.execute( - select(SysRole) - .where(SysRole.del_flag == '0', SysRole.role_id == role_id) - .distinct() - )).scalars().first() + query_role_info = ( + (await db.execute(select(SysRole).where(SysRole.del_flag == '0', SysRole.role_id == role_id).distinct())) + .scalars() + .first() + ) return query_role_info @@ -90,15 +107,22 @@ class RoleDao: :param db: orm对象 :return: 角色列表信息 """ - role_info = (await db.execute( - select(SysRole) - .where(SysRole.role_id != 1, SysRole.status == '0', SysRole.del_flag == '0') - )).scalars().all() + role_info = ( + ( + await db.execute( + select(SysRole).where(SysRole.role_id != 1, SysRole.status == '0', SysRole.del_flag == '0') + ) + ) + .scalars() + .all() + ) return role_info @classmethod - async def get_role_list(cls, db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False): + async def get_role_list( + cls, db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False + ): """ 根据查询参数获取角色列表信息 :param db: orm对象 @@ -107,21 +131,27 @@ class RoleDao: :param is_page: 是否开启分页 :return: 角色列表信息对象 """ - query = select(SysRole) \ - .join(SysUserRole, SysUserRole.role_id == SysRole.role_id, isouter=True) \ - .join(SysUser, SysUser.user_id == SysUserRole.user_id, isouter=True) \ - .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) \ - .where(SysRole.del_flag == '0', - SysRole.role_name.like(f'%{query_object.role_name}%') if query_object.role_name else True, - SysRole.role_key.like(f'%{query_object.role_key}%') if query_object.role_key else True, - SysRole.status == query_object.status if query_object.status else True, - SysRole.create_time.between( - datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), - datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True, - eval(data_scope_sql)) \ - .order_by(SysRole.role_sort) \ + query = ( + select(SysRole) + .join(SysUserRole, SysUserRole.role_id == SysRole.role_id, isouter=True) + .join(SysUser, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join(SysDept, SysDept.dept_id == SysUser.dept_id, isouter=True) + .where( + SysRole.del_flag == '0', + SysRole.role_name.like(f'%{query_object.role_name}%') if query_object.role_name else True, + SysRole.role_key.like(f'%{query_object.role_key}%') if query_object.role_key else True, + SysRole.status == query_object.status if query_object.status else True, + SysRole.create_time.between( + datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), + datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)), + ) + if query_object.begin_time and query_object.end_time + else True, + eval(data_scope_sql), + ) + .order_by(SysRole.role_sort) .distinct() + ) role_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return role_list @@ -148,10 +178,7 @@ class RoleDao: :param role: 需要更新的角色字典 :return: """ - await db.execute( - update(SysRole), - [role] - ) + await db.execute(update(SysRole), [role]) @classmethod async def delete_role_dao(cls, db: AsyncSession, role: RoleModel): @@ -163,8 +190,8 @@ class RoleDao: """ await db.execute( update(SysRole) - .where(SysRole.role_id == role.role_id) - .values(del_flag='2', update_by=role.update_by, update_time=role.update_time) + .where(SysRole.role_id == role.role_id) + .values(del_flag='2', update_by=role.update_by, update_time=role.update_time) ) @classmethod @@ -175,18 +202,30 @@ class RoleDao: :param role: 角色对象 :return: 角色菜单关联列表信息 """ - role_menu_query_all = (await db.execute( - select(SysMenu) - .join(SysRoleMenu, SysRoleMenu.menu_id == SysMenu.menu_id) - .where(SysRoleMenu.role_id == role.role_id, - ~SysMenu.menu_id.in_( - select(SysMenu.parent_id) - .select_from(SysMenu) - .join(SysRoleMenu, - and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysRoleMenu.role_id == role.role_id)) - ) if role.menu_check_strictly else True) - .order_by(SysMenu.parent_id, SysMenu.order_num) - )).scalars().all() + role_menu_query_all = ( + ( + await db.execute( + select(SysMenu) + .join(SysRoleMenu, SysRoleMenu.menu_id == SysMenu.menu_id) + .where( + SysRoleMenu.role_id == role.role_id, + ~SysMenu.menu_id.in_( + select(SysMenu.parent_id) + .select_from(SysMenu) + .join( + SysRoleMenu, + and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysRoleMenu.role_id == role.role_id), + ) + ) + if role.menu_check_strictly + else True, + ) + .order_by(SysMenu.parent_id, SysMenu.order_num) + ) + ) + .scalars() + .all() + ) return role_menu_query_all @@ -209,10 +248,7 @@ class RoleDao: :param role_menu: 角色菜单关联对象 :return: """ - await db.execute( - delete(SysRoleMenu) - .where(SysRoleMenu.role_id.in_([role_menu.role_id])) - ) + await db.execute(delete(SysRoleMenu).where(SysRoleMenu.role_id.in_([role_menu.role_id]))) @classmethod async def get_role_dept_dao(cls, db: AsyncSession, role: RoleModel): @@ -222,17 +258,30 @@ class RoleDao: :param role: 角色对象 :return: 角色部门关联列表信息 """ - role_dept_query_all = (await db.execute( - select(SysDept) - .join(SysRoleDept, SysRoleDept.dept_id == SysDept.dept_id) - .where(SysRoleDept.role_id == role.role_id, - ~SysDept.dept_id.in_( - select(SysDept.parent_id) - .select_from(SysDept) - .join(SysRoleDept, and_(SysRoleDept.dept_id == SysDept.dept_id, SysRoleDept.role_id == role.role_id)) - ) if role.dept_check_strictly else True) - .order_by(SysDept.parent_id, SysDept.order_num) - )).scalars().all() + role_dept_query_all = ( + ( + await db.execute( + select(SysDept) + .join(SysRoleDept, SysRoleDept.dept_id == SysDept.dept_id) + .where( + SysRoleDept.role_id == role.role_id, + ~SysDept.dept_id.in_( + select(SysDept.parent_id) + .select_from(SysDept) + .join( + SysRoleDept, + and_(SysRoleDept.dept_id == SysDept.dept_id, SysRoleDept.role_id == role.role_id), + ) + ) + if role.dept_check_strictly + else True, + ) + .order_by(SysDept.parent_id, SysDept.order_num) + ) + ) + .scalars() + .all() + ) return role_dept_query_all @@ -255,10 +304,7 @@ class RoleDao: :param role_dept: 角色部门关联对象 :return: """ - await db.execute( - delete(SysRoleDept) - .where(SysRoleDept.role_id.in_([role_dept.role_id])) - ) + await db.execute(delete(SysRoleDept).where(SysRoleDept.role_id.in_([role_dept.role_id]))) @classmethod async def count_user_role_dao(cls, db: AsyncSession, role_id: int): @@ -268,10 +314,8 @@ class RoleDao: :param role_id: 角色id :return: 角色关联用户数量 """ - user_count = (await db.execute( - select(func.count('*')) - .select_from(SysUserRole) - .where(SysUserRole.role_id == role_id) - )).scalar() + user_count = ( + await db.execute(select(func.count('*')).select_from(SysUserRole).where(SysUserRole.role_id == role_id)) + ).scalar() return user_count diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/role_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/role_do.py index db29244..fc2e34d 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/role_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/role_do.py @@ -1,19 +1,24 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysRole(Base): """ 角色信息表 """ + __tablename__ = 'sys_role' role_id = Column(Integer, primary_key=True, autoincrement=True, comment='角色ID') role_name = Column(String(30, collation='utf8_general_ci'), nullable=False, comment='角色名称') role_key = Column(String(100, collation='utf8_general_ci'), nullable=False, comment='角色权限字符串') role_sort = Column(Integer, nullable=False, comment='显示顺序') - data_scope = Column(String(1, collation='utf8_general_ci'), default='1', comment='数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)') + data_scope = Column( + String(1, collation='utf8_general_ci'), + default='1', + comment='数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)', + ) menu_check_strictly = Column(Integer, default=1, comment='菜单树选择项是否关联显示') dept_check_strictly = Column(Integer, default=1, comment='部门树选择项是否关联显示') status = Column(String(1, collation='utf8_general_ci'), nullable=False, comment='角色状态(0正常 1停用)') @@ -29,6 +34,7 @@ class SysRoleDept(Base): """ 角色和部门关联表 """ + __tablename__ = 'sys_role_dept' role_id = Column(Integer, primary_key=True, nullable=False, comment='角色ID') @@ -39,6 +45,7 @@ class SysRoleMenu(Base): """ 角色和菜单关联表 """ + __tablename__ = 'sys_role_menu' role_id = Column(Integer, primary_key=True, nullable=False, comment='角色ID') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py index aa69c3f..d6f60bc 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py @@ -1,22 +1,26 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from typing import Union, Optional, List, Literal -from datetime import datetime -from module_admin.annotation.pydantic_annotation import as_query, as_form +from typing import List, Literal, Optional, Union +from module_admin.annotation.pydantic_annotation import as_form, as_query class RoleModel(BaseModel): """ 角色表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) role_id: Optional[int] = Field(default=None, description='角色ID') role_name: Optional[str] = Field(default=None, description='角色名称') role_key: Optional[str] = Field(default=None, description='角色权限字符串') role_sort: Optional[int] = Field(default=None, description='显示顺序') - data_scope: Optional[Literal['1', '2', '3', '4', '5']] = Field(default=None, description='数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限)') + data_scope: Optional[Literal['1', '2', '3', '4', '5']] = Field( + default=None, + description='数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限 5:仅本人数据权限)', + ) menu_check_strictly: Optional[Union[int, bool]] = Field(default=None, description='菜单树选择项是否关联显示') dept_check_strictly: Optional[Union[int, bool]] = Field(default=None, description='部门树选择项是否关联显示') status: Optional[Literal['0', '1']] = Field(default=None, description='角色状态(0正常 1停用)') @@ -73,6 +77,7 @@ class RoleMenuModel(BaseModel): """ 角色和菜单关联表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) role_id: Optional[int] = Field(default=None, description='角色ID') @@ -83,6 +88,7 @@ class RoleDeptModel(BaseModel): """ 角色和部门关联表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) role_id: Optional[int] = Field(default=None, description='角色ID') @@ -93,6 +99,7 @@ class RoleQueryModel(RoleModel): """ 角色管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -103,6 +110,7 @@ class RolePageQueryModel(RoleQueryModel): """ 角色管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -111,6 +119,7 @@ class RoleMenuQueryModel(BaseModel): """ 角色菜单查询模型 """ + model_config = ConfigDict(alias_generator=to_camel) menus: List = Field(default=[], description='菜单信息') @@ -121,6 +130,7 @@ class RoleDeptQueryModel(BaseModel): """ 角色部门查询模型 """ + model_config = ConfigDict(alias_generator=to_camel) depts: List = Field(default=[], description='部门信息') @@ -131,6 +141,7 @@ class AddRoleModel(RoleModel): """ 新增角色模型 """ + dept_ids: List = Field(default=[], description='部门ID信息') menu_ids: List = Field(default=[], description='菜单ID信息') type: Optional[str] = Field(default=None, description='操作类型') @@ -140,6 +151,7 @@ class DeleteRoleModel(BaseModel): """ 删除角色模型 """ + model_config = ConfigDict(alias_generator=to_camel) role_ids: str = Field(description='需要删除的菜单ID') diff --git a/ruoyi-fastapi-backend/module_admin/service/role_service.py b/ruoyi-fastapi-backend/module_admin/service/role_service.py index 890f23a..dbd2b22 100644 --- a/ruoyi-fastapi-backend/module_admin/service/role_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/role_service.py @@ -1,11 +1,22 @@ -from module_admin.entity.vo.user_vo import UserInfoModel, UserRolePageQueryModel -from module_admin.entity.vo.common_vo import CrudResponseModel -from module_admin.dao.user_dao import UserDao -from module_admin.dao.role_dao import * +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List from config.constant import CommonConstant from exceptions.exception import ServiceException +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.role_vo import ( + AddRoleModel, + DeleteRoleModel, + RoleDeptModel, + RoleDeptQueryModel, + RoleMenuModel, + RoleModel, + RolePageQueryModel, +) +from module_admin.entity.vo.user_vo import UserInfoModel, UserRolePageQueryModel +from module_admin.dao.role_dao import RoleDao +from module_admin.dao.user_dao import UserDao +from utils.common_util import CamelCaseUtil, export_list2excel from utils.page_util import PageResponseModel -from utils.common_util import export_list2excel, CamelCaseUtil class RoleService: @@ -35,14 +46,14 @@ class RoleService: role = await cls.role_detail_services(query_db, role_id) role_dept_list = await RoleDao.get_role_dept_dao(query_db, role) checked_keys = [row.dept_id for row in role_dept_list] - result = RoleDeptQueryModel( - checkedKeys=checked_keys - ) + result = RoleDeptQueryModel(checkedKeys=checked_keys) return result @classmethod - async def get_role_list_services(cls, query_db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False): + async def get_role_list_services( + cls, query_db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False + ): """ 获取角色列表信息service :param query_db: orm对象 @@ -77,7 +88,9 @@ class RoleService: :return: 校验结果 """ for role_id in role_ids.split(','): - roles = await RoleDao.get_role_list(query_db, RolePageQueryModel(roleId=int(role_id)), data_scope_sql, is_page=False) + roles = await RoleDao.get_role_list( + query_db, RolePageQueryModel(roleId=int(role_id)), data_scope_sql, is_page=False + ) if roles: return CrudResponseModel(is_success=True, message='校验通过') else: @@ -163,7 +176,9 @@ class RoleService: await RoleDao.delete_role_menu_dao(query_db, RoleMenuModel(roleId=page_object.role_id)) if page_object.menu_ids: for menu in page_object.menu_ids: - await RoleDao.add_role_menu_dao(query_db, RoleMenuModel(roleId=page_object.role_id, menuId=menu)) + await RoleDao.add_role_menu_dao( + query_db, RoleMenuModel(roleId=page_object.role_id, menuId=menu) + ) await query_db.commit() return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: @@ -188,7 +203,9 @@ class RoleService: await RoleDao.delete_role_dept_dao(query_db, RoleDeptModel(roleId=page_object.role_id)) if page_object.dept_ids and page_object.data_scope == '2': for dept in page_object.dept_ids: - await RoleDao.add_role_dept_dao(query_db, RoleDeptModel(roleId=page_object.role_id, deptId=dept)) + await RoleDao.add_role_dept_dao( + query_db, RoleDeptModel(roleId=page_object.role_id, deptId=dept) + ) await query_db.commit() return CrudResponseModel(is_success=True, message='分配成功') except Exception as e: @@ -212,7 +229,9 @@ class RoleService: role = await cls.role_detail_services(query_db, int(role_id)) if (await RoleDao.count_user_role_dao(query_db, int(role_id))) > 0: raise ServiceException(message=f'角色{role.role_name}已分配,不能删除') - role_id_dict = dict(roleId=role_id, updateBy=page_object.update_by, updateTime=page_object.update_time) + role_id_dict = dict( + roleId=role_id, updateBy=page_object.update_by, updateTime=page_object.update_time + ) await RoleDao.delete_role_menu_dao(query_db, RoleMenuModel(**role_id_dict)) await RoleDao.delete_role_dept_dao(query_db, RoleDeptModel(**role_id_dict)) await RoleDao.delete_role_dao(query_db, RoleModel(**role_id_dict)) @@ -249,16 +268,16 @@ class RoleService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "roleId": "角色编号", - "roleName": "角色名称", - "roleKey": "权限字符", - "roleSort": "显示顺序", - "status": "状态", - "createBy": "创建者", - "createTime": "创建时间", - "updateBy": "更新者", - "updateTime": "更新时间", - "remark": "备注", + 'roleId': '角色编号', + 'roleName': '角色名称', + 'roleKey': '权限字符', + 'roleSort': '显示顺序', + 'status': '状态', + 'createBy': '创建者', + 'createTime': '创建时间', + 'updateBy': '更新者', + 'updateTime': '更新时间', + 'remark': '备注', } data = role_list @@ -268,13 +287,17 @@ class RoleService: item['status'] = '正常' else: item['status'] = '停用' - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data @classmethod - async def get_role_user_allocated_list_services(cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False): + async def get_role_user_allocated_list_services( + cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False + ): """ 根据角色id获取已分配用户列表 :param query_db: orm对象 @@ -283,18 +306,22 @@ class RoleService: :param is_page: 是否开启分页 :return: 已分配用户列表 """ - query_user_list = await UserDao.get_user_role_allocated_list_by_role_id(query_db, page_object, data_scope_sql, is_page) + query_user_list = await UserDao.get_user_role_allocated_list_by_role_id( + query_db, page_object, data_scope_sql, is_page + ) allocated_list = PageResponseModel( **{ **query_user_list.model_dump(by_alias=True), - 'rows': [UserInfoModel(**row) for row in query_user_list.rows] + 'rows': [UserInfoModel(**row) for row in query_user_list.rows], } ) return allocated_list @classmethod - async def get_role_user_unallocated_list_services(cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False): + async def get_role_user_unallocated_list_services( + cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False + ): """ 根据角色id获取未分配用户列表 :param query_db: orm对象 @@ -303,11 +330,13 @@ class RoleService: :param is_page: 是否开启分页 :return: 未分配用户列表 """ - query_user_list = await UserDao.get_user_role_unallocated_list_by_role_id(query_db, page_object, data_scope_sql, is_page) + query_user_list = await UserDao.get_user_role_unallocated_list_by_role_id( + query_db, page_object, data_scope_sql, is_page + ) unallocated_list = PageResponseModel( **{ **query_user_list.model_dump(by_alias=True), - 'rows': [UserInfoModel(**row) for row in query_user_list.rows] + 'rows': [UserInfoModel(**row) for row in query_user_list.rows], } ) -- Gitee From e80a44c43a995589925ecf9c15112859f63416da Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 09:36:08 +0800 Subject: [PATCH 082/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E7=94=A8=E6=88=B7=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97do=E5=B1=82=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_admin/entity/do/user_do.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/user_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/user_do.py index 9351547..21bba84 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/user_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/user_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysUser(Base): """ 用户信息表 """ + __tablename__ = 'sys_user' user_id = Column(Integer, primary_key=True, autoincrement=True, comment='用户ID') @@ -34,6 +35,7 @@ class SysUserRole(Base): """ 用户和角色关联表 """ + __tablename__ = 'sys_user_role' user_id = Column(Integer, primary_key=True, nullable=False, comment='用户ID') @@ -44,6 +46,7 @@ class SysUserPost(Base): """ 用户与岗位关联表 """ + __tablename__ = 'sys_user_post' user_id = Column(Integer, primary_key=True, nullable=False, comment='用户ID') -- Gitee From ca86c5ffb7508688d25da4be674eabf8a5250d29 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 09:38:56 +0800 Subject: [PATCH 083/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E5=B2=97=E4=BD=8D=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/post_controler.py | 64 +++++++++++------ .../module_admin/dao/post_dao.py | 70 +++++++++---------- .../module_admin/entity/do/post_do.py | 5 +- .../module_admin/entity/vo/post_vo.py | 10 ++- .../module_admin/service/post_service.py | 38 ++++++---- 5 files changed, 112 insertions(+), 75 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py index 299d900..f6f2fce 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py @@ -1,24 +1,32 @@ -from fastapi import APIRouter, Request -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, CurrentUserModel -from module_admin.service.post_service import * -from module_admin.entity.vo.post_vo import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * -from utils.page_util import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.service.login_service import LoginService +from module_admin.service.post_service import PostService +from module_admin.entity.vo.post_vo import DeletePostModel, PostModel, PostPageQueryModel +from module_admin.entity.vo.user_vo import CurrentUserModel from utils.common_util import bytes2file_response +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.response_util import ResponseUtil postController = APIRouter(prefix='/system/post', dependencies=[Depends(LoginService.get_current_user)]) -@postController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:list'))]) -async def get_system_post_list(request: Request, post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@postController.get( + '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:list'))] +) +async def get_system_post_list( + request: Request, + post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): # 获取分页数据 post_page_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=True) logger.info('获取成功') @@ -26,10 +34,15 @@ async def get_system_post_list(request: Request, post_page_query: PostPageQueryM return ResponseUtil.success(model_content=post_page_query_result) -@postController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))]) +@postController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))]) @ValidateFields(validate_model='add_post') @log_decorator(title='岗位管理', business_type=BusinessType.INSERT) -async def add_system_post(request: Request, add_post: PostModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_post( + request: Request, + add_post: PostModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_post.create_by = current_user.user.user_name add_post.create_time = datetime.now() add_post.update_by = current_user.user.user_name @@ -40,10 +53,15 @@ async def add_system_post(request: Request, add_post: PostModel, query_db: Async return ResponseUtil.success(msg=add_post_result.message) -@postController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))]) +@postController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))]) @ValidateFields(validate_model='edit_post') @log_decorator(title='岗位管理', business_type=BusinessType.UPDATE) -async def edit_system_post(request: Request, edit_post: PostModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def edit_system_post( + request: Request, + edit_post: PostModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): edit_post.update_by = current_user.user.user_name edit_post.update_time = datetime.now() edit_post_result = await PostService.edit_post_services(query_db, edit_post) @@ -52,7 +70,7 @@ async def edit_system_post(request: Request, edit_post: PostModel, query_db: Asy return ResponseUtil.success(msg=edit_post_result.message) -@postController.delete("/{post_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))]) +@postController.delete('/{post_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))]) @log_decorator(title='岗位管理', business_type=BusinessType.DELETE) async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSession = Depends(get_db)): delete_post = DeletePostModel(postIds=post_ids) @@ -62,7 +80,9 @@ async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSes return ResponseUtil.success(msg=delete_post_result.message) -@postController.get("/{post_id}", response_model=PostModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:query'))]) +@postController.get( + '/{post_id}', response_model=PostModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:query'))] +) async def query_detail_system_post(request: Request, post_id: int, query_db: AsyncSession = Depends(get_db)): post_detail_result = await PostService.post_detail_services(query_db, post_id) logger.info(f'获取post_id为{post_id}的信息成功') @@ -70,9 +90,13 @@ async def query_detail_system_post(request: Request, post_id: int, query_db: Asy return ResponseUtil.success(data=post_detail_result) -@postController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:post:export'))]) +@postController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:post:export'))]) @log_decorator(title='岗位管理', business_type=BusinessType.EXPORT) -async def export_system_post_list(request: Request, post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): +async def export_system_post_list( + request: Request, + post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), +): # 获取全量数据 post_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=False) post_export_result = await PostService.export_post_list_services(post_query_result) diff --git a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py index 6478012..4805306 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py @@ -1,8 +1,8 @@ -from sqlalchemy import select, update, delete, func +from sqlalchemy import delete, func, select, update from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.post_do import SysPost from module_admin.entity.do.user_do import SysUserPost -from module_admin.entity.vo.post_vo import * +from module_admin.entity.vo.post_vo import PostModel, PostPageQueryModel from utils.page_util import PageUtil @@ -19,11 +19,11 @@ class PostDao: :param post_id: 岗位id :return: 在用岗位信息对象 """ - post_info = (await db.execute( - select(SysPost) - .where(SysPost.post_id == post_id, - SysPost.status == '0') - )).scalars().first() + post_info = ( + (await db.execute(select(SysPost).where(SysPost.post_id == post_id, SysPost.status == '0'))) + .scalars() + .first() + ) return post_info @@ -35,10 +35,7 @@ class PostDao: :param post_id: 岗位id :return: 岗位信息对象 """ - post_info = (await db.execute( - select(SysPost) - .where(SysPost.post_id == post_id) - )).scalars().first() + post_info = (await db.execute(select(SysPost).where(SysPost.post_id == post_id))).scalars().first() return post_info @@ -50,12 +47,19 @@ class PostDao: :param post: 岗位参数对象 :return: 岗位信息对象 """ - post_info = (await db.execute( - select(SysPost) - .where(SysPost.post_name == post.post_name if post.post_name else True, - SysPost.post_code == post.post_code if post.post_code else True, - SysPost.post_sort == post.post_sort if post.post_sort else True) - )).scalars().first() + post_info = ( + ( + await db.execute( + select(SysPost).where( + SysPost.post_name == post.post_name if post.post_name else True, + SysPost.post_code == post.post_code if post.post_code else True, + SysPost.post_sort == post.post_sort if post.post_sort else True, + ) + ) + ) + .scalars() + .first() + ) return post_info @@ -68,12 +72,16 @@ class PostDao: :param is_page: 是否开启分页 :return: 岗位列表信息对象 """ - query = select(SysPost) \ - .where(SysPost.post_code.like(f'%{query_object.post_code}%') if query_object.post_code else True, - SysPost.post_name.like(f'%{query_object.post_name}%') if query_object.post_name else True, - SysPost.status == query_object.status if query_object.status else True) \ - .order_by(SysPost.post_sort) \ + query = ( + select(SysPost) + .where( + SysPost.post_code.like(f'%{query_object.post_code}%') if query_object.post_code else True, + SysPost.post_name.like(f'%{query_object.post_name}%') if query_object.post_name else True, + SysPost.status == query_object.status if query_object.status else True, + ) + .order_by(SysPost.post_sort) .distinct() + ) post_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return post_list @@ -100,10 +108,7 @@ class PostDao: :param post: 需要更新的岗位字典 :return: """ - await db.execute( - update(SysPost), - [post] - ) + await db.execute(update(SysPost), [post]) @classmethod async def delete_post_dao(cls, db: AsyncSession, post: PostModel): @@ -113,10 +118,7 @@ class PostDao: :param post: 岗位对象 :return: """ - await db.execute( - delete(SysPost) - .where(SysPost.post_id.in_([post.post_id])) - ) + await db.execute(delete(SysPost).where(SysPost.post_id.in_([post.post_id]))) @classmethod async def count_user_post_dao(cls, db: AsyncSession, post_id: int): @@ -126,10 +128,8 @@ class PostDao: :param post_id: 岗位id :return: 岗位关联的用户数量 """ - user_post_count = (await db.execute( - select(func.count('*')) - .select_from(SysUserPost) - .where(SysUserPost.post_id == post_id) - )).scalar() + user_post_count = ( + await db.execute(select(func.count('*')).select_from(SysUserPost).where(SysUserPost.post_id == post_id)) + ).scalar() return user_post_count diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/post_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/post_do.py index c6b189b..54ab38d 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/post_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/post_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysPost(Base): """ 岗位信息表 """ + __tablename__ = 'sys_post' post_id = Column(Integer, primary_key=True, autoincrement=True, comment='岗位ID') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py index 68dd079..ab85103 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py @@ -1,15 +1,16 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from typing import Union, Optional, List, Literal -from datetime import datetime -from module_admin.annotation.pydantic_annotation import as_query, as_form +from typing import Literal, Optional +from module_admin.annotation.pydantic_annotation import as_form, as_query class PostModel(BaseModel): """ 岗位信息表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) post_id: Optional[int] = Field(default=None, description='岗位ID') @@ -47,6 +48,7 @@ class PostQueryModel(PostModel): """ 岗位管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -57,6 +59,7 @@ class PostPageQueryModel(PostQueryModel): """ 岗位管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -65,6 +68,7 @@ class DeletePostModel(BaseModel): """ 删除岗位模型 """ + model_config = ConfigDict(alias_generator=to_camel) post_ids: str = Field(description='需要删除的岗位ID') diff --git a/ruoyi-fastapi-backend/module_admin/service/post_service.py b/ruoyi-fastapi-backend/module_admin/service/post_service.py index b9a088c..3ce4a6b 100644 --- a/ruoyi-fastapi-backend/module_admin/service/post_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/post_service.py @@ -1,16 +1,22 @@ -from module_admin.dao.post_dao import * -from module_admin.entity.vo.common_vo import CrudResponseModel +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List from config.constant import CommonConstant from exceptions.exception import ServiceException -from utils.common_util import export_list2excel, CamelCaseUtil +from module_admin.dao.post_dao import PostDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.post_vo import DeletePostModel, PostModel, PostPageQueryModel +from utils.common_util import CamelCaseUtil, export_list2excel class PostService: """ 岗位管理模块服务层 """ + @classmethod - async def get_post_list_services(cls, query_db: AsyncSession, query_object: PostPageQueryModel, is_page: bool = False): + async def get_post_list_services( + cls, query_db: AsyncSession, query_object: PostPageQueryModel, is_page: bool = False + ): """ 获取岗位列表信息service :param query_db: orm对象 @@ -146,16 +152,16 @@ class PostService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "postId": "岗位编号", - "postCode": "岗位编码", - "postName": "岗位名称", - "postSort": "显示顺序", - "status": "状态", - "createBy": "创建者", - "createTime": "创建时间", - "updateBy": "更新者", - "updateTime": "更新时间", - "remark": "备注", + 'postId': '岗位编号', + 'postCode': '岗位编码', + 'postName': '岗位名称', + 'postSort': '显示顺序', + 'status': '状态', + 'createBy': '创建者', + 'createTime': '创建时间', + 'updateBy': '更新者', + 'updateTime': '更新时间', + 'remark': '备注', } data = post_list @@ -165,7 +171,9 @@ class PostService: item['status'] = '正常' else: item['status'] = '停用' - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data -- Gitee From 6d0d772749e4c14a9f66829c2aa1ac9a57be3e0d Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 09:43:36 +0800 Subject: [PATCH 084/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E5=9C=A8=E7=BA=BF=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/online_controller.py | 33 +++++++++++-------- .../module_admin/entity/vo/online_vo.py | 7 ++-- .../module_admin/service/online_service.py | 10 +++--- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py index be9669c..c4b3897 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py @@ -1,29 +1,36 @@ -from fastapi import APIRouter -from fastapi import Depends +from fastapi import APIRouter, Depends, Request +from sqlalchemy.ext.asyncio import AsyncSession +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, AsyncSession -from module_admin.service.online_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * -from utils.page_util import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.online_vo import DeleteOnlineModel, OnlineQueryModel +from module_admin.service.login_service import LoginService +from module_admin.service.online_service import OnlineService +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.response_util import ResponseUtil onlineController = APIRouter(prefix='/monitor/online', dependencies=[Depends(LoginService.get_current_user)]) -@onlineController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:list'))]) -async def get_monitor_online_list(request: Request, online_page_query: OnlineQueryModel = Depends(OnlineQueryModel.as_query)): +@onlineController.get( + '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:list'))] +) +async def get_monitor_online_list( + request: Request, online_page_query: OnlineQueryModel = Depends(OnlineQueryModel.as_query) +): # 获取全量数据 online_query_result = await OnlineService.get_online_list_services(request, online_page_query) logger.info('获取成功') - return ResponseUtil.success(model_content=PageResponseModel(rows=online_query_result, total=len(online_query_result))) + return ResponseUtil.success( + model_content=PageResponseModel(rows=online_query_result, total=len(online_query_result)) + ) -@onlineController.delete("/{token_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))]) +@onlineController.delete('/{token_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))]) @log_decorator(title='在线用户', business_type=BusinessType.FORCE) async def delete_monitor_online(request: Request, token_ids: str, query_db: AsyncSession = Depends(get_db)): delete_online = DeleteOnlineModel(tokenIds=token_ids) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py index 663a7a6..ca68f1e 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py @@ -1,7 +1,7 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List -from datetime import datetime +from typing import Optional from module_admin.annotation.pydantic_annotation import as_query @@ -9,6 +9,7 @@ class OnlineModel(BaseModel): """ 在线用户对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel) token_id: Optional[str] = Field(default=None, description='会话编号') @@ -26,6 +27,7 @@ class OnlineQueryModel(OnlineModel): """ 岗位管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -34,6 +36,7 @@ class DeleteOnlineModel(BaseModel): """ 强退在线用户模型 """ + model_config = ConfigDict(alias_generator=to_camel) token_ids: str = Field(description='需要强退的会话编号') diff --git a/ruoyi-fastapi-backend/module_admin/service/online_service.py b/ruoyi-fastapi-backend/module_admin/service/online_service.py index 2b679f9..3e16eef 100644 --- a/ruoyi-fastapi-backend/module_admin/service/online_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/online_service.py @@ -1,9 +1,9 @@ from fastapi import Request from jose import jwt from config.env import JwtConfig, RedisInitKeyConfig -from module_admin.entity.vo.online_vo import * -from module_admin.entity.vo.common_vo import CrudResponseModel from exceptions.exception import ServiceException +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.online_vo import DeleteOnlineModel, OnlineQueryModel from utils.common_util import CamelCaseUtil @@ -35,7 +35,7 @@ class OnlineService: login_location=payload.get('login_info').get('loginLocation'), browser=payload.get('login_info').get('browser'), os=payload.get('login_info').get('os'), - login_time=payload.get('login_info').get('loginTime') + login_time=payload.get('login_info').get('loginTime'), ) if query_object.user_name and not query_object.ipaddr: if query_object.user_name == payload.get('login_info').get('ipaddr'): @@ -46,7 +46,9 @@ class OnlineService: online_info_list = [online_dict] break elif query_object.user_name and query_object.ipaddr: - if query_object.user_name == payload.get('user_name') and query_object.ipaddr == payload.get('login_info').get('ipaddr'): + if query_object.user_name == payload.get('user_name') and query_object.ipaddr == payload.get( + 'login_info' + ).get('ipaddr'): online_info_list = [online_dict] break else: -- Gitee From 2c86992cacdbfef46c0179d6d5e1a4ca1326d6a8 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 09:50:10 +0800 Subject: [PATCH 085/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E9=80=9A=E7=9F=A5=E5=85=AC=E5=91=8A?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/notice_controller.py | 55 +++++++++++----- .../module_admin/dao/notice_dao.py | 62 ++++++++++--------- .../module_admin/entity/do/notice_do.py | 5 +- .../module_admin/entity/vo/notice_vo.py | 10 ++- .../module_admin/service/notice_service.py | 12 ++-- 5 files changed, 89 insertions(+), 55 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py index 7e75306..4dbef45 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py @@ -1,22 +1,31 @@ -from fastapi import APIRouter, Request -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, CurrentUserModel -from module_admin.service.notice_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * -from utils.page_util import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.notice_vo import DeleteNoticeModel, NoticeModel, NoticePageQueryModel +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.login_service import LoginService +from module_admin.service.notice_service import NoticeService +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.response_util import ResponseUtil noticeController = APIRouter(prefix='/system/notice', dependencies=[Depends(LoginService.get_current_user)]) -@noticeController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:list'))]) -async def get_system_notice_list(request: Request, notice_page_query: NoticePageQueryModel = Depends(NoticePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@noticeController.get( + '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:list'))] +) +async def get_system_notice_list( + request: Request, + notice_page_query: NoticePageQueryModel = Depends(NoticePageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): # 获取分页数据 notice_page_query_result = await NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True) logger.info('获取成功') @@ -24,10 +33,15 @@ async def get_system_notice_list(request: Request, notice_page_query: NoticePage return ResponseUtil.success(model_content=notice_page_query_result) -@noticeController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))]) +@noticeController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))]) @ValidateFields(validate_model='add_notice') @log_decorator(title='通知公告管理', business_type=BusinessType.INSERT) -async def add_system_notice(request: Request, add_notice: NoticeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_notice( + request: Request, + add_notice: NoticeModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_notice.create_by = current_user.user.user_name add_notice.create_time = datetime.now() add_notice.update_by = current_user.user.user_name @@ -38,10 +52,15 @@ async def add_system_notice(request: Request, add_notice: NoticeModel, query_db: return ResponseUtil.success(msg=add_notice_result.message) -@noticeController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))]) +@noticeController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))]) @ValidateFields(validate_model='edit_notice') @log_decorator(title='通知公告管理', business_type=BusinessType.UPDATE) -async def edit_system_notice(request: Request, edit_notice: NoticeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def edit_system_notice( + request: Request, + edit_notice: NoticeModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): edit_notice.update_by = current_user.user.user_name edit_notice.update_time = datetime.now() edit_notice_result = await NoticeService.edit_notice_services(query_db, edit_notice) @@ -50,7 +69,7 @@ async def edit_system_notice(request: Request, edit_notice: NoticeModel, query_d return ResponseUtil.success(msg=edit_notice_result.message) -@noticeController.delete("/{notice_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))]) +@noticeController.delete('/{notice_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))]) @log_decorator(title='通知公告管理', business_type=BusinessType.DELETE) async def delete_system_notice(request: Request, notice_ids: str, query_db: AsyncSession = Depends(get_db)): delete_notice = DeleteNoticeModel(noticeIds=notice_ids) @@ -60,7 +79,9 @@ async def delete_system_notice(request: Request, notice_ids: str, query_db: Asyn return ResponseUtil.success(msg=delete_notice_result.message) -@noticeController.get("/{notice_id}", response_model=NoticeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:query'))]) +@noticeController.get( + '/{notice_id}', response_model=NoticeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:query'))] +) async def query_detail_system_post(request: Request, notice_id: int, query_db: AsyncSession = Depends(get_db)): notice_detail_result = await NoticeService.notice_detail_services(query_db, notice_id) logger.info(f'获取notice_id为{notice_id}的信息成功') diff --git a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py index d680aa7..534c26c 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py @@ -1,9 +1,9 @@ -from sqlalchemy import select, update, delete +from datetime import datetime, time +from sqlalchemy import delete, select, update from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.notice_do import SysNotice -from module_admin.entity.vo.notice_vo import * +from module_admin.entity.vo.notice_vo import NoticeModel, NoticePageQueryModel from utils.page_util import PageUtil -from datetime import datetime, time class NoticeDao: @@ -19,10 +19,7 @@ class NoticeDao: :param notice_id: 通知公告id :return: 通知公告信息对象 """ - notice_info = (await db.execute( - select(SysNotice) - .where(SysNotice.notice_id == notice_id) - )).scalars().first() + notice_info = (await db.execute(select(SysNotice).where(SysNotice.notice_id == notice_id))).scalars().first() return notice_info @@ -34,12 +31,19 @@ class NoticeDao: :param notice: 通知公告参数对象 :return: 通知公告信息对象 """ - notice_info = (await db.execute( - select(SysNotice) - .where(SysNotice.notice_title == notice.notice_title, - SysNotice.notice_type == notice.notice_type, - SysNotice.notice_content == notice.notice_content) - )).scalars().first() + notice_info = ( + ( + await db.execute( + select(SysNotice).where( + SysNotice.notice_title == notice.notice_title, + SysNotice.notice_type == notice.notice_type, + SysNotice.notice_content == notice.notice_content, + ) + ) + ) + .scalars() + .first() + ) return notice_info @@ -52,15 +56,21 @@ class NoticeDao: :param is_page: 是否开启分页 :return: 通知公告列表信息对象 """ - query = select(SysNotice) \ - .where(SysNotice.notice_title.like(f'%{query_object.notice_title}%') if query_object.notice_title else True, - SysNotice.create_by.like(f'%{query_object.create_by}%') if query_object.create_by else True, - SysNotice.notice_type == query_object.notice_type if query_object.notice_type else True, - SysNotice.create_time.between( - datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), - datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True) \ + query = ( + select(SysNotice) + .where( + SysNotice.notice_title.like(f'%{query_object.notice_title}%') if query_object.notice_title else True, + SysNotice.create_by.like(f'%{query_object.create_by}%') if query_object.create_by else True, + SysNotice.notice_type == query_object.notice_type if query_object.notice_type else True, + SysNotice.create_time.between( + datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), + datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)), + ) + if query_object.begin_time and query_object.end_time + else True, + ) .distinct() + ) notice_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return notice_list @@ -87,10 +97,7 @@ class NoticeDao: :param notice: 需要更新的通知公告字典 :return: """ - await db.execute( - update(SysNotice), - [notice] - ) + await db.execute(update(SysNotice), [notice]) @classmethod async def delete_notice_dao(cls, db: AsyncSession, notice: NoticeModel): @@ -100,7 +107,4 @@ class NoticeDao: :param notice: 通知公告对象 :return: """ - await db.execute( - delete(SysNotice) - .where(SysNotice.notice_id.in_([notice.notice_id])) - ) + await db.execute(delete(SysNotice).where(SysNotice.notice_id.in_([notice.notice_id]))) diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/notice_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/notice_do.py index 3856658..125a40a 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/notice_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/notice_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime, LargeBinary -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, LargeBinary, String +from config.database import Base class SysNotice(Base): """ 通知公告表 """ + __tablename__ = 'sys_notice' notice_id = Column(Integer, primary_key=True, autoincrement=True, comment='公告ID') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py index 75ef99c..bbf0a07 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py @@ -1,15 +1,16 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size, Xss -from typing import Union, Optional, List, Literal -from datetime import datetime -from module_admin.annotation.pydantic_annotation import as_query, as_form +from typing import Literal, Optional +from module_admin.annotation.pydantic_annotation import as_form, as_query class NoticeModel(BaseModel): """ 通知公告表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) notice_id: Optional[int] = Field(default=None, description='公告ID') @@ -37,6 +38,7 @@ class NoticeQueryModel(NoticeModel): """ 通知公告管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -47,6 +49,7 @@ class NoticePageQueryModel(NoticeQueryModel): """ 通知公告管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -55,6 +58,7 @@ class DeleteNoticeModel(BaseModel): """ 删除通知公告模型 """ + model_config = ConfigDict(alias_generator=to_camel) notice_ids: str = Field(description='需要删除的公告ID') diff --git a/ruoyi-fastapi-backend/module_admin/service/notice_service.py b/ruoyi-fastapi-backend/module_admin/service/notice_service.py index 1926ed7..d9e5594 100644 --- a/ruoyi-fastapi-backend/module_admin/service/notice_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/notice_service.py @@ -1,8 +1,10 @@ -from module_admin.dao.notice_dao import * -from module_admin.entity.vo.common_vo import CrudResponseModel +from sqlalchemy.ext.asyncio import AsyncSession from config.constant import CommonConstant from exceptions.exception import ServiceException -from utils.common_util import export_list2excel, CamelCaseUtil +from module_admin.dao.notice_dao import NoticeDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.notice_vo import DeleteNoticeModel, NoticeModel, NoticePageQueryModel +from utils.common_util import CamelCaseUtil class NoticeService: @@ -11,7 +13,9 @@ class NoticeService: """ @classmethod - async def get_notice_list_services(cls, query_db: AsyncSession, query_object: NoticePageQueryModel, is_page: bool = True): + async def get_notice_list_services( + cls, query_db: AsyncSession, query_object: NoticePageQueryModel, is_page: bool = True + ): """ 获取通知公告列表信息service :param query_db: orm对象 -- Gitee From 5891ec1930ba82f2c97f0b3f232407ea4b221a5a Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 09:59:12 +0800 Subject: [PATCH 086/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E8=8F=9C=E5=8D=95=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/menu_controller.py | 72 ++++++-- .../module_admin/dao/menu_dao.py | 172 ++++++++++-------- .../module_admin/entity/do/menu_do.py | 5 +- .../module_admin/entity/vo/menu_vo.py | 7 +- .../module_admin/service/menu_service.py | 42 +++-- 5 files changed, 185 insertions(+), 113 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py index 3baa142..d47f30a 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py @@ -1,47 +1,72 @@ -from fastapi import APIRouter, Request -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService -from module_admin.service.menu_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuModel, MenuQueryModel +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.login_service import LoginService +from module_admin.service.menu_service import MenuService +from utils.log_util import logger +from utils.response_util import ResponseUtil menuController = APIRouter(prefix='/system/menu', dependencies=[Depends(LoginService.get_current_user)]) -@menuController.get("/treeselect") -async def get_system_menu_tree(request: Request, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +@menuController.get('/treeselect') +async def get_system_menu_tree( + request: Request, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): menu_query_result = await MenuService.get_menu_tree_services(query_db, current_user) logger.info('获取成功') return ResponseUtil.success(data=menu_query_result) -@menuController.get("/roleMenuTreeselect/{role_id}") -async def get_system_role_menu_tree(request: Request, role_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +@menuController.get('/roleMenuTreeselect/{role_id}') +async def get_system_role_menu_tree( + request: Request, + role_id: int, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): role_menu_query_result = await MenuService.get_role_menu_tree_services(query_db, role_id, current_user) logger.info('获取成功') return ResponseUtil.success(model_content=role_menu_query_result) -@menuController.get("/list", response_model=List[MenuModel], dependencies=[Depends(CheckUserInterfaceAuth('system:menu:list'))]) -async def get_system_menu_list(request: Request, menu_query: MenuQueryModel = Depends(MenuQueryModel.as_query), query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +@menuController.get( + '/list', response_model=List[MenuModel], dependencies=[Depends(CheckUserInterfaceAuth('system:menu:list'))] +) +async def get_system_menu_list( + request: Request, + menu_query: MenuQueryModel = Depends(MenuQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): menu_query_result = await MenuService.get_menu_list_services(query_db, menu_query, current_user) logger.info('获取成功') return ResponseUtil.success(data=menu_query_result) -@menuController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) +@menuController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) @ValidateFields(validate_model='add_menu') @log_decorator(title='菜单管理', business_type=BusinessType.INSERT) -async def add_system_menu(request: Request, add_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_menu( + request: Request, + add_menu: MenuModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_menu.create_by = current_user.user.user_name add_menu.create_time = datetime.now() add_menu.update_by = current_user.user.user_name @@ -52,10 +77,15 @@ async def add_system_menu(request: Request, add_menu: MenuModel, query_db: Async return ResponseUtil.success(msg=add_menu_result.message) -@menuController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) +@menuController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) @ValidateFields(validate_model='edit_menu') @log_decorator(title='菜单管理', business_type=BusinessType.UPDATE) -async def edit_system_menu(request: Request, edit_menu: MenuModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def edit_system_menu( + request: Request, + edit_menu: MenuModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): edit_menu.update_by = current_user.user.user_name edit_menu.update_time = datetime.now() edit_menu_result = await MenuService.edit_menu_services(query_db, edit_menu) @@ -64,7 +94,7 @@ async def edit_system_menu(request: Request, edit_menu: MenuModel, query_db: Asy return ResponseUtil.success(msg=edit_menu_result.message) -@menuController.delete("/{menu_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) +@menuController.delete('/{menu_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) @log_decorator(title='菜单管理', business_type=BusinessType.DELETE) async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSession = Depends(get_db)): delete_menu = DeleteMenuModel(menuIds=menu_ids) @@ -74,7 +104,9 @@ async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSes return ResponseUtil.success(msg=delete_menu_result.message) -@menuController.get("/{menu_id}", response_model=MenuModel, dependencies=[Depends(CheckUserInterfaceAuth('system:menu:query'))]) +@menuController.get( + '/{menu_id}', response_model=MenuModel, dependencies=[Depends(CheckUserInterfaceAuth('system:menu:query'))] +) async def query_detail_system_menu(request: Request, menu_id: int, query_db: AsyncSession = Depends(get_db)): menu_detail_result = await MenuService.menu_detail_services(query_db, menu_id) logger.info(f'获取menu_id为{menu_id}的信息成功') diff --git a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py index dfa9ca2..223b84e 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py @@ -1,9 +1,9 @@ -from sqlalchemy import select, update, delete, and_, func +from sqlalchemy import and_, delete, func, select, update from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.menu_do import SysMenu -from module_admin.entity.do.user_do import SysUser, SysUserRole from module_admin.entity.do.role_do import SysRole, SysRoleMenu -from module_admin.entity.vo.menu_vo import * +from module_admin.entity.do.user_do import SysUser, SysUserRole +from module_admin.entity.vo.menu_vo import MenuModel, MenuQueryModel class MenuDao: @@ -19,10 +19,7 @@ class MenuDao: :param menu_id: 菜单id :return: 菜单信息对象 """ - menu_info = (await db.execute( - select(SysMenu) - .where(SysMenu.menu_id == menu_id) - )).scalars().first() + menu_info = (await db.execute(select(SysMenu).where(SysMenu.menu_id == menu_id))).scalars().first() return menu_info @@ -34,12 +31,19 @@ class MenuDao: :param menu: 菜单参数对象 :return: 菜单信息对象 """ - menu_info = (await db.execute( - select(SysMenu) - .where(SysMenu.parent_id == menu.parent_id if menu.parent_id else True, - SysMenu.menu_name == menu.menu_name if menu.menu_name else True, - SysMenu.menu_type == menu.menu_type if menu.menu_type else True) - )).scalars().first() + menu_info = ( + ( + await db.execute( + select(SysMenu).where( + SysMenu.parent_id == menu.parent_id if menu.parent_id else True, + SysMenu.menu_name == menu.menu_name if menu.menu_name else True, + SysMenu.menu_type == menu.menu_type if menu.menu_type else True, + ) + ) + ) + .scalars() + .first() + ) return menu_info @@ -54,26 +58,35 @@ class MenuDao: """ role_id_list = [item.role_id for item in role] if 1 in role_id_list: - menu_query_all = (await db.execute( - select(SysMenu) - .where(SysMenu.status == '0') - .order_by(SysMenu.order_num) - .distinct() - )).scalars().all() + menu_query_all = ( + (await db.execute(select(SysMenu).where(SysMenu.status == '0').order_by(SysMenu.order_num).distinct())) + .scalars() + .all() + ) else: - menu_query_all = (await db.execute( - select(SysMenu) - .select_from(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, - and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), - isouter=True) - .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) - .order_by(SysMenu.order_num) - .distinct() - )).scalars().all() + menu_query_all = ( + ( + await db.execute( + select(SysMenu) + .select_from(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join( + SysRole, + and_( + SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0' + ), + isouter=True, + ) + .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) + .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, SysMenu.status == '0')) + .order_by(SysMenu.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return menu_query_all @@ -89,31 +102,52 @@ class MenuDao: """ role_id_list = [item.role_id for item in role] if 1 in role_id_list: - menu_query_all = (await db.execute( - select(SysMenu) - .where(SysMenu.status == page_object.status if page_object.status else True, - SysMenu.menu_name.like( - f'%{page_object.menu_name}%') if page_object.menu_name else True) - .order_by(SysMenu.order_num) - .distinct() - )).scalars().all() + menu_query_all = ( + ( + await db.execute( + select(SysMenu) + .where( + SysMenu.status == page_object.status if page_object.status else True, + SysMenu.menu_name.like(f'%{page_object.menu_name}%') if page_object.menu_name else True, + ) + .order_by(SysMenu.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) else: - menu_query_all = (await db.execute( - select(SysMenu) - .select_from(SysUser) - .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) - .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) - .join(SysRole, - and_(SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0'), - isouter=True) - .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) - .join(SysMenu, and_(SysRoleMenu.menu_id == SysMenu.menu_id, - SysMenu.status == page_object.status if page_object.status else True, - SysMenu.menu_name.like( - f'%{page_object.menu_name}%') if page_object.menu_name else True)) - .order_by(SysMenu.order_num) - .distinct() - )).scalars().all() + menu_query_all = ( + ( + await db.execute( + select(SysMenu) + .select_from(SysUser) + .where(SysUser.status == '0', SysUser.del_flag == '0', SysUser.user_id == user_id) + .join(SysUserRole, SysUser.user_id == SysUserRole.user_id, isouter=True) + .join( + SysRole, + and_( + SysUserRole.role_id == SysRole.role_id, SysRole.status == '0', SysRole.del_flag == '0' + ), + isouter=True, + ) + .join(SysRoleMenu, SysRole.role_id == SysRoleMenu.role_id, isouter=True) + .join( + SysMenu, + and_( + SysRoleMenu.menu_id == SysMenu.menu_id, + SysMenu.status == page_object.status if page_object.status else True, + SysMenu.menu_name.like(f'%{page_object.menu_name}%') if page_object.menu_name else True, + ), + ) + .order_by(SysMenu.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return menu_query_all @@ -139,10 +173,7 @@ class MenuDao: :param menu: 需要更新的菜单字典 :return: """ - await db.execute( - update(SysMenu), - [menu] - ) + await db.execute(update(SysMenu), [menu]) @classmethod async def delete_menu_dao(cls, db: AsyncSession, menu: MenuModel): @@ -152,10 +183,7 @@ class MenuDao: :param menu: 菜单对象 :return: """ - await db.execute( - delete(SysMenu) - .where(SysMenu.menu_id.in_([menu.menu_id])) - ) + await db.execute(delete(SysMenu).where(SysMenu.menu_id.in_([menu.menu_id]))) @classmethod async def has_child_by_menu_id_dao(cls, db: AsyncSession, menu_id: int): @@ -165,11 +193,9 @@ class MenuDao: :param menu_id: 菜单id :return: 菜单关联子菜单的数量 """ - menu_count = (await db.execute( - select(func.count('*')) - .select_from(SysMenu) - .where(SysMenu.parent_id == menu_id) - )).scalar() + menu_count = ( + await db.execute(select(func.count('*')).select_from(SysMenu).where(SysMenu.parent_id == menu_id)) + ).scalar() return menu_count @@ -181,10 +207,8 @@ class MenuDao: :param menu_id: 菜单id :return: 菜单关联角色数量 """ - role_count = (await db.execute( - select(func.count('*')) - .select_from(SysRoleMenu) - .where(SysRoleMenu.menu_id == menu_id) - )).scalar() + role_count = ( + await db.execute(select(func.count('*')).select_from(SysRoleMenu).where(SysRoleMenu.menu_id == menu_id)) + ).scalar() return role_count diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py index 8f98be4..e7e5f50 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysMenu(Base): """ 菜单权限表 """ + __tablename__ = 'sys_menu' menu_id = Column(Integer, primary_key=True, autoincrement=True, comment='菜单ID') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py index 224015c..c5234d4 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/menu_vo.py @@ -1,8 +1,8 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from datetime import datetime -from typing import Union, Optional, List, Literal +from typing import Literal, Optional from module_admin.annotation.pydantic_annotation import as_query @@ -10,6 +10,7 @@ class MenuModel(BaseModel): """ 菜单表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) menu_id: Optional[int] = Field(default=None, description='菜单ID') @@ -71,6 +72,7 @@ class MenuQueryModel(MenuModel): """ 菜单管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -79,6 +81,7 @@ class DeleteMenuModel(BaseModel): """ 删除菜单模型 """ + model_config = ConfigDict(alias_generator=to_camel) menu_ids: str = Field(description='需要删除的菜单ID') diff --git a/ruoyi-fastapi-backend/module_admin/service/menu_service.py b/ruoyi-fastapi-backend/module_admin/service/menu_service.py index 3935495..f0f8ce2 100644 --- a/ruoyi-fastapi-backend/module_admin/service/menu_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/menu_service.py @@ -1,10 +1,13 @@ -from module_admin.entity.vo.user_vo import CurrentUserModel -from module_admin.entity.vo.role_vo import RoleMenuQueryModel -from module_admin.entity.vo.common_vo import CrudResponseModel -from module_admin.dao.role_dao import RoleDao -from module_admin.dao.menu_dao import * +from sqlalchemy.ext.asyncio import AsyncSession +from typing import Optional from config.constant import CommonConstant, MenuConstant from exceptions.exception import ServiceException, ServiceWarning +from module_admin.dao.menu_dao import MenuDao +from module_admin.dao.role_dao import RoleDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuQueryModel, MenuModel +from module_admin.entity.vo.role_vo import RoleMenuQueryModel +from module_admin.entity.vo.user_vo import CurrentUserModel from utils.common_util import CamelCaseUtil from utils.string_util import StringUtil @@ -22,13 +25,17 @@ class MenuService: :param current_user: 当前用户对象 :return: 菜单树信息对象 """ - menu_list_result = await MenuDao.get_menu_list_for_tree(query_db, current_user.user.user_id, current_user.user.role) + menu_list_result = await MenuDao.get_menu_list_for_tree( + query_db, current_user.user.user_id, current_user.user.role + ) menu_tree_result = cls.list_to_tree(menu_list_result) return menu_tree_result @classmethod - async def get_role_menu_tree_services(cls, query_db: AsyncSession, role_id: int, current_user: Optional[CurrentUserModel] = None): + async def get_role_menu_tree_services( + cls, query_db: AsyncSession, role_id: int, current_user: Optional[CurrentUserModel] = None + ): """ 根据角色id获取菜单树信息service :param query_db: orm对象 @@ -36,20 +43,21 @@ class MenuService: :param current_user: 当前用户对象 :return: 当前角色id的菜单树信息对象 """ - menu_list_result = await MenuDao.get_menu_list_for_tree(query_db, current_user.user.user_id, current_user.user.role) + menu_list_result = await MenuDao.get_menu_list_for_tree( + query_db, current_user.user.user_id, current_user.user.role + ) menu_tree_result = cls.list_to_tree(menu_list_result) role = await RoleDao.get_role_detail_by_id(query_db, role_id) role_menu_list = await RoleDao.get_role_menu_dao(query_db, role) checked_keys = [row.menu_id for row in role_menu_list] - result = RoleMenuQueryModel( - menus=menu_tree_result, - checkedKeys=checked_keys - ) + result = RoleMenuQueryModel(menus=menu_tree_result, checkedKeys=checked_keys) return result @classmethod - async def get_menu_list_services(cls, query_db: AsyncSession, page_object: MenuQueryModel, current_user: Optional[CurrentUserModel] = None): + async def get_menu_list_services( + cls, query_db: AsyncSession, page_object: MenuQueryModel, current_user: Optional[CurrentUserModel] = None + ): """ 获取菜单列表信息service :param query_db: orm对象 @@ -57,7 +65,9 @@ class MenuService: :param current_user: 当前用户对象 :return: 菜单列表信息对象 """ - menu_list_result = await MenuDao.get_menu_list(query_db, page_object, current_user.user.user_id, current_user.user.role) + menu_list_result = await MenuDao.get_menu_list( + query_db, page_object, current_user.user.user_id, current_user.user.role + ) return CamelCaseUtil.transform_result(menu_list_result) @@ -172,7 +182,9 @@ class MenuService: :param permission_list: 菜单列表信息 :return: 菜单树形嵌套数据 """ - permission_list = [dict(id=item.menu_id, label=item.menu_name, parentId=item.parent_id) for item in permission_list] + permission_list = [ + dict(id=item.menu_id, label=item.menu_name, parentId=item.parent_id) for item in permission_list + ] # 转成id为key的字典 mapping: dict = dict(zip([i['id'] for i in permission_list], permission_list)) -- Gitee From ccb9e2a31486f527714b17c8fc59af9e868b290c Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 10:13:34 +0800 Subject: [PATCH 087/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E6=97=A5=E5=BF=97=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/log_controller.py | 105 +++++++++++++----- .../module_admin/dao/log_dao.py | 87 ++++++++------- .../module_admin/entity/do/log_do.py | 10 +- .../module_admin/entity/vo/log_vo.py | 34 ++++-- .../module_admin/service/log_service.py | 98 ++++++++++------ 5 files changed, 216 insertions(+), 118 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py index 59bce15..328d5c2 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py @@ -1,30 +1,47 @@ -from fastapi import APIRouter -from fastapi import Depends +from fastapi import APIRouter, Depends, Request +from sqlalchemy.ext.asyncio import AsyncSession +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService -from module_admin.service.log_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * -from utils.page_util import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.log_vo import ( + DeleteLoginLogModel, + DeleteOperLogModel, + LoginLogPageQueryModel, + OperLogPageQueryModel, + UnlockUser, +) +from module_admin.service.log_service import LoginLogService, OperationLogService +from module_admin.service.login_service import LoginService from utils.common_util import bytes2file_response +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.response_util import ResponseUtil logController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)]) -@logController.get("/operlog/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:list'))]) -async def get_system_operation_log_list(request: Request, operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@logController.get( + '/operlog/list', + response_model=PageResponseModel, + dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:list'))], +) +async def get_system_operation_log_list( + request: Request, + operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): # 获取分页数据 - operation_log_page_query_result = await OperationLogService.get_operation_log_list_services(query_db, operation_log_page_query, is_page=True) + operation_log_page_query_result = await OperationLogService.get_operation_log_list_services( + query_db, operation_log_page_query, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=operation_log_page_query_result) -@logController.delete("/operlog/clean", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) +@logController.delete('/operlog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) @log_decorator(title='操作日志管理', business_type=BusinessType.CLEAN) async def clear_system_operation_log(request: Request, query_db: AsyncSession = Depends(get_db)): clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db) @@ -33,37 +50,57 @@ async def clear_system_operation_log(request: Request, query_db: AsyncSession = return ResponseUtil.success(msg=clear_operation_log_result.message) -@logController.delete("/operlog/{oper_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) +@logController.delete('/operlog/{oper_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) @log_decorator(title='操作日志管理', business_type=BusinessType.DELETE) async def delete_system_operation_log(request: Request, oper_ids: str, query_db: AsyncSession = Depends(get_db)): delete_operation_log = DeleteOperLogModel(operIds=oper_ids) - delete_operation_log_result = await OperationLogService.delete_operation_log_services(query_db, delete_operation_log) + delete_operation_log_result = await OperationLogService.delete_operation_log_services( + query_db, delete_operation_log + ) logger.info(delete_operation_log_result.message) return ResponseUtil.success(msg=delete_operation_log_result.message) -@logController.post("/operlog/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))]) +@logController.post('/operlog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))]) @log_decorator(title='操作日志管理', business_type=BusinessType.EXPORT) -async def export_system_operation_log_list(request: Request, operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): +async def export_system_operation_log_list( + request: Request, + operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), +): # 获取全量数据 - operation_log_query_result = await OperationLogService.get_operation_log_list_services(query_db, operation_log_page_query, is_page=False) - operation_log_export_result = await OperationLogService.export_operation_log_list_services(request, operation_log_query_result) + operation_log_query_result = await OperationLogService.get_operation_log_list_services( + query_db, operation_log_page_query, is_page=False + ) + operation_log_export_result = await OperationLogService.export_operation_log_list_services( + request, operation_log_query_result + ) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result)) -@logController.get("/logininfor/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:list'))]) -async def get_system_login_log_list(request: Request, login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@logController.get( + '/logininfor/list', + response_model=PageResponseModel, + dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:list'))], +) +async def get_system_login_log_list( + request: Request, + login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): # 获取分页数据 - login_log_page_query_result = await LoginLogService.get_login_log_list_services(query_db, login_log_page_query, is_page=True) + login_log_page_query_result = await LoginLogService.get_login_log_list_services( + query_db, login_log_page_query, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=login_log_page_query_result) -@logController.delete("/logininfor/clean", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) +@logController.delete('/logininfor/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) @log_decorator(title='登录日志管理', business_type=BusinessType.CLEAN) async def clear_system_login_log(request: Request, query_db: AsyncSession = Depends(get_db)): clear_login_log_result = await LoginLogService.clear_login_log_services(query_db) @@ -72,7 +109,9 @@ async def clear_system_login_log(request: Request, query_db: AsyncSession = Depe return ResponseUtil.success(msg=clear_login_log_result.message) -@logController.delete("/logininfor/{info_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) +@logController.delete( + '/logininfor/{info_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))] +) @log_decorator(title='登录日志管理', business_type=BusinessType.DELETE) async def delete_system_login_log(request: Request, info_ids: str, query_db: AsyncSession = Depends(get_db)): delete_login_log = DeleteLoginLogModel(infoIds=info_ids) @@ -82,9 +121,11 @@ async def delete_system_login_log(request: Request, info_ids: str, query_db: Asy return ResponseUtil.success(msg=delete_login_log_result.message) -@logController.get("/logininfor/unlock/{user_name}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:unlock'))]) +@logController.get( + '/logininfor/unlock/{user_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:unlock'))] +) @log_decorator(title='登录日志管理', business_type=BusinessType.OTHER) -async def clear_system_login_log(request: Request, user_name: str, query_db: AsyncSession = Depends(get_db)): +async def unlock_system_user(request: Request, user_name: str, query_db: AsyncSession = Depends(get_db)): unlock_user = UnlockUser(userName=user_name) unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user) logger.info(unlock_user_result.message) @@ -92,11 +133,17 @@ async def clear_system_login_log(request: Request, user_name: str, query_db: Asy return ResponseUtil.success(msg=unlock_user_result.message) -@logController.post("/logininfor/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))]) +@logController.post('/logininfor/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))]) @log_decorator(title='登录日志管理', business_type=BusinessType.EXPORT) -async def export_system_login_log_list(request: Request, login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): +async def export_system_login_log_list( + request: Request, + login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), +): # 获取全量数据 - login_log_query_result = await LoginLogService.get_login_log_list_services(query_db, login_log_page_query, is_page=False) + login_log_query_result = await LoginLogService.get_login_log_list_services( + query_db, login_log_page_query, is_page=False + ) login_log_export_result = await LoginLogService.export_login_log_list_services(login_log_query_result) logger.info('导出成功') diff --git a/ruoyi-fastapi-backend/module_admin/dao/log_dao.py b/ruoyi-fastapi-backend/module_admin/dao/log_dao.py index 5161bea..547aca9 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/log_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/log_dao.py @@ -1,10 +1,10 @@ -from sqlalchemy import select, update, delete, asc, desc +from datetime import datetime, time +from sqlalchemy import asc, delete, desc, select from sqlalchemy.ext.asyncio import AsyncSession -from module_admin.entity.do.log_do import SysOperLog, SysLogininfor -from module_admin.entity.vo.log_vo import * -from utils.page_util import PageUtil +from module_admin.entity.do.log_do import SysLogininfor, SysOperLog +from module_admin.entity.vo.log_vo import LogininforModel, LoginLogPageQueryModel, OperLogModel, OperLogPageQueryModel from utils.common_util import SnakeCaseUtil -from datetime import datetime, time +from utils.page_util import PageUtil class OperationLogDao: @@ -25,20 +25,27 @@ class OperationLogDao: order_by_column = asc(getattr(SysOperLog, SnakeCaseUtil.camel_to_snake(query_object.order_by_column), None)) elif query_object.is_asc == 'descending': order_by_column = desc( - getattr(SysOperLog, SnakeCaseUtil.camel_to_snake(query_object.order_by_column), None)) + getattr(SysOperLog, SnakeCaseUtil.camel_to_snake(query_object.order_by_column), None) + ) else: order_by_column = desc(SysOperLog.oper_time) - query = select(SysOperLog) \ - .where(SysOperLog.title.like(f'%{query_object.title}%') if query_object.title else True, - SysOperLog.oper_name.like(f'%{query_object.oper_name}%') if query_object.oper_name else True, - SysOperLog.business_type == query_object.business_type if query_object.business_type else True, - SysOperLog.status == query_object.status if query_object.status else True, - SysOperLog.oper_time.between( - datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), - datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True) \ - .distinct() \ + query = ( + select(SysOperLog) + .where( + SysOperLog.title.like(f'%{query_object.title}%') if query_object.title else True, + SysOperLog.oper_name.like(f'%{query_object.oper_name}%') if query_object.oper_name else True, + SysOperLog.business_type == query_object.business_type if query_object.business_type else True, + SysOperLog.status == query_object.status if query_object.status else True, + SysOperLog.oper_time.between( + datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), + datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)), + ) + if query_object.begin_time and query_object.end_time + else True, + ) + .distinct() .order_by(order_by_column) + ) operation_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return operation_log_list @@ -65,10 +72,7 @@ class OperationLogDao: :param operation_log: 操作日志对象 :return: """ - await db.execute( - delete(SysOperLog) - .where(SysOperLog.oper_id.in_([operation_log.oper_id])) - ) + await db.execute(delete(SysOperLog).where(SysOperLog.oper_id.in_([operation_log.oper_id]))) @classmethod async def clear_operation_log_dao(cls, db: AsyncSession): @@ -77,9 +81,7 @@ class OperationLogDao: :param db: orm对象 :return: """ - await db.execute( - delete(SysOperLog) - ) + await db.execute(delete(SysOperLog)) class LoginLogDao: @@ -98,22 +100,30 @@ class LoginLogDao: """ if query_object.is_asc == 'ascending': order_by_column = asc( - getattr(SysLogininfor, SnakeCaseUtil.camel_to_snake(query_object.order_by_column), None)) + getattr(SysLogininfor, SnakeCaseUtil.camel_to_snake(query_object.order_by_column), None) + ) elif query_object.is_asc == 'descending': order_by_column = desc( - getattr(SysLogininfor, SnakeCaseUtil.camel_to_snake(query_object.order_by_column), None)) + getattr(SysLogininfor, SnakeCaseUtil.camel_to_snake(query_object.order_by_column), None) + ) else: order_by_column = desc(SysLogininfor.login_time) - query = select(SysLogininfor) \ - .where(SysLogininfor.ipaddr.like(f'%{query_object.ipaddr}%') if query_object.ipaddr else True, - SysLogininfor.user_name.like(f'%{query_object.user_name}%') if query_object.user_name else True, - SysLogininfor.status == query_object.status if query_object.status else True, - SysLogininfor.login_time.between( - datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), - datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True) \ - .distinct() \ + query = ( + select(SysLogininfor) + .where( + SysLogininfor.ipaddr.like(f'%{query_object.ipaddr}%') if query_object.ipaddr else True, + SysLogininfor.user_name.like(f'%{query_object.user_name}%') if query_object.user_name else True, + SysLogininfor.status == query_object.status if query_object.status else True, + SysLogininfor.login_time.between( + datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), + datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)), + ) + if query_object.begin_time and query_object.end_time + else True, + ) + .distinct() .order_by(order_by_column) + ) login_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return login_log_list @@ -140,10 +150,7 @@ class LoginLogDao: :param login_log: 登录日志对象 :return: """ - await db.execute( - delete(SysLogininfor) - .where(SysLogininfor.info_id.in_([login_log.info_id])) - ) + await db.execute(delete(SysLogininfor).where(SysLogininfor.info_id.in_([login_log.info_id]))) @classmethod async def clear_login_log_dao(cls, db: AsyncSession): @@ -152,6 +159,4 @@ class LoginLogDao: :param db: orm对象 :return: """ - await db.execute( - delete(SysLogininfor) - ) + await db.execute(delete(SysLogininfor)) diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/log_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/log_do.py index 19d2b18..f915207 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/log_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/log_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime, Text, BigInteger, Index -from config.database import Base from datetime import datetime +from sqlalchemy import BigInteger, Column, DateTime, Index, Integer, String +from config.database import Base class SysLogininfor(Base): """ 系统访问记录 """ + __tablename__ = 'sys_logininfor' info_id = Column(Integer, primary_key=True, autoincrement=True, comment='访问ID') @@ -15,7 +16,9 @@ class SysLogininfor(Base): login_location = Column(String(255, collation='utf8_general_ci'), nullable=True, default='', comment='登录地点') browser = Column(String(50, collation='utf8_general_ci'), nullable=True, default='', comment='浏览器类型') os = Column(String(50, collation='utf8_general_ci'), nullable=True, default='', comment='操作系统') - status = Column(String(1, collation='utf8_general_ci'), nullable=True, default='0', comment='登录状态(0成功 1失败)') + status = Column( + String(1, collation='utf8_general_ci'), nullable=True, default='0', comment='登录状态(0成功 1失败)' + ) msg = Column(String(255, collation='utf8_general_ci'), nullable=True, default='', comment='提示消息') login_time = Column(DateTime, nullable=True, default=datetime.now(), comment='访问时间') @@ -27,6 +30,7 @@ class SysOperLog(Base): """ 操作日志记录 """ + __tablename__ = 'sys_oper_log' oper_id = Column(BigInteger, primary_key=True, autoincrement=True, comment='日志主键') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py index 0d47af9..1866513 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py @@ -1,22 +1,29 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Union, Optional, List, Literal -from datetime import datetime -from module_admin.annotation.pydantic_annotation import as_query, as_form +from typing import Literal, Optional +from module_admin.annotation.pydantic_annotation import as_form, as_query class OperLogModel(BaseModel): """ 操作日志表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) oper_id: Optional[int] = Field(default=None, description='日志主键') title: Optional[str] = Field(default=None, description='模块标题') - business_type: Optional[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']] = Field(default=None, description='业务类型(0其它 1新增 2修改 3删除 4授权 5导出 6导入 7强退 8生成代码 9清空数据)') + business_type: Optional[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']] = ( + Field( + default=None, description='业务类型(0其它 1新增 2修改 3删除 4授权 5导出 6导入 7强退 8生成代码 9清空数据)' + ) + ) method: Optional[str] = Field(default=None, description='方法名称') request_method: Optional[str] = Field(default=None, description='请求方式') - operator_type: Optional[Literal[0, 1, 2]] = Field(default=None, description='操作类别(0其它 1后台用户 2手机端用户)') + operator_type: Optional[Literal[0, 1, 2]] = Field( + default=None, description='操作类别(0其它 1后台用户 2手机端用户)' + ) oper_name: Optional[str] = Field(default=None, description='操作人员') dept_name: Optional[str] = Field(default=None, description='部门名称') oper_url: Optional[str] = Field(default=None, description='请求URL') @@ -34,6 +41,7 @@ class LogininforModel(BaseModel): """ 登录日志表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) info_id: Optional[int] = Field(default=None, description='访问ID') @@ -51,8 +59,11 @@ class OperLogQueryModel(OperLogModel): """ 操作日志管理不分页查询模型 """ + order_by_column: Optional[str] = Field(default=None, description='排序的字段名称') - is_asc: Optional[Literal['ascending', 'descending']] = Field(default=None, description='排序方式(ascending升序 descending降序)') + is_asc: Optional[Literal['ascending', 'descending']] = Field( + default=None, description='排序方式(ascending升序 descending降序)' + ) begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -63,6 +74,7 @@ class OperLogPageQueryModel(OperLogQueryModel): """ 操作日志管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -71,6 +83,7 @@ class DeleteOperLogModel(BaseModel): """ 删除操作日志模型 """ + model_config = ConfigDict(alias_generator=to_camel) oper_ids: str = Field(description='需要删除的日志主键') @@ -80,19 +93,22 @@ class LoginLogQueryModel(LogininforModel): """ 登录日志管理不分页查询模型 """ + order_by_column: Optional[str] = Field(default=None, description='排序的字段名称') - is_asc: Optional[Literal['ascending', 'descending']] = Field(default=None, description='排序方式(ascending升序 descending降序)') + is_asc: Optional[Literal['ascending', 'descending']] = Field( + default=None, description='排序方式(ascending升序 descending降序)' + ) begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') - @as_query @as_form class LoginLogPageQueryModel(LoginLogQueryModel): """ 登录日志管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -101,6 +117,7 @@ class DeleteLoginLogModel(BaseModel): """ 删除登录日志模型 """ + model_config = ConfigDict(alias_generator=to_camel) info_ids: str = Field(description='需要删除的访问ID') @@ -110,6 +127,7 @@ class UnlockUser(BaseModel): """ 解锁用户模型 """ + model_config = ConfigDict(alias_generator=to_camel) user_name: str = Field(description='用户名称') diff --git a/ruoyi-fastapi-backend/module_admin/service/log_service.py b/ruoyi-fastapi-backend/module_admin/service/log_service.py index 51b57c2..0ac8464 100644 --- a/ruoyi-fastapi-backend/module_admin/service/log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/log_service.py @@ -1,8 +1,20 @@ -from module_admin.dao.log_dao import * -from module_admin.service.dict_service import Request, DictDataService -from module_admin.entity.vo.common_vo import CrudResponseModel +from fastapi import Request +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List from exceptions.exception import ServiceException -from utils.common_util import export_list2excel, CamelCaseUtil +from module_admin.dao.log_dao import LoginLogDao, OperationLogDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.log_vo import ( + DeleteLoginLogModel, + DeleteOperLogModel, + LogininforModel, + LoginLogPageQueryModel, + OperLogModel, + OperLogPageQueryModel, + UnlockUser, +) +from module_admin.service.dict_service import DictDataService +from utils.common_util import export_list2excel class OperationLogService: @@ -11,7 +23,9 @@ class OperationLogService: """ @classmethod - async def get_operation_log_list_services(cls, query_db: AsyncSession, query_object: OperLogPageQueryModel, is_page: bool = False): + async def get_operation_log_list_services( + cls, query_db: AsyncSession, query_object: OperLogPageQueryModel, is_page: bool = False + ): """ 获取操作日志列表信息service :param query_db: orm对象 @@ -85,27 +99,31 @@ class OperationLogService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "operId": "日志编号", - "title": "系统模块", - "businessType": "操作类型", - "method": "方法名称", - "requestMethod": "请求方式", - "operName": "操作人员", - "deptName": "部门名称", - "operUrl": "请求URL", - "operIp": "操作地址", - "operLocation": "操作地点", - "operParam": "请求参数", - "jsonResult": "返回参数", - "status": "操作状态", - "error_msg": "错误消息", - "operTime": "操作日期", - "costTime": "消耗时间(毫秒)" + 'operId': '日志编号', + 'title': '系统模块', + 'businessType': '操作类型', + 'method': '方法名称', + 'requestMethod': '请求方式', + 'operName': '操作人员', + 'deptName': '部门名称', + 'operUrl': '请求URL', + 'operIp': '操作地址', + 'operLocation': '操作地点', + 'operParam': '请求参数', + 'jsonResult': '返回参数', + 'status': '操作状态', + 'error_msg': '错误消息', + 'operTime': '操作日期', + 'costTime': '消耗时间(毫秒)', } data = operation_log_list - operation_type_list = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type='sys_oper_type') - operation_type_option = [dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in operation_type_list] + operation_type_list = await DictDataService.query_dict_data_list_from_cache_services( + request.app.state.redis, dict_type='sys_oper_type' + ) + operation_type_option = [ + dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in operation_type_list + ] operation_type_option_dict = {item.get('value'): item for item in operation_type_option} for item in data: @@ -116,7 +134,9 @@ class OperationLogService: if str(item.get('businessType')) in operation_type_option_dict.keys(): item['businessType'] = operation_type_option_dict.get(str(item.get('businessType'))).get('label') - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data @@ -128,7 +148,9 @@ class LoginLogService: """ @classmethod - async def get_login_log_list_services(cls, query_db: AsyncSession, query_object: LoginLogPageQueryModel, is_page: bool = False): + async def get_login_log_list_services( + cls, query_db: AsyncSession, query_object: LoginLogPageQueryModel, is_page: bool = False + ): """ 获取登录日志列表信息service :param query_db: orm对象 @@ -194,9 +216,9 @@ class LoginLogService: @classmethod async def unlock_user_services(cls, request: Request, unlock_user: UnlockUser): - locked_user = await request.app.state.redis.get(f"account_lock:{unlock_user.user_name}") + locked_user = await request.app.state.redis.get(f'account_lock:{unlock_user.user_name}') if locked_user: - await request.app.state.redis.delete(f"account_lock:{unlock_user.user_name}") + await request.app.state.redis.delete(f'account_lock:{unlock_user.user_name}') return CrudResponseModel(is_success=True, message='解锁成功') else: raise ServiceException(message='该用户未锁定') @@ -210,15 +232,15 @@ class LoginLogService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "infoId": "访问编号", - "userName": "用户名称", - "ipaddr": "登录地址", - "loginLocation": "登录地点", - "browser": "浏览器", - "os": "操作系统", - "status": "登录状态", - "msg": "操作信息", - "loginTime": "登录日期" + 'infoId': '访问编号', + 'userName': '用户名称', + 'ipaddr': '登录地址', + 'loginLocation': '登录地点', + 'browser': '浏览器', + 'os': '操作系统', + 'status': '登录状态', + 'msg': '操作信息', + 'loginTime': '登录日期', } data = login_log_list @@ -228,7 +250,9 @@ class LoginLogService: item['status'] = '成功' else: item['status'] = '失败' - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data -- Gitee From 659163d662cee164f5f5a29eae6b166e962319e0 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 10:28:28 +0800 Subject: [PATCH 088/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/job_controller.py | 113 +++++++++++++----- .../module_admin/dao/job_dao.py | 58 +++++---- .../module_admin/dao/job_log_dao.py | 37 +++--- .../module_admin/entity/do/job_do.py | 33 +++-- .../module_admin/entity/vo/job_vo.py | 19 ++- .../module_admin/service/job_log_service.py | 54 +++++---- .../module_admin/service/job_service.py | 71 +++++++---- 7 files changed, 248 insertions(+), 137 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py index f3d536b..961c472 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py @@ -1,24 +1,40 @@ -from fastapi import APIRouter -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, CurrentUserModel -from module_admin.service.job_service import * -from module_admin.service.job_log_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * -from utils.page_util import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.job_vo import ( + DeleteJobLogModel, + DeleteJobModel, + EditJobModel, + JobLogPageQueryModel, + JobModel, + JobPageQueryModel, +) +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.job_log_service import JobLogService +from module_admin.service.job_service import JobService +from module_admin.service.login_service import LoginService from utils.common_util import bytes2file_response +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.response_util import ResponseUtil jobController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)]) -@jobController.get("/job/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))]) -async def get_system_job_list(request: Request, job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@jobController.get( + '/job/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))] +) +async def get_system_job_list( + request: Request, + job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): try: # 获取分页数据 notice_page_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=True) @@ -29,10 +45,15 @@ async def get_system_job_list(request: Request, job_page_query: JobPageQueryMode return ResponseUtil.error(msg=str(e)) -@jobController.post("/job", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))]) +@jobController.post('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))]) @ValidateFields(validate_model='add_job') @log_decorator(title='定时任务管理', business_type=BusinessType.INSERT) -async def add_system_job(request: Request, add_job: JobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_job( + request: Request, + add_job: JobModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): try: add_job.create_by = current_user.user.user_name add_job.create_time = datetime.now() @@ -50,10 +71,15 @@ async def add_system_job(request: Request, add_job: JobModel, query_db: AsyncSes return ResponseUtil.error(msg=str(e)) -@jobController.put("/job", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))]) +@jobController.put('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))]) @ValidateFields(validate_model='edit_job') @log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) -async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def edit_system_job( + request: Request, + edit_job: EditJobModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): try: edit_job.update_by = current_user.user.user_name edit_job.update_time = datetime.now() @@ -69,9 +95,14 @@ async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: As return ResponseUtil.error(msg=str(e)) -@jobController.put("/job/changeStatus", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) +@jobController.put('/job/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) @log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) -async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def change_system_job_status( + request: Request, + edit_job: EditJobModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): try: edit_job.update_by = current_user.user.user_name edit_job.update_time = datetime.now() @@ -88,7 +119,7 @@ async def edit_system_job(request: Request, edit_job: EditJobModel, query_db: As return ResponseUtil.error(msg=str(e)) -@jobController.put("/job/run", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) +@jobController.put('/job/run', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) @log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) async def execute_system_job(request: Request, execute_job: JobModel, query_db: AsyncSession = Depends(get_db)): try: @@ -104,7 +135,7 @@ async def execute_system_job(request: Request, execute_job: JobModel, query_db: return ResponseUtil.error(msg=str(e)) -@jobController.delete("/job/{job_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) +@jobController.delete('/job/{job_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @log_decorator(title='定时任务管理', business_type=BusinessType.DELETE) async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSession = Depends(get_db)): try: @@ -121,7 +152,9 @@ async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSessi return ResponseUtil.error(msg=str(e)) -@jobController.get("/job/{job_id}", response_model=JobModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:query'))]) +@jobController.get( + '/job/{job_id}', response_model=JobModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:query'))] +) async def query_detail_system_job(request: Request, job_id: int, query_db: AsyncSession = Depends(get_db)): try: job_detail_result = await JobService.job_detail_services(query_db, job_id) @@ -132,9 +165,13 @@ async def query_detail_system_job(request: Request, job_id: int, query_db: Async return ResponseUtil.error(msg=str(e)) -@jobController.post("/job/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) +@jobController.post('/job/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) @log_decorator(title='定时任务管理', business_type=BusinessType.EXPORT) -async def export_system_job_list(request: Request, job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): +async def export_system_job_list( + request: Request, + job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), +): try: # 获取全量数据 job_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=False) @@ -146,11 +183,19 @@ async def export_system_job_list(request: Request, job_page_query: JobPageQueryM return ResponseUtil.error(msg=str(e)) -@jobController.get("/jobLog/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))]) -async def get_system_job_log_list(request: Request, job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@jobController.get( + '/jobLog/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))] +) +async def get_system_job_log_list( + request: Request, + job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): try: # 获取分页数据 - job_log_page_query_result = await JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=True) + job_log_page_query_result = await JobLogService.get_job_log_list_services( + query_db, job_log_page_query, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=job_log_page_query_result) except Exception as e: @@ -158,7 +203,7 @@ async def get_system_job_log_list(request: Request, job_log_page_query: JobLogPa return ResponseUtil.error(msg=str(e)) -@jobController.delete("/jobLog/clean", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) +@jobController.delete('/jobLog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @log_decorator(title='定时任务日志管理', business_type=BusinessType.CLEAN) async def clear_system_job_log(request: Request, query_db: AsyncSession = Depends(get_db)): try: @@ -174,7 +219,7 @@ async def clear_system_job_log(request: Request, query_db: AsyncSession = Depend return ResponseUtil.error(msg=str(e)) -@jobController.delete("/jobLog/{job_log_ids}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) +@jobController.delete('/jobLog/{job_log_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @log_decorator(title='定时任务日志管理', business_type=BusinessType.DELETE) async def delete_system_job_log(request: Request, job_log_ids: str, query_db: AsyncSession = Depends(get_db)): try: @@ -191,12 +236,18 @@ async def delete_system_job_log(request: Request, job_log_ids: str, query_db: As return ResponseUtil.error(msg=str(e)) -@jobController.post("/jobLog/export", dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) +@jobController.post('/jobLog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) @log_decorator(title='定时任务日志管理', business_type=BusinessType.EXPORT) -async def export_system_job_log_list(request: Request, job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): +async def export_system_job_log_list( + request: Request, + job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), +): try: # 获取全量数据 - job_log_query_result = await JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=False) + job_log_query_result = await JobLogService.get_job_log_list_services( + query_db, job_log_page_query, is_page=False + ) job_log_export_result = await JobLogService.export_job_log_list_services(request, job_log_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(job_log_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py index 6fd1181..4c984f8 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py @@ -1,7 +1,7 @@ -from sqlalchemy import select, update, delete +from sqlalchemy import delete, select, update from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.job_do import SysJob -from module_admin.entity.vo.job_vo import * +from module_admin.entity.vo.job_vo import JobModel, JobPageQueryModel from utils.page_util import PageUtil @@ -18,10 +18,7 @@ class JobDao: :param job_id: 定时任务id :return: 定时任务信息对象 """ - job_info = (await db.execute( - select(SysJob) - .where(SysJob.job_id == job_id) - )).scalars().first() + job_info = (await db.execute(select(SysJob).where(SysJob.job_id == job_id))).scalars().first() return job_info @@ -33,13 +30,20 @@ class JobDao: :param job: 定时任务参数对象 :return: 定时任务信息对象 """ - job_info = (await db.execute( - select(SysJob) - .where(SysJob.job_name == job.job_name if job.job_name else True, - SysJob.job_group == job.job_group if job.job_group else True, - SysJob.invoke_target == job.invoke_target if job.invoke_target else True, - SysJob.cron_expression == job.cron_expression if job.cron_expression else True) - )).scalars().first() + job_info = ( + ( + await db.execute( + select(SysJob).where( + SysJob.job_name == job.job_name if job.job_name else True, + SysJob.job_group == job.job_group if job.job_group else True, + SysJob.invoke_target == job.invoke_target if job.invoke_target else True, + SysJob.cron_expression == job.cron_expression if job.cron_expression else True, + ) + ) + ) + .scalars() + .first() + ) return job_info @@ -52,11 +56,15 @@ class JobDao: :param is_page: 是否开启分页 :return: 定时任务列表信息对象 """ - query = select(SysJob) \ - .where(SysJob.job_name.like(f'%{query_object.job_name}%') if query_object.job_name else True, - SysJob.job_group == query_object.job_group if query_object.job_group else True, - SysJob.status == query_object.status if query_object.status else True) \ + query = ( + select(SysJob) + .where( + SysJob.job_name.like(f'%{query_object.job_name}%') if query_object.job_name else True, + SysJob.job_group == query_object.job_group if query_object.job_group else True, + SysJob.status == query_object.status if query_object.status else True, + ) .distinct() + ) job_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return job_list @@ -68,11 +76,7 @@ class JobDao: :param db: orm对象 :return: 定时任务列表信息对象 """ - job_list = (await db.execute( - select(SysJob) - .where(SysJob.status == '0') - .distinct() - )).scalars().all() + job_list = (await db.execute(select(SysJob).where(SysJob.status == '0').distinct())).scalars().all() return job_list @@ -98,10 +102,7 @@ class JobDao: :param job: 需要更新的定时任务字典 :return: """ - await db.execute( - update(SysJob), - [job] - ) + await db.execute(update(SysJob), [job]) @classmethod async def delete_job_dao(cls, db: AsyncSession, job: JobModel): @@ -111,7 +112,4 @@ class JobDao: :param job: 定时任务对象 :return: """ - await db.execute( - delete(SysJob) - .where(SysJob.job_id.in_([job.job_id])) - ) + await db.execute(delete(SysJob).where(SysJob.job_id.in_([job.job_id]))) diff --git a/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py b/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py index 7bc8abe..6d64a91 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py @@ -1,10 +1,10 @@ -from sqlalchemy import select, delete +from datetime import datetime, time +from sqlalchemy import delete, select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import Session from module_admin.entity.do.job_do import SysJobLog -from module_admin.entity.vo.job_vo import * +from module_admin.entity.vo.job_vo import JobLogModel, JobLogPageQueryModel from utils.page_util import PageUtil -from datetime import datetime, time class JobLogDao: @@ -21,15 +21,21 @@ class JobLogDao: :param is_page: 是否开启分页 :return: 定时任务日志列表信息对象 """ - query = select(SysJobLog) \ - .where(SysJobLog.job_name.like(f'%{query_object.job_name}%') if query_object.job_name else True, - SysJobLog.job_group == query_object.job_group if query_object.job_group else True, - SysJobLog.status == query_object.status if query_object.status else True, - SysJobLog.create_time.between( - datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), - datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True) \ + query = ( + select(SysJobLog) + .where( + SysJobLog.job_name.like(f'%{query_object.job_name}%') if query_object.job_name else True, + SysJobLog.job_group == query_object.job_group if query_object.job_group else True, + SysJobLog.status == query_object.status if query_object.status else True, + SysJobLog.create_time.between( + datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), + datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)), + ) + if query_object.begin_time and query_object.end_time + else True, + ) .distinct() + ) job_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return job_log_list @@ -56,10 +62,7 @@ class JobLogDao: :param job_log: 定时任务日志对象 :return: """ - await db.execute( - delete(SysJobLog) - .where(SysJobLog.job_log_id.in_([job_log.job_log_id])) - ) + await db.execute(delete(SysJobLog).where(SysJobLog.job_log_id.in_([job_log.job_log_id]))) @classmethod async def clear_job_log_dao(cls, db: AsyncSession): @@ -68,6 +71,4 @@ class JobLogDao: :param db: orm对象 :return: """ - await db.execute( - delete(SysJobLog) - ) + await db.execute(delete(SysJobLog)) diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/job_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/job_do.py index aef168f..c6d671b 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/job_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/job_do.py @@ -1,24 +1,36 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysJob(Base): """ 定时任务调度表 """ + __tablename__ = 'sys_job' job_id = Column(Integer, primary_key=True, autoincrement=True, comment='任务ID') job_name = Column(String(64, collation='utf8_general_ci'), nullable=False, comment='任务名称') job_group = Column(String(64, collation='utf8_general_ci'), nullable=False, default='default', comment='任务组名') - job_executor = Column(String(64, collation='utf8_general_ci'), nullable=False, default='default', comment='任务执行器') + job_executor = Column( + String(64, collation='utf8_general_ci'), nullable=False, default='default', comment='任务执行器' + ) invoke_target = Column(String(500, collation='utf8_general_ci'), nullable=False, comment='调用目标字符串') job_args = Column(String(255, collation='utf8_general_ci'), nullable=True, comment='位置参数') job_kwargs = Column(String(255, collation='utf8_general_ci'), nullable=True, comment='关键字参数') - cron_expression = Column(String(255, collation='utf8_general_ci'), nullable=True, default='', comment='cron执行表达式') - misfire_policy = Column(String(20, collation='utf8_general_ci'), nullable=True, default='3', comment='计划执行错误策略(1立即执行 2执行一次 3放弃执行)') - concurrent = Column(String(1, collation='utf8_general_ci'), nullable=True, default='1', comment='是否并发执行(0允许 1禁止)') + cron_expression = Column( + String(255, collation='utf8_general_ci'), nullable=True, default='', comment='cron执行表达式' + ) + misfire_policy = Column( + String(20, collation='utf8_general_ci'), + nullable=True, + default='3', + comment='计划执行错误策略(1立即执行 2执行一次 3放弃执行)', + ) + concurrent = Column( + String(1, collation='utf8_general_ci'), nullable=True, default='1', comment='是否并发执行(0允许 1禁止)' + ) status = Column(String(1, collation='utf8_general_ci'), nullable=True, default='0', comment='状态(0正常 1暂停)') create_by = Column(String(64, collation='utf8_general_ci'), nullable=True, default='', comment='创建者') create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') @@ -31,17 +43,22 @@ class SysJobLog(Base): """ 定时任务调度日志表 """ + __tablename__ = 'sys_job_log' job_log_id = Column(Integer, primary_key=True, autoincrement=True, comment='任务日志ID') job_name = Column(String(64, collation='utf8_general_ci'), nullable=False, comment='任务名称') job_group = Column(String(64, collation='utf8_general_ci'), nullable=False, comment='任务组名') - job_executor = Column(String(64, collation='utf8_general_ci'), nullable=False, default='default', comment='任务执行器') + job_executor = Column( + String(64, collation='utf8_general_ci'), nullable=False, default='default', comment='任务执行器' + ) invoke_target = Column(String(500, collation='utf8_general_ci'), nullable=False, comment='调用目标字符串') job_args = Column(String(255, collation='utf8_general_ci'), nullable=True, comment='位置参数') job_kwargs = Column(String(255, collation='utf8_general_ci'), nullable=True, comment='关键字参数') job_trigger = Column(String(255, collation='utf8_general_ci'), nullable=True, comment='任务触发器') job_message = Column(String(500, collation='utf8_general_ci'), nullable=True, default='', comment='日志信息') - status = Column(String(1, collation='utf8_general_ci'), nullable=True, default='0', comment='执行状态(0正常 1失败)') + status = Column( + String(1, collation='utf8_general_ci'), nullable=True, default='0', comment='执行状态(0正常 1失败)' + ) exception_info = Column(String(2000, collation='utf8_general_ci'), nullable=True, default='', comment='异常信息') create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py index f39cc21..4dd9e38 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py @@ -1,15 +1,16 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from typing import Union, Optional, List, Literal -from datetime import datetime -from module_admin.annotation.pydantic_annotation import as_query, as_form +from typing import Literal, Optional +from module_admin.annotation.pydantic_annotation import as_form, as_query class JobModel(BaseModel): """ 定时任务调度表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) job_id: Optional[int] = Field(default=None, description='任务ID') @@ -20,7 +21,9 @@ class JobModel(BaseModel): job_args: Optional[str] = Field(default=None, description='位置参数') job_kwargs: Optional[str] = Field(default=None, description='关键字参数') cron_expression: Optional[str] = Field(default=None, description='cron执行表达式') - misfire_policy: Optional[Literal['1', '2', '3']] = Field(default=None, description='计划执行错误策略(1立即执行 2执行一次 3放弃执行)') + misfire_policy: Optional[Literal['1', '2', '3']] = Field( + default=None, description='计划执行错误策略(1立即执行 2执行一次 3放弃执行)' + ) concurrent: Optional[Literal['0', '1']] = Field(default=None, description='是否并发执行(0允许 1禁止)') status: Optional[Literal['0', '1']] = Field(default=None, description='状态(0正常 1暂停)') create_by: Optional[str] = Field(default=None, description='创建者') @@ -48,6 +51,7 @@ class JobLogModel(BaseModel): """ 定时任务调度日志表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) job_log_id: Optional[int] = Field(default=None, description='任务日志ID') @@ -68,6 +72,7 @@ class JobQueryModel(JobModel): """ 定时任务管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -78,6 +83,7 @@ class JobPageQueryModel(JobQueryModel): """ 定时任务管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -86,6 +92,7 @@ class EditJobModel(JobModel): """ 编辑定时任务模型 """ + type: Optional[str] = Field(default=None, description='操作类型') @@ -93,6 +100,7 @@ class DeleteJobModel(BaseModel): """ 删除定时任务模型 """ + model_config = ConfigDict(alias_generator=to_camel) job_ids: str = Field(description='需要删除的定时任务ID') @@ -102,6 +110,7 @@ class JobLogQueryModel(JobLogModel): """ 定时任务日志不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -112,6 +121,7 @@ class JobLogPageQueryModel(JobLogQueryModel): """ 定时任务日志管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -120,6 +130,7 @@ class DeleteJobLogModel(BaseModel): """ 删除定时任务日志模型 """ + model_config = ConfigDict(alias_generator=to_camel) job_log_ids: str = Field(description='需要删除的定时任务日志ID') diff --git a/ruoyi-fastapi-backend/module_admin/service/job_log_service.py b/ruoyi-fastapi-backend/module_admin/service/job_log_service.py index 99d2231..a425b0b 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_log_service.py @@ -1,6 +1,11 @@ -from module_admin.dao.job_log_dao import * -from module_admin.service.dict_service import Request, DictDataService +from fastapi import Request +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy.orm import Session +from typing import List +from module_admin.dao.job_log_dao import JobLogDao from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.job_vo import DeleteJobLogModel, JobLogModel, JobLogPageQueryModel +from module_admin.service.dict_service import DictDataService from utils.common_util import export_list2excel @@ -10,7 +15,9 @@ class JobLogService: """ @classmethod - async def get_job_log_list_services(cls, query_db: AsyncSession, query_object: JobLogPageQueryModel, is_page: bool = False): + async def get_job_log_list_services( + cls, query_db: AsyncSession, query_object: JobLogPageQueryModel, is_page: bool = False + ): """ 获取定时任务日志列表信息service :param query_db: orm对象 @@ -89,26 +96,32 @@ class JobLogService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "jobLogId": "任务日志编码", - "jobName": "任务名称", - "jobGroup": "任务组名", - "jobExecutor": "任务执行器", - "invokeTarget": "调用目标字符串", - "jobArgs": "位置参数", - "jobKwargs": "关键字参数", - "jobTrigger": "任务触发器", - "jobMessage": "日志信息", - "status": "执行状态", - "exceptionInfo": "异常信息", - "createTime": "创建时间", + 'jobLogId': '任务日志编码', + 'jobName': '任务名称', + 'jobGroup': '任务组名', + 'jobExecutor': '任务执行器', + 'invokeTarget': '调用目标字符串', + 'jobArgs': '位置参数', + 'jobKwargs': '关键字参数', + 'jobTrigger': '任务触发器', + 'jobMessage': '日志信息', + 'status': '执行状态', + 'exceptionInfo': '异常信息', + 'createTime': '创建时间', } data = job_log_list - job_group_list = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type='sys_job_group') + job_group_list = await DictDataService.query_dict_data_list_from_cache_services( + request.app.state.redis, dict_type='sys_job_group' + ) job_group_option = [dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in job_group_list] job_group_option_dict = {item.get('value'): item for item in job_group_option} - job_executor_list = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type='sys_job_executor') - job_executor_option = [dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in job_executor_list] + job_executor_list = await DictDataService.query_dict_data_list_from_cache_services( + request.app.state.redis, dict_type='sys_job_executor' + ) + job_executor_option = [ + dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in job_executor_list + ] job_executor_option_dict = {item.get('value'): item for item in job_executor_option} for item in data: @@ -120,8 +133,9 @@ class JobLogService: item['jobGroup'] = job_group_option_dict.get(str(item.get('jobGroup'))).get('label') if str(item.get('jobExecutor')) in job_executor_option_dict.keys(): item['jobExecutor'] = job_executor_option_dict.get(str(item.get('jobExecutor'))).get('label') - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in - data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data diff --git a/ruoyi-fastapi-backend/module_admin/service/job_service.py b/ruoyi-fastapi-backend/module_admin/service/job_service.py index 78775d4..87e460f 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_service.py @@ -1,8 +1,12 @@ -from module_admin.dao.job_dao import * -from module_admin.service.dict_service import Request, DictDataService -from module_admin.entity.vo.common_vo import CrudResponseModel -from utils.common_util import export_list2excel, CamelCaseUtil +from fastapi import Request +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List from config.get_scheduler import SchedulerUtil +from module_admin.dao.job_dao import JobDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.job_vo import DeleteJobModel, EditJobModel, JobModel, JobPageQueryModel +from module_admin.service.dict_service import DictDataService +from utils.common_util import CamelCaseUtil, export_list2excel class JobService: @@ -11,7 +15,9 @@ class JobService: """ @classmethod - async def get_job_list_services(cls, query_db: AsyncSession, query_object: JobPageQueryModel, is_page: bool = False): + async def get_job_list_services( + cls, query_db: AsyncSession, query_object: JobPageQueryModel, is_page: bool = False + ): """ 获取定时任务列表信息service :param query_db: orm对象 @@ -61,7 +67,12 @@ class JobService: del edit_job['type'] job_info = await cls.job_detail_services(query_db, edit_job.get('job_id')) if job_info: - if page_object.type != 'status' and (job_info.job_name != page_object.job_name or job_info.job_group != page_object.job_group or job_info.invoke_target != page_object.invoke_target or job_info.cron_expression != page_object.cron_expression): + if page_object.type != 'status' and ( + job_info.job_name != page_object.job_name + or job_info.job_group != page_object.job_group + or job_info.invoke_target != page_object.invoke_target + or job_info.cron_expression != page_object.cron_expression + ): job = await JobDao.get_job_detail_by_info(query_db, page_object) if job: result = dict(is_success=False, message='定时任务已存在') @@ -152,30 +163,36 @@ class JobService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "jobId": "任务编码", - "jobName": "任务名称", - "jobGroup": "任务组名", - "jobExecutor": "任务执行器", - "invokeTarget": "调用目标字符串", - "jobArgs": "位置参数", - "jobKwargs": "关键字参数", - "cronExpression": "cron执行表达式", - "misfirePolicy": "计划执行错误策略", - "concurrent": "是否并发执行", - "status": "状态", - "createBy": "创建者", - "createTime": "创建时间", - "updateBy": "更新者", - "updateTime": "更新时间", - "remark": "备注", + 'jobId': '任务编码', + 'jobName': '任务名称', + 'jobGroup': '任务组名', + 'jobExecutor': '任务执行器', + 'invokeTarget': '调用目标字符串', + 'jobArgs': '位置参数', + 'jobKwargs': '关键字参数', + 'cronExpression': 'cron执行表达式', + 'misfirePolicy': '计划执行错误策略', + 'concurrent': '是否并发执行', + 'status': '状态', + 'createBy': '创建者', + 'createTime': '创建时间', + 'updateBy': '更新者', + 'updateTime': '更新时间', + 'remark': '备注', } data = job_list - job_group_list = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type='sys_job_group') + job_group_list = await DictDataService.query_dict_data_list_from_cache_services( + request.app.state.redis, dict_type='sys_job_group' + ) job_group_option = [dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in job_group_list] job_group_option_dict = {item.get('value'): item for item in job_group_option} - job_executor_list = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type='sys_job_executor') - job_executor_option = [dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in job_executor_list] + job_executor_list = await DictDataService.query_dict_data_list_from_cache_services( + request.app.state.redis, dict_type='sys_job_executor' + ) + job_executor_option = [ + dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in job_executor_list + ] job_executor_option_dict = {item.get('value'): item for item in job_executor_option} for item in data: @@ -197,7 +214,9 @@ class JobService: item['concurrent'] = '允许' else: item['concurrent'] = '禁止' - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data -- Gitee From eac920fcae9c90e89e811ef9b24dd3f1a710dfe7 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 10:38:36 +0800 Subject: [PATCH 089/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E5=AD=97=E5=85=B8=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/dict_controller.py | 147 ++++++++++++----- .../module_admin/dao/dict_dao.py | 150 ++++++++++-------- .../module_admin/entity/do/dict_do.py | 10 +- .../module_admin/entity/vo/dict_vo.py | 20 ++- .../module_admin/service/dict_service.py | 135 +++++++++++----- 5 files changed, 303 insertions(+), 159 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py index 7c7a6b3..b828d46 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py @@ -1,34 +1,58 @@ -from fastapi import APIRouter -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, CurrentUserModel -from module_admin.service.dict_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * -from utils.page_util import PageResponseModel +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.dict_vo import ( + DeleteDictDataModel, + DeleteDictTypeModel, + DictDataModel, + DictDataPageQueryModel, + DictTypeModel, + DictTypePageQueryModel, +) +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.dict_service import DictDataService, DictTypeService +from module_admin.service.login_service import LoginService from utils.common_util import bytes2file_response +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.response_util import ResponseUtil dictController = APIRouter(prefix='/system/dict', dependencies=[Depends(LoginService.get_current_user)]) -@dictController.get("/type/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]) -async def get_system_dict_type_list(request: Request, dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@dictController.get( + '/type/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))] +) +async def get_system_dict_type_list( + request: Request, + dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): # 获取分页数据 - dict_type_page_query_result = await DictTypeService.get_dict_type_list_services(query_db, dict_type_page_query, is_page=True) + dict_type_page_query_result = await DictTypeService.get_dict_type_list_services( + query_db, dict_type_page_query, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=dict_type_page_query_result) -@dictController.post("/type", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) +@dictController.post('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) @ValidateFields(validate_model='add_dict_type') @log_decorator(title='字典管理', business_type=BusinessType.INSERT) -async def add_system_dict_type(request: Request, add_dict_type: DictTypeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_dict_type( + request: Request, + add_dict_type: DictTypeModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_dict_type.create_by = current_user.user.user_name add_dict_type.create_time = datetime.now() add_dict_type.update_by = current_user.user.user_name @@ -39,10 +63,15 @@ async def add_system_dict_type(request: Request, add_dict_type: DictTypeModel, q return ResponseUtil.success(msg=add_dict_type_result.message) -@dictController.put("/type", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) +@dictController.put('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) @ValidateFields(validate_model='edit_dict_type') @log_decorator(title='字典管理', business_type=BusinessType.UPDATE) -async def edit_system_dict_type(request: Request, edit_dict_type: DictTypeModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def edit_system_dict_type( + request: Request, + edit_dict_type: DictTypeModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): edit_dict_type.update_by = current_user.user.user_name edit_dict_type.update_time = datetime.now() edit_dict_type_result = await DictTypeService.edit_dict_type_services(request, query_db, edit_dict_type) @@ -51,7 +80,7 @@ async def edit_system_dict_type(request: Request, edit_dict_type: DictTypeModel, return ResponseUtil.success(msg=edit_dict_type_result.message) -@dictController.delete("/type/refreshCache", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) +@dictController.delete('/type/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @log_decorator(title='字典管理', business_type=BusinessType.UPDATE) async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends(get_db)): refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db) @@ -60,7 +89,7 @@ async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends return ResponseUtil.success(msg=refresh_dict_result.message) -@dictController.delete("/type/{dict_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) +@dictController.delete('/type/{dict_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @log_decorator(title='字典管理', business_type=BusinessType.DELETE) async def delete_system_dict_type(request: Request, dict_ids: str, query_db: AsyncSession = Depends(get_db)): delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids) @@ -70,15 +99,19 @@ async def delete_system_dict_type(request: Request, dict_ids: str, query_db: Asy return ResponseUtil.success(msg=delete_dict_type_result.message) -@dictController.get("/type/optionselect", response_model=List[DictTypeModel]) +@dictController.get('/type/optionselect', response_model=List[DictTypeModel]) async def query_system_dict_type_options(request: Request, query_db: AsyncSession = Depends(get_db)): - dict_type_query_result = await DictTypeService.get_dict_type_list_services(query_db, DictTypePageQueryModel(**dict()), is_page=False) - logger.info(f'获取成功') + dict_type_query_result = await DictTypeService.get_dict_type_list_services( + query_db, DictTypePageQueryModel(**dict()), is_page=False + ) + logger.info('获取成功') return ResponseUtil.success(data=dict_type_query_result) -@dictController.get("/type/{dict_id}", response_model=DictTypeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))]) +@dictController.get( + '/type/{dict_id}', response_model=DictTypeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))] +) async def query_detail_system_dict_type(request: Request, dict_id: int, query_db: AsyncSession = Depends(get_db)): dict_type_detail_result = await DictTypeService.dict_type_detail_services(query_db, dict_id) logger.info(f'获取dict_id为{dict_id}的信息成功') @@ -86,39 +119,60 @@ async def query_detail_system_dict_type(request: Request, dict_id: int, query_db return ResponseUtil.success(data=dict_type_detail_result) -@dictController.post("/type/export", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) +@dictController.post('/type/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) @log_decorator(title='字典管理', business_type=BusinessType.EXPORT) -async def export_system_dict_type_list(request: Request, dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): +async def export_system_dict_type_list( + request: Request, + dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), +): # 获取全量数据 - dict_type_query_result = await DictTypeService.get_dict_type_list_services(query_db, dict_type_page_query, is_page=False) + dict_type_query_result = await DictTypeService.get_dict_type_list_services( + query_db, dict_type_page_query, is_page=False + ) dict_type_export_result = await DictTypeService.export_dict_type_list_services(dict_type_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(dict_type_export_result)) -@dictController.get("/data/type/{dict_type}") +@dictController.get('/data/type/{dict_type}') async def query_system_dict_type_data(request: Request, dict_type: str, query_db: AsyncSession = Depends(get_db)): # 获取全量数据 - dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type) + dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services( + request.app.state.redis, dict_type + ) logger.info('获取成功') return ResponseUtil.success(data=dict_data_query_result) -@dictController.get("/data/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]) -async def get_system_dict_data_list(request: Request, dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@dictController.get( + '/data/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))] +) +async def get_system_dict_data_list( + request: Request, + dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): # 获取分页数据 - dict_data_page_query_result = await DictDataService.get_dict_data_list_services(query_db, dict_data_page_query, is_page=True) + dict_data_page_query_result = await DictDataService.get_dict_data_list_services( + query_db, dict_data_page_query, is_page=True + ) logger.info('获取成功') return ResponseUtil.success(model_content=dict_data_page_query_result) -@dictController.post("/data", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) +@dictController.post('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) @ValidateFields(validate_model='add_dict_data') @log_decorator(title='字典管理', business_type=BusinessType.INSERT) -async def add_system_dict_data(request: Request, add_dict_data: DictDataModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_dict_data( + request: Request, + add_dict_data: DictDataModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_dict_data.create_by = current_user.user.user_name add_dict_data.create_time = datetime.now() add_dict_data.update_by = current_user.user.user_name @@ -129,10 +183,15 @@ async def add_system_dict_data(request: Request, add_dict_data: DictDataModel, q return ResponseUtil.success(msg=add_dict_data_result.message) -@dictController.put("/data", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) +@dictController.put('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) @ValidateFields(validate_model='edit_dict_data') @log_decorator(title='字典管理', business_type=BusinessType.UPDATE) -async def edit_system_dict_data(request: Request, edit_dict_data: DictDataModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def edit_system_dict_data( + request: Request, + edit_dict_data: DictDataModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): edit_dict_data.update_by = current_user.user.user_name edit_dict_data.update_time = datetime.now() edit_dict_data_result = await DictDataService.edit_dict_data_services(request, query_db, edit_dict_data) @@ -141,7 +200,7 @@ async def edit_system_dict_data(request: Request, edit_dict_data: DictDataModel, return ResponseUtil.success(msg=edit_dict_data_result.message) -@dictController.delete("/data/{dict_codes}", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) +@dictController.delete('/data/{dict_codes}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @log_decorator(title='字典管理', business_type=BusinessType.DELETE) async def delete_system_dict_data(request: Request, dict_codes: str, query_db: AsyncSession = Depends(get_db)): delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes) @@ -151,7 +210,11 @@ async def delete_system_dict_data(request: Request, dict_codes: str, query_db: A return ResponseUtil.success(msg=delete_dict_data_result.message) -@dictController.get("/data/{dict_code}", response_model=DictDataModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))]) +@dictController.get( + '/data/{dict_code}', + response_model=DictDataModel, + dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))], +) async def query_detail_system_dict_data(request: Request, dict_code: int, query_db: AsyncSession = Depends(get_db)): detail_dict_data_result = await DictDataService.dict_data_detail_services(query_db, dict_code) logger.info(f'获取dict_code为{dict_code}的信息成功') @@ -159,11 +222,17 @@ async def query_detail_system_dict_data(request: Request, dict_code: int, query_ return ResponseUtil.success(data=detail_dict_data_result) -@dictController.post("/data/export", dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) +@dictController.post('/data/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) @log_decorator(title='字典管理', business_type=BusinessType.EXPORT) -async def export_system_dict_data_list(request: Request, dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): +async def export_system_dict_data_list( + request: Request, + dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), +): # 获取全量数据 - dict_data_query_result = await DictDataService.get_dict_data_list_services(query_db, dict_data_page_query, is_page=False) + dict_data_query_result = await DictDataService.get_dict_data_list_services( + query_db, dict_data_page_query, is_page=False + ) dict_data_export_result = await DictDataService.export_dict_data_list_services(dict_data_query_result) logger.info('导出成功') diff --git a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py index 3342f6b..2c4460c 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py @@ -1,10 +1,10 @@ -from sqlalchemy import select, update, delete, and_, func +from datetime import datetime, time +from sqlalchemy import and_, delete, func, select, update from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.dict_do import SysDictType, SysDictData -from module_admin.entity.vo.dict_vo import * -from utils.time_format_util import list_format_datetime +from module_admin.entity.vo.dict_vo import DictDataModel, DictDataPageQueryModel, DictTypeModel, DictTypePageQueryModel from utils.page_util import PageUtil -from datetime import datetime, time +from utils.time_format_util import list_format_datetime class DictTypeDao: @@ -20,10 +20,7 @@ class DictTypeDao: :param dict_id: 字典类型id :return: 字典类型信息对象 """ - dict_type_info = (await db.execute( - select(SysDictType) - .where(SysDictType.dict_id == dict_id) - )).scalars().first() + dict_type_info = (await db.execute(select(SysDictType).where(SysDictType.dict_id == dict_id))).scalars().first() return dict_type_info @@ -35,11 +32,18 @@ class DictTypeDao: :param dict_type: 字典类型参数对象 :return: 字典类型信息对象 """ - dict_type_info = (await db.execute( - select(SysDictType) - .where(SysDictType.dict_type == dict_type.dict_type if dict_type.dict_type else True, - SysDictType.dict_name == dict_type.dict_name if dict_type.dict_name else True) - )).scalars().first() + dict_type_info = ( + ( + await db.execute( + select(SysDictType).where( + SysDictType.dict_type == dict_type.dict_type if dict_type.dict_type else True, + SysDictType.dict_name == dict_type.dict_name if dict_type.dict_name else True, + ) + ) + ) + .scalars() + .first() + ) return dict_type_info @@ -50,9 +54,7 @@ class DictTypeDao: :param db: orm对象 :return: 字典类型信息列表对象 """ - dict_type_info = (await db.execute( - select(SysDictType) - )).scalars().all() + dict_type_info = (await db.execute(select(SysDictType))).scalars().all() return list_format_datetime(dict_type_info) @@ -65,15 +67,21 @@ class DictTypeDao: :param is_page: 是否开启分页 :return: 字典类型列表信息对象 """ - query = select(SysDictType) \ - .where(SysDictType.dict_name.like(f'%{query_object.dict_name}%') if query_object.dict_name else True, - SysDictType.dict_type.like(f'%{query_object.dict_type}%') if query_object.dict_type else True, - SysDictType.status == query_object.status if query_object.status else True, - SysDictType.create_time.between( - datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), - datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True) \ + query = ( + select(SysDictType) + .where( + SysDictType.dict_name.like(f'%{query_object.dict_name}%') if query_object.dict_name else True, + SysDictType.dict_type.like(f'%{query_object.dict_type}%') if query_object.dict_type else True, + SysDictType.status == query_object.status if query_object.status else True, + SysDictType.create_time.between( + datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), + datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)), + ) + if query_object.begin_time and query_object.end_time + else True, + ) .distinct() + ) dict_type_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return dict_type_list @@ -100,10 +108,7 @@ class DictTypeDao: :param dict_type: 需要更新的字典类型字典 :return: """ - await db.execute( - update(SysDictType), - [dict_type] - ) + await db.execute(update(SysDictType), [dict_type]) @classmethod async def delete_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel): @@ -113,10 +118,7 @@ class DictTypeDao: :param dict_type: 字典类型对象 :return: """ - await db.execute( - delete(SysDictType) - .where(SysDictType.dict_id.in_([dict_type.dict_id])) - ) + await db.execute(delete(SysDictType).where(SysDictType.dict_id.in_([dict_type.dict_id]))) class DictDataDao: @@ -132,10 +134,9 @@ class DictDataDao: :param dict_code: 字典数据id :return: 字典数据信息对象 """ - dict_data_info = (await db.execute( - select(SysDictData) - .where(SysDictData.dict_code == dict_code) - )).scalars().first() + dict_data_info = ( + (await db.execute(select(SysDictData).where(SysDictData.dict_code == dict_code))).scalars().first() + ) return dict_data_info @@ -147,12 +148,19 @@ class DictDataDao: :param dict_data: 字典数据参数对象 :return: 字典数据信息对象 """ - dict_data_info = (await db.execute( - select(SysDictData) - .where(SysDictData.dict_type == dict_data.dict_type, - SysDictData.dict_label == dict_data.dict_label, - SysDictData.dict_value == dict_data.dict_value) - )).scalars().first() + dict_data_info = ( + ( + await db.execute( + select(SysDictData).where( + SysDictData.dict_type == dict_data.dict_type, + SysDictData.dict_label == dict_data.dict_label, + SysDictData.dict_value == dict_data.dict_value, + ) + ) + ) + .scalars() + .first() + ) return dict_data_info @@ -165,12 +173,16 @@ class DictDataDao: :param is_page: 是否开启分页 :return: 字典数据列表信息对象 """ - query = select(SysDictData) \ - .where(SysDictData.dict_type == query_object.dict_type if query_object.dict_type else True, - SysDictData.dict_label.like(f'%{query_object.dict_label}%') if query_object.dict_label else True, - SysDictData.status == query_object.status if query_object.status else True)\ - .order_by(SysDictData.dict_sort)\ + query = ( + select(SysDictData) + .where( + SysDictData.dict_type == query_object.dict_type if query_object.dict_type else True, + SysDictData.dict_label.like(f'%{query_object.dict_label}%') if query_object.dict_label else True, + SysDictData.status == query_object.status if query_object.status else True, + ) + .order_by(SysDictData.dict_sort) .distinct() + ) dict_data_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return dict_data_list @@ -183,14 +195,24 @@ class DictDataDao: :param dict_type: 字典类型 :return: 字典数据列表信息对象 """ - dict_data_list = (await db.execute( - select(SysDictData) - .select_from(SysDictType) - .where(SysDictType.dict_type == dict_type if dict_type else True, SysDictType.status == '0') - .join(SysDictData, and_(SysDictType.dict_type == SysDictData.dict_type, SysDictData.status == '0'), isouter=True) - .order_by(SysDictData.dict_sort) - .distinct() - )).scalars().all() + dict_data_list = ( + ( + await db.execute( + select(SysDictData) + .select_from(SysDictType) + .where(SysDictType.dict_type == dict_type if dict_type else True, SysDictType.status == '0') + .join( + SysDictData, + and_(SysDictType.dict_type == SysDictData.dict_type, SysDictData.status == '0'), + isouter=True, + ) + .order_by(SysDictData.dict_sort) + .distinct() + ) + ) + .scalars() + .all() + ) return dict_data_list @@ -216,10 +238,7 @@ class DictDataDao: :param dict_data: 需要更新的字典数据字典 :return: """ - await db.execute( - update(SysDictData), - [dict_data] - ) + await db.execute(update(SysDictData), [dict_data]) @classmethod async def delete_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel): @@ -229,10 +248,7 @@ class DictDataDao: :param dict_data: 字典数据对象 :return: """ - await db.execute( - delete(SysDictData) - .where(SysDictData.dict_code.in_([dict_data.dict_code])) - ) + await db.execute(delete(SysDictData).where(SysDictData.dict_code.in_([dict_data.dict_code]))) @classmethod async def count_dict_data_dao(cls, db: AsyncSession, dict_type: str): @@ -242,10 +258,8 @@ class DictDataDao: :param dict_type: 字典类型 :return: 字典类型关联的字典数据数量 """ - dict_data_count = (await db.execute( - select(func.count('*')) - .select_from(SysDictData) - .where(SysDictData.dict_type == dict_type) - )).scalar() + dict_data_count = ( + await db.execute(select(func.count('*')).select_from(SysDictData).where(SysDictData.dict_type == dict_type)) + ).scalar() return dict_data_count diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/dict_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/dict_do.py index a7d630e..061c88f 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/dict_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/dict_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime, UniqueConstraint -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String, UniqueConstraint +from config.database import Base class SysDictType(Base): """ 字典类型表 """ + __tablename__ = 'sys_dict_type' dict_id = Column(Integer, primary_key=True, autoincrement=True, comment='字典主键') @@ -19,15 +20,14 @@ class SysDictType(Base): update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') remark = Column(String(500), nullable=True, default='', comment='备注') - __table_args__ = ( - UniqueConstraint('dict_type', name='uq_sys_dict_type_dict_type'), - ) + __table_args__ = (UniqueConstraint('dict_type', name='uq_sys_dict_type_dict_type'),) class SysDictData(Base): """ 字典数据表 """ + __tablename__ = 'sys_dict_data' dict_code = Column(Integer, primary_key=True, autoincrement=True, comment='字典编码') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py index 3c24554..4961674 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py @@ -1,15 +1,16 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Pattern, Size -from typing import Union, Optional, List, Literal -from datetime import datetime -from module_admin.annotation.pydantic_annotation import as_query, as_form +from typing import Literal, Optional +from module_admin.annotation.pydantic_annotation import as_form, as_query class DictTypeModel(BaseModel): """ 字典类型表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) dict_id: Optional[int] = Field(default=None, description='字典主键') @@ -29,7 +30,11 @@ class DictTypeModel(BaseModel): @NotBlank(field_name='dict_type', message='字典类型不能为空') @Size(field_name='dict_type', min_length=0, max_length=100, message='字典类型类型长度不能超过100个字符') - @Pattern(field_name='dict_type', regexp='^[a-z][a-z0-9_]*$', message='字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)') + @Pattern( + field_name='dict_type', + regexp='^[a-z][a-z0-9_]*$', + message='字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)', + ) def get_dict_type(self): return self.dict_type @@ -42,6 +47,7 @@ class DictDataModel(BaseModel): """ 字典数据表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) dict_code: Optional[int] = Field(default=None, description='字典编码') @@ -89,6 +95,7 @@ class DictTypeQueryModel(DictTypeModel): """ 字典类型管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -99,6 +106,7 @@ class DictTypePageQueryModel(DictTypeQueryModel): """ 字典类型管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -107,6 +115,7 @@ class DeleteDictTypeModel(BaseModel): """ 删除字典类型模型 """ + model_config = ConfigDict(alias_generator=to_camel) dict_ids: str = Field(description='需要删除的字典主键') @@ -116,6 +125,7 @@ class DictDataQueryModel(DictDataModel): """ 字典数据管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -126,6 +136,7 @@ class DictDataPageQueryModel(DictDataQueryModel): """ 字典数据管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -134,6 +145,7 @@ class DeleteDictDataModel(BaseModel): """ 删除字典数据模型 """ + model_config = ConfigDict(alias_generator=to_camel) dict_codes: str = Field(description='需要删除的字典编码') diff --git a/ruoyi-fastapi-backend/module_admin/service/dict_service.py b/ruoyi-fastapi-backend/module_admin/service/dict_service.py index 9d373ae..06fb80a 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dict_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dict_service.py @@ -1,11 +1,21 @@ -from fastapi import Request import json -from module_admin.dao.dict_dao import * -from module_admin.entity.vo.common_vo import CrudResponseModel +from fastapi import Request +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List from config.constant import CommonConstant from config.env import RedisInitKeyConfig from exceptions.exception import ServiceException -from utils.common_util import export_list2excel, CamelCaseUtil +from module_admin.dao.dict_dao import DictDataDao, DictTypeDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.dict_vo import ( + DeleteDictDataModel, + DeleteDictTypeModel, + DictDataModel, + DictDataPageQueryModel, + DictTypeModel, + DictTypePageQueryModel, +) +from utils.common_util import CamelCaseUtil, export_list2excel class DictTypeService: @@ -14,7 +24,9 @@ class DictTypeService: """ @classmethod - async def get_dict_type_list_services(cls, query_db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False): + async def get_dict_type_list_services( + cls, query_db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False + ): """ 获取字典类型列表信息service :param query_db: orm对象 @@ -35,7 +47,9 @@ class DictTypeService: :return: 校验结果 """ dict_id = -1 if page_object.dict_id is None else page_object.dict_id - dict_type = await DictTypeDao.get_dict_type_detail_by_info(query_db, DictTypeModel(dictType=page_object.dict_type)) + dict_type = await DictTypeDao.get_dict_type_detail_by_info( + query_db, DictTypeModel(dictType=page_object.dict_type) + ) if dict_type and dict_type.dict_id != dict_id: return CommonConstant.NOT_UNIQUE return CommonConstant.UNIQUE @@ -55,7 +69,9 @@ class DictTypeService: try: await DictTypeDao.add_dict_type_dao(query_db, page_object) await query_db.commit() - await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", '') + await request.app.state.redis.set( + f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", '' + ) result = dict(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() @@ -83,13 +99,20 @@ class DictTypeService: dict_data_list = await DictDataDao.get_dict_data_list(query_db, query_dict_data, is_page=False) if dict_type_info.dict_type != page_object.dict_type: for dict_data in dict_data_list: - edit_dict_data = DictDataModel(dictCode=dict_data.dict_code, dictType=page_object.dict_type, updateBy=page_object.update_by).model_dump(exclude_unset=True) + edit_dict_data = DictDataModel( + dictCode=dict_data.dict_code, + dictType=page_object.dict_type, + updateBy=page_object.update_by, + ).model_dump(exclude_unset=True) await DictDataDao.edit_dict_data_dao(query_db, edit_dict_data) await DictTypeDao.edit_dict_type_dao(query_db, edit_dict_type) await query_db.commit() if dict_type_info.dict_type != page_object.dict_type: dict_data = [CamelCaseUtil.transform_result(row) for row in dict_data_list if row] - await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", json.dumps(dict_data, ensure_ascii=False, default=str)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", + json.dumps(dict_data, ensure_ascii=False, default=str), + ) return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: await query_db.rollback() @@ -98,7 +121,9 @@ class DictTypeService: raise ServiceException(message='字典类型不存在') @classmethod - async def delete_dict_type_services(cls, request: Request, query_db: AsyncSession, page_object: DeleteDictTypeModel): + async def delete_dict_type_services( + cls, request: Request, query_db: AsyncSession, page_object: DeleteDictTypeModel + ): """ 删除字典类型信息service :param request: Request对象 @@ -151,15 +176,15 @@ class DictTypeService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "dictId": "字典编号", - "dictName": "字典名称", - "dictType": "字典类型", - "status": "状态", - "createBy": "创建者", - "createTime": "创建时间", - "updateBy": "更新者", - "updateTime": "更新时间", - "remark": "备注", + 'dictId': '字典编号', + 'dictName': '字典名称', + 'dictType': '字典类型', + 'status': '状态', + 'createBy': '创建者', + 'createTime': '创建时间', + 'updateBy': '更新者', + 'updateTime': '更新时间', + 'remark': '备注', } data = dict_type_list @@ -169,7 +194,9 @@ class DictTypeService: item['status'] = '正常' else: item['status'] = '停用' - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data @@ -194,7 +221,9 @@ class DictDataService: """ @classmethod - async def get_dict_data_list_services(cls, query_db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False): + async def get_dict_data_list_services( + cls, query_db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False + ): """ 获取字典数据列表信息service :param query_db: orm对象 @@ -236,7 +265,10 @@ class DictDataService: dict_type = dict_type_obj.dict_type dict_data_list = await DictDataDao.query_dict_data_list(query_db, dict_type) dict_data = [CamelCaseUtil.transform_result(row) for row in dict_data_list if row] - await redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{dict_type}", json.dumps(dict_data, ensure_ascii=False, default=str)) + await redis.set( + f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{dict_type}", + json.dumps(dict_data, ensure_ascii=False, default=str), + ) @classmethod async def query_dict_data_list_from_cache_services(cls, redis, dict_type: str): @@ -277,13 +309,18 @@ class DictDataService: :return: 新增字典数据校验结果 """ if not await cls.check_dict_data_unique_services(query_db, page_object): - raise ServiceException(message=f'新增字典数据{page_object.dict_label}失败,{page_object.dict_type}下已存在该字典数据') + raise ServiceException( + message=f'新增字典数据{page_object.dict_label}失败,{page_object.dict_type}下已存在该字典数据' + ) else: try: await DictDataDao.add_dict_data_dao(query_db, page_object) await query_db.commit() dict_data_list = await cls.query_dict_data_list_services(query_db, page_object.dict_type) - await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", + json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str), + ) return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() @@ -302,13 +339,18 @@ class DictDataService: dict_data_info = await cls.dict_data_detail_services(query_db, page_object.dict_code) if dict_data_info.dict_code: if not await cls.check_dict_data_unique_services(query_db, page_object): - raise ServiceException(message=f'新增字典数据{page_object.dict_label}失败,{page_object.dict_type}下已存在该字典数据') + raise ServiceException( + message=f'新增字典数据{page_object.dict_label}失败,{page_object.dict_type}下已存在该字典数据' + ) else: try: await DictDataDao.edit_dict_data_dao(query_db, edit_data_type) await query_db.commit() dict_data_list = await cls.query_dict_data_list_services(query_db, page_object.dict_type) - await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{page_object.dict_type}", + json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str), + ) return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: await query_db.rollback() @@ -317,7 +359,9 @@ class DictDataService: raise ServiceException(message='字典数据不存在') @classmethod - async def delete_dict_data_services(cls, request: Request, query_db: AsyncSession, page_object: DeleteDictDataModel): + async def delete_dict_data_services( + cls, request: Request, query_db: AsyncSession, page_object: DeleteDictDataModel + ): """ 删除字典数据信息service :param request: Request对象 @@ -336,7 +380,10 @@ class DictDataService: await query_db.commit() for dict_type in list(set(delete_dict_type_list)): dict_data_list = await cls.query_dict_data_list_services(query_db, dict_type) - await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{dict_type}", json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.SYS_DICT.get('key')}:{dict_type}", + json.dumps(CamelCaseUtil.transform_result(dict_data_list), ensure_ascii=False, default=str), + ) return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() @@ -369,20 +416,20 @@ class DictDataService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "dictCode": "字典编码", - "dictSort": "字典标签", - "dictLabel": "字典键值", - "dictValue": "字典排序", - "dictType": "字典类型", - "cssClass": "样式属性", - "listClass": "表格回显样式", - "isDefault": "是否默认", - "status": "状态", - "createBy": "创建者", - "createTime": "创建时间", - "updateBy": "更新者", - "updateTime": "更新时间", - "remark": "备注", + 'dictCode': '字典编码', + 'dictSort': '字典标签', + 'dictLabel': '字典键值', + 'dictValue': '字典排序', + 'dictType': '字典类型', + 'cssClass': '样式属性', + 'listClass': '表格回显样式', + 'isDefault': '是否默认', + 'status': '状态', + 'createBy': '创建者', + 'createTime': '创建时间', + 'updateBy': '更新者', + 'updateTime': '更新时间', + 'remark': '备注', } data = dict_data_list @@ -396,7 +443,9 @@ class DictDataService: item['isDefault'] = '是' else: item['isDefault'] = '否' - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data -- Gitee From eb29d616d1cee6c34e7254cd52755131e483a1fc Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 10:45:10 +0800 Subject: [PATCH 090/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E9=83=A8=E9=97=A8=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/dept_controller.py | 87 +++++++-- .../module_admin/dao/dept_dao.py | 183 ++++++++++-------- .../module_admin/entity/do/dept_do.py | 5 +- .../module_admin/entity/vo/dept_vo.py | 7 +- .../module_admin/service/dept_service.py | 31 ++- 5 files changed, 198 insertions(+), 115 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py index fe927c7..03416b7 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py @@ -1,22 +1,35 @@ -from fastapi import APIRouter, Request -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, CurrentUserModel -from module_admin.service.dept_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from module_admin.aspect.data_scope import GetDataScope from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * +from module_admin.aspect.data_scope import GetDataScope +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel, DeptQueryModel +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.dept_service import DeptService +from module_admin.service.login_service import LoginService +from utils.log_util import logger +from utils.response_util import ResponseUtil deptController = APIRouter(prefix='/system/dept', dependencies=[Depends(LoginService.get_current_user)]) -@deptController.get("/list/exclude/{dept_id}", response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))]) -async def get_system_dept_tree_for_edit_option(request: Request, dept_id: int, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +@deptController.get( + '/list/exclude/{dept_id}', + response_model=List[DeptModel], + dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))], +) +async def get_system_dept_tree_for_edit_option( + request: Request, + dept_id: int, + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): dept_query = DeptModel(deptId=dept_id) dept_query_result = await DeptService.get_dept_for_edit_option_services(query_db, dept_query, data_scope_sql) logger.info('获取成功') @@ -24,18 +37,30 @@ async def get_system_dept_tree_for_edit_option(request: Request, dept_id: int, q return ResponseUtil.success(data=dept_query_result) -@deptController.get("/list", response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))]) -async def get_system_dept_list(request: Request, dept_query: DeptQueryModel = Depends(DeptQueryModel.as_query), query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +@deptController.get( + '/list', response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))] +) +async def get_system_dept_list( + request: Request, + dept_query: DeptQueryModel = Depends(DeptQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): dept_query_result = await DeptService.get_dept_list_services(query_db, dept_query, data_scope_sql) logger.info('获取成功') return ResponseUtil.success(data=dept_query_result) -@deptController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) +@deptController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) @ValidateFields(validate_model='add_dept') @log_decorator(title='部门管理', business_type=BusinessType.INSERT) -async def add_system_dept(request: Request, add_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_dept( + request: Request, + add_dept: DeptModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_dept.create_by = current_user.user.user_name add_dept.create_time = datetime.now() add_dept.update_by = current_user.user.user_name @@ -46,10 +71,16 @@ async def add_system_dept(request: Request, add_dept: DeptModel, query_db: Async return ResponseUtil.success(data=add_dept_result) -@deptController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) +@deptController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) @ValidateFields(validate_model='edit_dept') @log_decorator(title='部门管理', business_type=BusinessType.UPDATE) -async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def edit_system_dept( + request: Request, + edit_dept: DeptModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): if not current_user.user.admin: await DeptService.check_dept_data_scope_services(query_db, edit_dept.dept_id, data_scope_sql) edit_dept.update_by = current_user.user.user_name @@ -60,9 +91,15 @@ async def edit_system_dept(request: Request, edit_dept: DeptModel, query_db: Asy return ResponseUtil.success(msg=edit_dept_result.message) -@deptController.delete("/{dept_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) +@deptController.delete('/{dept_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) @log_decorator(title='部门管理', business_type=BusinessType.DELETE) -async def delete_system_dept(request: Request, dept_ids: str, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +async def delete_system_dept( + request: Request, + dept_ids: str, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): dept_id_list = dept_ids.split(',') for dept_id in dept_id_list: if not current_user.user.admin: @@ -76,8 +113,16 @@ async def delete_system_dept(request: Request, dept_ids: str, query_db: AsyncSes return ResponseUtil.success(msg=delete_dept_result.message) -@deptController.get("/{dept_id}", response_model=DeptModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dept:query'))]) -async def query_detail_system_dept(request: Request, dept_id: int, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), data_scope_sql: str = Depends(GetDataScope('SysDept'))): +@deptController.get( + '/{dept_id}', response_model=DeptModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dept:query'))] +) +async def query_detail_system_dept( + request: Request, + dept_id: int, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), + data_scope_sql: str = Depends(GetDataScope('SysDept')), +): if not current_user.user.admin: await DeptService.check_dept_data_scope_services(query_db, dept_id, data_scope_sql) detail_dept_result = await DeptService.dept_detail_services(query_db, dept_id) diff --git a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py index 7dfc8a1..cfd7c2e 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py @@ -1,10 +1,11 @@ -from sqlalchemy import select, update, delete, or_, func, bindparam +from sqlalchemy import bindparam, func, or_, select, update # noqa: F401 from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.util import immutabledict +from typing import List from module_admin.entity.do.dept_do import SysDept +from module_admin.entity.do.role_do import SysRoleDept # noqa: F401 from module_admin.entity.do.user_do import SysUser -from module_admin.entity.do.role_do import SysRoleDept -from module_admin.entity.vo.dept_vo import * +from module_admin.entity.vo.dept_vo import DeptModel class DeptDao: @@ -20,10 +21,7 @@ class DeptDao: :param dept_id: 部门id :return: 在用部门信息对象 """ - dept_info = (await db.execute( - select(SysDept) - .where(SysDept.dept_id == dept_id) - )).scalars().first() + dept_info = (await db.execute(select(SysDept).where(SysDept.dept_id == dept_id))).scalars().first() return dept_info @@ -35,11 +33,11 @@ class DeptDao: :param dept_id: 部门id :return: 部门信息对象 """ - dept_info = (await db.execute( - select(SysDept) - .where(SysDept.dept_id == dept_id, - SysDept.del_flag == '0') - )).scalars().first() + dept_info = ( + (await db.execute(select(SysDept).where(SysDept.dept_id == dept_id, SysDept.del_flag == '0'))) + .scalars() + .first() + ) return dept_info @@ -51,11 +49,18 @@ class DeptDao: :param dept: 部门参数对象 :return: 部门信息对象 """ - dept_info = (await db.execute( - select(SysDept) - .where(SysDept.parent_id == dept.parent_id if dept.parent_id else True, - SysDept.dept_name == dept.dept_name if dept.dept_name else True) - )).scalars().first() + dept_info = ( + ( + await db.execute( + select(SysDept).where( + SysDept.parent_id == dept.parent_id if dept.parent_id else True, + SysDept.dept_name == dept.dept_name if dept.dept_name else True, + ) + ) + ) + .scalars() + .first() + ) return dept_info @@ -68,15 +73,26 @@ class DeptDao: :param data_scope_sql: 数据权限对应的查询sql语句 :return: 部门列表信息 """ - dept_result = (await db.execute( - select(SysDept) - .where(SysDept.dept_id != dept_info.dept_id, - ~SysDept.dept_id.in_(select(SysDept.dept_id).where(func.find_in_set(dept_info.dept_id, SysDept.ancestors))), - SysDept.del_flag == '0', SysDept.status == '0', - eval(data_scope_sql)) - .order_by(SysDept.order_num) - .distinct() - )).scalars().all() + dept_result = ( + ( + await db.execute( + select(SysDept) + .where( + SysDept.dept_id != dept_info.dept_id, + ~SysDept.dept_id.in_( + select(SysDept.dept_id).where(func.find_in_set(dept_info.dept_id, SysDept.ancestors)) + ), + SysDept.del_flag == '0', + SysDept.status == '0', + eval(data_scope_sql), + ) + .order_by(SysDept.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return dept_result @@ -88,10 +104,9 @@ class DeptDao: :param dept_id: 部门id :return: 子部门信息列表 """ - dept_result = (await db.execute( - select(SysDept) - .where(func.find_in_set(dept_id, SysDept.ancestors)) - )).scalars().all() + dept_result = ( + (await db.execute(select(SysDept).where(func.find_in_set(dept_id, SysDept.ancestors)))).scalars().all() + ) return dept_result @@ -104,15 +119,23 @@ class DeptDao: :param data_scope_sql: 数据权限对应的查询sql语句 :return: 在用部门列表信息 """ - dept_result = (await db.execute( - select(SysDept) - .where(SysDept.status == '0', - SysDept.del_flag == '0', - SysDept.dept_name.like(f'%{dept_info.dept_name}%') if dept_info.dept_name else True, - eval(data_scope_sql)) - .order_by(SysDept.order_num) - .distinct() - )).scalars().all() + dept_result = ( + ( + await db.execute( + select(SysDept) + .where( + SysDept.status == '0', + SysDept.del_flag == '0', + SysDept.dept_name.like(f'%{dept_info.dept_name}%') if dept_info.dept_name else True, + eval(data_scope_sql), + ) + .order_by(SysDept.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return dept_result @@ -125,15 +148,23 @@ class DeptDao: :param data_scope_sql: 数据权限对应的查询sql语句 :return: 部门列表信息对象 """ - dept_result = (await db.execute( - select(SysDept) - .where(SysDept.del_flag == '0', - SysDept.status == page_object.status if page_object.status else True, - SysDept.dept_name.like(f'%{page_object.dept_name}%') if page_object.dept_name else True, - eval(data_scope_sql)) - .order_by(SysDept.order_num) - .distinct() - )).scalars().all() + dept_result = ( + ( + await db.execute( + select(SysDept) + .where( + SysDept.del_flag == '0', + SysDept.status == page_object.status if page_object.status else True, + SysDept.dept_name.like(f'%{page_object.dept_name}%') if page_object.dept_name else True, + eval(data_scope_sql), + ) + .order_by(SysDept.order_num) + .distinct() + ) + ) + .scalars() + .all() + ) return dept_result @@ -159,10 +190,7 @@ class DeptDao: :param dept: 需要更新的部门字典 :return: 编辑校验结果 """ - await db.execute( - update(SysDept), - [dept] - ) + await db.execute(update(SysDept), [dept]) @classmethod async def update_dept_children_dao(cls, db: AsyncSession, update_dept: List): @@ -174,17 +202,15 @@ class DeptDao: """ await db.execute( update(SysDept) - .where(SysDept.dept_id == bindparam('dept_id')) - .values( + .where(SysDept.dept_id == bindparam('dept_id')) + .values( { 'dept_id': bindparam('dept_id'), 'ancestors': bindparam('ancestors'), } ), update_dept, - execution_options=immutabledict( - {"synchronize_session": None} - ) + execution_options=immutabledict({'synchronize_session': None}), ) @classmethod @@ -195,11 +221,7 @@ class DeptDao: :param dept_id_list: 部门id列表 :return: """ - await db.execute( - update(SysDept) - .where(SysDept.dept_id.in_(dept_id_list)) - .values(status='0') - ) + await db.execute(update(SysDept).where(SysDept.dept_id.in_(dept_id_list)).values(status='0')) @classmethod async def delete_dept_dao(cls, db: AsyncSession, dept: DeptModel): @@ -211,8 +233,8 @@ class DeptDao: """ await db.execute( update(SysDept) - .where(SysDept.dept_id == dept.dept_id) - .values(del_flag='2', update_by=dept.update_by, update_time=dept.update_time) + .where(SysDept.dept_id == dept.dept_id) + .values(del_flag='2', update_by=dept.update_by, update_time=dept.update_time) ) @classmethod @@ -223,15 +245,13 @@ class DeptDao: :param dept_id: 部门id :return: 所有子部门(正常状态)的数量 """ - normal_children_dept_count = (await db.execute( - select(func.count('*')) + normal_children_dept_count = ( + await db.execute( + select(func.count('*')) .select_from(SysDept) - .where( - SysDept.status == '0', - SysDept.del_flag == '0', - func.find_in_set(dept_id, SysDept.ancestors) + .where(SysDept.status == '0', SysDept.del_flag == '0', func.find_in_set(dept_id, SysDept.ancestors)) ) - )).scalar() + ).scalar() return normal_children_dept_count @@ -243,13 +263,14 @@ class DeptDao: :param dept_id: 部门id :return: 所有子部门(所有状态)的数量 """ - children_dept_count = (await db.execute( - select(func.count('*')) + children_dept_count = ( + await db.execute( + select(func.count('*')) .select_from(SysDept) - .where(SysDept.del_flag == '0', - SysDept.parent_id == dept_id) + .where(SysDept.del_flag == '0', SysDept.parent_id == dept_id) .limit(1) - )).scalar() + ) + ).scalar() return children_dept_count @@ -261,10 +282,10 @@ class DeptDao: :param dept_id: 部门id :return: 部门下的用户数量 """ - dept_user_count = (await db.execute( - select(func.count('*')) - .select_from(SysUser) - .where(SysUser.dept_id == dept_id, SysUser.del_flag == '0') - )).scalar() + dept_user_count = ( + await db.execute( + select(func.count('*')).select_from(SysUser).where(SysUser.dept_id == dept_id, SysUser.del_flag == '0') + ) + ).scalar() return dept_user_count diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py index 0572927..96ac8da 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysDept(Base): """ 部门表 """ + __tablename__ = 'sys_dept' dept_id = Column(Integer, primary_key=True, autoincrement=True, comment='部门id') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py index f91d820..dcad117 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dept_vo.py @@ -1,8 +1,8 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import Network, NotBlank, Size -from typing import Union, Optional, List, Literal -from datetime import datetime +from typing import Literal, Optional from module_admin.annotation.pydantic_annotation import as_query @@ -10,6 +10,7 @@ class DeptModel(BaseModel): """ 部门表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) dept_id: Optional[int] = Field(default=None, description='部门id') @@ -57,6 +58,7 @@ class DeptQueryModel(DeptModel): """ 部门管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -65,6 +67,7 @@ class DeleteDeptModel(BaseModel): """ 删除部门模型 """ + model_config = ConfigDict(alias_generator=to_camel) dept_ids: str = Field(default=None, description='需要删除的部门id') diff --git a/ruoyi-fastapi-backend/module_admin/service/dept_service.py b/ruoyi-fastapi-backend/module_admin/service/dept_service.py index 85685a2..3fe5208 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dept_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dept_service.py @@ -1,7 +1,9 @@ -from module_admin.dao.dept_dao import * -from module_admin.entity.vo.common_vo import CrudResponseModel +from sqlalchemy.ext.asyncio import AsyncSession from config.constant import CommonConstant from exceptions.exception import ServiceException, ServiceWarning +from module_admin.dao.dept_dao import DeptDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel from utils.common_util import CamelCaseUtil @@ -25,8 +27,9 @@ class DeptService: return dept_tree_result @classmethod - async def get_dept_for_edit_option_services(cls, query_db: AsyncSession, page_object: DeptModel, - data_scope_sql: str): + async def get_dept_for_edit_option_services( + cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str + ): """ 获取部门编辑部门树信息service :param query_db: orm对象 @@ -75,7 +78,9 @@ class DeptService: :return: 校验结果 """ dept_id = -1 if page_object.dept_id is None else page_object.dept_id - dept = await DeptDao.get_dept_detail_by_info(query_db, DeptModel(deptName=page_object.dept_name, parentId=page_object.parent_id)) + dept = await DeptDao.get_dept_detail_by_info( + query_db, DeptModel(deptName=page_object.dept_name, parentId=page_object.parent_id) + ) if dept and dept.dept_id != dept_id: return CommonConstant.NOT_UNIQUE return CommonConstant.UNIQUE @@ -114,7 +119,10 @@ class DeptService: raise ServiceException(message=f'修改部门{page_object.dept_name}失败,部门名称已存在') elif page_object.dept_id == page_object.parent_id: raise ServiceException(message=f'修改部门{page_object.dept_name}失败,上级部门不能是自己') - elif page_object.status == CommonConstant.DEPT_DISABLE and (await DeptDao.count_normal_children_dept_dao(query_db, page_object.dept_id)) > 0: + elif ( + page_object.status == CommonConstant.DEPT_DISABLE + and (await DeptDao.count_normal_children_dept_dao(query_db, page_object.dept_id)) > 0 + ): raise ServiceException(message=f'修改部门{page_object.dept_name}失败,该部门包含未停用的子部门') new_parent_dept = await DeptDao.get_dept_by_id(query_db, page_object.parent_id) old_dept = await DeptDao.get_dept_by_id(query_db, page_object.dept_id) @@ -126,7 +134,11 @@ class DeptService: await cls.update_dept_children(query_db, page_object.dept_id, new_ancestors, old_ancestors) edit_dept = page_object.model_dump(exclude_unset=True) await DeptDao.edit_dept_dao(query_db, edit_dept) - if page_object.status == CommonConstant.DEPT_NORMAL and page_object.ancestors and page_object.ancestors != 0: + if ( + page_object.status == CommonConstant.DEPT_NORMAL + and page_object.ancestors + and page_object.ancestors != 0 + ): await cls.update_parent_dept_status_normal(query_db, page_object) await query_db.commit() return CrudResponseModel(is_success=True, message='更新成功') @@ -183,8 +195,9 @@ class DeptService: :param permission_list: 部门列表信息 :return: 部门树形嵌套数据 """ - permission_list = [dict(id=item.dept_id, label=item.dept_name, parentId=item.parent_id) for item in - permission_list] + permission_list = [ + dict(id=item.dept_id, label=item.dept_name, parentId=item.parent_id) for item in permission_list + ] # 转成id为key的字典 mapping: dict = dict(zip([i['id'] for i in permission_list], permission_list)) -- Gitee From 749fe85cad9d4ba5809030f5d31212237aa83317 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 10:51:34 +0800 Subject: [PATCH 091/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E5=8F=82=E6=95=B0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/config_controller.py | 67 +++++++++++++------ .../module_admin/dao/config_dao.py | 60 +++++++++-------- .../module_admin/entity/do/config_do.py | 7 +- .../module_admin/entity/vo/config_vo.py | 10 ++- .../module_admin/service/config_service.py | 58 ++++++++++------ 5 files changed, 127 insertions(+), 75 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py index 3c26783..cee889d 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py @@ -1,23 +1,32 @@ -from fastapi import APIRouter -from fastapi import Depends +from datetime import datetime +from fastapi import APIRouter, Depends, Request from pydantic_validation_decorator import ValidateFields +from sqlalchemy.ext.asyncio import AsyncSession +from config.enums import BusinessType from config.get_db import get_db -from module_admin.service.login_service import LoginService, CurrentUserModel -from module_admin.service.config_service import * -from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator -from config.enums import BusinessType -from utils.response_util import * -from utils.log_util import * -from utils.page_util import * +from module_admin.aspect.interface_auth import CheckUserInterfaceAuth +from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.config_service import ConfigService +from module_admin.service.login_service import LoginService from utils.common_util import bytes2file_response +from utils.log_util import logger +from utils.page_util import PageResponseModel +from utils.response_util import ResponseUtil configController = APIRouter(prefix='/system/config', dependencies=[Depends(LoginService.get_current_user)]) -@configController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:list'))]) -async def get_system_config_list(request: Request, config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db)): +@configController.get( + '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:list'))] +) +async def get_system_config_list( + request: Request, + config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_query), + query_db: AsyncSession = Depends(get_db), +): # 获取分页数据 config_page_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=True) logger.info('获取成功') @@ -25,10 +34,15 @@ async def get_system_config_list(request: Request, config_page_query: ConfigPage return ResponseUtil.success(model_content=config_page_query_result) -@configController.post("", dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))]) +@configController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))]) @ValidateFields(validate_model='add_config') @log_decorator(title='参数管理', business_type=BusinessType.INSERT) -async def add_system_config(request: Request, add_config: ConfigModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def add_system_config( + request: Request, + add_config: ConfigModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): add_config.create_by = current_user.user.user_name add_config.create_time = datetime.now() add_config.update_by = current_user.user.user_name @@ -39,10 +53,15 @@ async def add_system_config(request: Request, add_config: ConfigModel, query_db: return ResponseUtil.success(msg=add_config_result.message) -@configController.put("", dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))]) +@configController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))]) @ValidateFields(validate_model='edit_config') @log_decorator(title='参数管理', business_type=BusinessType.UPDATE) -async def edit_system_config(request: Request, edit_config: ConfigModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user)): +async def edit_system_config( + request: Request, + edit_config: ConfigModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user), +): edit_config.update_by = current_user.user.user_name edit_config.update_time = datetime.now() edit_config_result = await ConfigService.edit_config_services(request, query_db, edit_config) @@ -51,7 +70,7 @@ async def edit_system_config(request: Request, edit_config: ConfigModel, query_d return ResponseUtil.success(msg=edit_config_result.message) -@configController.delete("/refreshCache", dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) +@configController.delete('/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) @log_decorator(title='参数管理', business_type=BusinessType.UPDATE) async def refresh_system_config(request: Request, query_db: AsyncSession = Depends(get_db)): refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db) @@ -60,7 +79,7 @@ async def refresh_system_config(request: Request, query_db: AsyncSession = Depen return ResponseUtil.success(msg=refresh_config_result.message) -@configController.delete("/{config_ids}", dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) +@configController.delete('/{config_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) @log_decorator(title='参数管理', business_type=BusinessType.DELETE) async def delete_system_config(request: Request, config_ids: str, query_db: AsyncSession = Depends(get_db)): delete_config = DeleteConfigModel(configIds=config_ids) @@ -70,7 +89,9 @@ async def delete_system_config(request: Request, config_ids: str, query_db: Asyn return ResponseUtil.success(msg=delete_config_result.message) -@configController.get("/{config_id}", response_model=ConfigModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:query'))]) +@configController.get( + '/{config_id}', response_model=ConfigModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:query'))] +) async def query_detail_system_config(request: Request, config_id: int, query_db: AsyncSession = Depends(get_db)): config_detail_result = await ConfigService.config_detail_services(query_db, config_id) logger.info(f'获取config_id为{config_id}的信息成功') @@ -78,7 +99,7 @@ async def query_detail_system_config(request: Request, config_id: int, query_db: return ResponseUtil.success(data=config_detail_result) -@configController.get("/configKey/{config_key}") +@configController.get('/configKey/{config_key}') async def query_system_config(request: Request, config_key: str): # 获取全量数据 config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key) @@ -87,9 +108,13 @@ async def query_system_config(request: Request, config_key: str): return ResponseUtil.success(msg=config_query_result) -@configController.post("/export", dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))]) +@configController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))]) @log_decorator(title='参数管理', business_type=BusinessType.EXPORT) -async def export_system_config_list(request: Request, config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db)): +async def export_system_config_list( + request: Request, + config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_form), + query_db: AsyncSession = Depends(get_db), +): # 获取全量数据 config_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=False) config_export_result = await ConfigService.export_config_list_services(config_query_result) diff --git a/ruoyi-fastapi-backend/module_admin/dao/config_dao.py b/ruoyi-fastapi-backend/module_admin/dao/config_dao.py index 79304c2..df3e3f4 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/config_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/config_dao.py @@ -1,9 +1,9 @@ -from sqlalchemy import select, update, delete +from datetime import datetime, time +from sqlalchemy import delete, select, update from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.config_do import SysConfig -from module_admin.entity.vo.config_vo import * +from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel from utils.page_util import PageUtil -from datetime import datetime, time class ConfigDao: @@ -19,10 +19,7 @@ class ConfigDao: :param config_id: 参数配置id :return: 参数配置信息对象 """ - config_info = (await db.execute( - select(SysConfig) - .where(SysConfig.config_id == config_id) - )).scalars().first() + config_info = (await db.execute(select(SysConfig).where(SysConfig.config_id == config_id))).scalars().first() return config_info @@ -34,11 +31,18 @@ class ConfigDao: :param config: 参数配置参数对象 :return: 参数配置信息对象 """ - config_info = (await db.execute( - select(SysConfig) - .where(SysConfig.config_key == config.config_key if config.config_key else True, - SysConfig.config_value == config.config_value if config.config_value else True) - )).scalars().first() + config_info = ( + ( + await db.execute( + select(SysConfig).where( + SysConfig.config_key == config.config_key if config.config_key else True, + SysConfig.config_value == config.config_value if config.config_value else True, + ) + ) + ) + .scalars() + .first() + ) return config_info @@ -51,15 +55,21 @@ class ConfigDao: :param is_page: 是否开启分页 :return: 参数配置列表信息对象 """ - query = select(SysConfig) \ - .where(SysConfig.config_name.like(f'%{query_object.config_name}%') if query_object.config_name else True, - SysConfig.config_key.like(f'%{query_object.config_key}%') if query_object.config_key else True, - SysConfig.config_type == query_object.config_type if query_object.config_type else True, - SysConfig.create_time.between( - datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), - datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) - if query_object.begin_time and query_object.end_time else True) \ + query = ( + select(SysConfig) + .where( + SysConfig.config_name.like(f'%{query_object.config_name}%') if query_object.config_name else True, + SysConfig.config_key.like(f'%{query_object.config_key}%') if query_object.config_key else True, + SysConfig.config_type == query_object.config_type if query_object.config_type else True, + SysConfig.create_time.between( + datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)), + datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)), + ) + if query_object.begin_time and query_object.end_time + else True, + ) .distinct() + ) config_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return config_list @@ -86,10 +96,7 @@ class ConfigDao: :param config: 需要更新的参数配置字典 :return: """ - await db.execute( - update(SysConfig), - [config] - ) + await db.execute(update(SysConfig), [config]) @classmethod async def delete_config_dao(cls, db: AsyncSession, config: ConfigModel): @@ -99,7 +106,4 @@ class ConfigDao: :param config: 参数配置对象 :return: """ - await db.execute( - delete(SysConfig) - .where(SysConfig.config_id.in_([config.config_id])) - ) + await db.execute(delete(SysConfig).where(SysConfig.config_id.in_([config.config_id]))) diff --git a/ruoyi-fastapi-backend/module_admin/entity/do/config_do.py b/ruoyi-fastapi-backend/module_admin/entity/do/config_do.py index 5fb6476..32af3b0 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/config_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/config_do.py @@ -1,12 +1,13 @@ -from sqlalchemy import Column, Integer, String, DateTime -from config.database import Base from datetime import datetime +from sqlalchemy import Column, DateTime, Integer, String +from config.database import Base class SysConfig(Base): """ 参数配置表 """ + __tablename__ = 'sys_config' config_id = Column(Integer, primary_key=True, autoincrement=True, comment='参数主键') @@ -18,4 +19,4 @@ class SysConfig(Base): create_time = Column(DateTime, nullable=True, default=datetime.now(), comment='创建时间') update_by = Column(String(64), nullable=True, default='', comment='更新者') update_time = Column(DateTime, nullable=True, default=datetime.now(), comment='更新时间') - remark = Column(String(500), nullable=True, default='', comment='备注') \ No newline at end of file + remark = Column(String(500), nullable=True, default='', comment='备注') diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py index c749190..c398d23 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py @@ -1,15 +1,16 @@ +from datetime import datetime from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from typing import Union, Optional, List, Literal -from datetime import datetime -from module_admin.annotation.pydantic_annotation import as_query, as_form +from typing import Literal, Optional +from module_admin.annotation.pydantic_annotation import as_form, as_query class ConfigModel(BaseModel): """ 参数配置表对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) config_id: Optional[int] = Field(default=None, description='参数主键') @@ -48,6 +49,7 @@ class ConfigQueryModel(ConfigModel): """ 参数配置管理不分页查询模型 """ + begin_time: Optional[str] = Field(default=None, description='开始时间') end_time: Optional[str] = Field(default=None, description='结束时间') @@ -58,6 +60,7 @@ class ConfigPageQueryModel(ConfigQueryModel): """ 参数配置管理分页查询模型 """ + page_num: int = Field(default=1, description='当前页码') page_size: int = Field(default=10, description='每页记录数') @@ -66,6 +69,7 @@ class DeleteConfigModel(BaseModel): """ 删除参数配置模型 """ + model_config = ConfigDict(alias_generator=to_camel) config_ids: str = Field(description='需要删除的参数主键') diff --git a/ruoyi-fastapi-backend/module_admin/service/config_service.py b/ruoyi-fastapi-backend/module_admin/service/config_service.py index 6759a8b..8d3b9e6 100644 --- a/ruoyi-fastapi-backend/module_admin/service/config_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/config_service.py @@ -1,10 +1,13 @@ from fastapi import Request -from module_admin.dao.config_dao import * -from module_admin.entity.vo.common_vo import CrudResponseModel +from sqlalchemy.ext.asyncio import AsyncSession +from typing import List from config.constant import CommonConstant from config.env import RedisInitKeyConfig from exceptions.exception import ServiceException -from utils.common_util import export_list2excel, CamelCaseUtil +from module_admin.dao.config_dao import ConfigDao +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel +from utils.common_util import CamelCaseUtil, export_list2excel class ConfigService: @@ -13,7 +16,9 @@ class ConfigService: """ @classmethod - async def get_config_list_services(cls, query_db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False): + async def get_config_list_services( + cls, query_db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False + ): """ 获取参数配置列表信息service :param query_db: orm对象 @@ -40,7 +45,10 @@ class ConfigService: await redis.delete(*keys) config_all = await ConfigDao.get_config_list(query_db, ConfigPageQueryModel(**dict()), is_page=False) for config_obj in config_all: - await redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_obj.get('configKey')}", config_obj.get('configValue')) + await redis.set( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_obj.get('configKey')}", + config_obj.get('configValue'), + ) @classmethod async def query_config_list_from_cache_services(cls, redis, config_key: str): @@ -83,7 +91,9 @@ class ConfigService: try: await ConfigDao.add_config_dao(query_db, page_object) await query_db.commit() - await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{page_object.config_key}", page_object.config_value) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{page_object.config_key}", page_object.config_value + ) return CrudResponseModel(is_success=True, message='新增成功') except Exception as e: await query_db.rollback() @@ -108,8 +118,12 @@ class ConfigService: await ConfigDao.edit_config_dao(query_db, edit_config) await query_db.commit() if config_info.config_key != page_object.config_key: - await request.app.state.redis.delete(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_info.config_key}") - await request.app.state.redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{page_object.config_key}", page_object.config_value) + await request.app.state.redis.delete( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_info.config_key}" + ) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{page_object.config_key}", page_object.config_value + ) return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: await query_db.rollback() @@ -136,7 +150,9 @@ class ConfigService: raise ServiceException(message=f'内置参数{config_info.config_key}不能删除') else: await ConfigDao.delete_config_dao(query_db, ConfigModel(configId=int(config_id))) - delete_config_key_list.append(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_info.config_key}") + delete_config_key_list.append( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_info.config_key}" + ) await query_db.commit() if delete_config_key_list: await request.app.state.redis.delete(*delete_config_key_list) @@ -172,16 +188,16 @@ class ConfigService: """ # 创建一个映射字典,将英文键映射到中文键 mapping_dict = { - "configId": "参数主键", - "configName": "参数名称", - "configKey": "参数键名", - "configValue": "参数键值", - "configType": "系统内置", - "createBy": "创建者", - "createTime": "创建时间", - "updateBy": "更新者", - "updateTime": "更新时间", - "remark": "备注", + 'configId': '参数主键', + 'configName': '参数名称', + 'configKey': '参数键名', + 'configValue': '参数键值', + 'configType': '系统内置', + 'createBy': '创建者', + 'createTime': '创建时间', + 'updateBy': '更新者', + 'updateTime': '更新时间', + 'remark': '备注', } data = config_list @@ -191,7 +207,9 @@ class ConfigService: item['configType'] = '是' else: item['configType'] = '否' - new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] + new_data = [ + {mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data + ] binary_data = export_list2excel(new_data) return binary_data -- Gitee From f41ee2606713a24b5d67a8a7e9e18a35b15f2bdb Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 10:56:26 +0800 Subject: [PATCH 092/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E9=80=9A=E7=94=A8=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/common_controller.py | 24 +++++++++++-------- .../module_admin/entity/vo/common_vo.py | 4 +++- .../module_admin/service/common_service.py | 18 ++++++++------ 3 files changed, 28 insertions(+), 18 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/common_controller.py b/ruoyi-fastapi-backend/module_admin/controller/common_controller.py index dc93030..d2fd621 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/common_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/common_controller.py @@ -1,14 +1,13 @@ -from fastapi import APIRouter -from fastapi import Depends, File, Query +from fastapi import APIRouter, BackgroundTasks, Depends, File, Query, Request, UploadFile +from module_admin.service.common_service import CommonService from module_admin.service.login_service import LoginService -from module_admin.service.common_service import * -from utils.response_util import * -from utils.log_util import * +from utils.log_util import logger +from utils.response_util import ResponseUtil commonController = APIRouter(prefix='/common', dependencies=[Depends(LoginService.get_current_user)]) -@commonController.post("/upload") +@commonController.post('/upload') async def common_upload(request: Request, file: UploadFile = File(...)): upload_result = await CommonService.upload_service(request, file) logger.info('上传成功') @@ -16,16 +15,21 @@ async def common_upload(request: Request, file: UploadFile = File(...)): return ResponseUtil.success(model_content=upload_result.result) -@commonController.get("/download") -async def common_download(request: Request, background_tasks: BackgroundTasks, file_name: str = Query(alias='fileName'), delete: bool = Query()): +@commonController.get('/download') +async def common_download( + request: Request, + background_tasks: BackgroundTasks, + file_name: str = Query(alias='fileName'), + delete: bool = Query(), +): download_result = await CommonService.download_services(background_tasks, file_name, delete) logger.info(download_result.message) return ResponseUtil.streaming(data=download_result.result) -@commonController.get("/download/resource") -async def common_download(request: Request, resource: str = Query()): +@commonController.get('/download/resource') +async def common_download_resource(request: Request, resource: str = Query()): download_resource_result = await CommonService.download_resource_services(resource) logger.info(download_resource_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py index b99534e..258be5d 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py @@ -1,12 +1,13 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Optional, Any +from typing import Any, Optional class CrudResponseModel(BaseModel): """ 操作响应模型 """ + is_success: bool = Field(description='操作是否成功') message: str = Field(description='响应信息') result: Optional[Any] = Field(default=None, description='响应结果') @@ -16,6 +17,7 @@ class UploadResponseModel(BaseModel): """ 上传响应模型 """ + model_config = ConfigDict(alias_generator=to_camel) file_name: Optional[str] = Field(default=None, description='新文件映射路径') diff --git a/ruoyi-fastapi-backend/module_admin/service/common_service.py b/ruoyi-fastapi-backend/module_admin/service/common_service.py index 105f351..bea97c2 100644 --- a/ruoyi-fastapi-backend/module_admin/service/common_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/common_service.py @@ -1,10 +1,9 @@ -from fastapi import Request, BackgroundTasks import os -from fastapi import UploadFile from datetime import datetime +from fastapi import BackgroundTasks, Request, UploadFile from config.env import UploadConfig -from module_admin.entity.vo.common_vo import * from exceptions.exception import ServiceException +from module_admin.entity.vo.common_vo import CrudResponseModel, UploadResponseModel from utils.upload_util import UploadUtil @@ -43,9 +42,9 @@ class CommonService: fileName=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{filename}', newFileName=filename, originalFilename=file.filename, - url=f'{request.base_url}{UploadConfig.UPLOAD_PREFIX[1:]}/{relative_path}/{filename}' + url=f'{request.base_url}{UploadConfig.UPLOAD_PREFIX[1:]}/{relative_path}/{filename}', ), - message='上传成功' + message='上传成功', ) @classmethod @@ -75,8 +74,13 @@ class CommonService: :return: 上传结果 """ filepath = os.path.join(resource.replace(UploadConfig.UPLOAD_PREFIX, UploadConfig.UPLOAD_PATH)) - filename = resource.rsplit("/", 1)[-1] - if '..' in filename or not UploadUtil.check_file_timestamp(filename) or not UploadUtil.check_file_machine(filename) or not UploadUtil.check_file_random_code(filename): + filename = resource.rsplit('/', 1)[-1] + if ( + '..' in filename + or not UploadUtil.check_file_timestamp(filename) + or not UploadUtil.check_file_machine(filename) + or not UploadUtil.check_file_random_code(filename) + ): raise ServiceException(message='文件名称不合法') elif not UploadUtil.check_file_exists(filepath): raise ServiceException(message='文件不存在') -- Gitee From 371fed69df3247b8389d9323129382e20e2c0036 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 10:59:41 +0800 Subject: [PATCH 093/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E7=BC=93=E5=AD=98=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E5=8F=8A=E5=88=97=E8=A1=A8=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/cache_controller.py | 45 +++++++++++++------ .../module_admin/entity/vo/cache_vo.py | 4 +- .../module_admin/service/cache_service.py | 37 +++++++-------- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py b/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py index 459c8c6..9e72713 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py @@ -1,16 +1,19 @@ -from fastapi import APIRouter -from fastapi import Depends -from module_admin.service.login_service import LoginService -from module_admin.service.cache_service import * +from fastapi import APIRouter, Depends, Request +from typing import List from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from utils.response_util import * -from utils.log_util import * +from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel +from module_admin.service.cache_service import CacheService +from module_admin.service.login_service import LoginService +from utils.log_util import logger +from utils.response_util import ResponseUtil cacheController = APIRouter(prefix='/monitor/cache', dependencies=[Depends(LoginService.get_current_user)]) -@cacheController.get("", response_model=CacheMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) +@cacheController.get( + '', response_model=CacheMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))] +) async def get_monitor_cache_info(request: Request): # 获取全量数据 cache_info_query_result = await CacheService.get_cache_monitor_statistical_info_services(request) @@ -19,7 +22,11 @@ async def get_monitor_cache_info(request: Request): return ResponseUtil.success(data=cache_info_query_result) -@cacheController.get("/getNames", response_model=List[CacheInfoModel], dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) +@cacheController.get( + '/getNames', + response_model=List[CacheInfoModel], + dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))], +) async def get_monitor_cache_name(request: Request): # 获取全量数据 cache_name_list_result = await CacheService.get_cache_monitor_cache_name_services() @@ -28,7 +35,11 @@ async def get_monitor_cache_name(request: Request): return ResponseUtil.success(data=cache_name_list_result) -@cacheController.get("/getKeys/{cache_name}", response_model=List[str], dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) +@cacheController.get( + '/getKeys/{cache_name}', + response_model=List[str], + dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))], +) async def get_monitor_cache_key(request: Request, cache_name: str): # 获取全量数据 cache_key_list_result = await CacheService.get_cache_monitor_cache_key_services(request, cache_name) @@ -37,7 +48,11 @@ async def get_monitor_cache_key(request: Request, cache_name: str): return ResponseUtil.success(data=cache_key_list_result) -@cacheController.get("/getValue/{cache_name}/{cache_key}", response_model=CacheInfoModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) +@cacheController.get( + '/getValue/{cache_name}/{cache_key}', + response_model=CacheInfoModel, + dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))], +) async def get_monitor_cache_value(request: Request, cache_name: str, cache_key: str): # 获取全量数据 cache_value_list_result = await CacheService.get_cache_monitor_cache_value_services(request, cache_name, cache_key) @@ -46,7 +61,9 @@ async def get_monitor_cache_value(request: Request, cache_name: str, cache_key: return ResponseUtil.success(data=cache_value_list_result) -@cacheController.delete("/clearCacheName/{cache_name}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) +@cacheController.delete( + '/clearCacheName/{cache_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))] +) async def clear_monitor_cache_name(request: Request, cache_name: str): clear_cache_name_result = await CacheService.clear_cache_monitor_cache_name_services(request, cache_name) logger.info(clear_cache_name_result.message) @@ -54,7 +71,9 @@ async def clear_monitor_cache_name(request: Request, cache_name: str): return ResponseUtil.success(msg=clear_cache_name_result.message) -@cacheController.delete("/clearCacheKey/{cache_key}", dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) +@cacheController.delete( + '/clearCacheKey/{cache_key}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))] +) async def clear_monitor_cache_key(request: Request, cache_key: str): clear_cache_key_result = await CacheService.clear_cache_monitor_cache_key_services(request, cache_key) logger.info(clear_cache_key_result.message) @@ -62,7 +81,7 @@ async def clear_monitor_cache_key(request: Request, cache_key: str): return ResponseUtil.success(msg=clear_cache_key_result.message) -@cacheController.delete("/clearCacheAll", dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) +@cacheController.delete('/clearCacheAll', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) async def clear_monitor_cache_all(request: Request): clear_cache_all_result = await CacheService.clear_cache_monitor_all_services(request) logger.info(clear_cache_all_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py index 8fa1231..79b49fb 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py @@ -1,12 +1,13 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Optional, List, Any +from typing import Any, List, Optional class CacheMonitorModel(BaseModel): """ 缓存监控信息对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel) command_stats: Optional[List] = Field(default=[], description='命令统计') @@ -18,6 +19,7 @@ class CacheInfoModel(BaseModel): """ 缓存监控对象对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel) cache_key: Optional[str] = Field(default=None, description='缓存键名') diff --git a/ruoyi-fastapi-backend/module_admin/service/cache_service.py b/ruoyi-fastapi-backend/module_admin/service/cache_service.py index 06000d1..d134b68 100644 --- a/ruoyi-fastapi-backend/module_admin/service/cache_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/cache_service.py @@ -1,7 +1,7 @@ from fastapi import Request -from module_admin.entity.vo.cache_vo import * from config.env import RedisInitKeyConfig from config.get_redis import RedisUtil +from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel from module_admin.entity.vo.common_vo import CrudResponseModel @@ -20,13 +20,10 @@ class CacheService: info = await request.app.state.redis.info() db_size = await request.app.state.redis.dbsize() command_stats_dict = await request.app.state.redis.info('commandstats') - command_stats = [dict(name=key.split('_')[1], value=str(value.get('calls'))) for key, value in - command_stats_dict.items()] - result = CacheMonitorModel( - commandStats=command_stats, - dbSize=db_size, - info=info - ) + command_stats = [ + dict(name=key.split('_')[1], value=str(value.get('calls'))) for key, value in command_stats_dict.items() + ] + result = CacheMonitorModel(commandStats=command_stats, dbSize=db_size, info=info) return result @@ -41,10 +38,10 @@ class CacheService: if not attr_name.startswith('__') and isinstance(getattr(RedisInitKeyConfig, attr_name), dict): name_list.append( CacheInfoModel( - cacheKey="", + cacheKey='', cacheName=getattr(RedisInitKeyConfig, attr_name).get('key'), - cacheValue="", - remark=getattr(RedisInitKeyConfig, attr_name).get('remark') + cacheValue='', + remark=getattr(RedisInitKeyConfig, attr_name).get('remark'), ) ) @@ -58,8 +55,8 @@ class CacheService: :param cache_name: 缓存名称 :return: 缓存键名列表信息 """ - cache_keys = await request.app.state.redis.keys(f"{cache_name}*") - cache_key_list = [key.split(':', 1)[1] for key in cache_keys if key.startswith(f"{cache_name}:")] + cache_keys = await request.app.state.redis.keys(f'{cache_name}*') + cache_key_list = [key.split(':', 1)[1] for key in cache_keys if key.startswith(f'{cache_name}:')] return cache_key_list @@ -72,9 +69,9 @@ class CacheService: :param cache_key: 缓存键名 :return: 缓存内容信息 """ - cache_value = await request.app.state.redis.get(f"{cache_name}:{cache_key}") + cache_value = await request.app.state.redis.get(f'{cache_name}:{cache_key}') - return CacheInfoModel(cacheKey=cache_key, cacheName=cache_name, cacheValue=cache_value, remark="") + return CacheInfoModel(cacheKey=cache_key, cacheName=cache_name, cacheValue=cache_value, remark='') @classmethod async def clear_cache_monitor_cache_name_services(cls, request: Request, cache_name: str): @@ -84,11 +81,11 @@ class CacheService: :param cache_name: 缓存名称 :return: 操作缓存响应信息 """ - cache_keys = await request.app.state.redis.keys(f"{cache_name}*") + cache_keys = await request.app.state.redis.keys(f'{cache_name}*') if cache_keys: await request.app.state.redis.delete(*cache_keys) - return CrudResponseModel(is_success=True, message=f"{cache_name}对应键值清除成功") + return CrudResponseModel(is_success=True, message=f'{cache_name}对应键值清除成功') @classmethod async def clear_cache_monitor_cache_key_services(cls, request: Request, cache_key: str): @@ -98,11 +95,11 @@ class CacheService: :param cache_key: 缓存键名 :return: 操作缓存响应信息 """ - cache_keys = await request.app.state.redis.keys(f"*{cache_key}") + cache_keys = await request.app.state.redis.keys(f'*{cache_key}') if cache_keys: await request.app.state.redis.delete(*cache_keys) - return CrudResponseModel(is_success=True, message=f"{cache_key}清除成功") + return CrudResponseModel(is_success=True, message=f'{cache_key}清除成功') @classmethod async def clear_cache_monitor_all_services(cls, request: Request): @@ -118,4 +115,4 @@ class CacheService: await RedisUtil.init_sys_dict(request.app.state.redis) await RedisUtil.init_sys_config(request.app.state.redis) - return CrudResponseModel(is_success=True, message="所有缓存清除成功") + return CrudResponseModel(is_success=True, message='所有缓存清除成功') -- Gitee From 91e31cfbf76be25789046639a4df6f320c7258dc Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:04:40 +0800 Subject: [PATCH 094/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E6=9C=8D=E5=8A=A1=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/server_controller.py | 16 ++++++++------ .../module_admin/entity/vo/server_vo.py | 3 ++- .../module_admin/service/server_service.py | 22 ++++++++++--------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/server_controller.py b/ruoyi-fastapi-backend/module_admin/controller/server_controller.py index 86c970a..f63fdf8 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/server_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/server_controller.py @@ -1,16 +1,18 @@ -from fastapi import APIRouter, Request -from fastapi import Depends -from module_admin.service.login_service import LoginService -from module_admin.service.server_service import * +from fastapi import APIRouter, Depends, Request from module_admin.aspect.interface_auth import CheckUserInterfaceAuth -from utils.response_util import * -from utils.log_util import * +from module_admin.entity.vo.server_vo import ServerMonitorModel +from module_admin.service.login_service import LoginService +from module_admin.service.server_service import ServerService +from utils.response_util import ResponseUtil +from utils.log_util import logger serverController = APIRouter(prefix='/monitor/server', dependencies=[Depends(LoginService.get_current_user)]) -@serverController.get("", response_model=ServerMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:server:list'))]) +@serverController.get( + '', response_model=ServerMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:server:list'))] +) async def get_monitor_server_info(request: Request): # 获取全量数据 server_info_query_result = await ServerService.get_server_monitor_info() diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/server_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/server_vo.py index f7693be..810ecac 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/server_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/server_vo.py @@ -1,6 +1,6 @@ from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Optional, List +from typing import List, Optional class CpuInfo(BaseModel): @@ -57,6 +57,7 @@ class ServerMonitorModel(BaseModel): """ 服务监控对应pydantic模型 """ + model_config = ConfigDict(alias_generator=to_camel) cpu: Optional[CpuInfo] = Field(description='CPU相关信息') diff --git a/ruoyi-fastapi-backend/module_admin/service/server_service.py b/ruoyi-fastapi-backend/module_admin/service/server_service.py index da6e2a2..2f9a53f 100644 --- a/ruoyi-fastapi-backend/module_admin/service/server_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/server_service.py @@ -1,10 +1,10 @@ -import psutil -from utils.common_util import bytes2human +import os import platform +import psutil import socket -import os import time -from module_admin.entity.vo.server_vo import * +from module_admin.entity.vo.server_vo import CpuInfo, MemoryInfo, PyInfo, ServerMonitorModel, SysFiles, SysInfo +from utils.common_util import bytes2human class ServerService: @@ -40,7 +40,9 @@ class ServerService: computer_name = platform.node() os_arch = platform.machine() user_dir = os.path.abspath(os.getcwd()) - sys = SysInfo(computerIp=computer_ip, computerName=computer_name, osArch=os_arch, osName=os_name, userDir=user_dir) + sys = SysInfo( + computerIp=computer_ip, computerName=computer_name, osArch=os_arch, osName=os_name, userDir=user_dir + ) # python解释器信息 current_pid = os.getpid() @@ -49,14 +51,14 @@ class ServerService: python_version = platform.python_version() python_home = current_process.exe() start_time_stamp = current_process.create_time() - start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time_stamp)) + start_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(start_time_stamp)) current_time_stamp = time.time() difference = current_time_stamp - start_time_stamp # 将时间差转换为天、小时和分钟数 days = int(difference // (24 * 60 * 60)) # 每天的秒数 hours = int((difference % (24 * 60 * 60)) // (60 * 60)) # 每小时的秒数 minutes = int((difference % (60 * 60)) // 60) # 每分钟的秒数 - run_time = f"{days}天{hours}小时{minutes}分钟" + run_time = f'{days}天{hours}小时{minutes}分钟' # 获取当前Python程序的pid pid = os.getpid() # 获取该进程的内存信息 @@ -70,7 +72,7 @@ class ServerService: total=bytes2human(memory_info.available), used=bytes2human(current_process_memory_info.rss), free=bytes2human(memory_info.available - current_process_memory_info.rss), - usage=round((current_process_memory_info.rss / memory_info.available) * 100, 2) + usage=round((current_process_memory_info.rss / memory_info.available) * 100, 2), ) # 磁盘信息 @@ -81,11 +83,11 @@ class ServerService: disk_data = SysFiles( dirName=i.device, sysTypeName=i.fstype, - typeName="本地固定磁盘(" + i.mountpoint.replace('\\', '') + ")", + typeName='本地固定磁盘(' + i.mountpoint.replace('\\', '') + ')', total=bytes2human(o.total), used=bytes2human(o.used), free=bytes2human(o.free), - usage=f'{psutil.disk_usage(i.device).percent}%' + usage=f'{psutil.disk_usage(i.device).percent}%', ) sys_files.append(disk_data) -- Gitee From 380693c66d6c98b44c40a3c99c54c505cc90b502 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:06:57 +0800 Subject: [PATCH 095/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96=E9=AA=8C=E8=AF=81=E7=A0=81=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/captcha_controller.py | 33 +++++++++++++------ .../module_admin/service/captcha_service.py | 6 ++-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py b/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py index 3ad1543..df0eb89 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py @@ -1,28 +1,41 @@ import uuid +from datetime import timedelta from fastapi import APIRouter, Request from config.env import RedisInitKeyConfig -from module_admin.service.captcha_service import * from module_admin.entity.vo.login_vo import CaptchaCode -from utils.response_util import * -from utils.log_util import * -from datetime import timedelta +from module_admin.service.captcha_service import CaptchaService +from utils.response_util import ResponseUtil +from utils.log_util import logger captchaController = APIRouter() -@captchaController.get("/captchaImage") +@captchaController.get('/captchaImage') async def get_captcha_image(request: Request): - captcha_enabled = True if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") == 'true' else False - register_enabled = True if await request.app.state.redis.get( - f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.registerUser") == 'true' else False + captcha_enabled = ( + True + if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") + == 'true' + else False + ) + register_enabled = ( + True + if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.registerUser") + == 'true' + else False + ) session_id = str(uuid.uuid4()) captcha_result = await CaptchaService.create_captcha_image_service() image = captcha_result[0] computed_result = captcha_result[1] - await request.app.state.redis.set(f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{session_id}", computed_result, ex=timedelta(minutes=2)) + await request.app.state.redis.set( + f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{session_id}", computed_result, ex=timedelta(minutes=2) + ) logger.info(f'编号为{session_id}的会话获取图片验证码成功') return ResponseUtil.success( - model_content=CaptchaCode(captchaEnabled=captcha_enabled, registerEnabled=register_enabled, img=image, uuid=session_id) + model_content=CaptchaCode( + captchaEnabled=captcha_enabled, registerEnabled=register_enabled, img=image, uuid=session_id + ) ) diff --git a/ruoyi-fastapi-backend/module_admin/service/captcha_service.py b/ruoyi-fastapi-backend/module_admin/service/captcha_service.py index 85b0912..1be8ffb 100644 --- a/ruoyi-fastapi-backend/module_admin/service/captcha_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/captcha_service.py @@ -1,8 +1,8 @@ -from PIL import Image, ImageDraw, ImageFont +import base64 import io import os import random -import base64 +from PIL import Image, ImageDraw, ImageFont class CaptchaService: @@ -35,7 +35,7 @@ class CaptchaService: else: result = num1 * num2 # 绘制文本 - text = f"{num1} {operational_character} {num2} = ?" + text = f'{num1} {operational_character} {num2} = ?' draw.text((25, 15), text, fill='blue', font=font) # 将图像数据保存到内存中 -- Gitee From ed9ad54b4657de3112cdcfbd26b014b89f9e9419 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:13:01 +0800 Subject: [PATCH 096/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96utils=E6=A8=A1=E5=9D=97=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/utils/common_util.py | 59 +++++++--- ruoyi-fastapi-backend/utils/log_util.py | 2 +- ruoyi-fastapi-backend/utils/message_util.py | 2 +- ruoyi-fastapi-backend/utils/page_util.py | 23 ++-- ruoyi-fastapi-backend/utils/pwd_util.py | 2 +- ruoyi-fastapi-backend/utils/response_util.py | 111 +++++++++---------- ruoyi-fastapi-backend/utils/upload_util.py | 6 +- 7 files changed, 113 insertions(+), 92 deletions(-) diff --git a/ruoyi-fastapi-backend/utils/common_util.py b/ruoyi-fastapi-backend/utils/common_util.py index 1dd8c93..67145d9 100644 --- a/ruoyi-fastapi-backend/utils/common_util.py +++ b/ruoyi-fastapi-backend/utils/common_util.py @@ -1,6 +1,6 @@ -import pandas as pd import io import os +import pandas as pd import re from openpyxl import Workbook from openpyxl.styles import Alignment, PatternFill @@ -33,7 +33,7 @@ def worship(): // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // -// 佛祖保佑 永不宕机 永无BUG // +// 佛祖保佑 永不宕机 永无BUG // //////////////////////////////////////////////////////////////////// """) @@ -42,6 +42,7 @@ class CamelCaseUtil: """ 下划线形式(snake_case)转小驼峰形式(camelCase)工具方法 """ + @classmethod def snake_to_camel(cls, snake_str): """ @@ -68,10 +69,24 @@ class CamelCaseUtil: return {cls.snake_to_camel(k): v for k, v in result.items()} # 如果是一组字典或其他类型的列表,遍历列表进行转换 elif isinstance(result, list): - return [cls.transform_result(row) if isinstance(row, (dict, Row)) else (cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row) for row in result] + return [ + cls.transform_result(row) + if isinstance(row, (dict, Row)) + else ( + cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row + ) + for row in result + ] # 如果是sqlalchemy的Row实例,遍历Row进行转换 elif isinstance(result, Row): - return [cls.transform_result(row) if isinstance(row, dict) else (cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row) for row in result] + return [ + cls.transform_result(row) + if isinstance(row, dict) + else ( + cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row + ) + for row in result + ] # 如果是其他类型,如模型实例,先转换为字典 else: return cls.transform_result({c.name: getattr(result, c.name) for c in result.__table__.columns}) @@ -81,6 +96,7 @@ class SnakeCaseUtil: """ 小驼峰形式(camelCase)转下划线形式(snake_case)工具方法 """ + @classmethod def camel_to_snake(cls, camel_str): """ @@ -106,16 +122,30 @@ class SnakeCaseUtil: return {cls.camel_to_snake(k): v for k, v in result.items()} # 如果是一组字典或其他类型的列表,遍历列表进行转换 elif isinstance(result, list): - return [cls.transform_result(row) if isinstance(row, (dict, Row)) else (cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row) for row in result] + return [ + cls.transform_result(row) + if isinstance(row, (dict, Row)) + else ( + cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row + ) + for row in result + ] # 如果是sqlalchemy的Row实例,遍历Row进行转换 elif isinstance(result, Row): - return [cls.transform_result(row) if isinstance(row, dict) else (cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row) for row in result] + return [ + cls.transform_result(row) + if isinstance(row, dict) + else ( + cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row + ) + for row in result + ] # 如果是其他类型,如模型实例,先转换为字典 else: return cls.transform_result({c.name: getattr(result, c.name) for c in result.__table__.columns}) -def bytes2human(n, format_str="%(value).1f%(symbol)s"): +def bytes2human(n, format_str='%(value).1f%(symbol)s'): """Used by various scripts. See: http://goo.gl/zeJZl @@ -170,7 +200,7 @@ def get_excel_template(header_list: List, selector_header_list: List, option_lis headers = header_list # 设置表头背景样式为灰色,前景色为白色 - header_fill = PatternFill(start_color="ababab", end_color="ababab", fill_type="solid") + header_fill = PatternFill(start_color='ababab', end_color='ababab', fill_type='solid') # 将表头写入第一行 for col_num, header in enumerate(headers, 1): @@ -194,10 +224,11 @@ def get_excel_template(header_list: List, selector_header_list: List, option_lis for option in options: if option.get(selector_header): header_option = option.get(selector_header) - dv = DataValidation(type="list", formula1=f'"{",".join(header_option)}"') + dv = DataValidation(type='list', formula1=f'"{",".join(header_option)}"') # 设置数据有效性规则的起始单元格和结束单元格 dv.add( - f'{get_column_letter(column_selector_header_index)}2:{get_column_letter(column_selector_header_index)}1048576') + f'{get_column_letter(column_selector_header_index)}2:{get_column_letter(column_selector_header_index)}1048576' + ) # 添加数据有效性规则到工作表 ws.add_data_validation(dv) @@ -218,10 +249,10 @@ def get_filepath_from_url(url: str): :param url: 请求参数中的url参数 :return: 文件路径 """ - file_info = url.split("?")[1].split("&") - task_id = file_info[0].split("=")[1] - file_name = file_info[1].split("=")[1] - task_path = file_info[2].split("=")[1] + file_info = url.split('?')[1].split('&') + task_id = file_info[0].split('=')[1] + file_name = file_info[1].split('=')[1] + task_path = file_info[2].split('=')[1] filepath = os.path.join(CachePathConfig.PATH, task_path, task_id, file_name) return filepath diff --git a/ruoyi-fastapi-backend/utils/log_util.py b/ruoyi-fastapi-backend/utils/log_util.py index e904653..e42f393 100644 --- a/ruoyi-fastapi-backend/utils/log_util.py +++ b/ruoyi-fastapi-backend/utils/log_util.py @@ -8,4 +8,4 @@ if not os.path.exists(log_path): log_path_error = os.path.join(log_path, f'{time.strftime("%Y-%m-%d")}_error.log') -logger.add(log_path_error, rotation="50MB", encoding="utf-8", enqueue=True, compression="zip") +logger.add(log_path_error, rotation='50MB', encoding='utf-8', enqueue=True, compression='zip') diff --git a/ruoyi-fastapi-backend/utils/message_util.py b/ruoyi-fastapi-backend/utils/message_util.py index 6a21f88..3d3eb51 100644 --- a/ruoyi-fastapi-backend/utils/message_util.py +++ b/ruoyi-fastapi-backend/utils/message_util.py @@ -2,4 +2,4 @@ from utils.log_util import logger def message_service(sms_code: str): - logger.info(f"短信验证码为{sms_code}") + logger.info(f'短信验证码为{sms_code}') diff --git a/ruoyi-fastapi-backend/utils/page_util.py b/ruoyi-fastapi-backend/utils/page_util.py index d46d260..0a18c9b 100644 --- a/ruoyi-fastapi-backend/utils/page_util.py +++ b/ruoyi-fastapi-backend/utils/page_util.py @@ -1,9 +1,9 @@ import math -from typing import Optional, List -from sqlalchemy import Select, select, func -from sqlalchemy.ext.asyncio import AsyncSession from pydantic import BaseModel, ConfigDict from pydantic.alias_generators import to_camel +from sqlalchemy import func, select, Select +from sqlalchemy.ext.asyncio import AsyncSession +from typing import Optional, List from utils.common_util import CamelCaseUtil @@ -11,6 +11,7 @@ class PageResponseModel(BaseModel): """ 列表分页查询返回模型 """ + model_config = ConfigDict(alias_generator=to_camel) rows: List = [] @@ -43,11 +44,7 @@ class PageUtil: has_next = True if math.ceil(len(data_list) / page_size) > page_num else False result = PageResponseModel( - rows=paginated_data, - pageNum=page_num, - pageSize=page_size, - total=len(data_list), - hasNext=has_next + rows=paginated_data, pageNum=page_num, pageSize=page_size, total=len(data_list), hasNext=has_next ) return result @@ -65,7 +62,7 @@ class PageUtil: """ if is_page: total = (await db.execute(select(func.count('*')).select_from(query.subquery()))).scalar() - query_result = (await db.execute(query.offset((page_num - 1) * page_size).limit(page_size))) + query_result = await db.execute(query.offset((page_num - 1) * page_size).limit(page_size)) paginated_data = [] for row in query_result: if row and len(row) == 1: @@ -78,7 +75,7 @@ class PageUtil: pageNum=page_num, pageSize=page_size, total=total, - hasNext=has_next + hasNext=has_next, ) else: query_result = await db.execute(query) @@ -110,11 +107,7 @@ def get_page_obj(data_list: List, page_num: int, page_size: int): has_next = True if math.ceil(len(data_list) / page_size) > page_num else False result = PageResponseModel( - rows=paginated_data, - pageNum=page_num, - pageSize=page_size, - total=len(data_list), - hasNext=has_next + rows=paginated_data, pageNum=page_num, pageSize=page_size, total=len(data_list), hasNext=has_next ) return result diff --git a/ruoyi-fastapi-backend/utils/pwd_util.py b/ruoyi-fastapi-backend/utils/pwd_util.py index 2e9a2f9..badaa04 100644 --- a/ruoyi-fastapi-backend/utils/pwd_util.py +++ b/ruoyi-fastapi-backend/utils/pwd_util.py @@ -1,6 +1,6 @@ from passlib.context import CryptContext -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") +pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto') class PwdUtil: diff --git a/ruoyi-fastapi-backend/utils/response_util.py b/ruoyi-fastapi-backend/utils/response_util.py index 512c939..d06a7fa 100644 --- a/ruoyi-fastapi-backend/utils/response_util.py +++ b/ruoyi-fastapi-backend/utils/response_util.py @@ -1,9 +1,9 @@ +from datetime import datetime from fastapi import status -from fastapi.responses import JSONResponse, Response, StreamingResponse from fastapi.encoders import jsonable_encoder -from typing import Any, Dict, Optional +from fastapi.responses import JSONResponse, Response, StreamingResponse from pydantic import BaseModel -from datetime import datetime +from typing import Any, Dict, Optional from config.constant import HttpStatusConstant @@ -13,8 +13,14 @@ class ResponseUtil: """ @classmethod - def success(cls, msg: str = '操作成功', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, model_content: Optional[BaseModel] = None) -> Response: + def success( + cls, + msg: str = '操作成功', + data: Optional[Any] = None, + rows: Optional[Any] = None, + dict_content: Optional[Dict] = None, + model_content: Optional[BaseModel] = None, + ) -> Response: """ 成功响应方法 :param msg: 可选,自定义成功响应信息 @@ -24,10 +30,7 @@ class ResponseUtil: :param model_content: 可选,BaseModel类型,成功响应结果中自定义属性的值 :return: 成功响应结果 """ - result = { - 'code': HttpStatusConstant.SUCCESS, - 'msg': msg - } + result = {'code': HttpStatusConstant.SUCCESS, 'msg': msg} if data is not None: result['data'] = data @@ -40,14 +43,17 @@ class ResponseUtil: result.update({'success': True, 'time': datetime.now()}) - return JSONResponse( - status_code=status.HTTP_200_OK, - content=jsonable_encoder(result) - ) + return JSONResponse(status_code=status.HTTP_200_OK, content=jsonable_encoder(result)) @classmethod - def failure(cls, msg: str = '操作失败', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, model_content: Optional[BaseModel] = None) -> Response: + def failure( + cls, + msg: str = '操作失败', + data: Optional[Any] = None, + rows: Optional[Any] = None, + dict_content: Optional[Dict] = None, + model_content: Optional[BaseModel] = None, + ) -> Response: """ 失败响应方法 :param msg: 可选,自定义失败响应信息 @@ -57,10 +63,7 @@ class ResponseUtil: :param model_content: 可选,BaseModel类型,失败响应结果中自定义属性的值 :return: 失败响应结果 """ - result = { - 'code': HttpStatusConstant.WARN, - 'msg': msg - } + result = {'code': HttpStatusConstant.WARN, 'msg': msg} if data is not None: result['data'] = data @@ -73,14 +76,17 @@ class ResponseUtil: result.update({'success': False, 'time': datetime.now()}) - return JSONResponse( - status_code=status.HTTP_200_OK, - content=jsonable_encoder(result) - ) + return JSONResponse(status_code=status.HTTP_200_OK, content=jsonable_encoder(result)) @classmethod - def unauthorized(cls, msg: str = '登录信息已过期,访问系统资源失败', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, model_content: Optional[BaseModel] = None) -> Response: + def unauthorized( + cls, + msg: str = '登录信息已过期,访问系统资源失败', + data: Optional[Any] = None, + rows: Optional[Any] = None, + dict_content: Optional[Dict] = None, + model_content: Optional[BaseModel] = None, + ) -> Response: """ 未认证响应方法 :param msg: 可选,自定义未认证响应信息 @@ -90,10 +96,7 @@ class ResponseUtil: :param model_content: 可选,BaseModel类型,未认证响应结果中自定义属性的值 :return: 未认证响应结果 """ - result = { - 'code': HttpStatusConstant.UNAUTHORIZED, - 'msg': msg - } + result = {'code': HttpStatusConstant.UNAUTHORIZED, 'msg': msg} if data is not None: result['data'] = data @@ -106,14 +109,17 @@ class ResponseUtil: result.update({'success': False, 'time': datetime.now()}) - return JSONResponse( - status_code=status.HTTP_200_OK, - content=jsonable_encoder(result) - ) + return JSONResponse(status_code=status.HTTP_200_OK, content=jsonable_encoder(result)) @classmethod - def forbidden(cls, msg: str = '该用户无此接口权限', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, model_content: Optional[BaseModel] = None) -> Response: + def forbidden( + cls, + msg: str = '该用户无此接口权限', + data: Optional[Any] = None, + rows: Optional[Any] = None, + dict_content: Optional[Dict] = None, + model_content: Optional[BaseModel] = None, + ) -> Response: """ 未认证响应方法 :param msg: 可选,自定义未认证响应信息 @@ -123,10 +129,7 @@ class ResponseUtil: :param model_content: 可选,BaseModel类型,未认证响应结果中自定义属性的值 :return: 未认证响应结果 """ - result = { - 'code': HttpStatusConstant.FORBIDDEN, - 'msg': msg - } + result = {'code': HttpStatusConstant.FORBIDDEN, 'msg': msg} if data is not None: result['data'] = data @@ -139,14 +142,17 @@ class ResponseUtil: result.update({'success': False, 'time': datetime.now()}) - return JSONResponse( - status_code=status.HTTP_200_OK, - content=jsonable_encoder(result) - ) + return JSONResponse(status_code=status.HTTP_200_OK, content=jsonable_encoder(result)) @classmethod - def error(cls, msg: str = '接口异常', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, model_content: Optional[BaseModel] = None) -> Response: + def error( + cls, + msg: str = '接口异常', + data: Optional[Any] = None, + rows: Optional[Any] = None, + dict_content: Optional[Dict] = None, + model_content: Optional[BaseModel] = None, + ) -> Response: """ 错误响应方法 :param msg: 可选,自定义错误响应信息 @@ -156,10 +162,7 @@ class ResponseUtil: :param model_content: 可选,BaseModel类型,错误响应结果中自定义属性的值 :return: 错误响应结果 """ - result = { - 'code': HttpStatusConstant.ERROR, - 'msg': msg - } + result = {'code': HttpStatusConstant.ERROR, 'msg': msg} if data is not None: result['data'] = data @@ -172,10 +175,7 @@ class ResponseUtil: result.update({'success': False, 'time': datetime.now()}) - return JSONResponse( - status_code=status.HTTP_200_OK, - content=jsonable_encoder(result) - ) + return JSONResponse(status_code=status.HTTP_200_OK, content=jsonable_encoder(result)) @classmethod def streaming(cls, *, data: Any = None): @@ -184,7 +184,4 @@ class ResponseUtil: :param data: 流式传输的内容 :return: 流式响应结果 """ - return StreamingResponse( - status_code=status.HTTP_200_OK, - content=data - ) + return StreamingResponse(status_code=status.HTTP_200_OK, content=data) diff --git a/ruoyi-fastapi-backend/utils/upload_util.py b/ruoyi-fastapi-backend/utils/upload_util.py index dc71255..99b00bb 100644 --- a/ruoyi-fastapi-backend/utils/upload_util.py +++ b/ruoyi-fastapi-backend/utils/upload_util.py @@ -1,7 +1,7 @@ -import random import os -from fastapi import UploadFile +import random from datetime import datetime +from fastapi import UploadFile from config.env import UploadConfig @@ -62,7 +62,7 @@ class UploadUtil: """ 校验文件随机码是否合法 """ - valid_code_list = [f"{i:03}" for i in range(1, 999)] + valid_code_list = [f'{i:03}' for i in range(1, 999)] if filename.rsplit('.', 1)[0][-3:] in valid_code_list: return True return False -- Gitee From 9b40c05e641c5686362dbd500849b8d57e52c1aa Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:19:07 +0800 Subject: [PATCH 097/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96config=E6=A8=A1=E5=9D=97=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/config/constant.py | 3 + ruoyi-fastapi-backend/config/database.py | 8 ++- ruoyi-fastapi-backend/config/enums.py | 1 + ruoyi-fastapi-backend/config/env.py | 40 +++++++++--- ruoyi-fastapi-backend/config/get_db.py | 6 +- ruoyi-fastapi-backend/config/get_redis.py | 26 ++++---- ruoyi-fastapi-backend/config/get_scheduler.py | 62 ++++++++++--------- 7 files changed, 91 insertions(+), 55 deletions(-) diff --git a/ruoyi-fastapi-backend/config/constant.py b/ruoyi-fastapi-backend/config/constant.py index fb860f7..e30fa78 100644 --- a/ruoyi-fastapi-backend/config/constant.py +++ b/ruoyi-fastapi-backend/config/constant.py @@ -11,6 +11,7 @@ class CommonConstant: UNIQUE: 校验是否唯一的返回标识(是) NOT_UNIQUE: 校验是否唯一的返回标识(否) """ + WWW = 'www.' HTTP = 'http://' HTTPS = 'https://' @@ -43,6 +44,7 @@ class HttpStatusConstant: NOT_IMPLEMENTED: 接口未实现 WARN: 系统警告消息 """ + SUCCESS = 200 CREATED = 201 ACCEPTED = 202 @@ -74,6 +76,7 @@ class MenuConstant: PARENT_VIEW: ParentView组件标识 INNER_LINK: InnerLink组件标识 """ + TYPE_DIR = 'M' TYPE_MENU = 'C' TYPE_BUTTON = 'F' diff --git a/ruoyi-fastapi-backend/config/database.py b/ruoyi-fastapi-backend/config/database.py index 512ae1b..14c5a80 100644 --- a/ruoyi-fastapi-backend/config/database.py +++ b/ruoyi-fastapi-backend/config/database.py @@ -5,8 +5,10 @@ from sqlalchemy.orm import DeclarativeBase from urllib.parse import quote_plus from config.env import DataBaseConfig -ASYNC_SQLALCHEMY_DATABASE_URL = f"mysql+asyncmy://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@" \ - f"{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}" +ASYNC_SQLALCHEMY_DATABASE_URL = ( + f'mysql+asyncmy://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@' + f'{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}' +) async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, @@ -14,7 +16,7 @@ async_engine = create_async_engine( max_overflow=DataBaseConfig.db_max_overflow, pool_size=DataBaseConfig.db_pool_size, pool_recycle=DataBaseConfig.db_pool_recycle, - pool_timeout=DataBaseConfig.db_pool_timeout + pool_timeout=DataBaseConfig.db_pool_timeout, ) AsyncSessionLocal = async_sessionmaker(autocommit=False, autoflush=False, bind=async_engine) diff --git a/ruoyi-fastapi-backend/config/enums.py b/ruoyi-fastapi-backend/config/enums.py index b02e5f3..673a4cb 100644 --- a/ruoyi-fastapi-backend/config/enums.py +++ b/ruoyi-fastapi-backend/config/enums.py @@ -15,6 +15,7 @@ class BusinessType(Enum): GENCODE: 生成代码 CLEAN: 清空数据 """ + OTHER = 0 INSERT = 1 UPDATE = 2 diff --git a/ruoyi-fastapi-backend/config/env.py b/ruoyi-fastapi-backend/config/env.py index 71718f9..6c5e8bf 100644 --- a/ruoyi-fastapi-backend/config/env.py +++ b/ruoyi-fastapi-backend/config/env.py @@ -1,15 +1,16 @@ +import argparse import os import sys -import argparse -from pydantic_settings import BaseSettings -from functools import lru_cache from dotenv import load_dotenv +from functools import lru_cache +from pydantic_settings import BaseSettings class AppSettings(BaseSettings): """ 应用配置 """ + app_env: str = 'dev' app_name: str = 'RuoYi-FasAPI' app_root_path: str = '/dev-api' @@ -25,6 +26,7 @@ class JwtSettings(BaseSettings): """ Jwt配置 """ + jwt_secret_key: str = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55' jwt_algorithm: str = 'HS256' jwt_expire_minutes: int = 1440 @@ -35,6 +37,7 @@ class DataBaseSettings(BaseSettings): """ 数据库配置 """ + db_host: str = '127.0.0.1' db_port: int = 3306 db_username: str = 'root' @@ -51,6 +54,7 @@ class RedisSettings(BaseSettings): """ Redis配置 """ + redis_host: str = '127.0.0.1' redis_port: int = 6379 redis_username: str = '' @@ -62,20 +66,38 @@ class UploadSettings: """ 上传配置 """ + UPLOAD_PREFIX = '/profile' UPLOAD_PATH = 'vf_admin/upload_path' UPLOAD_MACHINE = 'A' DEFAULT_ALLOWED_EXTENSION = [ # 图片 - "bmp", "gif", "jpg", "jpeg", "png", + 'bmp', + 'gif', + 'jpg', + 'jpeg', + 'png', # word excel powerpoint - "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", + 'doc', + 'docx', + 'xls', + 'xlsx', + 'ppt', + 'pptx', + 'html', + 'htm', + 'txt', # 压缩文件 - "rar", "zip", "gz", "bz2", + 'rar', + 'zip', + 'gz', + 'bz2', # 视频格式 - "mp4", "avi", "rmvb", + 'mp4', + 'avi', + 'rmvb', # pdf - "pdf" + 'pdf', ] DOWNLOAD_PATH = 'vf_admin/download_path' @@ -90,6 +112,7 @@ class CachePathConfig: """ 缓存目录配置 """ + PATH = os.path.join(os.path.abspath(os.getcwd()), 'caches') PATHSTR = 'caches' @@ -98,6 +121,7 @@ class RedisInitKeyConfig: """ 系统内置Redis键名 """ + ACCESS_TOKEN = {'key': 'access_token', 'remark': '登录令牌信息'} SYS_DICT = {'key': 'sys_dict', 'remark': '数据字典'} SYS_CONFIG = {'key': 'sys_config', 'remark': '配置信息'} diff --git a/ruoyi-fastapi-backend/config/get_db.py b/ruoyi-fastapi-backend/config/get_db.py index 9c12561..d88405d 100644 --- a/ruoyi-fastapi-backend/config/get_db.py +++ b/ruoyi-fastapi-backend/config/get_db.py @@ -1,4 +1,4 @@ -from config.database import * +from config.database import async_engine, AsyncSessionLocal, Base from utils.log_util import logger @@ -16,7 +16,7 @@ async def init_create_table(): 应用启动时初始化数据库连接 :return: """ - logger.info("初始化数据库连接...") + logger.info('初始化数据库连接...') async with async_engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) - logger.info("数据库连接成功") + logger.info('数据库连接成功') diff --git a/ruoyi-fastapi-backend/config/get_redis.py b/ruoyi-fastapi-backend/config/get_redis.py index aa78f4c..0543193 100644 --- a/ruoyi-fastapi-backend/config/get_redis.py +++ b/ruoyi-fastapi-backend/config/get_redis.py @@ -1,9 +1,9 @@ from redis import asyncio as aioredis from redis.exceptions import AuthenticationError, TimeoutError, RedisError -from module_admin.service.dict_service import DictDataService -from module_admin.service.config_service import ConfigService -from config.env import RedisConfig from config.database import AsyncSessionLocal +from config.env import RedisConfig +from module_admin.service.config_service import ConfigService +from module_admin.service.dict_service import DictDataService from utils.log_util import logger @@ -18,28 +18,28 @@ class RedisUtil: 应用启动时初始化redis连接 :return: Redis连接对象 """ - logger.info("开始连接redis...") + logger.info('开始连接redis...') redis = await aioredis.from_url( - url=f"redis://{RedisConfig.redis_host}", + url=f'redis://{RedisConfig.redis_host}', port=RedisConfig.redis_port, username=RedisConfig.redis_username, password=RedisConfig.redis_password, db=RedisConfig.redis_database, - encoding="utf-8", - decode_responses=True + encoding='utf-8', + decode_responses=True, ) try: connection = await redis.ping() if connection: - logger.info("redis连接成功") + logger.info('redis连接成功') else: - logger.error("redis连接失败") + logger.error('redis连接失败') except AuthenticationError as e: - logger.error(f"redis用户名或密码错误,详细错误信息:{e}") + logger.error(f'redis用户名或密码错误,详细错误信息:{e}') except TimeoutError as e: - logger.error(f"redis连接超时,详细错误信息:{e}") + logger.error(f'redis连接超时,详细错误信息:{e}') except RedisError as e: - logger.error(f"redis连接错误,详细错误信息:{e}") + logger.error(f'redis连接错误,详细错误信息:{e}') return redis @classmethod @@ -50,7 +50,7 @@ class RedisUtil: :return: """ await app.state.redis.close() - logger.info("关闭redis连接成功") + logger.info('关闭redis连接成功') @classmethod async def init_sys_dict(cls, redis): diff --git a/ruoyi-fastapi-backend/config/get_scheduler.py b/ruoyi-fastapi-backend/config/get_scheduler.py index ae4f932..68c6f63 100644 --- a/ruoyi-fastapi-backend/config/get_scheduler.py +++ b/ruoyi-fastapi-backend/config/get_scheduler.py @@ -1,20 +1,21 @@ import json +from apscheduler.events import EVENT_ALL +from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor from apscheduler.schedulers.background import BackgroundScheduler -from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore from apscheduler.jobstores.memory import MemoryJobStore from apscheduler.jobstores.redis import RedisJobStore -from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor +from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore from apscheduler.triggers.cron import CronTrigger -from apscheduler.events import EVENT_ALL +from datetime import datetime, timedelta from sqlalchemy.engine import create_engine from sqlalchemy.orm import sessionmaker -from datetime import datetime, timedelta -from config.database import quote_plus, AsyncSessionLocal +from config.database import AsyncSessionLocal, quote_plus from config.env import DataBaseConfig, RedisConfig -from module_admin.service.job_log_service import JobLogService, JobLogModel from module_admin.dao.job_dao import JobDao +from module_admin.entity.vo.job_vo import JobLogModel +from module_admin.service.job_log_service import JobLogService from utils.log_util import logger -import module_task +import module_task # noqa: F401 # 重写Cron定时 @@ -48,8 +49,17 @@ class MyCronTrigger(CronTrigger): else: day_of_week = None year = values[6] if len(values) == 7 else None - return cls(second=second, minute=minute, hour=hour, day=day, month=month, week=week, - day_of_week=day_of_week, year=year, timezone=timezone) + return cls( + second=second, + minute=minute, + hour=hour, + day=day, + month=month, + week=week, + day_of_week=day_of_week, + year=year, + timezone=timezone, + ) @classmethod def __find_recent_workday(cls, day): @@ -67,15 +77,17 @@ class MyCronTrigger(CronTrigger): diff += 1 -SQLALCHEMY_DATABASE_URL = f"mysql+pymysql://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@" \ - f"{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}" +SQLALCHEMY_DATABASE_URL = ( + f'mysql+pymysql://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@' + f'{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}' +) engine = create_engine( SQLALCHEMY_DATABASE_URL, echo=DataBaseConfig.db_echo, max_overflow=DataBaseConfig.db_max_overflow, pool_size=DataBaseConfig.db_pool_size, pool_recycle=DataBaseConfig.db_pool_recycle, - pool_timeout=DataBaseConfig.db_pool_timeout + pool_timeout=DataBaseConfig.db_pool_timeout, ) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) job_stores = { @@ -87,18 +99,12 @@ job_stores = { port=RedisConfig.redis_port, username=RedisConfig.redis_username, password=RedisConfig.redis_password, - db=RedisConfig.redis_database + db=RedisConfig.redis_database, ) - ) -} -executors = { - 'default': ThreadPoolExecutor(20), - 'processpool': ProcessPoolExecutor(5) -} -job_defaults = { - 'coalesce': False, - 'max_instance': 1 + ), } +executors = {'default': ThreadPoolExecutor(20), 'processpool': ProcessPoolExecutor(5)} +job_defaults = {'coalesce': False, 'max_instance': 1} scheduler = BackgroundScheduler() scheduler.configure(jobstores=job_stores, executors=executors, job_defaults=job_defaults) @@ -114,7 +120,7 @@ class SchedulerUtil: 应用启动时初始化定时任务 :return: """ - logger.info("开始启动定时任务...") + logger.info('开始启动定时任务...') scheduler.start() async with AsyncSessionLocal() as session: job_list = await JobDao.get_job_list_for_scheduler(session) @@ -124,7 +130,7 @@ class SchedulerUtil: cls.remove_scheduler_job(job_id=str(item.job_id)) cls.add_scheduler_job(item) scheduler.add_listener(cls.scheduler_event_listener, EVENT_ALL) - logger.info("系统初始定时任务加载成功") + logger.info('系统初始定时任务加载成功') @classmethod async def close_system_scheduler(cls): @@ -133,7 +139,7 @@ class SchedulerUtil: :return: """ scheduler.shutdown() - logger.info("关闭定时任务成功") + logger.info('关闭定时任务成功') @classmethod def get_scheduler_job(cls, job_id): @@ -164,7 +170,7 @@ class SchedulerUtil: coalesce=True if job_info.misfire_policy == '2' else False, max_instances=3 if job_info.concurrent == '0' else 1, jobstore=job_info.job_group, - executor=job_info.job_executor + executor=job_info.job_executor, ) @classmethod @@ -186,7 +192,7 @@ class SchedulerUtil: coalesce=True if job_info.misfire_policy == '2' else False, max_instances=3 if job_info.concurrent == '0' else 1, jobstore=job_info.job_group, - executor=job_info.job_executor + executor=job_info.job_executor, ) @classmethod @@ -239,7 +245,7 @@ class SchedulerUtil: jobMessage=job_message, status=status, exceptionInfo=exception_info, - createTime=datetime.now() + createTime=datetime.now(), ) session = SessionLocal() JobLogService.add_job_log_services(session, job_log) -- Gitee From 13cfc607824d7d90a55e2df9a82f0a7d9d42d2db Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:21:37 +0800 Subject: [PATCH 098/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96exceptions=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/handle.py | 39 +++++++++++++--------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index 5895586..879019c 100644 --- a/ruoyi-fastapi-backend/exceptions/handle.py +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -1,15 +1,23 @@ from fastapi import FastAPI, Request from fastapi.exceptions import HTTPException from pydantic_validation_decorator import FieldValidationError -from exceptions.exception import AuthException, LoginException, PermissionException, ServiceException, ServiceWarning, ModelValidatorException +from exceptions.exception import ( + AuthException, + LoginException, + ModelValidatorException, + PermissionException, + ServiceException, + ServiceWarning, +) from utils.log_util import logger -from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder +from utils.response_util import jsonable_encoder, JSONResponse, ResponseUtil def handle_exception(app: FastAPI): """ 全局异常处理 """ + # 自定义token检验异常 @app.exception_handler(AuthException) async def auth_exception_handler(request: Request, exc: AuthException): @@ -20,6 +28,18 @@ def handle_exception(app: FastAPI): async def login_exception_handler(request: Request, exc: LoginException): return ResponseUtil.failure(data=exc.data, msg=exc.message) + # 自定义模型检验异常 + @app.exception_handler(ModelValidatorException) + async def model_validator_exception_handler(request: Request, exc: ModelValidatorException): + logger.warning(exc.message) + return ResponseUtil.failure(data=exc.data, msg=exc.message) + + # 自定义字段检验异常 + @app.exception_handler(FieldValidationError) + async def field_validation_error_handler(request: Request, exc: FieldValidationError): + logger.warning(exc.message) + return ResponseUtil.failure(msg=exc.message) + # 自定义权限检验异常 @app.exception_handler(PermissionException) async def permission_exception_handler(request: Request, exc: PermissionException): @@ -37,24 +57,11 @@ def handle_exception(app: FastAPI): logger.warning(exc.message) return ResponseUtil.failure(data=exc.data, msg=exc.message) - # 自定义模型检验异常 - @app.exception_handler(ModelValidatorException) - async def model_validator_exception_handler(request: Request, exc: ModelValidatorException): - logger.warning(exc.message) - return ResponseUtil.failure(data=exc.data, msg=exc.message) - - # 自定义字段检验异常 - @app.exception_handler(FieldValidationError) - async def field_validation_error_handler(request: Request, exc: FieldValidationError): - logger.warning(exc.message) - return ResponseUtil.failure(msg=exc.message) - # 处理其他http请求异常 @app.exception_handler(HTTPException) async def http_exception_handler(request: Request, exc: HTTPException): return JSONResponse( - content=jsonable_encoder({"code": exc.status_code, "msg": exc.detail}), - status_code=exc.status_code + content=jsonable_encoder({'code': exc.status_code, 'msg': exc.detail}), status_code=exc.status_code ) # 处理其他异常 -- Gitee From 44af38612c4c1faa6974f43cbeec5896674ee8fe Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:22:23 +0800 Subject: [PATCH 099/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96middlewares=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/middlewares/cors_middleware.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ruoyi-fastapi-backend/middlewares/cors_middleware.py b/ruoyi-fastapi-backend/middlewares/cors_middleware.py index 4b78db9..754fc1a 100644 --- a/ruoyi-fastapi-backend/middlewares/cors_middleware.py +++ b/ruoyi-fastapi-backend/middlewares/cors_middleware.py @@ -5,8 +5,8 @@ from fastapi.middleware.cors import CORSMiddleware def add_cors_middleware(app: FastAPI): # 前端页面url origins = [ - "http://localhost:80", - "http://127.0.0.1:80", + 'http://localhost:80', + 'http://127.0.0.1:80', ] # 后台api允许跨域 @@ -14,6 +14,6 @@ def add_cors_middleware(app: FastAPI): CORSMiddleware, allow_origins=origins, allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], + allow_methods=['*'], + allow_headers=['*'], ) -- Gitee From fea346413cf735c91c6fa099f9556170a4f67c83 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:23:01 +0800 Subject: [PATCH 100/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96module=5Ftask=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/module_task/__init__.py | 2 +- ruoyi-fastapi-backend/module_task/scheduler_test.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ruoyi-fastapi-backend/module_task/__init__.py b/ruoyi-fastapi-backend/module_task/__init__.py index 36fefe9..1f4b412 100644 --- a/ruoyi-fastapi-backend/module_task/__init__.py +++ b/ruoyi-fastapi-backend/module_task/__init__.py @@ -1 +1 @@ -from . import scheduler_test +from . import scheduler_test # noqa: F401 diff --git a/ruoyi-fastapi-backend/module_task/scheduler_test.py b/ruoyi-fastapi-backend/module_task/scheduler_test.py index b22dc6f..1c8441f 100644 --- a/ruoyi-fastapi-backend/module_task/scheduler_test.py +++ b/ruoyi-fastapi-backend/module_task/scheduler_test.py @@ -4,4 +4,4 @@ from datetime import datetime def job(*args, **kwargs): print(args) print(kwargs) - print(f"{datetime.now()}执行了") + print(f'{datetime.now()}执行了') -- Gitee From 7af22e97ad7dbf37d0c929d05f16ecf07dd27a9c Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:23:46 +0800 Subject: [PATCH 101/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96sub=5Fapplications=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/sub_applications/staticfiles.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/sub_applications/staticfiles.py b/ruoyi-fastapi-backend/sub_applications/staticfiles.py index 6899035..c481d72 100644 --- a/ruoyi-fastapi-backend/sub_applications/staticfiles.py +++ b/ruoyi-fastapi-backend/sub_applications/staticfiles.py @@ -7,4 +7,4 @@ def mount_staticfiles(app: FastAPI): """ 挂载静态文件 """ - app.mount(f"{UploadConfig.UPLOAD_PREFIX}", StaticFiles(directory=f"{UploadConfig.UPLOAD_PATH}"), name="profile") + app.mount(f'{UploadConfig.UPLOAD_PREFIX}', StaticFiles(directory=f'{UploadConfig.UPLOAD_PATH}'), name='profile') -- Gitee From bdb1a67d442699877a1f76ce521de3fd1297ace4 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:29:15 +0800 Subject: [PATCH 102/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96annotation=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/annotation/log_annotation.py | 64 ++++++++++++------- .../annotation/pydantic_annotation.py | 13 ++-- 2 files changed, 47 insertions(+), 30 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py index 6474b07..36f531b 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py @@ -1,23 +1,27 @@ -from functools import wraps, lru_cache -from fastapi import Request -from fastapi.responses import JSONResponse, ORJSONResponse, UJSONResponse import inspect -import os import json -import time -from datetime import datetime +import os import requests +import time import warnings +from datetime import datetime +from fastapi import Request +from fastapi.responses import JSONResponse, ORJSONResponse, UJSONResponse +from functools import lru_cache, wraps +from typing import Literal, Optional, Union from user_agents import parse -from typing import Optional, Union, Literal +from module_admin.entity.vo.log_vo import LogininforModel, OperLogModel +from module_admin.service.log_service import LoginLogService, OperationLogService from module_admin.service.login_service import LoginService -from module_admin.service.log_service import OperationLogService, LoginLogService -from module_admin.entity.vo.log_vo import OperLogModel, LogininforModel -from config.env import AppConfig from config.enums import BusinessType +from config.env import AppConfig -def log_decorator(title: str, business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], BusinessType], log_type: Optional[Literal['login', 'operation']] = 'operation'): +def log_decorator( + title: str, + business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], BusinessType], + log_type: Optional[Literal['login', 'operation']] = 'operation', +): """ 日志装饰器 :param log_type: 日志类型(login表示登录日志,为空表示为操作日志) @@ -29,7 +33,11 @@ def log_decorator(title: str, business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, if isinstance(business_type, BusinessType): business_type = business_type.value else: - warnings.warn('@log_decorator的business_type参数未来版本将不再支持int类型,请使用BusinessType枚举类型', category=DeprecationWarning, stacklevel=2) + warnings.warn( + '@log_decorator的business_type参数未来版本将不再支持int类型,请使用BusinessType枚举类型', + category=DeprecationWarning, + stacklevel=2, + ) def decorator(func): @wraps(func) @@ -50,22 +58,24 @@ def log_decorator(title: str, business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, request_method = request.method operator_type = 0 user_agent = request.headers.get('User-Agent') - if "Windows" in user_agent or "Macintosh" in user_agent or "Linux" in user_agent: + if 'Windows' in user_agent or 'Macintosh' in user_agent or 'Linux' in user_agent: operator_type = 1 - if "Mobile" in user_agent or "Android" in user_agent or "iPhone" in user_agent: + if 'Mobile' in user_agent or 'Android' in user_agent or 'iPhone' in user_agent: operator_type = 2 # 获取请求的url oper_url = request.url.path # 获取请求的ip及ip归属区域 - oper_ip = request.headers.get("X-Forwarded-For") + oper_ip = request.headers.get('X-Forwarded-For') oper_location = '内网IP' if AppConfig.app_ip_location_query: oper_location = get_ip_location(oper_ip) # 根据不同的请求类型使用不同的方法获取请求参数 - content_type = request.headers.get("Content-Type") - if content_type and ("multipart/form-data" in content_type or 'application/x-www-form-urlencoded' in content_type): + content_type = request.headers.get('Content-Type') + if content_type and ( + 'multipart/form-data' in content_type or 'application/x-www-form-urlencoded' in content_type + ): payload = await request.form() - oper_param = "\n".join([f"{key}: {value}" for key, value in payload.items()]) + oper_param = '\n'.join([f'{key}: {value}' for key, value in payload.items()]) else: payload = await request.body() # 通过 request.path_params 直接访问路径参数 @@ -97,7 +107,7 @@ def log_decorator(title: str, business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, loginLocation=oper_location, browser=browser, os=system_os, - loginTime=oper_time.strftime('%Y-%m-%d %H:%M:%S') + loginTime=oper_time.strftime('%Y-%m-%d %H:%M:%S'), ) kwargs['form_data'].login_info = login_log # 调用原始函数 @@ -105,10 +115,18 @@ def log_decorator(title: str, business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, # 获取请求耗时 cost_time = float(time.time() - start_time) * 100 # 判断请求是否来自api文档 - request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False - request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False + request_from_swagger = ( + request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False + ) + request_from_redoc = ( + request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False + ) # 根据响应结果的类型使用不同的方法获取响应结果参数 - if isinstance(result, JSONResponse) or isinstance(result, ORJSONResponse) or isinstance(result, UJSONResponse): + if ( + isinstance(result, JSONResponse) + or isinstance(result, ORJSONResponse) + or isinstance(result, UJSONResponse) + ): result_dict = json.loads(str(result.body, 'utf-8')) else: if request_from_swagger or request_from_redoc: @@ -160,7 +178,7 @@ def log_decorator(title: str, business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, status=status, errorMsg=error_msg, operTime=oper_time, - costTime=int(cost_time) + costTime=int(cost_time), ) await OperationLogService.add_operation_log_services(query_db, operation_log) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/pydantic_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/pydantic_annotation.py index 3069015..3b7070f 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/pydantic_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/pydantic_annotation.py @@ -1,9 +1,8 @@ import inspect -from typing import Type - -from fastapi import Query, Form +from fastapi import Form, Query from pydantic import BaseModel from pydantic.fields import FieldInfo +from typing import Type def as_query(cls: Type[BaseModel]): @@ -21,7 +20,7 @@ def as_query(cls: Type[BaseModel]): model_field.alias, inspect.Parameter.POSITIONAL_ONLY, default=Query(model_field.default), - annotation=model_field.annotation + annotation=model_field.annotation, ) ) else: @@ -30,7 +29,7 @@ def as_query(cls: Type[BaseModel]): model_field.alias, inspect.Parameter.POSITIONAL_ONLY, default=Query(...), - annotation=model_field.annotation + annotation=model_field.annotation, ) ) @@ -59,7 +58,7 @@ def as_form(cls: Type[BaseModel]): model_field.alias, inspect.Parameter.POSITIONAL_ONLY, default=Form(model_field.default), - annotation=model_field.annotation + annotation=model_field.annotation, ) ) else: @@ -68,7 +67,7 @@ def as_form(cls: Type[BaseModel]): model_field.alias, inspect.Parameter.POSITIONAL_ONLY, default=Form(...), - annotation=model_field.annotation + annotation=model_field.annotation, ) ) -- Gitee From 5dd6513706049f6e58e69bc789aa4fc957e4117d Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:31:10 +0800 Subject: [PATCH 103/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96aspect=E6=A8=A1=E5=9D=97=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/aspect/data_scope.py | 15 ++++++++++++--- .../module_admin/aspect/interface_auth.py | 11 ++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py b/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py index f097907..7183a88 100644 --- a/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py +++ b/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py @@ -1,14 +1,21 @@ from fastapi import Depends +from typing import Optional from module_admin.entity.vo.user_vo import CurrentUserModel from module_admin.service.login_service import LoginService -from typing import Optional class GetDataScope: """ 获取当前用户数据权限对应的查询sql语句 """ - def __init__(self, query_alias: Optional[str] = '', db_alias: Optional[str] = 'db', user_alias: Optional[str] = 'user_id', dept_alias: Optional[str] = 'dept_id'): + + def __init__( + self, + query_alias: Optional[str] = '', + db_alias: Optional[str] = 'db', + user_alias: Optional[str] = 'user_id', + dept_alias: Optional[str] = 'dept_id', + ): self.query_alias = query_alias self.db_alias = db_alias self.user_alias = user_alias @@ -17,7 +24,9 @@ class GetDataScope: def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)): user_id = current_user.user.user_id dept_id = current_user.user.dept_id - role_datascope_list = [dict(role_id=item.role_id, data_scope=int(item.data_scope)) for item in current_user.user.role] + role_datascope_list = [ + dict(role_id=item.role_id, data_scope=int(item.data_scope)) for item in current_user.user.role + ] max_data_scope_dict = min(role_datascope_list, key=lambda x: x['data_scope']) max_role_id = max_data_scope_dict['role_id'] max_data_scope = max_data_scope_dict['data_scope'] diff --git a/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py b/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py index e688ad8..486cd72 100644 --- a/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py +++ b/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py @@ -1,8 +1,8 @@ from fastapi import Depends -from typing import Union, List +from typing import List, Union +from exceptions.exception import PermissionException from module_admin.entity.vo.user_vo import CurrentUserModel from module_admin.service.login_service import LoginService -from exceptions.exception import PermissionException class CheckUserInterfaceAuth: @@ -11,6 +11,7 @@ class CheckUserInterfaceAuth: :param perm: 权限标识 :param is_strict: 当传入的权限标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个权限标识,所有的校验结果都需要为True才会通过 """ + def __init__(self, perm: Union[str, List], is_strict: bool = False): self.perm = perm self.is_strict = is_strict @@ -29,7 +30,7 @@ class CheckUserInterfaceAuth: else: if any([perm_str in user_auth_list for perm_str in self.perm]): return True - raise PermissionException(data="", message="该用户无此接口权限") + raise PermissionException(data='', message='该用户无此接口权限') class CheckRoleInterfaceAuth: @@ -38,6 +39,7 @@ class CheckRoleInterfaceAuth: :param role_key: 角色标识 :param is_strict: 当传入的角色标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个角色标识,所有的校验结果都需要为True才会通过 """ + def __init__(self, role_key: Union[str, List], is_strict: bool = False): self.role_key = role_key self.is_strict = is_strict @@ -55,5 +57,4 @@ class CheckRoleInterfaceAuth: else: if any([role_key_str in user_role_key_list for role_key_str in self.role_key]): return True - raise PermissionException(data="", message="该用户无此接口权限") - + raise PermissionException(data='', message='该用户无此接口权限') -- Gitee From 5d8b177a12f2ae844610e5dfc15676c913852db6 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:35:58 +0800 Subject: [PATCH 104/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96server.py=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/server.py | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/ruoyi-fastapi-backend/server.py b/ruoyi-fastapi-backend/server.py index f7f85c2..00b4661 100644 --- a/ruoyi-fastapi-backend/server.py +++ b/ruoyi-fastapi-backend/server.py @@ -1,43 +1,43 @@ -from fastapi import FastAPI from contextlib import asynccontextmanager -from sub_applications.handle import handle_sub_applications -from middlewares.handle import handle_middleware +from fastapi import FastAPI +from config.env import AppConfig +from config.get_db import init_create_table +from config.get_redis import RedisUtil +from config.get_scheduler import SchedulerUtil from exceptions.handle import handle_exception -from module_admin.controller.login_controller import loginController +from middlewares.handle import handle_middleware +from module_admin.controller.cache_controller import cacheController from module_admin.controller.captcha_controller import captchaController -from module_admin.controller.user_controller import userController -from module_admin.controller.menu_controller import menuController +from module_admin.controller.common_controller import commonController +from module_admin.controller.config_controller import configController from module_admin.controller.dept_controller import deptController -from module_admin.controller.role_controller import roleController -from module_admin.controller.post_controler import postController from module_admin.controller.dict_controller import dictController -from module_admin.controller.config_controller import configController -from module_admin.controller.notice_controller import noticeController from module_admin.controller.log_controller import logController -from module_admin.controller.online_controller import onlineController +from module_admin.controller.login_controller import loginController from module_admin.controller.job_controller import jobController +from module_admin.controller.menu_controller import menuController +from module_admin.controller.notice_controller import noticeController +from module_admin.controller.online_controller import onlineController +from module_admin.controller.post_controler import postController +from module_admin.controller.role_controller import roleController from module_admin.controller.server_controller import serverController -from module_admin.controller.cache_controller import cacheController -from module_admin.controller.common_controller import commonController -from config.env import AppConfig -from config.get_redis import RedisUtil -from config.get_db import init_create_table -from config.get_scheduler import SchedulerUtil -from utils.log_util import logger +from module_admin.controller.user_controller import userController +from sub_applications.handle import handle_sub_applications from utils.common_util import worship +from utils.log_util import logger # 生命周期事件 @asynccontextmanager async def lifespan(app: FastAPI): - logger.info(f"{AppConfig.app_name}开始启动") + logger.info(f'{AppConfig.app_name}开始启动') worship() await init_create_table() app.state.redis = await RedisUtil.create_redis_pool() await RedisUtil.init_sys_dict(app.state.redis) await RedisUtil.init_sys_config(app.state.redis) await SchedulerUtil.init_system_scheduler() - logger.info(f"{AppConfig.app_name}启动成功") + logger.info(f'{AppConfig.app_name}启动成功') yield await RedisUtil.close_redis_pool(app) await SchedulerUtil.close_system_scheduler() @@ -48,7 +48,7 @@ app = FastAPI( title=AppConfig.app_name, description=f'{AppConfig.app_name}接口文档', version=AppConfig.app_version, - lifespan=lifespan + lifespan=lifespan, ) # 挂载子应用 @@ -76,7 +76,7 @@ controller_list = [ {'router': jobController, 'tags': ['系统监控-定时任务']}, {'router': serverController, 'tags': ['系统监控-菜单管理']}, {'router': cacheController, 'tags': ['系统监控-缓存监控']}, - {'router': commonController, 'tags': ['通用模块']} + {'router': commonController, 'tags': ['通用模块']}, ] for controller in controller_list: -- Gitee From c23a3ccfafdaf6a4ccd4371eb958b5ab63c44e6b Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 12 Jul 2024 11:36:06 +0800 Subject: [PATCH 105/129] =?UTF-8?q?style:=20=E4=BD=BF=E7=94=A8ruff?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96app.py=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=AF=BC=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/app.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruoyi-fastapi-backend/app.py b/ruoyi-fastapi-backend/app.py index 7797fa9..1ee7695 100644 --- a/ruoyi-fastapi-backend/app.py +++ b/ruoyi-fastapi-backend/app.py @@ -1,5 +1,5 @@ import uvicorn -from server import app, AppConfig +from server import app, AppConfig # noqa: F401 if __name__ == '__main__': @@ -8,5 +8,5 @@ if __name__ == '__main__': host=AppConfig.app_host, port=AppConfig.app_port, root_path=AppConfig.app_root_path, - reload=AppConfig.app_reload + reload=AppConfig.app_reload, ) -- Gitee From e3b422cc6e82f4b4f86082c794ca3bdbd4385aa2 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sat, 13 Jul 2024 18:15:35 +0800 Subject: [PATCH 106/129] =?UTF-8?q?style:=20=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=96=87=E4=BB=B6=E4=B8=AD=E7=9A=84=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E5=8F=8A=E7=B1=BB=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/config/constant.py | 3 ++ ruoyi-fastapi-backend/config/enums.py | 1 + ruoyi-fastapi-backend/config/get_db.py | 2 ++ ruoyi-fastapi-backend/config/get_redis.py | 4 +++ ruoyi-fastapi-backend/config/get_scheduler.py | 6 ++++ .../module_admin/annotation/log_annotation.py | 4 ++- .../module_admin/aspect/interface_auth.py | 16 +++++++--- .../module_admin/dao/config_dao.py | 6 ++++ .../module_admin/dao/dept_dao.py | 15 +++++++++ .../module_admin/dao/dict_dao.py | 15 +++++++++ .../module_admin/dao/job_dao.py | 7 ++++ .../module_admin/dao/job_log_dao.py | 4 +++ .../module_admin/dao/log_dao.py | 8 +++++ .../module_admin/dao/login_dao.py | 1 + .../module_admin/dao/menu_dao.py | 9 ++++++ .../module_admin/dao/notice_dao.py | 6 ++++ .../module_admin/dao/post_dao.py | 8 +++++ .../module_admin/dao/role_dao.py | 16 ++++++++++ .../module_admin/dao/user_dao.py | 17 ++++++++++ .../module_admin/service/cache_service.py | 7 ++++ .../module_admin/service/common_service.py | 3 ++ .../module_admin/service/config_service.py | 10 ++++++ .../module_admin/service/dept_service.py | 13 ++++++++ .../module_admin/service/dict_service.py | 18 +++++++++++ .../module_admin/service/job_log_service.py | 5 +++ .../module_admin/service/job_service.py | 7 ++++ .../module_admin/service/log_service.py | 10 ++++++ .../module_admin/service/login_service.py | 20 ++++++++++++ .../module_admin/service/menu_service.py | 9 ++++++ .../module_admin/service/notice_service.py | 6 ++++ .../module_admin/service/online_service.py | 2 ++ .../module_admin/service/post_service.py | 8 +++++ .../module_admin/service/role_service.py | 15 +++++++++ .../module_admin/service/user_service.py | 21 +++++++++++- ruoyi-fastapi-backend/utils/common_util.py | 9 +++++- ruoyi-fastapi-backend/utils/page_util.py | 3 ++ ruoyi-fastapi-backend/utils/pwd_util.py | 2 ++ ruoyi-fastapi-backend/utils/response_util.py | 20 ++++++++---- ruoyi-fastapi-backend/utils/string_util.py | 3 ++ .../utils/time_format_util.py | 1 + ruoyi-fastapi-backend/utils/upload_util.py | 32 ++++++++++++++++--- 41 files changed, 353 insertions(+), 19 deletions(-) diff --git a/ruoyi-fastapi-backend/config/constant.py b/ruoyi-fastapi-backend/config/constant.py index e30fa78..46ad2ea 100644 --- a/ruoyi-fastapi-backend/config/constant.py +++ b/ruoyi-fastapi-backend/config/constant.py @@ -1,6 +1,7 @@ class CommonConstant: """ 常用常量 + WWW: www主域 HTTP: http请求 HTTPS: https请求 @@ -26,6 +27,7 @@ class CommonConstant: class HttpStatusConstant: """ 返回状态码 + SUCCESS: 操作成功 CREATED: 对象创建成功 ACCEPTED: 请求已经被接受 @@ -67,6 +69,7 @@ class HttpStatusConstant: class MenuConstant: """ 菜单常量 + TYPE_DIR: 菜单类型(目录) TYPE_MENU: 菜单类型(菜单) TYPE_BUTTON: 菜单类型(按钮) diff --git a/ruoyi-fastapi-backend/config/enums.py b/ruoyi-fastapi-backend/config/enums.py index 673a4cb..d1a9e56 100644 --- a/ruoyi-fastapi-backend/config/enums.py +++ b/ruoyi-fastapi-backend/config/enums.py @@ -4,6 +4,7 @@ from enum import Enum class BusinessType(Enum): """ 业务操作类型 + OTHER: 其它 INSERT: 新增 UPDATE: 修改 diff --git a/ruoyi-fastapi-backend/config/get_db.py b/ruoyi-fastapi-backend/config/get_db.py index d88405d..20986ae 100644 --- a/ruoyi-fastapi-backend/config/get_db.py +++ b/ruoyi-fastapi-backend/config/get_db.py @@ -5,6 +5,7 @@ from utils.log_util import logger async def get_db(): """ 每一个请求处理完毕后会关闭当前连接,不同的请求使用不同的连接 + :return: """ async with AsyncSessionLocal() as current_db: @@ -14,6 +15,7 @@ async def get_db(): async def init_create_table(): """ 应用启动时初始化数据库连接 + :return: """ logger.info('初始化数据库连接...') diff --git a/ruoyi-fastapi-backend/config/get_redis.py b/ruoyi-fastapi-backend/config/get_redis.py index 0543193..9d78cad 100644 --- a/ruoyi-fastapi-backend/config/get_redis.py +++ b/ruoyi-fastapi-backend/config/get_redis.py @@ -16,6 +16,7 @@ class RedisUtil: async def create_redis_pool(cls) -> aioredis.Redis: """ 应用启动时初始化redis连接 + :return: Redis连接对象 """ logger.info('开始连接redis...') @@ -46,6 +47,7 @@ class RedisUtil: async def close_redis_pool(cls, app): """ 应用关闭时关闭redis连接 + :param app: fastapi对象 :return: """ @@ -56,6 +58,7 @@ class RedisUtil: async def init_sys_dict(cls, redis): """ 应用启动时缓存字典表 + :param redis: redis对象 :return: """ @@ -66,6 +69,7 @@ class RedisUtil: async def init_sys_config(cls, redis): """ 应用启动时缓存参数配置表 + :param redis: redis对象 :return: """ diff --git a/ruoyi-fastapi-backend/config/get_scheduler.py b/ruoyi-fastapi-backend/config/get_scheduler.py index 68c6f63..b9cfa00 100644 --- a/ruoyi-fastapi-backend/config/get_scheduler.py +++ b/ruoyi-fastapi-backend/config/get_scheduler.py @@ -118,6 +118,7 @@ class SchedulerUtil: async def init_system_scheduler(cls): """ 应用启动时初始化定时任务 + :return: """ logger.info('开始启动定时任务...') @@ -136,6 +137,7 @@ class SchedulerUtil: async def close_system_scheduler(cls): """ 应用关闭时关闭定时任务 + :return: """ scheduler.shutdown() @@ -145,6 +147,7 @@ class SchedulerUtil: def get_scheduler_job(cls, job_id): """ 根据任务id获取任务对象 + :param job_id: 任务id :return: 任务对象 """ @@ -156,6 +159,7 @@ class SchedulerUtil: def add_scheduler_job(cls, job_info): """ 根据输入的任务对象信息添加任务 + :param job_info: 任务对象信息 :return: """ @@ -177,6 +181,7 @@ class SchedulerUtil: def execute_scheduler_job_once(cls, job_info): """ 根据输入的任务对象执行一次任务 + :param job_info: 任务对象信息 :return: """ @@ -199,6 +204,7 @@ class SchedulerUtil: def remove_scheduler_job(cls, job_id): """ 根据任务id移除任务 + :param job_id: 任务id :return: """ diff --git a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py index 36f531b..a074c5b 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py @@ -24,9 +24,10 @@ def log_decorator( ): """ 日志装饰器 - :param log_type: 日志类型(login表示登录日志,为空表示为操作日志) + :param title: 当前日志装饰器装饰的模块标题 :param business_type: 业务类型(0其它 1新增 2修改 3删除 4授权 5导出 6导入 7强退 8生成代码 9清空数据) + :param log_type: 日志类型(login表示登录日志,operation表示为操作日志) :return: """ warnings.simplefilter('always', category=DeprecationWarning) @@ -193,6 +194,7 @@ def log_decorator( def get_ip_location(oper_ip: str): """ 查询ip归属区域 + :param oper_ip: 需要查询的ip :return: ip归属区域 """ diff --git a/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py b/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py index 486cd72..8f8349d 100644 --- a/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py +++ b/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py @@ -8,11 +8,15 @@ from module_admin.service.login_service import LoginService class CheckUserInterfaceAuth: """ 校验当前用户是否具有相应的接口权限 - :param perm: 权限标识 - :param is_strict: 当传入的权限标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个权限标识,所有的校验结果都需要为True才会通过 """ def __init__(self, perm: Union[str, List], is_strict: bool = False): + """ + 校验当前用户是否具有相应的接口权限 + + :param perm: 权限标识 + :param is_strict: 当传入的权限标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个权限标识,所有的校验结果都需要为True才会通过 + """ self.perm = perm self.is_strict = is_strict @@ -36,11 +40,15 @@ class CheckUserInterfaceAuth: class CheckRoleInterfaceAuth: """ 根据角色校验当前用户是否具有相应的接口权限 - :param role_key: 角色标识 - :param is_strict: 当传入的角色标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个角色标识,所有的校验结果都需要为True才会通过 """ def __init__(self, role_key: Union[str, List], is_strict: bool = False): + """ + 根据角色校验当前用户是否具有相应的接口权限 + + :param role_key: 角色标识 + :param is_strict: 当传入的角色标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个角色标识,所有的校验结果都需要为True才会通过 + """ self.role_key = role_key self.is_strict = is_strict diff --git a/ruoyi-fastapi-backend/module_admin/dao/config_dao.py b/ruoyi-fastapi-backend/module_admin/dao/config_dao.py index df3e3f4..7b3c067 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/config_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/config_dao.py @@ -15,6 +15,7 @@ class ConfigDao: async def get_config_detail_by_id(cls, db: AsyncSession, config_id: int): """ 根据参数配置id获取参数配置详细信息 + :param db: orm对象 :param config_id: 参数配置id :return: 参数配置信息对象 @@ -27,6 +28,7 @@ class ConfigDao: async def get_config_detail_by_info(cls, db: AsyncSession, config: ConfigModel): """ 根据参数配置参数获取参数配置信息 + :param db: orm对象 :param config: 参数配置参数对象 :return: 参数配置信息对象 @@ -50,6 +52,7 @@ class ConfigDao: async def get_config_list(cls, db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False): """ 根据查询参数获取参数配置列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -78,6 +81,7 @@ class ConfigDao: async def add_config_dao(cls, db: AsyncSession, config: ConfigModel): """ 新增参数配置数据库操作 + :param db: orm对象 :param config: 参数配置对象 :return: @@ -92,6 +96,7 @@ class ConfigDao: async def edit_config_dao(cls, db: AsyncSession, config: dict): """ 编辑参数配置数据库操作 + :param db: orm对象 :param config: 需要更新的参数配置字典 :return: @@ -102,6 +107,7 @@ class ConfigDao: async def delete_config_dao(cls, db: AsyncSession, config: ConfigModel): """ 删除参数配置数据库操作 + :param db: orm对象 :param config: 参数配置对象 :return: diff --git a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py index cfd7c2e..8a4d64d 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py @@ -17,6 +17,7 @@ class DeptDao: async def get_dept_by_id(cls, db: AsyncSession, dept_id: int): """ 根据部门id获取在用部门信息 + :param db: orm对象 :param dept_id: 部门id :return: 在用部门信息对象 @@ -29,6 +30,7 @@ class DeptDao: async def get_dept_detail_by_id(cls, db: AsyncSession, dept_id: int): """ 根据部门id获取部门详细信息 + :param db: orm对象 :param dept_id: 部门id :return: 部门信息对象 @@ -45,6 +47,7 @@ class DeptDao: async def get_dept_detail_by_info(cls, db: AsyncSession, dept: DeptModel): """ 根据部门参数获取部门信息 + :param db: orm对象 :param dept: 部门参数对象 :return: 部门信息对象 @@ -68,6 +71,7 @@ class DeptDao: async def get_dept_info_for_edit_option(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str): """ 获取部门编辑对应的在用部门列表信息 + :param db: orm对象 :param dept_info: 部门对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -100,6 +104,7 @@ class DeptDao: async def get_children_dept_dao(cls, db: AsyncSession, dept_id: int): """ 根据部门id查询当前部门的子部门列表信息 + :param db: orm对象 :param dept_id: 部门id :return: 子部门信息列表 @@ -114,6 +119,7 @@ class DeptDao: async def get_dept_list_for_tree(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str): """ 获取所有在用部门列表信息 + :param db: orm对象 :param dept_info: 部门对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -143,6 +149,7 @@ class DeptDao: async def get_dept_list(cls, db: AsyncSession, page_object: DeptModel, data_scope_sql: str): """ 根据查询参数获取部门列表信息 + :param db: orm对象 :param page_object: 不分页查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -172,6 +179,7 @@ class DeptDao: async def add_dept_dao(cls, db: AsyncSession, dept: DeptModel): """ 新增部门数据库操作 + :param db: orm对象 :param dept: 部门对象 :return: 新增校验结果 @@ -186,6 +194,7 @@ class DeptDao: async def edit_dept_dao(cls, db: AsyncSession, dept: dict): """ 编辑部门数据库操作 + :param db: orm对象 :param dept: 需要更新的部门字典 :return: 编辑校验结果 @@ -196,6 +205,7 @@ class DeptDao: async def update_dept_children_dao(cls, db: AsyncSession, update_dept: List): """ 更新子部门信息 + :param db: orm对象 :param update_dept: 需要更新的部门列表 :return: @@ -217,6 +227,7 @@ class DeptDao: async def update_dept_status_normal_dao(cls, db: AsyncSession, dept_id_list: List): """ 批量更新部门状态为正常 + :param db: orm对象 :param dept_id_list: 部门id列表 :return: @@ -227,6 +238,7 @@ class DeptDao: async def delete_dept_dao(cls, db: AsyncSession, dept: DeptModel): """ 删除部门数据库操作 + :param db: orm对象 :param dept: 部门对象 :return: @@ -241,6 +253,7 @@ class DeptDao: async def count_normal_children_dept_dao(cls, db: AsyncSession, dept_id: int): """ 根据部门id查询查询所有子部门(正常状态)的数量 + :param db: orm对象 :param dept_id: 部门id :return: 所有子部门(正常状态)的数量 @@ -259,6 +272,7 @@ class DeptDao: async def count_children_dept_dao(cls, db: AsyncSession, dept_id: int): """ 根据部门id查询查询所有子部门(所有状态)的数量 + :param db: orm对象 :param dept_id: 部门id :return: 所有子部门(所有状态)的数量 @@ -278,6 +292,7 @@ class DeptDao: async def count_dept_user_dao(cls, db: AsyncSession, dept_id: int): """ 根据部门id查询查询部门下的用户数量 + :param db: orm对象 :param dept_id: 部门id :return: 部门下的用户数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py index 2c4460c..8f4aab2 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py @@ -16,6 +16,7 @@ class DictTypeDao: async def get_dict_type_detail_by_id(cls, db: AsyncSession, dict_id: int): """ 根据字典类型id获取字典类型详细信息 + :param db: orm对象 :param dict_id: 字典类型id :return: 字典类型信息对象 @@ -28,6 +29,7 @@ class DictTypeDao: async def get_dict_type_detail_by_info(cls, db: AsyncSession, dict_type: DictTypeModel): """ 根据字典类型参数获取字典类型信息 + :param db: orm对象 :param dict_type: 字典类型参数对象 :return: 字典类型信息对象 @@ -51,6 +53,7 @@ class DictTypeDao: async def get_all_dict_type(cls, db: AsyncSession): """ 获取所有的字典类型信息 + :param db: orm对象 :return: 字典类型信息列表对象 """ @@ -62,6 +65,7 @@ class DictTypeDao: async def get_dict_type_list(cls, db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False): """ 根据查询参数获取字典类型列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -90,6 +94,7 @@ class DictTypeDao: async def add_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel): """ 新增字典类型数据库操作 + :param db: orm对象 :param dict_type: 字典类型对象 :return: @@ -104,6 +109,7 @@ class DictTypeDao: async def edit_dict_type_dao(cls, db: AsyncSession, dict_type: dict): """ 编辑字典类型数据库操作 + :param db: orm对象 :param dict_type: 需要更新的字典类型字典 :return: @@ -114,6 +120,7 @@ class DictTypeDao: async def delete_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel): """ 删除字典类型数据库操作 + :param db: orm对象 :param dict_type: 字典类型对象 :return: @@ -130,6 +137,7 @@ class DictDataDao: async def get_dict_data_detail_by_id(cls, db: AsyncSession, dict_code: int): """ 根据字典数据id获取字典数据详细信息 + :param db: orm对象 :param dict_code: 字典数据id :return: 字典数据信息对象 @@ -144,6 +152,7 @@ class DictDataDao: async def get_dict_data_detail_by_info(cls, db: AsyncSession, dict_data: DictDataModel): """ 根据字典数据参数获取字典数据信息 + :param db: orm对象 :param dict_data: 字典数据参数对象 :return: 字典数据信息对象 @@ -168,6 +177,7 @@ class DictDataDao: async def get_dict_data_list(cls, db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False): """ 根据查询参数获取字典数据列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -191,6 +201,7 @@ class DictDataDao: async def query_dict_data_list(cls, db: AsyncSession, dict_type: str): """ 根据查询参数获取字典数据列表信息 + :param db: orm对象 :param dict_type: 字典类型 :return: 字典数据列表信息对象 @@ -220,6 +231,7 @@ class DictDataDao: async def add_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel): """ 新增字典数据数据库操作 + :param db: orm对象 :param dict_data: 字典数据对象 :return: @@ -234,6 +246,7 @@ class DictDataDao: async def edit_dict_data_dao(cls, db: AsyncSession, dict_data: dict): """ 编辑字典数据数据库操作 + :param db: orm对象 :param dict_data: 需要更新的字典数据字典 :return: @@ -244,6 +257,7 @@ class DictDataDao: async def delete_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel): """ 删除字典数据数据库操作 + :param db: orm对象 :param dict_data: 字典数据对象 :return: @@ -254,6 +268,7 @@ class DictDataDao: async def count_dict_data_dao(cls, db: AsyncSession, dict_type: str): """ 根据字典类型查询字典类型关联的字典数据数量 + :param db: orm对象 :param dict_type: 字典类型 :return: 字典类型关联的字典数据数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py index 4c984f8..c2488c1 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py @@ -14,6 +14,7 @@ class JobDao: async def get_job_detail_by_id(cls, db: AsyncSession, job_id: int): """ 根据定时任务id获取定时任务详细信息 + :param db: orm对象 :param job_id: 定时任务id :return: 定时任务信息对象 @@ -26,6 +27,7 @@ class JobDao: async def get_job_detail_by_info(cls, db: AsyncSession, job: JobModel): """ 根据定时任务参数获取定时任务信息 + :param db: orm对象 :param job: 定时任务参数对象 :return: 定时任务信息对象 @@ -51,6 +53,7 @@ class JobDao: async def get_job_list(cls, db: AsyncSession, query_object: JobPageQueryModel, is_page: bool = False): """ 根据查询参数获取定时任务列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -73,6 +76,7 @@ class JobDao: async def get_job_list_for_scheduler(cls, db: AsyncSession): """ 获取定时任务列表信息 + :param db: orm对象 :return: 定时任务列表信息对象 """ @@ -84,6 +88,7 @@ class JobDao: async def add_job_dao(cls, db: AsyncSession, job: JobModel): """ 新增定时任务数据库操作 + :param db: orm对象 :param job: 定时任务对象 :return: @@ -98,6 +103,7 @@ class JobDao: async def edit_job_dao(cls, db: AsyncSession, job: dict): """ 编辑定时任务数据库操作 + :param db: orm对象 :param job: 需要更新的定时任务字典 :return: @@ -108,6 +114,7 @@ class JobDao: async def delete_job_dao(cls, db: AsyncSession, job: JobModel): """ 删除定时任务数据库操作 + :param db: orm对象 :param job: 定时任务对象 :return: diff --git a/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py b/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py index 6d64a91..730be5a 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py @@ -16,6 +16,7 @@ class JobLogDao: async def get_job_log_list(cls, db: AsyncSession, query_object: JobLogPageQueryModel, is_page: bool = False): """ 根据查询参数获取定时任务日志列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -44,6 +45,7 @@ class JobLogDao: def add_job_log_dao(cls, db: Session, job_log: JobLogModel): """ 新增定时任务日志数据库操作 + :param db: orm对象 :param job_log: 定时任务日志对象 :return: @@ -58,6 +60,7 @@ class JobLogDao: async def delete_job_log_dao(cls, db: AsyncSession, job_log: JobLogModel): """ 删除定时任务日志数据库操作 + :param db: orm对象 :param job_log: 定时任务日志对象 :return: @@ -68,6 +71,7 @@ class JobLogDao: async def clear_job_log_dao(cls, db: AsyncSession): """ 清除定时任务日志数据库操作 + :param db: orm对象 :return: """ diff --git a/ruoyi-fastapi-backend/module_admin/dao/log_dao.py b/ruoyi-fastapi-backend/module_admin/dao/log_dao.py index 547aca9..1e4ad41 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/log_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/log_dao.py @@ -16,6 +16,7 @@ class OperationLogDao: async def get_operation_log_list(cls, db: AsyncSession, query_object: OperLogPageQueryModel, is_page: bool = False): """ 根据查询参数获取操作日志列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -54,6 +55,7 @@ class OperationLogDao: async def add_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel): """ 新增操作日志数据库操作 + :param db: orm对象 :param operation_log: 操作日志对象 :return: 新增校验结果 @@ -68,6 +70,7 @@ class OperationLogDao: async def delete_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel): """ 删除操作日志数据库操作 + :param db: orm对象 :param operation_log: 操作日志对象 :return: @@ -78,6 +81,7 @@ class OperationLogDao: async def clear_operation_log_dao(cls, db: AsyncSession): """ 清除操作日志数据库操作 + :param db: orm对象 :return: """ @@ -93,6 +97,7 @@ class LoginLogDao: async def get_login_log_list(cls, db: AsyncSession, query_object: LoginLogPageQueryModel, is_page: bool = False): """ 根据查询参数获取登录日志列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -132,6 +137,7 @@ class LoginLogDao: async def add_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel): """ 新增登录日志数据库操作 + :param db: orm对象 :param login_log: 登录日志对象 :return: 新增校验结果 @@ -146,6 +152,7 @@ class LoginLogDao: async def delete_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel): """ 删除登录日志数据库操作 + :param db: orm对象 :param login_log: 登录日志对象 :return: @@ -156,6 +163,7 @@ class LoginLogDao: async def clear_login_log_dao(cls, db: AsyncSession): """ 清除登录日志数据库操作 + :param db: orm对象 :return: """ diff --git a/ruoyi-fastapi-backend/module_admin/dao/login_dao.py b/ruoyi-fastapi-backend/module_admin/dao/login_dao.py index 9bafa65..9764a4a 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/login_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/login_dao.py @@ -7,6 +7,7 @@ from module_admin.entity.do.user_do import SysUser async def login_by_account(db: AsyncSession, user_name: str): """ 根据用户名查询用户信息 + :param db: orm对象 :param user_name: 用户名 :return: 用户对象 diff --git a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py index 223b84e..19831e0 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py @@ -15,6 +15,7 @@ class MenuDao: async def get_menu_detail_by_id(cls, db: AsyncSession, menu_id: int): """ 根据菜单id获取菜单详细信息 + :param db: orm对象 :param menu_id: 菜单id :return: 菜单信息对象 @@ -27,6 +28,7 @@ class MenuDao: async def get_menu_detail_by_info(cls, db: AsyncSession, menu: MenuModel): """ 根据菜单参数获取菜单信息 + :param db: orm对象 :param menu: 菜单参数对象 :return: 菜单信息对象 @@ -51,6 +53,7 @@ class MenuDao: async def get_menu_list_for_tree(cls, db: AsyncSession, user_id: int, role: list): """ 根据角色信息获取所有在用菜单列表信息 + :param db: orm对象 :param user_id: 用户id :param role: 用户角色列表信息 @@ -94,6 +97,7 @@ class MenuDao: async def get_menu_list(cls, db: AsyncSession, page_object: MenuQueryModel, user_id: int, role: list): """ 根据查询参数获取菜单列表信息 + :param db: orm对象 :param page_object: 不分页查询参数对象 :param user_id: 用户id @@ -155,6 +159,7 @@ class MenuDao: async def add_menu_dao(cls, db: AsyncSession, menu: MenuModel): """ 新增菜单数据库操作 + :param db: orm对象 :param menu: 菜单对象 :return: @@ -169,6 +174,7 @@ class MenuDao: async def edit_menu_dao(cls, db: AsyncSession, menu: dict): """ 编辑菜单数据库操作 + :param db: orm对象 :param menu: 需要更新的菜单字典 :return: @@ -179,6 +185,7 @@ class MenuDao: async def delete_menu_dao(cls, db: AsyncSession, menu: MenuModel): """ 删除菜单数据库操作 + :param db: orm对象 :param menu: 菜单对象 :return: @@ -189,6 +196,7 @@ class MenuDao: async def has_child_by_menu_id_dao(cls, db: AsyncSession, menu_id: int): """ 根据菜单id查询菜单关联子菜单的数量 + :param db: orm对象 :param menu_id: 菜单id :return: 菜单关联子菜单的数量 @@ -203,6 +211,7 @@ class MenuDao: async def check_menu_exist_role_dao(cls, db: AsyncSession, menu_id: int): """ 根据菜单id查询菜单关联角色数量 + :param db: orm对象 :param menu_id: 菜单id :return: 菜单关联角色数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py index 534c26c..961a992 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py @@ -15,6 +15,7 @@ class NoticeDao: async def get_notice_detail_by_id(cls, db: AsyncSession, notice_id: int): """ 根据通知公告id获取通知公告详细信息 + :param db: orm对象 :param notice_id: 通知公告id :return: 通知公告信息对象 @@ -27,6 +28,7 @@ class NoticeDao: async def get_notice_detail_by_info(cls, db: AsyncSession, notice: NoticeModel): """ 根据通知公告参数获取通知公告信息 + :param db: orm对象 :param notice: 通知公告参数对象 :return: 通知公告信息对象 @@ -51,6 +53,7 @@ class NoticeDao: async def get_notice_list(cls, db: AsyncSession, query_object: NoticePageQueryModel, is_page: bool = False): """ 根据查询参数获取通知公告列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -79,6 +82,7 @@ class NoticeDao: async def add_notice_dao(cls, db: AsyncSession, notice: NoticeModel): """ 新增通知公告数据库操作 + :param db: orm对象 :param notice: 通知公告对象 :return: @@ -93,6 +97,7 @@ class NoticeDao: async def edit_notice_dao(cls, db: AsyncSession, notice: dict): """ 编辑通知公告数据库操作 + :param db: orm对象 :param notice: 需要更新的通知公告字典 :return: @@ -103,6 +108,7 @@ class NoticeDao: async def delete_notice_dao(cls, db: AsyncSession, notice: NoticeModel): """ 删除通知公告数据库操作 + :param db: orm对象 :param notice: 通知公告对象 :return: diff --git a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py index 4805306..7d90088 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py @@ -15,6 +15,7 @@ class PostDao: async def get_post_by_id(cls, db: AsyncSession, post_id: int): """ 根据岗位id获取在用岗位详细信息 + :param db: orm对象 :param post_id: 岗位id :return: 在用岗位信息对象 @@ -31,6 +32,7 @@ class PostDao: async def get_post_detail_by_id(cls, db: AsyncSession, post_id: int): """ 根据岗位id获取岗位详细信息 + :param db: orm对象 :param post_id: 岗位id :return: 岗位信息对象 @@ -43,6 +45,7 @@ class PostDao: async def get_post_detail_by_info(cls, db: AsyncSession, post: PostModel): """ 根据岗位参数获取岗位信息 + :param db: orm对象 :param post: 岗位参数对象 :return: 岗位信息对象 @@ -67,6 +70,7 @@ class PostDao: async def get_post_list(cls, db: AsyncSession, query_object: PostPageQueryModel, is_page: bool = False): """ 根据查询参数获取岗位列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -90,6 +94,7 @@ class PostDao: async def add_post_dao(cls, db: AsyncSession, post: PostModel): """ 新增岗位数据库操作 + :param db: orm对象 :param post: 岗位对象 :return: @@ -104,6 +109,7 @@ class PostDao: async def edit_post_dao(cls, db: AsyncSession, post: dict): """ 编辑岗位数据库操作 + :param db: orm对象 :param post: 需要更新的岗位字典 :return: @@ -114,6 +120,7 @@ class PostDao: async def delete_post_dao(cls, db: AsyncSession, post: PostModel): """ 删除岗位数据库操作 + :param db: orm对象 :param post: 岗位对象 :return: @@ -124,6 +131,7 @@ class PostDao: async def count_user_post_dao(cls, db: AsyncSession, post_id: int): """ 根据岗位id查询岗位关联的用户数量 + :param db: orm对象 :param post_id: 岗位id :return: 岗位关联的用户数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py index 30352e8..6c6bb43 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py @@ -18,6 +18,7 @@ class RoleDao: async def get_role_by_name(cls, db: AsyncSession, role_name: str): """ 根据角色名获取在用角色信息 + :param db: orm对象 :param role_name: 角色名 :return: 当前角色名的角色信息对象 @@ -41,6 +42,7 @@ class RoleDao: async def get_role_by_info(cls, db: AsyncSession, role: RoleModel): """ 根据角色参数获取角色信息 + :param db: orm对象 :param role: 角色参数 :return: 当前角色参数的角色信息对象 @@ -68,6 +70,7 @@ class RoleDao: async def get_role_by_id(cls, db: AsyncSession, role_id: int): """ 根据角色id获取在用角色信息 + :param db: orm对象 :param role_id: 角色id :return: 当前角色id的角色信息对象 @@ -88,6 +91,7 @@ class RoleDao: async def get_role_detail_by_id(cls, db: AsyncSession, role_id: int): """ 根据role_id获取角色详细信息 + :param db: orm对象 :param role_id: 角色id :return: 当前role_id的角色信息对象 @@ -104,6 +108,7 @@ class RoleDao: async def get_role_select_option_dao(cls, db: AsyncSession): """ 获取编辑页面对应的在用角色列表信息 + :param db: orm对象 :return: 角色列表信息 """ @@ -125,6 +130,7 @@ class RoleDao: ): """ 根据查询参数获取角色列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -160,6 +166,7 @@ class RoleDao: async def add_role_dao(cls, db: AsyncSession, role: RoleModel): """ 新增角色数据库操作 + :param db: orm对象 :param role: 角色对象 :return: @@ -174,6 +181,7 @@ class RoleDao: async def edit_role_dao(cls, db: AsyncSession, role: dict): """ 编辑角色数据库操作 + :param db: orm对象 :param role: 需要更新的角色字典 :return: @@ -184,6 +192,7 @@ class RoleDao: async def delete_role_dao(cls, db: AsyncSession, role: RoleModel): """ 删除角色数据库操作 + :param db: orm对象 :param role: 角色对象 :return: @@ -198,6 +207,7 @@ class RoleDao: async def get_role_menu_dao(cls, db: AsyncSession, role: RoleModel): """ 根据角色id获取角色菜单关联列表信息 + :param db: orm对象 :param role: 角色对象 :return: 角色菜单关联列表信息 @@ -233,6 +243,7 @@ class RoleDao: async def add_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel): """ 新增角色菜单关联信息数据库操作 + :param db: orm对象 :param role_menu: 用户角色菜单关联对象 :return: @@ -244,6 +255,7 @@ class RoleDao: async def delete_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel): """ 删除角色菜单关联信息数据库操作 + :param db: orm对象 :param role_menu: 角色菜单关联对象 :return: @@ -254,6 +266,7 @@ class RoleDao: async def get_role_dept_dao(cls, db: AsyncSession, role: RoleModel): """ 根据角色id获取角色部门关联列表信息 + :param db: orm对象 :param role: 角色对象 :return: 角色部门关联列表信息 @@ -289,6 +302,7 @@ class RoleDao: async def add_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel): """ 新增角色部门关联信息数据库操作 + :param db: orm对象 :param role_dept: 用户角色部门关联对象 :return: @@ -300,6 +314,7 @@ class RoleDao: async def delete_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel): """ 删除角色部门关联信息数据库操作 + :param db: orm对象 :param role_dept: 角色部门关联对象 :return: @@ -310,6 +325,7 @@ class RoleDao: async def count_user_role_dao(cls, db: AsyncSession, role_id: int): """ 根据角色id查询角色关联用户数量 + :param db: orm对象 :param role_id: 角色id :return: 角色关联用户数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py index 05e47bc..e32656c 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py @@ -26,6 +26,7 @@ class UserDao: async def get_user_by_name(cls, db: AsyncSession, user_name: str): """ 根据用户名获取用户信息 + :param db: orm对象 :param user_name: 用户名 :return: 当前用户名的用户信息对象 @@ -49,6 +50,7 @@ class UserDao: async def get_user_by_info(cls, db: AsyncSession, user: UserModel): """ 根据用户参数获取用户信息 + :param db: orm对象 :param user: 用户参数 :return: 当前用户参数的用户信息对象 @@ -77,6 +79,7 @@ class UserDao: async def get_user_by_id(cls, db: AsyncSession, user_id: int): """ 根据user_id获取用户信息 + :param db: orm对象 :param user_id: 用户id :return: 当前user_id的用户信息对象 @@ -183,6 +186,7 @@ class UserDao: async def get_user_detail_by_id(cls, db: AsyncSession, user_id: int): """ 根据user_id获取用户详细信息 + :param db: orm对象 :param user_id: 用户id :return: 当前user_id的用户信息对象 @@ -275,6 +279,7 @@ class UserDao: ): """ 根据查询参数获取用户列表信息 + :param db: orm对象 :param query_object: 查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -323,6 +328,7 @@ class UserDao: async def add_user_dao(cls, db: AsyncSession, user: UserModel): """ 新增用户数据库操作 + :param db: orm对象 :param user: 用户对象 :return: 新增校验结果 @@ -337,6 +343,7 @@ class UserDao: async def edit_user_dao(cls, db: AsyncSession, user: dict): """ 编辑用户数据库操作 + :param db: orm对象 :param user: 需要更新的用户字典 :return: 编辑校验结果 @@ -347,6 +354,7 @@ class UserDao: async def delete_user_dao(cls, db: AsyncSession, user: UserModel): """ 删除用户数据库操作 + :param db: orm对象 :param user: 用户对象 :return: @@ -361,6 +369,7 @@ class UserDao: async def get_user_role_allocated_list_by_user_id(cls, db: AsyncSession, query_object: UserRoleQueryModel): """ 根据用户id获取用户已分配的角色列表信息数据库操作 + :param db: orm对象 :param query_object: 用户角色查询对象 :return: 用户已分配的角色列表信息 @@ -393,6 +402,7 @@ class UserDao: ): """ 根据角色id获取已分配的用户列表信息 + :param db: orm对象 :param query_object: 用户角色查询对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -423,6 +433,7 @@ class UserDao: ): """ 根据角色id获取未分配的用户列表信息 + :param db: orm对象 :param query_object: 用户角色查询对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -461,6 +472,7 @@ class UserDao: async def add_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel): """ 新增用户角色关联信息数据库操作 + :param db: orm对象 :param user_role: 用户角色关联对象 :return: @@ -472,6 +484,7 @@ class UserDao: async def delete_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel): """ 删除用户角色关联信息数据库操作 + :param db: orm对象 :param user_role: 用户角色关联对象 :return: @@ -482,6 +495,7 @@ class UserDao: async def delete_user_role_by_user_and_role_dao(cls, db: AsyncSession, user_role: UserRoleModel): """ 根据用户id及角色id删除用户角色关联信息数据库操作 + :param db: orm对象 :param user_role: 用户角色关联对象 :return: @@ -497,6 +511,7 @@ class UserDao: async def get_user_role_detail(cls, db: AsyncSession, user_role: UserRoleModel): """ 根据用户角色关联获取用户角色关联详细信息 + :param db: orm对象 :param user_role: 用户角色关联对象 :return: 用户角色关联信息 @@ -519,6 +534,7 @@ class UserDao: async def add_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel): """ 新增用户岗位关联信息数据库操作 + :param db: orm对象 :param user_post: 用户岗位关联对象 :return: @@ -530,6 +546,7 @@ class UserDao: async def delete_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel): """ 删除用户岗位关联信息数据库操作 + :param db: orm对象 :param user_post: 用户岗位关联对象 :return: diff --git a/ruoyi-fastapi-backend/module_admin/service/cache_service.py b/ruoyi-fastapi-backend/module_admin/service/cache_service.py index d134b68..49f4fe7 100644 --- a/ruoyi-fastapi-backend/module_admin/service/cache_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/cache_service.py @@ -14,6 +14,7 @@ class CacheService: async def get_cache_monitor_statistical_info_services(cls, request: Request): """ 获取缓存监控信息service + :param request: Request对象 :return: 缓存监控信息 """ @@ -31,6 +32,7 @@ class CacheService: async def get_cache_monitor_cache_name_services(cls): """ 获取缓存名称列表信息service + :return: 缓存名称列表信息 """ name_list = [] @@ -51,6 +53,7 @@ class CacheService: async def get_cache_monitor_cache_key_services(cls, request: Request, cache_name: str): """ 获取缓存键名列表信息service + :param request: Request对象 :param cache_name: 缓存名称 :return: 缓存键名列表信息 @@ -64,6 +67,7 @@ class CacheService: async def get_cache_monitor_cache_value_services(cls, request: Request, cache_name: str, cache_key: str): """ 获取缓存内容信息service + :param request: Request对象 :param cache_name: 缓存名称 :param cache_key: 缓存键名 @@ -77,6 +81,7 @@ class CacheService: async def clear_cache_monitor_cache_name_services(cls, request: Request, cache_name: str): """ 清除缓存名称对应所有键值service + :param request: Request对象 :param cache_name: 缓存名称 :return: 操作缓存响应信息 @@ -91,6 +96,7 @@ class CacheService: async def clear_cache_monitor_cache_key_services(cls, request: Request, cache_key: str): """ 清除缓存名称对应所有键值service + :param request: Request对象 :param cache_key: 缓存键名 :return: 操作缓存响应信息 @@ -105,6 +111,7 @@ class CacheService: async def clear_cache_monitor_all_services(cls, request: Request): """ 清除所有缓存service + :param request: Request对象 :return: 操作缓存响应信息 """ diff --git a/ruoyi-fastapi-backend/module_admin/service/common_service.py b/ruoyi-fastapi-backend/module_admin/service/common_service.py index bea97c2..20eb868 100644 --- a/ruoyi-fastapi-backend/module_admin/service/common_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/common_service.py @@ -16,6 +16,7 @@ class CommonService: async def upload_service(cls, request: Request, file: UploadFile): """ 通用上传service + :param request: Request对象 :param file: 上传文件对象 :return: 上传结果 @@ -51,6 +52,7 @@ class CommonService: async def download_services(cls, background_tasks: BackgroundTasks, file_name, delete: bool): """ 下载下载目录文件service + :param background_tasks: 后台任务对象 :param file_name: 下载的文件名称 :param delete: 是否在下载完成后删除文件 @@ -70,6 +72,7 @@ class CommonService: async def download_resource_services(cls, resource: str): """ 下载上传目录文件service + :param resource: 下载的文件名称 :return: 上传结果 """ diff --git a/ruoyi-fastapi-backend/module_admin/service/config_service.py b/ruoyi-fastapi-backend/module_admin/service/config_service.py index 8d3b9e6..d463979 100644 --- a/ruoyi-fastapi-backend/module_admin/service/config_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/config_service.py @@ -21,6 +21,7 @@ class ConfigService: ): """ 获取参数配置列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -34,6 +35,7 @@ class ConfigService: async def init_cache_sys_config_services(cls, query_db: AsyncSession, redis): """ 应用初始化:获取所有参数配置对应的键值对信息并缓存service + :param query_db: orm对象 :param redis: redis对象 :return: @@ -54,6 +56,7 @@ class ConfigService: async def query_config_list_from_cache_services(cls, redis, config_key: str): """ 从缓存获取参数键名对应值service + :param redis: redis对象 :param config_key: 参数键名 :return: 参数键名对应值 @@ -66,6 +69,7 @@ class ConfigService: async def check_config_key_unique_services(cls, query_db: AsyncSession, page_object: ConfigModel): """ 校验参数键名是否唯一service + :param query_db: orm对象 :param page_object: 参数配置对象 :return: 校验结果 @@ -80,6 +84,7 @@ class ConfigService: async def add_config_services(cls, request: Request, query_db: AsyncSession, page_object: ConfigModel): """ 新增参数配置信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 新增参数配置对象 @@ -103,6 +108,7 @@ class ConfigService: async def edit_config_services(cls, request: Request, query_db: AsyncSession, page_object: ConfigModel): """ 编辑参数配置信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 编辑参数配置对象 @@ -135,6 +141,7 @@ class ConfigService: async def delete_config_services(cls, request: Request, query_db: AsyncSession, page_object: DeleteConfigModel): """ 删除参数配置信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 删除参数配置对象 @@ -167,6 +174,7 @@ class ConfigService: async def config_detail_services(cls, query_db: AsyncSession, config_id: int): """ 获取参数配置详细信息service + :param query_db: orm对象 :param config_id: 参数配置id :return: 参数配置id对应的信息 @@ -183,6 +191,7 @@ class ConfigService: async def export_config_list_services(config_list: List): """ 导出参数配置信息service + :param config_list: 参数配置信息列表 :return: 参数配置信息对应excel的二进制数据 """ @@ -218,6 +227,7 @@ class ConfigService: async def refresh_sys_config_services(cls, request: Request, query_db: AsyncSession): """ 刷新字典缓存信息service + :param request: Request对象 :param query_db: orm对象 :return: 刷新字典缓存校验结果 diff --git a/ruoyi-fastapi-backend/module_admin/service/dept_service.py b/ruoyi-fastapi-backend/module_admin/service/dept_service.py index 3fe5208..e7ba1dc 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dept_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dept_service.py @@ -16,6 +16,7 @@ class DeptService: async def get_dept_tree_services(cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str): """ 获取部门树信息service + :param query_db: orm对象 :param page_object: 查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -32,6 +33,7 @@ class DeptService: ): """ 获取部门编辑部门树信息service + :param query_db: orm对象 :param page_object: 查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -45,6 +47,7 @@ class DeptService: async def get_dept_list_services(cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str): """ 获取部门列表信息service + :param query_db: orm对象 :param page_object: 分页查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -58,6 +61,7 @@ class DeptService: async def check_dept_data_scope_services(cls, query_db: AsyncSession, dept_id: int, data_scope_sql: str): """ 校验部门是否有数据权限service + :param query_db: orm对象 :param dept_id: 部门id :param data_scope_sql: 数据权限对应的查询sql语句 @@ -73,6 +77,7 @@ class DeptService: async def check_dept_name_unique_services(cls, query_db: AsyncSession, page_object: DeptModel): """ 校验部门名称是否唯一service + :param query_db: orm对象 :param page_object: 部门对象 :return: 校验结果 @@ -89,6 +94,7 @@ class DeptService: async def add_dept_services(cls, query_db: AsyncSession, page_object: DeptModel): """ 新增部门信息service + :param query_db: orm对象 :param page_object: 新增部门对象 :return: 新增部门校验结果 @@ -111,6 +117,7 @@ class DeptService: async def edit_dept_services(cls, query_db: AsyncSession, page_object: DeptModel): """ 编辑部门信息service + :param query_db: orm对象 :param page_object: 编辑部门对象 :return: 编辑部门校验结果 @@ -150,6 +157,7 @@ class DeptService: async def delete_dept_services(cls, query_db: AsyncSession, page_object: DeleteDeptModel): """ 删除部门信息service + :param query_db: orm对象 :param page_object: 删除部门对象 :return: 删除部门校验结果 @@ -176,6 +184,7 @@ class DeptService: async def dept_detail_services(cls, query_db: AsyncSession, dept_id: int): """ 获取部门详细信息service + :param query_db: orm对象 :param dept_id: 部门id :return: 部门id对应的信息 @@ -192,6 +201,7 @@ class DeptService: def list_to_tree(cls, permission_list: list) -> list: """ 工具方法:根据部门列表信息生成树形嵌套数据 + :param permission_list: 部门列表信息 :return: 部门树形嵌套数据 """ @@ -222,6 +232,7 @@ class DeptService: async def replace_first(cls, original_str: str, old_str: str, new_str: str): """ 工具方法:替换字符串 + :param original_str: 需要替换的原始字符串 :param old_str: 用于匹配的字符串 :param new_str: 替换的字符串 @@ -236,6 +247,7 @@ class DeptService: async def update_parent_dept_status_normal(cls, query_db: AsyncSession, dept: DeptModel): """ 更新父部门状态为正常 + :param query_db: orm对象 :param dept: 部门对象 :return: @@ -247,6 +259,7 @@ class DeptService: async def update_dept_children(cls, query_db: AsyncSession, dept_id: int, new_ancestors: str, old_ancestors: str): """ 更新子部门信息 + :param query_db: orm对象 :param dept_id: 部门id :param new_ancestors: 新的祖先 diff --git a/ruoyi-fastapi-backend/module_admin/service/dict_service.py b/ruoyi-fastapi-backend/module_admin/service/dict_service.py index 06fb80a..8b82449 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dict_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dict_service.py @@ -29,6 +29,7 @@ class DictTypeService: ): """ 获取字典类型列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -42,6 +43,7 @@ class DictTypeService: async def check_dict_type_unique_services(cls, query_db: AsyncSession, page_object: DictTypeModel): """ 校验字典类型称是否唯一service + :param query_db: orm对象 :param page_object: 字典类型对象 :return: 校验结果 @@ -58,6 +60,7 @@ class DictTypeService: async def add_dict_type_services(cls, request: Request, query_db: AsyncSession, page_object: DictTypeModel): """ 新增字典类型信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 新增岗位对象 @@ -83,6 +86,7 @@ class DictTypeService: async def edit_dict_type_services(cls, request: Request, query_db: AsyncSession, page_object: DictTypeModel): """ 编辑字典类型信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 编辑字典类型对象 @@ -126,6 +130,7 @@ class DictTypeService: ): """ 删除字典类型信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 删除字典类型对象 @@ -155,6 +160,7 @@ class DictTypeService: async def dict_type_detail_services(cls, query_db: AsyncSession, dict_id: int): """ 获取字典类型详细信息service + :param query_db: orm对象 :param dict_id: 字典类型id :return: 字典类型id对应的信息 @@ -171,6 +177,7 @@ class DictTypeService: async def export_dict_type_list_services(dict_type_list: List): """ 导出字典类型信息service + :param dict_type_list: 字典信息列表 :return: 字典信息对应excel的二进制数据 """ @@ -205,6 +212,7 @@ class DictTypeService: async def refresh_sys_dict_services(cls, request: Request, query_db: AsyncSession): """ 刷新字典缓存信息service + :param request: Request对象 :param query_db: orm对象 :return: 刷新字典缓存校验结果 @@ -226,6 +234,7 @@ class DictDataService: ): """ 获取字典数据列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -239,6 +248,7 @@ class DictDataService: async def query_dict_data_list_services(cls, query_db: AsyncSession, dict_type: str): """ 获取字典数据列表信息service + :param query_db: orm对象 :param dict_type: 字典类型 :return: 字典数据列表信息对象 @@ -251,6 +261,7 @@ class DictDataService: async def init_cache_sys_dict_services(cls, query_db: AsyncSession, redis): """ 应用初始化:获取所有字典类型对应的字典数据信息并缓存service + :param query_db: orm对象 :param redis: redis对象 :return: @@ -274,6 +285,7 @@ class DictDataService: async def query_dict_data_list_from_cache_services(cls, redis, dict_type: str): """ 从缓存获取字典数据列表信息service + :param redis: redis对象 :param dict_type: 字典类型 :return: 字典数据列表信息对象 @@ -289,6 +301,7 @@ class DictDataService: async def check_dict_data_unique_services(cls, query_db: AsyncSession, page_object: DictDataModel): """ 校验字典数据是否唯一service + :param query_db: orm对象 :param page_object: 字典数据对象 :return: 校验结果 @@ -303,6 +316,7 @@ class DictDataService: async def add_dict_data_services(cls, request: Request, query_db: AsyncSession, page_object: DictDataModel): """ 新增字典数据信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 新增岗位对象 @@ -330,6 +344,7 @@ class DictDataService: async def edit_dict_data_services(cls, request: Request, query_db: AsyncSession, page_object: DictDataModel): """ 编辑字典数据信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 编辑字典数据对象 @@ -364,6 +379,7 @@ class DictDataService: ): """ 删除字典数据信息service + :param request: Request对象 :param query_db: orm对象 :param page_object: 删除字典数据对象 @@ -395,6 +411,7 @@ class DictDataService: async def dict_data_detail_services(cls, query_db: AsyncSession, dict_code: int): """ 获取字典数据详细信息service + :param query_db: orm对象 :param dict_code: 字典数据id :return: 字典数据id对应的信息 @@ -411,6 +428,7 @@ class DictDataService: async def export_dict_data_list_services(dict_data_list: List): """ 导出字典数据信息service + :param dict_data_list: 字典数据信息列表 :return: 字典数据信息对应excel的二进制数据 """ diff --git a/ruoyi-fastapi-backend/module_admin/service/job_log_service.py b/ruoyi-fastapi-backend/module_admin/service/job_log_service.py index a425b0b..a029409 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_log_service.py @@ -20,6 +20,7 @@ class JobLogService: ): """ 获取定时任务日志列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -33,6 +34,7 @@ class JobLogService: def add_job_log_services(cls, query_db: Session, page_object: JobLogModel): """ 新增定时任务日志信息service + :param query_db: orm对象 :param page_object: 新增定时任务日志对象 :return: 新增定时任务日志校验结果 @@ -51,6 +53,7 @@ class JobLogService: async def delete_job_log_services(cls, query_db: AsyncSession, page_object: DeleteJobLogModel): """ 删除定时任务日志信息service + :param query_db: orm对象 :param page_object: 删除定时任务日志对象 :return: 删除定时任务日志校验结果 @@ -73,6 +76,7 @@ class JobLogService: async def clear_job_log_services(cls, query_db: AsyncSession): """ 清除定时任务日志信息service + :param query_db: orm对象 :return: 清除定时任务日志校验结果 """ @@ -90,6 +94,7 @@ class JobLogService: async def export_job_log_list_services(request: Request, job_log_list: List): """ 导出定时任务日志信息service + :param request: Request对象 :param job_log_list: 定时任务日志信息列表 :return: 定时任务日志信息对应excel的二进制数据 diff --git a/ruoyi-fastapi-backend/module_admin/service/job_service.py b/ruoyi-fastapi-backend/module_admin/service/job_service.py index 87e460f..12a9b93 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_service.py @@ -20,6 +20,7 @@ class JobService: ): """ 获取定时任务列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -33,6 +34,7 @@ class JobService: async def add_job_services(cls, query_db: AsyncSession, page_object: JobModel): """ 新增定时任务信息service + :param query_db: orm对象 :param page_object: 新增定时任务对象 :return: 新增定时任务校验结果 @@ -58,6 +60,7 @@ class JobService: async def edit_job_services(cls, query_db: AsyncSession, page_object: EditJobModel): """ 编辑定时任务信息service + :param query_db: orm对象 :param page_object: 编辑定时任务对象 :return: 编辑定时任务校验结果 @@ -99,6 +102,7 @@ class JobService: async def execute_job_once_services(cls, query_db: AsyncSession, page_object: JobModel): """ 执行一次定时任务service + :param query_db: orm对象 :param page_object: 定时任务对象 :return: 执行一次定时任务结果 @@ -119,6 +123,7 @@ class JobService: async def delete_job_services(cls, query_db: AsyncSession, page_object: DeleteJobModel): """ 删除定时任务信息service + :param query_db: orm对象 :param page_object: 删除定时任务对象 :return: 删除定时任务校验结果 @@ -144,6 +149,7 @@ class JobService: async def job_detail_services(cls, query_db: AsyncSession, job_id: int): """ 获取定时任务详细信息service + :param query_db: orm对象 :param job_id: 定时任务id :return: 定时任务id对应的信息 @@ -157,6 +163,7 @@ class JobService: async def export_job_list_services(request: Request, job_list: List): """ 导出定时任务信息service + :param request: Request对象 :param job_list: 定时任务信息列表 :return: 定时任务信息对应excel的二进制数据 diff --git a/ruoyi-fastapi-backend/module_admin/service/log_service.py b/ruoyi-fastapi-backend/module_admin/service/log_service.py index 0ac8464..047ec45 100644 --- a/ruoyi-fastapi-backend/module_admin/service/log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/log_service.py @@ -28,6 +28,7 @@ class OperationLogService: ): """ 获取操作日志列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -41,6 +42,7 @@ class OperationLogService: async def add_operation_log_services(cls, query_db: AsyncSession, page_object: OperLogModel): """ 新增操作日志service + :param query_db: orm对象 :param page_object: 新增操作日志对象 :return: 新增操作日志校验结果 @@ -57,6 +59,7 @@ class OperationLogService: async def delete_operation_log_services(cls, query_db: AsyncSession, page_object: DeleteOperLogModel): """ 删除操作日志信息service + :param query_db: orm对象 :param page_object: 删除操作日志对象 :return: 删除操作日志校验结果 @@ -78,6 +81,7 @@ class OperationLogService: async def clear_operation_log_services(cls, query_db: AsyncSession): """ 清除操作日志信息service + :param query_db: orm对象 :return: 清除操作日志校验结果 """ @@ -93,6 +97,7 @@ class OperationLogService: async def export_operation_log_list_services(cls, request: Request, operation_log_list: List): """ 导出操作日志信息service + :param request: Request对象 :param operation_log_list: 操作日志信息列表 :return: 操作日志信息对应excel的二进制数据 @@ -153,6 +158,7 @@ class LoginLogService: ): """ 获取登录日志列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -166,6 +172,7 @@ class LoginLogService: async def add_login_log_services(cls, query_db: AsyncSession, page_object: LogininforModel): """ 新增登录日志service + :param query_db: orm对象 :param page_object: 新增登录日志对象 :return: 新增登录日志校验结果 @@ -182,6 +189,7 @@ class LoginLogService: async def delete_login_log_services(cls, query_db: AsyncSession, page_object: DeleteLoginLogModel): """ 删除操作日志信息service + :param query_db: orm对象 :param page_object: 删除操作日志对象 :return: 删除操作日志校验结果 @@ -203,6 +211,7 @@ class LoginLogService: async def clear_login_log_services(cls, query_db: AsyncSession): """ 清除操作日志信息service + :param query_db: orm对象 :return: 清除操作日志校验结果 """ @@ -227,6 +236,7 @@ class LoginLogService: async def export_login_log_list_services(login_log_list: List): """ 导出登录日志信息service + :param login_log_list: 登录日志信息列表 :return: 登录日志信息对应excel的二进制数据 """ diff --git a/ruoyi-fastapi-backend/module_admin/service/login_service.py b/ruoyi-fastapi-backend/module_admin/service/login_service.py index ddf792a..6f654c4 100644 --- a/ruoyi-fastapi-backend/module_admin/service/login_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/login_service.py @@ -64,6 +64,7 @@ class LoginService: async def authenticate_user(cls, request: Request, query_db: AsyncSession, login_user: UserLogin): """ 根据用户名密码校验用户登录 + :param request: Request对象 :param query_db: orm对象 :param login_user: 登录用户对象 @@ -132,6 +133,7 @@ class LoginService: async def __check_login_ip(cls, request: Request): """ 校验用户登录ip是否在黑名单内 + :param request: Request对象 :return: 校验结果 """ @@ -148,6 +150,7 @@ class LoginService: async def __check_login_captcha(cls, request: Request, login_user: UserLogin): """ 校验用户登录验证码 + :param request: Request对象 :param login_user: 登录用户对象 :return: 校验结果 @@ -167,6 +170,7 @@ class LoginService: async def create_access_token(cls, data: dict, expires_delta: Union[timedelta, None] = None): """ 根据登录信息创建当前用户token + :param data: 登录信息 :param expires_delta: token有效期 :return: token @@ -186,6 +190,7 @@ class LoginService: ): """ 根据token获取当前用户信息 + :param request: Request对象 :param token: 用户token :param query_db: orm对象 @@ -264,6 +269,7 @@ class LoginService: async def get_current_user_routers(cls, user_id: int, query_db: AsyncSession): """ 根据用户id获取当前用户路由信息 + :param user_id: 用户id :param query_db: orm对象 :return: 当前用户路由信息对象 @@ -285,6 +291,7 @@ class LoginService: def __generate_menus(cls, pid: int, permission_list: List[SysMenu]): """ 工具方法:根据菜单信息生成菜单信息树形嵌套数据 + :param pid: 菜单id :param permission_list: 菜单列表信息 :return: 菜单信息树形嵌套数据 @@ -304,6 +311,7 @@ class LoginService: def __generate_user_router_menu(cls, permission_list: List[MenuTreeModel]): """ 工具方法:根据菜单树信息生成路由信息树形嵌套数据 + :param permission_list: 菜单树列表信息 :return: 路由信息树形嵌套数据 """ @@ -370,6 +378,7 @@ class LoginService: async def register_user_services(cls, request: Request, query_db: AsyncSession, user_register: UserRegister): """ 用户注册services + :param request: Request对象 :param query_db: orm对象 :param user_register: 注册用户对象 @@ -415,6 +424,7 @@ class LoginService: async def get_sms_code_services(cls, request: Request, query_db: AsyncSession, user: ResetUserModel): """ 获取短信验证码service + :param request: Request对象 :param query_db: orm对象 :param user: 用户对象 @@ -443,6 +453,7 @@ class LoginService: async def forget_user_services(cls, request: Request, query_db: AsyncSession, forget_user: ResetUserModel): """ 用户忘记密码services + :param request: Request对象 :param query_db: orm对象 :param forget_user: 重置用户对象 @@ -468,6 +479,7 @@ class LoginService: async def logout_services(cls, request: Request, session_id: str): """ 退出登录services + :param request: Request对象 :param session_id: 会话编号 :return: 退出登录结果 @@ -488,6 +500,7 @@ class RouterUtil: def get_router_name(cls, menu: MenuTreeModel): """ 获取路由名称 + :param menu: 菜单数对象 :return: 路由名称 """ @@ -501,6 +514,7 @@ class RouterUtil: def get_router_path(cls, menu: MenuTreeModel): """ 获取路由地址 + :param menu: 菜单数对象 :return: 路由地址 """ @@ -520,6 +534,7 @@ class RouterUtil: def get_component(cls, menu: MenuTreeModel): """ 获取组件信息 + :param menu: 菜单数对象 :return: 组件信息 """ @@ -536,6 +551,7 @@ class RouterUtil: def is_menu_frame(cls, menu: MenuTreeModel): """ 判断是否为菜单内部跳转 + :param menu: 菜单数对象 :return: 是否为菜单内部跳转 """ @@ -547,6 +563,7 @@ class RouterUtil: def is_inner_link(cls, menu: MenuTreeModel): """ 判断是否为内链组件 + :param menu: 菜单数对象 :return: 是否为内链组件 """ @@ -556,6 +573,7 @@ class RouterUtil: def is_parent_view(cls, menu: MenuTreeModel): """ 判断是否为parent_view组件 + :param menu: 菜单数对象 :return: 是否为parent_view组件 """ @@ -565,6 +583,7 @@ class RouterUtil: def is_http(cls, link: str): """ 判断是否为http(s)://开头 + :param link: 链接 :return: 是否为http(s)://开头 """ @@ -574,6 +593,7 @@ class RouterUtil: def inner_link_replace_each(cls, path: str): """ 内链域名特殊字符替换 + :param path: 内链域名 :return: 替换后的内链域名 """ diff --git a/ruoyi-fastapi-backend/module_admin/service/menu_service.py b/ruoyi-fastapi-backend/module_admin/service/menu_service.py index f0f8ce2..6020d1a 100644 --- a/ruoyi-fastapi-backend/module_admin/service/menu_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/menu_service.py @@ -21,6 +21,7 @@ class MenuService: async def get_menu_tree_services(cls, query_db: AsyncSession, current_user: Optional[CurrentUserModel] = None): """ 获取菜单树信息service + :param query_db: orm对象 :param current_user: 当前用户对象 :return: 菜单树信息对象 @@ -38,6 +39,7 @@ class MenuService: ): """ 根据角色id获取菜单树信息service + :param query_db: orm对象 :param role_id: 角色id :param current_user: 当前用户对象 @@ -60,6 +62,7 @@ class MenuService: ): """ 获取菜单列表信息service + :param query_db: orm对象 :param page_object: 分页查询参数对象 :param current_user: 当前用户对象 @@ -75,6 +78,7 @@ class MenuService: async def check_menu_name_unique_services(cls, query_db: AsyncSession, page_object: MenuModel): """ 校验菜单名称是否唯一service + :param query_db: orm对象 :param page_object: 菜单对象 :return: 校验结果 @@ -89,6 +93,7 @@ class MenuService: async def add_menu_services(cls, query_db: AsyncSession, page_object: MenuModel): """ 新增菜单信息service + :param query_db: orm对象 :param page_object: 新增菜单对象 :return: 新增菜单校验结果 @@ -110,6 +115,7 @@ class MenuService: async def edit_menu_services(cls, query_db: AsyncSession, page_object: MenuModel): """ 编辑菜单信息service + :param query_db: orm对象 :param page_object: 编辑部门对象 :return: 编辑菜单校验结果 @@ -138,6 +144,7 @@ class MenuService: async def delete_menu_services(cls, query_db: AsyncSession, page_object: DeleteMenuModel): """ 删除菜单信息service + :param query_db: orm对象 :param page_object: 删除菜单对象 :return: 删除菜单校验结果 @@ -163,6 +170,7 @@ class MenuService: async def menu_detail_services(cls, query_db: AsyncSession, menu_id: int): """ 获取菜单详细信息service + :param query_db: orm对象 :param menu_id: 菜单id :return: 菜单id对应的信息 @@ -179,6 +187,7 @@ class MenuService: def list_to_tree(cls, permission_list: list) -> list: """ 工具方法:根据菜单列表信息生成树形嵌套数据 + :param permission_list: 菜单列表信息 :return: 菜单树形嵌套数据 """ diff --git a/ruoyi-fastapi-backend/module_admin/service/notice_service.py b/ruoyi-fastapi-backend/module_admin/service/notice_service.py index d9e5594..5ee69e7 100644 --- a/ruoyi-fastapi-backend/module_admin/service/notice_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/notice_service.py @@ -18,6 +18,7 @@ class NoticeService: ): """ 获取通知公告列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -31,6 +32,7 @@ class NoticeService: async def check_notice_unique_services(cls, query_db: AsyncSession, page_object: NoticeModel): """ 校验通知公告是否存在service + :param query_db: orm对象 :param page_object: 通知公告对象 :return: 校验结果 @@ -45,6 +47,7 @@ class NoticeService: async def add_notice_services(cls, query_db: AsyncSession, page_object: NoticeModel): """ 新增通知公告信息service + :param query_db: orm对象 :param page_object: 新增通知公告对象 :return: 新增通知公告校验结果 @@ -64,6 +67,7 @@ class NoticeService: async def edit_notice_services(cls, query_db: AsyncSession, page_object: NoticeModel): """ 编辑通知公告信息service + :param query_db: orm对象 :param page_object: 编辑通知公告对象 :return: 编辑通知公告校验结果 @@ -88,6 +92,7 @@ class NoticeService: async def delete_notice_services(cls, query_db: AsyncSession, page_object: DeleteNoticeModel): """ 删除通知公告信息service + :param query_db: orm对象 :param page_object: 删除通知公告对象 :return: 删除通知公告校验结果 @@ -109,6 +114,7 @@ class NoticeService: async def notice_detail_services(cls, query_db: AsyncSession, notice_id: int): """ 获取通知公告详细信息service + :param query_db: orm对象 :param notice_id: 通知公告id :return: 通知公告id对应的信息 diff --git a/ruoyi-fastapi-backend/module_admin/service/online_service.py b/ruoyi-fastapi-backend/module_admin/service/online_service.py index 3e16eef..e861213 100644 --- a/ruoyi-fastapi-backend/module_admin/service/online_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/online_service.py @@ -16,6 +16,7 @@ class OnlineService: async def get_online_list_services(cls, request: Request, query_object: OnlineQueryModel): """ 获取在线用户表信息service + :param request: Request对象 :param query_object: 查询参数对象 :return: 在线用户列表信息 @@ -60,6 +61,7 @@ class OnlineService: async def delete_online_services(cls, request: Request, page_object: DeleteOnlineModel): """ 强退在线用户信息service + :param request: Request对象 :param page_object: 强退在线用户对象 :return: 强退在线用户校验结果 diff --git a/ruoyi-fastapi-backend/module_admin/service/post_service.py b/ruoyi-fastapi-backend/module_admin/service/post_service.py index 3ce4a6b..b435393 100644 --- a/ruoyi-fastapi-backend/module_admin/service/post_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/post_service.py @@ -19,6 +19,7 @@ class PostService: ): """ 获取岗位列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param is_page: 是否开启分页 @@ -32,6 +33,7 @@ class PostService: async def check_post_name_unique_services(cls, query_db: AsyncSession, page_object: PostModel): """ 检查岗位名称是否唯一service + :param query_db: orm对象 :param page_object: 岗位对象 :return: 校验结果 @@ -46,6 +48,7 @@ class PostService: async def check_post_code_unique_services(cls, query_db: AsyncSession, page_object: PostModel): """ 检查岗位编码是否唯一service + :param query_db: orm对象 :param page_object: 岗位对象 :return: 校验结果 @@ -60,6 +63,7 @@ class PostService: async def add_post_services(cls, query_db: AsyncSession, page_object: PostModel): """ 新增岗位信息service + :param query_db: orm对象 :param page_object: 新增岗位对象 :return: 新增岗位校验结果 @@ -81,6 +85,7 @@ class PostService: async def edit_post_services(cls, query_db: AsyncSession, page_object: PostModel): """ 编辑岗位信息service + :param query_db: orm对象 :param page_object: 编辑岗位对象 :return: 编辑岗位校验结果 @@ -107,6 +112,7 @@ class PostService: async def delete_post_services(cls, query_db: AsyncSession, page_object: DeletePostModel): """ 删除岗位信息service + :param query_db: orm对象 :param page_object: 删除岗位对象 :return: 删除岗位校验结果 @@ -131,6 +137,7 @@ class PostService: async def post_detail_services(cls, query_db: AsyncSession, post_id: int): """ 获取岗位详细信息service + :param query_db: orm对象 :param post_id: 岗位id :return: 岗位id对应的信息 @@ -147,6 +154,7 @@ class PostService: async def export_post_list_services(post_list: List): """ 导出岗位信息service + :param post_list: 岗位信息列表 :return: 岗位信息对应excel的二进制数据 """ diff --git a/ruoyi-fastapi-backend/module_admin/service/role_service.py b/ruoyi-fastapi-backend/module_admin/service/role_service.py index dbd2b22..cd6fa57 100644 --- a/ruoyi-fastapi-backend/module_admin/service/role_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/role_service.py @@ -28,6 +28,7 @@ class RoleService: async def get_role_select_option_services(cls, query_db: AsyncSession): """ 获取角色列表不分页信息service + :param query_db: orm对象 :return: 角色列表不分页信息对象 """ @@ -39,6 +40,7 @@ class RoleService: async def get_role_dept_tree_services(cls, query_db: AsyncSession, role_id: int): """ 根据角色id获取部门树信息service + :param query_db: orm对象 :param role_id: 角色id :return: 当前角色id的部门树信息对象 @@ -56,6 +58,7 @@ class RoleService: ): """ 获取角色列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -70,6 +73,7 @@ class RoleService: async def check_role_allowed_services(cls, check_role: RoleModel): """ 校验角色是否允许操作service + :param check_role: 角色信息 :return: 校验结果 """ @@ -82,6 +86,7 @@ class RoleService: async def check_role_data_scope_services(cls, query_db: AsyncSession, role_ids: str, data_scope_sql: str): """ 校验角色是否有数据权限service + :param query_db: orm对象 :param role_ids: 角色id :param data_scope_sql: 数据权限对应的查询sql语句 @@ -100,6 +105,7 @@ class RoleService: async def check_role_name_unique_services(cls, query_db: AsyncSession, page_object: RoleModel): """ 校验角色名称是否唯一service + :param query_db: orm对象 :param page_object: 角色对象 :return: 校验结果 @@ -114,6 +120,7 @@ class RoleService: async def check_role_key_unique_services(cls, query_db: AsyncSession, page_object: RoleModel): """ 校验角色权限字符是否唯一service + :param query_db: orm对象 :param page_object: 角色对象 :return: 校验结果 @@ -128,6 +135,7 @@ class RoleService: async def add_role_services(cls, query_db: AsyncSession, page_object: AddRoleModel): """ 新增角色信息service + :param query_db: orm对象 :param page_object: 新增角色对象 :return: 新增角色校验结果 @@ -154,6 +162,7 @@ class RoleService: async def edit_role_services(cls, query_db: AsyncSession, page_object: AddRoleModel): """ 编辑角色信息service + :param query_db: orm对象 :param page_object: 编辑角色对象 :return: 编辑角色校验结果 @@ -191,6 +200,7 @@ class RoleService: async def role_datascope_services(cls, query_db: AsyncSession, page_object: AddRoleModel): """ 分配角色数据权限service + :param query_db: orm对象 :param page_object: 角色数据权限对象 :return: 分配角色数据权限结果 @@ -218,6 +228,7 @@ class RoleService: async def delete_role_services(cls, query_db: AsyncSession, page_object: DeleteRoleModel): """ 删除角色信息service + :param query_db: orm对象 :param page_object: 删除角色对象 :return: 删除角色校验结果 @@ -247,6 +258,7 @@ class RoleService: async def role_detail_services(cls, query_db: AsyncSession, role_id: int): """ 获取角色详细信息service + :param query_db: orm对象 :param role_id: 角色id :return: 角色id对应的信息 @@ -263,6 +275,7 @@ class RoleService: async def export_role_list_services(role_list: List): """ 导出角色列表信息service + :param role_list: 角色信息列表 :return: 角色列表信息对象 """ @@ -300,6 +313,7 @@ class RoleService: ): """ 根据角色id获取已分配用户列表 + :param query_db: orm对象 :param page_object: 用户关联角色对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -324,6 +338,7 @@ class RoleService: ): """ 根据角色id获取未分配用户列表 + :param query_db: orm对象 :param page_object: 用户关联角色对象 :param data_scope_sql: 数据权限对应的查询sql语句 diff --git a/ruoyi-fastapi-backend/module_admin/service/user_service.py b/ruoyi-fastapi-backend/module_admin/service/user_service.py index 37d9dac..9213406 100644 --- a/ruoyi-fastapi-backend/module_admin/service/user_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/user_service.py @@ -47,6 +47,7 @@ class UserService: ): """ 获取用户列表信息service + :param query_db: orm对象 :param query_object: 查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 @@ -72,6 +73,7 @@ class UserService: async def check_user_allowed_services(cls, check_user: UserModel): """ 校验用户是否允许操作service + :param check_user: 用户信息 :return: 校验结果 """ @@ -84,6 +86,7 @@ class UserService: async def check_user_data_scope_services(cls, query_db: AsyncSession, user_id: int, data_scope_sql: str): """ 校验用户数据权限service + :param query_db: orm对象 :param user_id: 用户id :param data_scope_sql: 数据权限对应的查询sql语句 @@ -99,6 +102,7 @@ class UserService: async def check_user_name_unique_services(cls, query_db: AsyncSession, page_object: UserModel): """ 校验用户名是否唯一service + :param query_db: orm对象 :param page_object: 用户对象 :return: 校验结果 @@ -113,6 +117,7 @@ class UserService: async def check_phonenumber_unique_services(cls, query_db: AsyncSession, page_object: UserModel): """ 校验用户手机号是否唯一service + :param query_db: orm对象 :param page_object: 用户对象 :return: 校验结果 @@ -127,6 +132,7 @@ class UserService: async def check_email_unique_services(cls, query_db: AsyncSession, page_object: UserModel): """ 校验用户邮箱是否唯一service + :param query_db: orm对象 :param page_object: 用户对象 :return: 校验结果 @@ -141,6 +147,7 @@ class UserService: async def add_user_services(cls, query_db: AsyncSession, page_object: AddUserModel): """ 新增用户信息service + :param query_db: orm对象 :param page_object: 新增用户对象 :return: 新增用户校验结果 @@ -172,6 +179,7 @@ class UserService: async def edit_user_services(cls, query_db: AsyncSession, page_object: EditUserModel): """ 编辑用户信息service + :param query_db: orm对象 :param page_object: 编辑用户对象 :return: 编辑用户校验结果 @@ -219,6 +227,7 @@ class UserService: async def delete_user_services(cls, query_db: AsyncSession, page_object: DeleteUserModel): """ 删除用户信息service + :param query_db: orm对象 :param page_object: 删除用户对象 :return: 删除用户校验结果 @@ -245,6 +254,7 @@ class UserService: async def user_detail_services(cls, query_db: AsyncSession, user_id: Union[int, str]): """ 获取用户详细信息service + :param query_db: orm对象 :param user_id: 用户id :return: 用户id对应的信息 @@ -277,7 +287,8 @@ class UserService: @classmethod async def user_profile_services(cls, query_db: AsyncSession, user_id: int): """ - 获取用户详细信息service + 获取用户个人详细信息service + :param query_db: orm对象 :param user_id: 用户id :return: 用户id对应的信息 @@ -304,6 +315,7 @@ class UserService: async def reset_user_services(cls, query_db: AsyncSession, page_object: ResetUserModel): """ 重置用户密码service + :param query_db: orm对象 :param page_object: 重置用户对象 :return: 重置用户校验结果 @@ -341,6 +353,7 @@ class UserService: ): """ 批量导入用户service + :param request: Request对象 :param query_db: orm对象 :param file: 用户导入文件对象 @@ -441,6 +454,7 @@ class UserService: async def get_user_import_template_services(): """ 获取用户导入模板service + :return: 用户导入模板excel的二进制数据 """ header_list = ['部门编号', '登录名称', '用户名称', '用户邮箱', '手机号码', '用户性别', '帐号状态'] @@ -456,6 +470,7 @@ class UserService: async def export_user_list_services(user_list: List): """ 导出用户信息service + :param user_list: 用户信息列表 :return: 用户信息对应excel的二进制数据 """ @@ -500,6 +515,7 @@ class UserService: async def get_user_role_allocated_list_services(cls, query_db: AsyncSession, page_object: UserRoleQueryModel): """ 根据用户id获取已分配角色列表 + :param query_db: orm对象 :param page_object: 用户关联角色对象 :return: 已分配角色列表 @@ -529,6 +545,7 @@ class UserService: async def add_user_role_services(cls, query_db: AsyncSession, page_object: CrudUserRoleModel): """ 新增用户关联角色信息service + :param query_db: orm对象 :param page_object: 新增用户关联角色对象 :return: 新增用户关联角色校验结果 @@ -584,6 +601,7 @@ class UserService: async def delete_user_role_services(cls, query_db: AsyncSession, page_object: CrudUserRoleModel): """ 删除用户关联角色信息service + :param query_db: orm对象 :param page_object: 删除用户关联角色对象 :return: 删除用户关联角色校验结果 @@ -620,6 +638,7 @@ class UserService: async def detail_user_role_services(cls, query_db: AsyncSession, page_object: UserRoleModel): """ 获取用户关联角色详细信息service + :param query_db: orm对象 :param page_object: 用户关联角色对象 :return: 用户关联角色详细信息 diff --git a/ruoyi-fastapi-backend/utils/common_util.py b/ruoyi-fastapi-backend/utils/common_util.py index 67145d9..853cfe3 100644 --- a/ruoyi-fastapi-backend/utils/common_util.py +++ b/ruoyi-fastapi-backend/utils/common_util.py @@ -33,7 +33,7 @@ def worship(): // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // -// 佛祖保佑 永不宕机 永无BUG // +// 佛祖保佑 永不宕机 永无BUG // //////////////////////////////////////////////////////////////////// """) @@ -47,6 +47,7 @@ class CamelCaseUtil: def snake_to_camel(cls, snake_str): """ 下划线形式字符串(snake_case)转换为小驼峰形式字符串(camelCase) + :param snake_str: 下划线形式字符串 :return: 小驼峰形式字符串 """ @@ -59,6 +60,7 @@ class CamelCaseUtil: def transform_result(cls, result): """ 针对不同类型将下划线形式(snake_case)批量转换为小驼峰形式(camelCase)方法 + :param result: 输入数据 :return: 小驼峰形式结果 """ @@ -101,6 +103,7 @@ class SnakeCaseUtil: def camel_to_snake(cls, camel_str): """ 小驼峰形式字符串(camelCase)转换为下划线形式字符串(snake_case) + :param camel_str: 小驼峰形式字符串 :return: 下划线形式字符串 """ @@ -112,6 +115,7 @@ class SnakeCaseUtil: def transform_result(cls, result): """ 针对不同类型将下划线形式(snake_case)批量转换为小驼峰形式(camelCase)方法 + :param result: 输入数据 :return: 小驼峰形式结果 """ @@ -172,6 +176,7 @@ def bytes2file_response(bytes_info): def export_list2excel(list_data: List): """ 工具方法:将需要导出的list数据转化为对应excel的二进制数据 + :param list_data: 数据列表 :return: 字典信息对应excel的二进制数据 """ @@ -186,6 +191,7 @@ def export_list2excel(list_data: List): def get_excel_template(header_list: List, selector_header_list: List, option_list: List[dict]): """ 工具方法:将需要导出的list数据转化为对应excel的二进制数据 + :param header_list: 表头数据列表 :param selector_header_list: 需要设置为选择器格式的表头数据列表 :param option_list: 选择器格式的表头预设的选项列表 @@ -246,6 +252,7 @@ def get_excel_template(header_list: List, selector_header_list: List, option_lis def get_filepath_from_url(url: str): """ 工具方法:根据请求参数获取文件路径 + :param url: 请求参数中的url参数 :return: 文件路径 """ diff --git a/ruoyi-fastapi-backend/utils/page_util.py b/ruoyi-fastapi-backend/utils/page_util.py index 0a18c9b..6e7bfe2 100644 --- a/ruoyi-fastapi-backend/utils/page_util.py +++ b/ruoyi-fastapi-backend/utils/page_util.py @@ -30,6 +30,7 @@ class PageUtil: def get_page_obj(cls, data_list: List, page_num: int, page_size: int): """ 输入数据列表data_list和分页信息,返回分页数据列表结果 + :param data_list: 原始数据列表 :param page_num: 当前页码 :param page_size: 当前页面数据量 @@ -53,6 +54,7 @@ class PageUtil: async def paginate(cls, db: AsyncSession, query: Select, page_num: int, page_size: int, is_page: bool = False): """ 输入查询语句和分页信息,返回分页数据列表结果 + :param db: orm对象 :param query: sqlalchemy查询语句 :param page_num: 当前页码 @@ -93,6 +95,7 @@ class PageUtil: def get_page_obj(data_list: List, page_num: int, page_size: int): """ 输入数据列表data_list和分页信息,返回分页数据列表结果 + :param data_list: 原始数据列表 :param page_num: 当前页码 :param page_size: 当前页面数据量 diff --git a/ruoyi-fastapi-backend/utils/pwd_util.py b/ruoyi-fastapi-backend/utils/pwd_util.py index badaa04..86e9c27 100644 --- a/ruoyi-fastapi-backend/utils/pwd_util.py +++ b/ruoyi-fastapi-backend/utils/pwd_util.py @@ -12,6 +12,7 @@ class PwdUtil: def verify_password(cls, plain_password, hashed_password): """ 工具方法:校验当前输入的密码与数据库存储的密码是否一致 + :param plain_password: 当前输入的密码 :param hashed_password: 数据库存储的密码 :return: 校验结果 @@ -22,6 +23,7 @@ class PwdUtil: def get_password_hash(cls, input_password): """ 工具方法:对当前输入的密码进行加密 + :param input_password: 输入的密码 :return: 加密成功的密码 """ diff --git a/ruoyi-fastapi-backend/utils/response_util.py b/ruoyi-fastapi-backend/utils/response_util.py index d06a7fa..88d2e37 100644 --- a/ruoyi-fastapi-backend/utils/response_util.py +++ b/ruoyi-fastapi-backend/utils/response_util.py @@ -23,6 +23,7 @@ class ResponseUtil: ) -> Response: """ 成功响应方法 + :param msg: 可选,自定义成功响应信息 :param data: 可选,成功响应结果中属性为data的值 :param rows: 可选,成功响应结果中属性为rows的值 @@ -56,6 +57,7 @@ class ResponseUtil: ) -> Response: """ 失败响应方法 + :param msg: 可选,自定义失败响应信息 :param data: 可选,失败响应结果中属性为data的值 :param rows: 可选,失败响应结果中属性为rows的值 @@ -89,6 +91,7 @@ class ResponseUtil: ) -> Response: """ 未认证响应方法 + :param msg: 可选,自定义未认证响应信息 :param data: 可选,未认证响应结果中属性为data的值 :param rows: 可选,未认证响应结果中属性为rows的值 @@ -121,13 +124,14 @@ class ResponseUtil: model_content: Optional[BaseModel] = None, ) -> Response: """ - 未认证响应方法 - :param msg: 可选,自定义未认证响应信息 - :param data: 可选,未认证响应结果中属性为data的值 - :param rows: 可选,未认证响应结果中属性为rows的值 - :param dict_content: 可选,dict类型,未认证响应结果中自定义属性的值 - :param model_content: 可选,BaseModel类型,未认证响应结果中自定义属性的值 - :return: 未认证响应结果 + 未授权响应方法 + + :param msg: 可选,自定义未授权响应信息 + :param data: 可选,未授权响应结果中属性为data的值 + :param rows: 可选,未授权响应结果中属性为rows的值 + :param dict_content: 可选,dict类型,未授权响应结果中自定义属性的值 + :param model_content: 可选,BaseModel类型,未授权响应结果中自定义属性的值 + :return: 未授权响应结果 """ result = {'code': HttpStatusConstant.FORBIDDEN, 'msg': msg} @@ -155,6 +159,7 @@ class ResponseUtil: ) -> Response: """ 错误响应方法 + :param msg: 可选,自定义错误响应信息 :param data: 可选,错误响应结果中属性为data的值 :param rows: 可选,错误响应结果中属性为rows的值 @@ -181,6 +186,7 @@ class ResponseUtil: def streaming(cls, *, data: Any = None): """ 流式响应方法 + :param data: 流式传输的内容 :return: 流式响应结果 """ diff --git a/ruoyi-fastapi-backend/utils/string_util.py b/ruoyi-fastapi-backend/utils/string_util.py index 738e0ac..0a9d25d 100644 --- a/ruoyi-fastapi-backend/utils/string_util.py +++ b/ruoyi-fastapi-backend/utils/string_util.py @@ -10,6 +10,7 @@ class StringUtil: def is_blank(cls, string: str) -> bool: """ 校验字符串是否为''或全空格 + :param string: 需要校验的字符串 :return: 校验结果 """ @@ -28,6 +29,7 @@ class StringUtil: def is_empty(cls, string) -> bool: """ 校验字符串是否为''或None + :param string: 需要校验的字符串 :return: 校验结果 """ @@ -37,6 +39,7 @@ class StringUtil: def is_http(cls, link: str): """ 判断是否为http(s)://开头 + :param link: 链接 :return: 是否为http(s)://开头 """ diff --git a/ruoyi-fastapi-backend/utils/time_format_util.py b/ruoyi-fastapi-backend/utils/time_format_util.py index ba19489..380537e 100644 --- a/ruoyi-fastapi-backend/utils/time_format_util.py +++ b/ruoyi-fastapi-backend/utils/time_format_util.py @@ -29,6 +29,7 @@ def list_format_datetime(lst): def format_datetime_dict_list(dicts): """ 递归遍历嵌套字典,并将 datetime 值转换为字符串格式 + :param dicts: 输入一个嵌套字典的列表 :return: 对目标列表中所有字典的datetime类型的属性格式化 """ diff --git a/ruoyi-fastapi-backend/utils/upload_util.py b/ruoyi-fastapi-backend/utils/upload_util.py index 99b00bb..726789e 100644 --- a/ruoyi-fastapi-backend/utils/upload_util.py +++ b/ruoyi-fastapi-backend/utils/upload_util.py @@ -14,15 +14,20 @@ class UploadUtil: def generate_random_number(cls): """ 生成3位数字构成的字符串 + + :return: 3位数字构成的字符串 """ random_number = random.randint(1, 999) return f'{random_number:03}' @classmethod - def check_file_exists(cls, filepath): + def check_file_exists(cls, filepath: str): """ 检查文件是否存在 + + :param filepath: 文件路径 + :return: 校验结果 """ return os.path.exists(filepath) @@ -30,6 +35,9 @@ class UploadUtil: def check_file_extension(cls, file: UploadFile): """ 检查文件后缀是否合法 + + :param file: 文件对象 + :return: 校验结果 """ file_extension = file.filename.rsplit('.', 1)[-1] if file_extension in UploadConfig.DEFAULT_ALLOWED_EXTENSION: @@ -37,9 +45,12 @@ class UploadUtil: return False @classmethod - def check_file_timestamp(cls, filename): + def check_file_timestamp(cls, filename: str): """ 校验文件时间戳是否合法 + + :param filename: 文件名称 + :return: 校验结果 """ timestamp = filename.rsplit('.', 1)[0].split('_')[-1].split(UploadConfig.UPLOAD_MACHINE)[0] try: @@ -49,18 +60,24 @@ class UploadUtil: return False @classmethod - def check_file_machine(cls, filename): + def check_file_machine(cls, filename: str): """ 校验文件机器码是否合法 + + :param filename: 文件名称 + :return: 校验结果 """ if filename.rsplit('.', 1)[0][-4] == UploadConfig.UPLOAD_MACHINE: return True return False @classmethod - def check_file_random_code(cls, filename): + def check_file_random_code(cls, filename: str): """ 校验文件随机码是否合法 + + :param filename: 文件名称 + :return: 校验结果 """ valid_code_list = [f'{i:03}' for i in range(1, 999)] if filename.rsplit('.', 1)[0][-3:] in valid_code_list: @@ -68,9 +85,12 @@ class UploadUtil: return False @classmethod - def generate_file(cls, filepath): + def generate_file(cls, filepath: str): """ 根据文件生成二进制数据 + + :param filepath: 文件路径 + :yield: 二进制数据 """ with open(filepath, 'rb') as response_file: yield from response_file @@ -79,5 +99,7 @@ class UploadUtil: def delete_file(cls, filepath: str): """ 根据文件路径删除对应文件 + + :param filepath: 文件路径 """ os.remove(filepath) -- Gitee From 4669d6b29ba846370a2c25a9227b08869515fc84 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sat, 13 Jul 2024 18:16:55 +0800 Subject: [PATCH 107/129] =?UTF-8?q?chore:=20=E8=B0=83=E6=95=B4ServiceExcep?= =?UTF-8?q?tion=E7=9A=84=E6=97=A5=E5=BF=97=E7=BA=A7=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/exceptions/handle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index 879019c..dec516a 100644 --- a/ruoyi-fastapi-backend/exceptions/handle.py +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -48,7 +48,7 @@ def handle_exception(app: FastAPI): # 自定义服务异常 @app.exception_handler(ServiceException) async def service_exception_handler(request: Request, exc: ServiceException): - logger.warning(exc.message) + logger.error(exc.message) return ResponseUtil.error(data=exc.data, msg=exc.message) # 自定义服务警告 -- Gitee From c39375b776723f3ecc356ed347e81ccb10edadb4 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Sun, 14 Jul 2024 22:37:35 +0800 Subject: [PATCH 108/129] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E6=A8=A1=E5=9D=97service=E5=B1=82?= =?UTF-8?q?=E5=8F=8A=E5=BC=82=E5=B8=B8=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/config/constant.py | 27 +++ ruoyi-fastapi-backend/config/get_scheduler.py | 171 ++++++++++++++- .../module_admin/controller/job_controller.py | 206 ++++++------------ .../module_admin/dao/job_dao.py | 11 +- .../module_admin/service/job_service.py | 100 ++++++--- ruoyi-fastapi-backend/utils/string_util.py | 55 +++++ .../src/views/monitor/job/index.vue | 2 +- 7 files changed, 398 insertions(+), 174 deletions(-) diff --git a/ruoyi-fastapi-backend/config/constant.py b/ruoyi-fastapi-backend/config/constant.py index 46ad2ea..9129fe0 100644 --- a/ruoyi-fastapi-backend/config/constant.py +++ b/ruoyi-fastapi-backend/config/constant.py @@ -5,6 +5,9 @@ class CommonConstant: WWW: www主域 HTTP: http请求 HTTPS: https请求 + LOOKUP_RMI: RMI远程方法调用 + LOOKUP_LDAP: LDAP远程方法调用 + LOOKUP_LDAPS: LDAPS远程方法调用 YES: 是否为系统默认(是) NO: 是否为系统默认(否) DEPT_NORMAL: 部门正常状态 @@ -16,6 +19,9 @@ class CommonConstant: WWW = 'www.' HTTP = 'http://' HTTPS = 'https://' + LOOKUP_RMI = 'rmi:' + LOOKUP_LDAP = 'ldap:' + LOOKUP_LDAPS = 'ldaps:' YES = 'Y' NO = 'N' DEPT_NORMAL = '0' @@ -66,6 +72,27 @@ class HttpStatusConstant: WARN = 601 +class JobConstant: + """ + 定时任务常量 + + JOB_ERROR_LIST: 定时任务禁止调用模块列表 + JOB_WHITE_LIST: 定时任务允许调用模块列表 + """ + + JOB_ERROR_LIST = [ + 'app', + 'config', + 'exceptions', + 'middlewares', + 'module_admin', + 'server', + 'sub_applications', + 'utils', + ] + JOB_WHITE_LIST = ['module_task'] + + class MenuConstant: """ 菜单常量 diff --git a/ruoyi-fastapi-backend/config/get_scheduler.py b/ruoyi-fastapi-backend/config/get_scheduler.py index b9cfa00..9b6ed2a 100644 --- a/ruoyi-fastapi-backend/config/get_scheduler.py +++ b/ruoyi-fastapi-backend/config/get_scheduler.py @@ -1,4 +1,5 @@ import json +import re from apscheduler.events import EVENT_ALL from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor from apscheduler.schedulers.background import BackgroundScheduler @@ -9,10 +10,12 @@ from apscheduler.triggers.cron import CronTrigger from datetime import datetime, timedelta from sqlalchemy.engine import create_engine from sqlalchemy.orm import sessionmaker +from typing import Union from config.database import AsyncSessionLocal, quote_plus from config.env import DataBaseConfig, RedisConfig +from exceptions.exception import ServiceException from module_admin.dao.job_dao import JobDao -from module_admin.entity.vo.job_vo import JobLogModel +from module_admin.entity.vo.job_vo import JobLogModel, JobModel from module_admin.service.job_log_service import JobLogService from utils.log_util import logger import module_task # noqa: F401 @@ -21,7 +24,7 @@ import module_task # noqa: F401 # 重写Cron定时 class MyCronTrigger(CronTrigger): @classmethod - def from_crontab(cls, expr, timezone=None): + def from_crontab(cls, expr: str, timezone=None): values = expr.split() if len(values) != 6 and len(values) != 7: raise ValueError('Wrong number of fields; got {}, expected 6 or 7'.format(len(values))) @@ -62,7 +65,7 @@ class MyCronTrigger(CronTrigger): ) @classmethod - def __find_recent_workday(cls, day): + def __find_recent_workday(cls, day: int): now = datetime.now() date = datetime(now.year, now.month, day) if date.weekday() < 5: @@ -144,7 +147,7 @@ class SchedulerUtil: logger.info('关闭定时任务成功') @classmethod - def get_scheduler_job(cls, job_id): + def get_scheduler_job(cls, job_id: Union[str, int]): """ 根据任务id获取任务对象 @@ -156,7 +159,7 @@ class SchedulerUtil: return query_job @classmethod - def add_scheduler_job(cls, job_info): + def add_scheduler_job(cls, job_info: JobModel): """ 根据输入的任务对象信息添加任务 @@ -178,7 +181,7 @@ class SchedulerUtil: ) @classmethod - def execute_scheduler_job_once(cls, job_info): + def execute_scheduler_job_once(cls, job_info: JobModel): """ 根据输入的任务对象执行一次任务 @@ -201,7 +204,7 @@ class SchedulerUtil: ) @classmethod - def remove_scheduler_job(cls, job_id): + def remove_scheduler_job(cls, job_id: Union[str, int]): """ 根据任务id移除任务 @@ -210,6 +213,160 @@ class SchedulerUtil: """ scheduler.remove_job(job_id=str(job_id)) + @classmethod + def __valid_range(cls, search_str: str, start_range: int, end_range: int): + match = re.match(r'^(\d+)-(\d+)$', search_str) + if match: + start, end = int(match.group(1)), int(match.group(2)) + return start_range <= start < end <= end_range + return False + + @classmethod + def __valid_sum( + cls, search_str: str, start_range_a: int, start_range_b: int, end_range_a: int, end_range_b: int, sum_range: int + ): + match = re.match(r'^(\d+)/(\d+)$', search_str) + if match: + start, end = int(match.group(1)), int(match.group(2)) + return ( + start_range_a <= start <= start_range_b + and end_range_a <= end <= end_range_b + and start + end <= sum_range + ) + return False + + @classmethod + def __validate_second_or_minute(cls, second_or_minute: str): + """ + 校验秒或分钟值是否正确 + + :param second_or_minute: 秒或分钟值 + :return: 校验结果 + """ + if ( + second_or_minute == '*' + or ('-' in second_or_minute and cls.__valid_range(second_or_minute, 0, 59)) + or ('/' in second_or_minute and cls.__valid_sum(second_or_minute, 0, 58, 1, 59)) + or re.match(r'^(?:[0-5]?\d|59)(?:,[0-5]?\d|59)*$', second_or_minute) + ): + return True + return False + + @classmethod + def __validate_hour(cls, hour: str): + """ + 校验小时值是否正确 + :param hour: 小时值 + :return: 校验结果 + """ + if ( + hour == '*' + or ('-' in hour and cls.__valid_range(hour, 0, 23)) + or ('/' in hour and cls.__valid_sum(hour, 0, 22, 1, 23, 23)) + or re.match(r'^(?:0|[1-9]|1\d|2[0-3])(?:,(?:0|[1-9]|1\d|2[0-3]))*$', hour) + ): + return True + return False + + @classmethod + def __validate_day(cls, day: str): + """ + 校验日值是否正确 + :param day: 日值 + :return: 校验结果 + """ + if ( + day in ['*', '?', 'L'] + or ('-' in day and cls.__valid_range(day, 1, 31)) + or ('/' in day and cls.__valid_sum(day, 1, 30, 1, 30, 31)) + or ('W' in day and re.match(r'^(?:[1-9]|1\d|2\d|3[01])W$', day)) + or re.match(r'^(?:0|[1-9]|1\d|2[0-9]|3[0-1])(?:,(?:0|[1-9]|1\d|2[0-9]|3[0-1]))*$', day) + ): + return True + return False + + @classmethod + def __validate_month(cls, month: str): + """ + 校验月值是否正确 + :param month: 月值 + :return: 校验结果 + """ + if ( + month == '*' + or ('-' in month and cls.__valid_range(month, 1, 12)) + or ('/' in month and cls.__valid_sum(month, 1, 11, 1, 11, 12)) + or re.match(r'^(?:0|[1-9]|1[0-2])(?:,(?:0|[1-9]|1[0-2]))*$', month) + ): + return True + return False + + @classmethod + def __validate_week(cls, week: str): + """ + 校验周值是否正确 + :param week: 周值 + :return: 校验结果 + """ + if ( + week in ['*', '?'] + or ('-' in week and cls.__valid_range(week, 1, 7)) + or re.match(r'^[1-7]#[1-4]$', week) + or re.match(r'^[1-7]L$', week) + or re.match(r'^[1-7](?:(,[1-7]))*$', week) + ): + return True + return False + + @classmethod + def __validate_year(cls, year: str): + """ + 校验年值是否正确 + :param year: 年值 + :return: 校验结果 + """ + current_year = int(datetime.now().year) + if ( + year == '*' + or ('-' in year and cls.__valid_range(year, current_year, 2099)) + or ('/' in year and cls.__valid_sum(year, current_year, 2098, 1, 2099 - current_year, 2099)) + or re.match(r'^[1-7]#[1-4]$', year) + or re.match(r'^[1-7]L$', year) + ): + return True + return False + + @classmethod + def validate_cron_expression(cls, cron_expression: str): + """ + 校验Cron表达式是否正确 + + :param cron_expression: Cron表达式 + :return: 校验结果 + """ + values = cron_expression.split() + if len(values) != 6 and len(values) != 7: + return False + second_validation = cls.__validate_second_or_minute(values[0]) + minute_validation = cls.__validate_second_or_minute(values[1]) + hour_validation = cls.__validate_hour(values[2]) + day_validation = cls.__validate_day(values[3]) + month_validation = cls.__validate_month(values[4]) + week_validation = cls.__validate_week(values[5]) + validation = ( + second_validation + and minute_validation + and hour_validation + and day_validation + and month_validation + and week_validation + ) + if len(values) == 6: + return validation + if len(values) == 7: + year_validation = cls.__validate_year(values[6]) + return validation and year_validation + @classmethod def scheduler_event_listener(cls, event): # 获取事件类型和任务ID diff --git a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py index 961c472..3e3b095 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py @@ -35,14 +35,11 @@ async def get_system_job_list( job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), ): - try: - # 获取分页数据 - notice_page_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=True) - logger.info('获取成功') - return ResponseUtil.success(model_content=notice_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + notice_page_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=True) + logger.info('获取成功') + + return ResponseUtil.success(model_content=notice_page_query_result) @jobController.post('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))]) @@ -54,21 +51,14 @@ async def add_system_job( query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), ): - try: - add_job.create_by = current_user.user.user_name - add_job.create_time = datetime.now() - add_job.update_by = current_user.user.user_name - add_job.update_time = datetime.now() - add_job_result = await JobService.add_job_services(query_db, add_job) - if add_job_result.is_success: - logger.info(add_job_result.message) - return ResponseUtil.success(msg=add_job_result.message) - else: - logger.warning(add_job_result.message) - return ResponseUtil.failure(msg=add_job_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + add_job.create_by = current_user.user.user_name + add_job.create_time = datetime.now() + add_job.update_by = current_user.user.user_name + add_job.update_time = datetime.now() + add_job_result = await JobService.add_job_services(query_db, add_job) + logger.info(add_job_result.message) + + return ResponseUtil.success(msg=add_job_result.message) @jobController.put('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))]) @@ -80,89 +70,62 @@ async def edit_system_job( query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), ): - try: - edit_job.update_by = current_user.user.user_name - edit_job.update_time = datetime.now() - edit_job_result = await JobService.edit_job_services(query_db, edit_job) - if edit_job_result.is_success: - logger.info(edit_job_result.message) - return ResponseUtil.success(msg=edit_job_result.message) - else: - logger.warning(edit_job_result.message) - return ResponseUtil.failure(msg=edit_job_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_job.update_by = current_user.user.user_name + edit_job.update_time = datetime.now() + edit_job_result = await JobService.edit_job_services(query_db, edit_job) + logger.info(edit_job_result.message) + + return ResponseUtil.success(msg=edit_job_result.message) @jobController.put('/job/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) @log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) async def change_system_job_status( request: Request, - edit_job: EditJobModel, + change_job: EditJobModel, query_db: AsyncSession = Depends(get_db), current_user: CurrentUserModel = Depends(LoginService.get_current_user), ): - try: - edit_job.update_by = current_user.user.user_name - edit_job.update_time = datetime.now() - edit_job.type = 'status' - edit_job_result = await JobService.edit_job_services(query_db, edit_job) - if edit_job_result.is_success: - logger.info(edit_job_result.message) - return ResponseUtil.success(msg=edit_job_result.message) - else: - logger.warning(edit_job_result.message) - return ResponseUtil.failure(msg=edit_job_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + edit_job = EditJobModel( + jobId=change_job.job_id, + status=change_job.status, + updateBy=current_user.user.user_name, + updateTime=datetime.now(), + type='status', + ) + edit_job_result = await JobService.edit_job_services(query_db, edit_job) + logger.info(edit_job_result.message) + + return ResponseUtil.success(msg=edit_job_result.message) @jobController.put('/job/run', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) @log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) async def execute_system_job(request: Request, execute_job: JobModel, query_db: AsyncSession = Depends(get_db)): - try: - execute_job_result = await JobService.execute_job_once_services(query_db, execute_job) - if execute_job_result.is_success: - logger.info(execute_job_result.message) - return ResponseUtil.success(msg=execute_job_result.message) - else: - logger.warning(execute_job_result.message) - return ResponseUtil.failure(msg=execute_job_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + execute_job_result = await JobService.execute_job_once_services(query_db, execute_job) + logger.info(execute_job_result.message) + + return ResponseUtil.success(msg=execute_job_result.message) @jobController.delete('/job/{job_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @log_decorator(title='定时任务管理', business_type=BusinessType.DELETE) async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_job = DeleteJobModel(jobIds=job_ids) - delete_job_result = await JobService.delete_job_services(query_db, delete_job) - if delete_job_result.is_success: - logger.info(delete_job_result.message) - return ResponseUtil.success(msg=delete_job_result.message) - else: - logger.warning(delete_job_result.message) - return ResponseUtil.failure(msg=delete_job_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_job = DeleteJobModel(jobIds=job_ids) + delete_job_result = await JobService.delete_job_services(query_db, delete_job) + logger.info(delete_job_result.message) + + return ResponseUtil.success(msg=delete_job_result.message) @jobController.get( '/job/{job_id}', response_model=JobModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:query'))] ) async def query_detail_system_job(request: Request, job_id: int, query_db: AsyncSession = Depends(get_db)): - try: - job_detail_result = await JobService.job_detail_services(query_db, job_id) - logger.info(f'获取job_id为{job_id}的信息成功') - return ResponseUtil.success(data=job_detail_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + job_detail_result = await JobService.job_detail_services(query_db, job_id) + logger.info(f'获取job_id为{job_id}的信息成功') + + return ResponseUtil.success(data=job_detail_result) @jobController.post('/job/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) @@ -172,15 +135,12 @@ async def export_system_job_list( job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), ): - try: - # 获取全量数据 - job_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=False) - job_export_result = await JobService.export_job_list_services(request, job_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(job_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + job_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=False) + job_export_result = await JobService.export_job_list_services(request, job_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(job_export_result)) @jobController.get( @@ -191,49 +151,32 @@ async def get_system_job_log_list( job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_query), query_db: AsyncSession = Depends(get_db), ): - try: - # 获取分页数据 - job_log_page_query_result = await JobLogService.get_job_log_list_services( - query_db, job_log_page_query, is_page=True - ) - logger.info('获取成功') - return ResponseUtil.success(model_content=job_log_page_query_result) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取分页数据 + job_log_page_query_result = await JobLogService.get_job_log_list_services( + query_db, job_log_page_query, is_page=True + ) + logger.info('获取成功') + + return ResponseUtil.success(model_content=job_log_page_query_result) @jobController.delete('/jobLog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @log_decorator(title='定时任务日志管理', business_type=BusinessType.CLEAN) async def clear_system_job_log(request: Request, query_db: AsyncSession = Depends(get_db)): - try: - clear_job_log_result = await JobLogService.clear_job_log_services(query_db) - if clear_job_log_result.is_success: - logger.info(clear_job_log_result.message) - return ResponseUtil.success(msg=clear_job_log_result.message) - else: - logger.warning(clear_job_log_result.message) - return ResponseUtil.failure(msg=clear_job_log_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + clear_job_log_result = await JobLogService.clear_job_log_services(query_db) + logger.info(clear_job_log_result.message) + + return ResponseUtil.success(msg=clear_job_log_result.message) @jobController.delete('/jobLog/{job_log_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @log_decorator(title='定时任务日志管理', business_type=BusinessType.DELETE) async def delete_system_job_log(request: Request, job_log_ids: str, query_db: AsyncSession = Depends(get_db)): - try: - delete_job_log = DeleteJobLogModel(jobLogIds=job_log_ids) - delete_job_log_result = await JobLogService.delete_job_log_services(query_db, delete_job_log) - if delete_job_log_result.is_success: - logger.info(delete_job_log_result.message) - return ResponseUtil.success(msg=delete_job_log_result.message) - else: - logger.warning(delete_job_log_result.message) - return ResponseUtil.failure(msg=delete_job_log_result.message) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + delete_job_log = DeleteJobLogModel(jobLogIds=job_log_ids) + delete_job_log_result = await JobLogService.delete_job_log_services(query_db, delete_job_log) + logger.info(delete_job_log_result.message) + + return ResponseUtil.success(msg=delete_job_log_result.message) @jobController.post('/jobLog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) @@ -243,14 +186,9 @@ async def export_system_job_log_list( job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_form), query_db: AsyncSession = Depends(get_db), ): - try: - # 获取全量数据 - job_log_query_result = await JobLogService.get_job_log_list_services( - query_db, job_log_page_query, is_page=False - ) - job_log_export_result = await JobLogService.export_job_log_list_services(request, job_log_query_result) - logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(job_log_export_result)) - except Exception as e: - logger.exception(e) - return ResponseUtil.error(msg=str(e)) + # 获取全量数据 + job_log_query_result = await JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=False) + job_log_export_result = await JobLogService.export_job_log_list_services(request, job_log_query_result) + logger.info('导出成功') + + return ResponseUtil.streaming(data=bytes2file_response(job_log_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py index c2488c1..7f4f4a3 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py @@ -36,10 +36,13 @@ class JobDao: ( await db.execute( select(SysJob).where( - SysJob.job_name == job.job_name if job.job_name else True, - SysJob.job_group == job.job_group if job.job_group else True, - SysJob.invoke_target == job.invoke_target if job.invoke_target else True, - SysJob.cron_expression == job.cron_expression if job.cron_expression else True, + SysJob.job_name == job.job_name, + SysJob.job_group == job.job_group, + SysJob.job_executor == job.job_executor, + SysJob.invoke_target == job.invoke_target, + SysJob.job_args == job.job_args, + SysJob.job_kwargs == job.job_kwargs, + SysJob.cron_expression == job.cron_expression, ) ) ) diff --git a/ruoyi-fastapi-backend/module_admin/service/job_service.py b/ruoyi-fastapi-backend/module_admin/service/job_service.py index 12a9b93..76c2dfa 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_service.py @@ -1,12 +1,15 @@ from fastapi import Request from sqlalchemy.ext.asyncio import AsyncSession from typing import List +from config.constant import CommonConstant, JobConstant from config.get_scheduler import SchedulerUtil +from exceptions.exception import ServiceException from module_admin.dao.job_dao import JobDao from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.entity.vo.job_vo import DeleteJobModel, EditJobModel, JobModel, JobPageQueryModel from module_admin.service.dict_service import DictDataService from utils.common_util import CamelCaseUtil, export_list2excel +from utils.string_util import StringUtil class JobService: @@ -30,6 +33,21 @@ class JobService: return job_list_result + @classmethod + async def check_job_unique_services(cls, query_db: AsyncSession, page_object: JobModel): + """ + 校验定时任务是否存在service + + :param query_db: orm对象 + :param page_object: 定时任务对象 + :return: 校验结果 + """ + job_id = -1 if page_object.job_id is None else page_object.job_id + job = await JobDao.get_job_detail_by_info(query_db, page_object) + if job and job.job_id != job_id: + return CommonConstant.NOT_UNIQUE + return CommonConstant.UNIQUE + @classmethod async def add_job_services(cls, query_db: AsyncSession, page_object: JobModel): """ @@ -39,13 +57,28 @@ class JobService: :param page_object: 新增定时任务对象 :return: 新增定时任务校验结果 """ - job = await JobDao.get_job_detail_by_info(query_db, page_object) - if job: - result = dict(is_success=False, message='定时任务已存在') + if not SchedulerUtil.validate_cron_expression(page_object.cron_expression): + raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,Cron表达式不正确') + elif not await cls.check_job_unique_services(query_db, page_object): + raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,定时任务已存在') + elif StringUtil.contains_ignore_case(page_object.invoke_target, CommonConstant.LOOKUP_RMI): + raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,目标字符串不允许rmi调用') + elif StringUtil.contains_any_ignore_case( + page_object.invoke_target, [CommonConstant.LOOKUP_LDAP, CommonConstant.LOOKUP_LDAPS] + ): + raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,目标字符串不允许ldap(s)调用') + elif StringUtil.contains_any_ignore_case( + page_object.invoke_target, [CommonConstant.HTTP, CommonConstant.HTTPS] + ): + raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,目标字符串不允许http(s)调用') + elif StringUtil.startswith_any_case(page_object.invoke_target, JobConstant.JOB_ERROR_LIST): + raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,目标字符串存在违规') + elif not StringUtil.startswith_any_case(page_object.invoke_target, JobConstant.JOB_WHITE_LIST): + raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,目标字符串不在白名单内') else: try: - await JobDao.add_job_dao(query_db, page_object) - job_info = await JobDao.get_job_detail_by_info(query_db, page_object) + add_job = await JobDao.add_job_dao(query_db, page_object) + job_info = await cls.job_detail_services(query_db, add_job.job_id) if job_info.status == '0': SchedulerUtil.add_scheduler_job(job_info=job_info) await query_db.commit() @@ -68,18 +101,31 @@ class JobService: edit_job = page_object.model_dump(exclude_unset=True) if page_object.type == 'status': del edit_job['type'] - job_info = await cls.job_detail_services(query_db, edit_job.get('job_id')) + job_info = await cls.job_detail_services(query_db, page_object.job_id) if job_info: - if page_object.type != 'status' and ( - job_info.job_name != page_object.job_name - or job_info.job_group != page_object.job_group - or job_info.invoke_target != page_object.invoke_target - or job_info.cron_expression != page_object.cron_expression - ): - job = await JobDao.get_job_detail_by_info(query_db, page_object) - if job: - result = dict(is_success=False, message='定时任务已存在') - return CrudResponseModel(**result) + if page_object.type != 'status': + if not SchedulerUtil.validate_cron_expression(page_object.cron_expression): + raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,Cron表达式不正确') + elif not await cls.check_job_unique_services(query_db, page_object): + raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,定时任务已存在') + elif StringUtil.contains_ignore_case(page_object.invoke_target, CommonConstant.LOOKUP_RMI): + raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,目标字符串不允许rmi调用') + elif StringUtil.contains_any_ignore_case( + page_object.invoke_target, [CommonConstant.LOOKUP_LDAP, CommonConstant.LOOKUP_LDAPS] + ): + raise ServiceException( + message=f'修改定时任务{page_object.job_name}失败,目标字符串不允许ldap(s)调用' + ) + elif StringUtil.contains_any_ignore_case( + page_object.invoke_target, [CommonConstant.HTTP, CommonConstant.HTTPS] + ): + raise ServiceException( + message=f'修改定时任务{page_object.job_name}失败,目标字符串不允许http(s)调用' + ) + elif StringUtil.startswith_any_case(page_object.invoke_target, JobConstant.JOB_ERROR_LIST): + raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,目标字符串存在违规') + elif not StringUtil.startswith_any_case(page_object.invoke_target, JobConstant.JOB_WHITE_LIST): + raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,目标字符串不在白名单内') try: await JobDao.edit_job_dao(query_db, edit_job) query_job = SchedulerUtil.get_scheduler_job(job_id=edit_job.get('job_id')) @@ -89,14 +135,12 @@ class JobService: job_info = await cls.job_detail_services(query_db, edit_job.get('job_id')) SchedulerUtil.add_scheduler_job(job_info=job_info) await query_db.commit() - result = dict(is_success=True, message='更新成功') + return CrudResponseModel(is_success=True, message='更新成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='定时任务不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='定时任务不存在') @classmethod async def execute_job_once_services(cls, query_db: AsyncSession, page_object: JobModel): @@ -113,11 +157,9 @@ class JobService: job_info = await cls.job_detail_services(query_db, page_object.job_id) if job_info: SchedulerUtil.execute_scheduler_job_once(job_info=job_info) - result = dict(is_success=True, message='执行成功') + return CrudResponseModel(is_success=True, message='执行成功') else: - result = dict(is_success=False, message='定时任务不存在') - - return CrudResponseModel(**result) + raise ServiceException(message='定时任务不存在') @classmethod async def delete_job_services(cls, query_db: AsyncSession, page_object: DeleteJobModel): @@ -137,13 +179,12 @@ class JobService: if query_job: SchedulerUtil.remove_scheduler_job(job_id=job_id) await query_db.commit() - result = dict(is_success=True, message='删除成功') + return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入定时任务id为空') - return CrudResponseModel(**result) + raise ServiceException(message='传入定时任务id为空') @classmethod async def job_detail_services(cls, query_db: AsyncSession, job_id: int): @@ -155,7 +196,10 @@ class JobService: :return: 定时任务id对应的信息 """ job = await JobDao.get_job_detail_by_id(query_db, job_id=job_id) - result = JobModel(**CamelCaseUtil.transform_result(job)) + if job: + result = JobModel(**CamelCaseUtil.transform_result(job)) + else: + result = JobModel(**dict()) return result diff --git a/ruoyi-fastapi-backend/utils/string_util.py b/ruoyi-fastapi-backend/utils/string_util.py index 0a9d25d..0be9e65 100644 --- a/ruoyi-fastapi-backend/utils/string_util.py +++ b/ruoyi-fastapi-backend/utils/string_util.py @@ -1,3 +1,4 @@ +from typing import List from config.constant import CommonConstant @@ -44,3 +45,57 @@ class StringUtil: :return: 是否为http(s)://开头 """ return link.startswith(CommonConstant.HTTP) or link.startswith(CommonConstant.HTTPS) + + @classmethod + def contains_ignore_case(cls, search_str: str, compare_str: str): + """ + 查找指定字符串是否包含指定字符串同时串忽略大小写 + + :param search_str: 查找的字符串 + :param compare_str: 比对的字符串 + :return: 查找结果 + """ + if compare_str and search_str: + return compare_str.lower() in search_str.lower() + return False + + @classmethod + def contains_any_ignore_case(cls, search_str: str, compare_str_list: List[str]): + """ + 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写 + + :param search_str: 查找的字符串 + :param compare_str_list: 比对的字符串列表 + :return: 查找结果 + """ + if search_str and compare_str_list: + for compare_str in compare_str_list: + return cls.contains_ignore_case(search_str, compare_str) + return False + + @classmethod + def startswith_case(cls, search_str: str, compare_str: str): + """ + 查找指定字符串是否以指定字符串开头 + + :param search_str: 查找的字符串 + :param compare_str: 比对的字符串 + :return: 查找结果 + """ + if compare_str and search_str: + return search_str.startswith(compare_str) + return False + + @classmethod + def startswith_any_case(cls, search_str: str, compare_str_list: List[str]): + """ + 查找指定字符串是否以指定字符串列表中的任意一个字符串开头 + + :param search_str: 查找的字符串 + :param compare_str_list: 比对的字符串列表 + :return: 查找结果 + """ + if search_str and compare_str_list: + for compare_str in compare_str_list: + return cls.startswith_case(search_str, compare_str) + return False diff --git a/ruoyi-fastapi-frontend/src/views/monitor/job/index.vue b/ruoyi-fastapi-frontend/src/views/monitor/job/index.vue index f820e5c..1b6b2ce 100644 --- a/ruoyi-fastapi-frontend/src/views/monitor/job/index.vue +++ b/ruoyi-fastapi-frontend/src/views/monitor/job/index.vue @@ -385,7 +385,7 @@ function reset() { cronExpression: undefined, misfirePolicy: "1", concurrent: "1", - status: "0" + status: "1" }; proxy.resetForm("jobRef"); } -- Gitee From 068503d275fb92a4c5d2b5683083dc4292444e03 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 15 Jul 2024 08:49:15 +0800 Subject: [PATCH 109/129] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9ECronUtil?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/config/get_scheduler.py | 156 ---------------- .../module_admin/service/job_service.py | 13 +- ruoyi-fastapi-backend/utils/cron_util.py | 172 ++++++++++++++++++ 3 files changed, 179 insertions(+), 162 deletions(-) create mode 100644 ruoyi-fastapi-backend/utils/cron_util.py diff --git a/ruoyi-fastapi-backend/config/get_scheduler.py b/ruoyi-fastapi-backend/config/get_scheduler.py index 9b6ed2a..5c5809c 100644 --- a/ruoyi-fastapi-backend/config/get_scheduler.py +++ b/ruoyi-fastapi-backend/config/get_scheduler.py @@ -1,5 +1,4 @@ import json -import re from apscheduler.events import EVENT_ALL from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor from apscheduler.schedulers.background import BackgroundScheduler @@ -13,7 +12,6 @@ from sqlalchemy.orm import sessionmaker from typing import Union from config.database import AsyncSessionLocal, quote_plus from config.env import DataBaseConfig, RedisConfig -from exceptions.exception import ServiceException from module_admin.dao.job_dao import JobDao from module_admin.entity.vo.job_vo import JobLogModel, JobModel from module_admin.service.job_log_service import JobLogService @@ -213,160 +211,6 @@ class SchedulerUtil: """ scheduler.remove_job(job_id=str(job_id)) - @classmethod - def __valid_range(cls, search_str: str, start_range: int, end_range: int): - match = re.match(r'^(\d+)-(\d+)$', search_str) - if match: - start, end = int(match.group(1)), int(match.group(2)) - return start_range <= start < end <= end_range - return False - - @classmethod - def __valid_sum( - cls, search_str: str, start_range_a: int, start_range_b: int, end_range_a: int, end_range_b: int, sum_range: int - ): - match = re.match(r'^(\d+)/(\d+)$', search_str) - if match: - start, end = int(match.group(1)), int(match.group(2)) - return ( - start_range_a <= start <= start_range_b - and end_range_a <= end <= end_range_b - and start + end <= sum_range - ) - return False - - @classmethod - def __validate_second_or_minute(cls, second_or_minute: str): - """ - 校验秒或分钟值是否正确 - - :param second_or_minute: 秒或分钟值 - :return: 校验结果 - """ - if ( - second_or_minute == '*' - or ('-' in second_or_minute and cls.__valid_range(second_or_minute, 0, 59)) - or ('/' in second_or_minute and cls.__valid_sum(second_or_minute, 0, 58, 1, 59)) - or re.match(r'^(?:[0-5]?\d|59)(?:,[0-5]?\d|59)*$', second_or_minute) - ): - return True - return False - - @classmethod - def __validate_hour(cls, hour: str): - """ - 校验小时值是否正确 - :param hour: 小时值 - :return: 校验结果 - """ - if ( - hour == '*' - or ('-' in hour and cls.__valid_range(hour, 0, 23)) - or ('/' in hour and cls.__valid_sum(hour, 0, 22, 1, 23, 23)) - or re.match(r'^(?:0|[1-9]|1\d|2[0-3])(?:,(?:0|[1-9]|1\d|2[0-3]))*$', hour) - ): - return True - return False - - @classmethod - def __validate_day(cls, day: str): - """ - 校验日值是否正确 - :param day: 日值 - :return: 校验结果 - """ - if ( - day in ['*', '?', 'L'] - or ('-' in day and cls.__valid_range(day, 1, 31)) - or ('/' in day and cls.__valid_sum(day, 1, 30, 1, 30, 31)) - or ('W' in day and re.match(r'^(?:[1-9]|1\d|2\d|3[01])W$', day)) - or re.match(r'^(?:0|[1-9]|1\d|2[0-9]|3[0-1])(?:,(?:0|[1-9]|1\d|2[0-9]|3[0-1]))*$', day) - ): - return True - return False - - @classmethod - def __validate_month(cls, month: str): - """ - 校验月值是否正确 - :param month: 月值 - :return: 校验结果 - """ - if ( - month == '*' - or ('-' in month and cls.__valid_range(month, 1, 12)) - or ('/' in month and cls.__valid_sum(month, 1, 11, 1, 11, 12)) - or re.match(r'^(?:0|[1-9]|1[0-2])(?:,(?:0|[1-9]|1[0-2]))*$', month) - ): - return True - return False - - @classmethod - def __validate_week(cls, week: str): - """ - 校验周值是否正确 - :param week: 周值 - :return: 校验结果 - """ - if ( - week in ['*', '?'] - or ('-' in week and cls.__valid_range(week, 1, 7)) - or re.match(r'^[1-7]#[1-4]$', week) - or re.match(r'^[1-7]L$', week) - or re.match(r'^[1-7](?:(,[1-7]))*$', week) - ): - return True - return False - - @classmethod - def __validate_year(cls, year: str): - """ - 校验年值是否正确 - :param year: 年值 - :return: 校验结果 - """ - current_year = int(datetime.now().year) - if ( - year == '*' - or ('-' in year and cls.__valid_range(year, current_year, 2099)) - or ('/' in year and cls.__valid_sum(year, current_year, 2098, 1, 2099 - current_year, 2099)) - or re.match(r'^[1-7]#[1-4]$', year) - or re.match(r'^[1-7]L$', year) - ): - return True - return False - - @classmethod - def validate_cron_expression(cls, cron_expression: str): - """ - 校验Cron表达式是否正确 - - :param cron_expression: Cron表达式 - :return: 校验结果 - """ - values = cron_expression.split() - if len(values) != 6 and len(values) != 7: - return False - second_validation = cls.__validate_second_or_minute(values[0]) - minute_validation = cls.__validate_second_or_minute(values[1]) - hour_validation = cls.__validate_hour(values[2]) - day_validation = cls.__validate_day(values[3]) - month_validation = cls.__validate_month(values[4]) - week_validation = cls.__validate_week(values[5]) - validation = ( - second_validation - and minute_validation - and hour_validation - and day_validation - and month_validation - and week_validation - ) - if len(values) == 6: - return validation - if len(values) == 7: - year_validation = cls.__validate_year(values[6]) - return validation and year_validation - @classmethod def scheduler_event_listener(cls, event): # 获取事件类型和任务ID diff --git a/ruoyi-fastapi-backend/module_admin/service/job_service.py b/ruoyi-fastapi-backend/module_admin/service/job_service.py index 76c2dfa..edd26e0 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_service.py @@ -9,6 +9,7 @@ from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.entity.vo.job_vo import DeleteJobModel, EditJobModel, JobModel, JobPageQueryModel from module_admin.service.dict_service import DictDataService from utils.common_util import CamelCaseUtil, export_list2excel +from utils.cron_util import CronUtil from utils.string_util import StringUtil @@ -57,10 +58,8 @@ class JobService: :param page_object: 新增定时任务对象 :return: 新增定时任务校验结果 """ - if not SchedulerUtil.validate_cron_expression(page_object.cron_expression): + if not CronUtil.validate_cron_expression(page_object.cron_expression): raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,Cron表达式不正确') - elif not await cls.check_job_unique_services(query_db, page_object): - raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,定时任务已存在') elif StringUtil.contains_ignore_case(page_object.invoke_target, CommonConstant.LOOKUP_RMI): raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,目标字符串不允许rmi调用') elif StringUtil.contains_any_ignore_case( @@ -75,6 +74,8 @@ class JobService: raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,目标字符串存在违规') elif not StringUtil.startswith_any_case(page_object.invoke_target, JobConstant.JOB_WHITE_LIST): raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,目标字符串不在白名单内') + elif not await cls.check_job_unique_services(query_db, page_object): + raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,定时任务已存在') else: try: add_job = await JobDao.add_job_dao(query_db, page_object) @@ -104,10 +105,8 @@ class JobService: job_info = await cls.job_detail_services(query_db, page_object.job_id) if job_info: if page_object.type != 'status': - if not SchedulerUtil.validate_cron_expression(page_object.cron_expression): + if not CronUtil.validate_cron_expression(page_object.cron_expression): raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,Cron表达式不正确') - elif not await cls.check_job_unique_services(query_db, page_object): - raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,定时任务已存在') elif StringUtil.contains_ignore_case(page_object.invoke_target, CommonConstant.LOOKUP_RMI): raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,目标字符串不允许rmi调用') elif StringUtil.contains_any_ignore_case( @@ -126,6 +125,8 @@ class JobService: raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,目标字符串存在违规') elif not StringUtil.startswith_any_case(page_object.invoke_target, JobConstant.JOB_WHITE_LIST): raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,目标字符串不在白名单内') + elif not await cls.check_job_unique_services(query_db, page_object): + raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,定时任务已存在') try: await JobDao.edit_job_dao(query_db, edit_job) query_job = SchedulerUtil.get_scheduler_job(job_id=edit_job.get('job_id')) diff --git a/ruoyi-fastapi-backend/utils/cron_util.py b/ruoyi-fastapi-backend/utils/cron_util.py new file mode 100644 index 0000000..09050e5 --- /dev/null +++ b/ruoyi-fastapi-backend/utils/cron_util.py @@ -0,0 +1,172 @@ +import re +from datetime import datetime + + +class CronUtil: + """ + Cron表达式工具类 + """ + + @classmethod + def __valid_range(cls, search_str: str, start_range: int, end_range: int): + match = re.match(r'^(\d+)-(\d+)$', search_str) + if match: + start, end = int(match.group(1)), int(match.group(2)) + return start_range <= start < end <= end_range + return False + + @classmethod + def __valid_sum( + cls, search_str: str, start_range_a: int, start_range_b: int, end_range_a: int, end_range_b: int, sum_range: int + ): + match = re.match(r'^(\d+)/(\d+)$', search_str) + if match: + start, end = int(match.group(1)), int(match.group(2)) + return ( + start_range_a <= start <= start_range_b + and end_range_a <= end <= end_range_b + and start + end <= sum_range + ) + return False + + @classmethod + def validate_second_or_minute(cls, second_or_minute: str): + """ + 校验秒或分钟值是否正确 + + :param second_or_minute: 秒或分钟值 + :return: 校验结果 + """ + if ( + second_or_minute == '*' + or ('-' in second_or_minute and cls.__valid_range(second_or_minute, 0, 59)) + or ('/' in second_or_minute and cls.__valid_sum(second_or_minute, 0, 58, 1, 59)) + or re.match(r'^(?:[0-5]?\d|59)(?:,[0-5]?\d|59)*$', second_or_minute) + ): + return True + return False + + @classmethod + def validate_hour(cls, hour: str): + """ + 校验小时值是否正确 + + :param hour: 小时值 + :return: 校验结果 + """ + if ( + hour == '*' + or ('-' in hour and cls.__valid_range(hour, 0, 23)) + or ('/' in hour and cls.__valid_sum(hour, 0, 22, 1, 23, 23)) + or re.match(r'^(?:0|[1-9]|1\d|2[0-3])(?:,(?:0|[1-9]|1\d|2[0-3]))*$', hour) + ): + return True + return False + + @classmethod + def validate_day(cls, day: str): + """ + 校验日值是否正确 + + :param day: 日值 + :return: 校验结果 + """ + if ( + day in ['*', '?', 'L'] + or ('-' in day and cls.__valid_range(day, 1, 31)) + or ('/' in day and cls.__valid_sum(day, 1, 30, 1, 30, 31)) + or ('W' in day and re.match(r'^(?:[1-9]|1\d|2\d|3[01])W$', day)) + or re.match(r'^(?:0|[1-9]|1\d|2[0-9]|3[0-1])(?:,(?:0|[1-9]|1\d|2[0-9]|3[0-1]))*$', day) + ): + return True + return False + + @classmethod + def validate_month(cls, month: str): + """ + 校验月值是否正确 + + :param month: 月值 + :return: 校验结果 + """ + if ( + month == '*' + or ('-' in month and cls.__valid_range(month, 1, 12)) + or ('/' in month and cls.__valid_sum(month, 1, 11, 1, 11, 12)) + or re.match(r'^(?:0|[1-9]|1[0-2])(?:,(?:0|[1-9]|1[0-2]))*$', month) + ): + return True + return False + + @classmethod + def validate_week(cls, week: str): + """ + 校验周值是否正确 + + :param week: 周值 + :return: 校验结果 + """ + if ( + week in ['*', '?'] + or ('-' in week and cls.__valid_range(week, 1, 7)) + or re.match(r'^[1-7]#[1-4]$', week) + or re.match(r'^[1-7]L$', week) + or re.match(r'^[1-7](?:(,[1-7]))*$', week) + ): + return True + return False + + @classmethod + def validate_year(cls, year: str): + """ + 校验年值是否正确 + + :param year: 年值 + :return: 校验结果 + """ + current_year = int(datetime.now().year) + future_years = [current_year + i for i in range(9)] + if ( + year == '*' + or ('-' in year and cls.__valid_range(year, current_year, 2099)) + or ('/' in year and cls.__valid_sum(year, current_year, 2098, 1, 2099 - current_year, 2099)) + or re.match(r'^[1-7]#[1-4]$', year) + or re.match(r'^[1-7]L$', year) + or ( + (len(year) == 4 or ',' in year) + and all(int(item) in future_years and current_year <= int(item) <= 2099 for item in year.split(',')) + ) + ): + return True + return False + + @classmethod + def validate_cron_expression(cls, cron_expression: str): + """ + 校验Cron表达式是否正确 + + :param cron_expression: Cron表达式 + :return: 校验结果 + """ + values = cron_expression.split() + if len(values) != 6 and len(values) != 7: + return False + second_validation = cls.validate_second_or_minute(values[0]) + minute_validation = cls.validate_second_or_minute(values[1]) + hour_validation = cls.validate_hour(values[2]) + day_validation = cls.validate_day(values[3]) + month_validation = cls.validate_month(values[4]) + week_validation = cls.validate_week(values[5]) + validation = ( + second_validation + and minute_validation + and hour_validation + and day_validation + and month_validation + and week_validation + ) + if len(values) == 6: + return validation + if len(values) == 7: + year_validation = cls.validate_year(values[6]) + return validation and year_validation -- Gitee From 82ce4f00f5ee0d33d76fae493c8c34a59c3fc56a Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 15 Jul 2024 10:39:52 +0800 Subject: [PATCH 110/129] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E8=A3=85=E9=A5=B0=E5=99=A8=E4=B8=BALog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/annotation/log_annotation.py | 182 +++++++++++++++++- .../controller/config_controller.py | 12 +- .../controller/dept_controller.py | 8 +- .../controller/dict_controller.py | 20 +- .../module_admin/controller/job_controller.py | 20 +- .../module_admin/controller/log_controller.py | 16 +- .../controller/login_controller.py | 4 +- .../controller/menu_controller.py | 8 +- .../controller/notice_controller.py | 8 +- .../controller/online_controller.py | 4 +- .../module_admin/controller/post_controler.py | 10 +- .../controller/role_controller.py | 20 +- .../controller/user_controller.py | 24 +-- 13 files changed, 253 insertions(+), 83 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py index a074c5b..4d0737e 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py @@ -17,6 +17,177 @@ from config.enums import BusinessType from config.env import AppConfig +class Log: + """ + 日志装饰器 + """ + + def __init__( + self, + title: str, + business_type: BusinessType, + log_type: Optional[Literal['login', 'operation']] = 'operation', + ): + """ + 日志装饰器 + + :param title: 当前日志装饰器装饰的模块标题 + :param business_type: 业务类型(OTHER其它 INSERT新增 UPDATE修改 DELETE删除 GRANT授权 EXPORT导出 IMPORT导入 FORCE强退 GENCODE生成代码 CLEAN清空数据) + :param log_type: 日志类型(login表示登录日志,operation表示为操作日志) + :return: + """ + self.title = title + self.business_type = business_type.value + self.log_type = log_type + + def __call__(self, func): + @wraps(func) + async def wrapper(*args, **kwargs): + start_time = time.time() + # 获取被装饰函数的文件路径 + file_path = inspect.getfile(func) + # 获取项目根路径 + project_root = os.getcwd() + # 处理文件路径,去除项目根路径部分 + relative_path = os.path.relpath(file_path, start=project_root)[0:-2].replace('\\', '.') + # 获取当前被装饰函数所在路径 + func_path = f'{relative_path}{func.__name__}()' + # 获取上下文信息 + request: Request = kwargs.get('request') + token = request.headers.get('Authorization') + query_db = kwargs.get('query_db') + request_method = request.method + operator_type = 0 + user_agent = request.headers.get('User-Agent') + if 'Windows' in user_agent or 'Macintosh' in user_agent or 'Linux' in user_agent: + operator_type = 1 + if 'Mobile' in user_agent or 'Android' in user_agent or 'iPhone' in user_agent: + operator_type = 2 + # 获取请求的url + oper_url = request.url.path + # 获取请求的ip及ip归属区域 + oper_ip = request.headers.get('X-Forwarded-For') + oper_location = '内网IP' + if AppConfig.app_ip_location_query: + oper_location = get_ip_location(oper_ip) + # 根据不同的请求类型使用不同的方法获取请求参数 + content_type = request.headers.get('Content-Type') + if content_type and ( + 'multipart/form-data' in content_type or 'application/x-www-form-urlencoded' in content_type + ): + payload = await request.form() + oper_param = '\n'.join([f'{key}: {value}' for key, value in payload.items()]) + else: + payload = await request.body() + # 通过 request.path_params 直接访问路径参数 + path_params = request.path_params + oper_param = {} + if payload: + oper_param.update(json.loads(str(payload, 'utf-8'))) + if path_params: + oper_param.update(path_params) + oper_param = json.dumps(oper_param, ensure_ascii=False) + # 日志表请求参数字段长度最大为2000,因此在此处判断长度 + if len(oper_param) > 2000: + oper_param = '请求参数过长' + + # 获取操作时间 + oper_time = datetime.now() + # 此处在登录之前向原始函数传递一些登录信息,用于监测在线用户的相关信息 + login_log = {} + if self.log_type == 'login': + user_agent_info = parse(user_agent) + browser = f'{user_agent_info.browser.family}' + system_os = f'{user_agent_info.os.family}' + if user_agent_info.browser.version != (): + browser += f' {user_agent_info.browser.version[0]}' + if user_agent_info.os.version != (): + system_os += f' {user_agent_info.os.version[0]}' + login_log = dict( + ipaddr=oper_ip, + loginLocation=oper_location, + browser=browser, + os=system_os, + loginTime=oper_time.strftime('%Y-%m-%d %H:%M:%S'), + ) + kwargs['form_data'].login_info = login_log + # 调用原始函数 + result = await func(*args, **kwargs) + # 获取请求耗时 + cost_time = float(time.time() - start_time) * 100 + # 判断请求是否来自api文档 + request_from_swagger = ( + request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False + ) + request_from_redoc = ( + request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False + ) + # 根据响应结果的类型使用不同的方法获取响应结果参数 + if ( + isinstance(result, JSONResponse) + or isinstance(result, ORJSONResponse) + or isinstance(result, UJSONResponse) + ): + result_dict = json.loads(str(result.body, 'utf-8')) + else: + if request_from_swagger or request_from_redoc: + result_dict = {} + else: + if result.status_code == 200: + result_dict = {'code': result.status_code, 'message': '获取成功'} + else: + result_dict = {'code': result.status_code, 'message': '获取失败'} + json_result = json.dumps(result_dict, ensure_ascii=False) + # 根据响应结果获取响应状态及异常信息 + status = 1 + error_msg = '' + if result_dict.get('code') == 200: + status = 0 + else: + error_msg = result_dict.get('msg') + # 根据日志类型向对应的日志表插入数据 + if self.log_type == 'login': + # 登录请求来自于api文档时不记录登录日志,其余情况则记录 + if request_from_swagger or request_from_redoc: + pass + else: + user = kwargs.get('form_data') + user_name = user.username + login_log['loginTime'] = oper_time + login_log['userName'] = user_name + login_log['status'] = str(status) + login_log['msg'] = result_dict.get('msg') + + await LoginLogService.add_login_log_services(query_db, LogininforModel(**login_log)) + else: + current_user = await LoginService.get_current_user(request, token, query_db) + oper_name = current_user.user.user_name + dept_name = current_user.user.dept.dept_name if current_user.user.dept else None + operation_log = OperLogModel( + title=self.title, + businessType=self.business_type, + method=func_path, + requestMethod=request_method, + operatorType=operator_type, + operName=oper_name, + deptName=dept_name, + operUrl=oper_url, + operIp=oper_ip, + operLocation=oper_location, + operParam=oper_param, + jsonResult=json_result, + status=status, + errorMsg=error_msg, + operTime=oper_time, + costTime=int(cost_time), + ) + await OperationLogService.add_operation_log_services(query_db, operation_log) + + return result + + return wrapper + + def log_decorator( title: str, business_type: Union[Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], BusinessType], @@ -33,12 +204,11 @@ def log_decorator( warnings.simplefilter('always', category=DeprecationWarning) if isinstance(business_type, BusinessType): business_type = business_type.value - else: - warnings.warn( - '@log_decorator的business_type参数未来版本将不再支持int类型,请使用BusinessType枚举类型', - category=DeprecationWarning, - stacklevel=2, - ) + warnings.warn( + '未来版本将会移除@log_decorator装饰器,请使用@Log装饰器', + category=DeprecationWarning, + stacklevel=2, + ) def decorator(func): @wraps(func) diff --git a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py index cee889d..d594da8 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py @@ -4,7 +4,7 @@ from pydantic_validation_decorator import ValidateFields from sqlalchemy.ext.asyncio import AsyncSession from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel from module_admin.entity.vo.user_vo import CurrentUserModel @@ -36,7 +36,7 @@ async def get_system_config_list( @configController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))]) @ValidateFields(validate_model='add_config') -@log_decorator(title='参数管理', business_type=BusinessType.INSERT) +@Log(title='参数管理', business_type=BusinessType.INSERT) async def add_system_config( request: Request, add_config: ConfigModel, @@ -55,7 +55,7 @@ async def add_system_config( @configController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))]) @ValidateFields(validate_model='edit_config') -@log_decorator(title='参数管理', business_type=BusinessType.UPDATE) +@Log(title='参数管理', business_type=BusinessType.UPDATE) async def edit_system_config( request: Request, edit_config: ConfigModel, @@ -71,7 +71,7 @@ async def edit_system_config( @configController.delete('/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) -@log_decorator(title='参数管理', business_type=BusinessType.UPDATE) +@Log(title='参数管理', business_type=BusinessType.UPDATE) async def refresh_system_config(request: Request, query_db: AsyncSession = Depends(get_db)): refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db) logger.info(refresh_config_result.message) @@ -80,7 +80,7 @@ async def refresh_system_config(request: Request, query_db: AsyncSession = Depen @configController.delete('/{config_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) -@log_decorator(title='参数管理', business_type=BusinessType.DELETE) +@Log(title='参数管理', business_type=BusinessType.DELETE) async def delete_system_config(request: Request, config_ids: str, query_db: AsyncSession = Depends(get_db)): delete_config = DeleteConfigModel(configIds=config_ids) delete_config_result = await ConfigService.delete_config_services(request, query_db, delete_config) @@ -109,7 +109,7 @@ async def query_system_config(request: Request, config_key: str): @configController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))]) -@log_decorator(title='参数管理', business_type=BusinessType.EXPORT) +@Log(title='参数管理', business_type=BusinessType.EXPORT) async def export_system_config_list( request: Request, config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_form), diff --git a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py index 03416b7..28f1d58 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py @@ -5,7 +5,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from typing import List from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.data_scope import GetDataScope from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel, DeptQueryModel @@ -54,7 +54,7 @@ async def get_system_dept_list( @deptController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) @ValidateFields(validate_model='add_dept') -@log_decorator(title='部门管理', business_type=BusinessType.INSERT) +@Log(title='部门管理', business_type=BusinessType.INSERT) async def add_system_dept( request: Request, add_dept: DeptModel, @@ -73,7 +73,7 @@ async def add_system_dept( @deptController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) @ValidateFields(validate_model='edit_dept') -@log_decorator(title='部门管理', business_type=BusinessType.UPDATE) +@Log(title='部门管理', business_type=BusinessType.UPDATE) async def edit_system_dept( request: Request, edit_dept: DeptModel, @@ -92,7 +92,7 @@ async def edit_system_dept( @deptController.delete('/{dept_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) -@log_decorator(title='部门管理', business_type=BusinessType.DELETE) +@Log(title='部门管理', business_type=BusinessType.DELETE) async def delete_system_dept( request: Request, dept_ids: str, diff --git a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py index b828d46..f86dbac 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py @@ -5,7 +5,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from typing import List from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.dict_vo import ( DeleteDictDataModel, @@ -46,7 +46,7 @@ async def get_system_dict_type_list( @dictController.post('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) @ValidateFields(validate_model='add_dict_type') -@log_decorator(title='字典管理', business_type=BusinessType.INSERT) +@Log(title='字典类型', business_type=BusinessType.INSERT) async def add_system_dict_type( request: Request, add_dict_type: DictTypeModel, @@ -65,7 +65,7 @@ async def add_system_dict_type( @dictController.put('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) @ValidateFields(validate_model='edit_dict_type') -@log_decorator(title='字典管理', business_type=BusinessType.UPDATE) +@Log(title='字典类型', business_type=BusinessType.UPDATE) async def edit_system_dict_type( request: Request, edit_dict_type: DictTypeModel, @@ -81,7 +81,7 @@ async def edit_system_dict_type( @dictController.delete('/type/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) -@log_decorator(title='字典管理', business_type=BusinessType.UPDATE) +@Log(title='字典类型', business_type=BusinessType.UPDATE) async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends(get_db)): refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db) logger.info(refresh_dict_result.message) @@ -90,7 +90,7 @@ async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends @dictController.delete('/type/{dict_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) -@log_decorator(title='字典管理', business_type=BusinessType.DELETE) +@Log(title='字典类型', business_type=BusinessType.DELETE) async def delete_system_dict_type(request: Request, dict_ids: str, query_db: AsyncSession = Depends(get_db)): delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids) delete_dict_type_result = await DictTypeService.delete_dict_type_services(request, query_db, delete_dict_type) @@ -120,7 +120,7 @@ async def query_detail_system_dict_type(request: Request, dict_id: int, query_db @dictController.post('/type/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) -@log_decorator(title='字典管理', business_type=BusinessType.EXPORT) +@Log(title='字典类型', business_type=BusinessType.EXPORT) async def export_system_dict_type_list( request: Request, dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_form), @@ -166,7 +166,7 @@ async def get_system_dict_data_list( @dictController.post('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) @ValidateFields(validate_model='add_dict_data') -@log_decorator(title='字典管理', business_type=BusinessType.INSERT) +@Log(title='字典数据', business_type=BusinessType.INSERT) async def add_system_dict_data( request: Request, add_dict_data: DictDataModel, @@ -185,7 +185,7 @@ async def add_system_dict_data( @dictController.put('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) @ValidateFields(validate_model='edit_dict_data') -@log_decorator(title='字典管理', business_type=BusinessType.UPDATE) +@Log(title='字典数据', business_type=BusinessType.UPDATE) async def edit_system_dict_data( request: Request, edit_dict_data: DictDataModel, @@ -201,7 +201,7 @@ async def edit_system_dict_data( @dictController.delete('/data/{dict_codes}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) -@log_decorator(title='字典管理', business_type=BusinessType.DELETE) +@Log(title='字典数据', business_type=BusinessType.DELETE) async def delete_system_dict_data(request: Request, dict_codes: str, query_db: AsyncSession = Depends(get_db)): delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes) delete_dict_data_result = await DictDataService.delete_dict_data_services(request, query_db, delete_dict_data) @@ -223,7 +223,7 @@ async def query_detail_system_dict_data(request: Request, dict_code: int, query_ @dictController.post('/data/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) -@log_decorator(title='字典管理', business_type=BusinessType.EXPORT) +@Log(title='字典数据', business_type=BusinessType.EXPORT) async def export_system_dict_data_list( request: Request, dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_form), diff --git a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py index 3e3b095..0c08fff 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py @@ -4,7 +4,7 @@ from pydantic_validation_decorator import ValidateFields from sqlalchemy.ext.asyncio import AsyncSession from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.job_vo import ( DeleteJobLogModel, @@ -44,7 +44,7 @@ async def get_system_job_list( @jobController.post('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))]) @ValidateFields(validate_model='add_job') -@log_decorator(title='定时任务管理', business_type=BusinessType.INSERT) +@Log(title='定时任务', business_type=BusinessType.INSERT) async def add_system_job( request: Request, add_job: JobModel, @@ -63,7 +63,7 @@ async def add_system_job( @jobController.put('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))]) @ValidateFields(validate_model='edit_job') -@log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) +@Log(title='定时任务', business_type=BusinessType.UPDATE) async def edit_system_job( request: Request, edit_job: EditJobModel, @@ -79,7 +79,7 @@ async def edit_system_job( @jobController.put('/job/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) -@log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) +@Log(title='定时任务', business_type=BusinessType.UPDATE) async def change_system_job_status( request: Request, change_job: EditJobModel, @@ -100,7 +100,7 @@ async def change_system_job_status( @jobController.put('/job/run', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) -@log_decorator(title='定时任务管理', business_type=BusinessType.UPDATE) +@Log(title='定时任务', business_type=BusinessType.UPDATE) async def execute_system_job(request: Request, execute_job: JobModel, query_db: AsyncSession = Depends(get_db)): execute_job_result = await JobService.execute_job_once_services(query_db, execute_job) logger.info(execute_job_result.message) @@ -109,7 +109,7 @@ async def execute_system_job(request: Request, execute_job: JobModel, query_db: @jobController.delete('/job/{job_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) -@log_decorator(title='定时任务管理', business_type=BusinessType.DELETE) +@Log(title='定时任务', business_type=BusinessType.DELETE) async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSession = Depends(get_db)): delete_job = DeleteJobModel(jobIds=job_ids) delete_job_result = await JobService.delete_job_services(query_db, delete_job) @@ -129,7 +129,7 @@ async def query_detail_system_job(request: Request, job_id: int, query_db: Async @jobController.post('/job/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) -@log_decorator(title='定时任务管理', business_type=BusinessType.EXPORT) +@Log(title='定时任务', business_type=BusinessType.EXPORT) async def export_system_job_list( request: Request, job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_form), @@ -161,7 +161,7 @@ async def get_system_job_log_list( @jobController.delete('/jobLog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) -@log_decorator(title='定时任务日志管理', business_type=BusinessType.CLEAN) +@Log(title='定时任务调度日志', business_type=BusinessType.CLEAN) async def clear_system_job_log(request: Request, query_db: AsyncSession = Depends(get_db)): clear_job_log_result = await JobLogService.clear_job_log_services(query_db) logger.info(clear_job_log_result.message) @@ -170,7 +170,7 @@ async def clear_system_job_log(request: Request, query_db: AsyncSession = Depend @jobController.delete('/jobLog/{job_log_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) -@log_decorator(title='定时任务日志管理', business_type=BusinessType.DELETE) +@Log(title='定时任务调度日志', business_type=BusinessType.DELETE) async def delete_system_job_log(request: Request, job_log_ids: str, query_db: AsyncSession = Depends(get_db)): delete_job_log = DeleteJobLogModel(jobLogIds=job_log_ids) delete_job_log_result = await JobLogService.delete_job_log_services(query_db, delete_job_log) @@ -180,7 +180,7 @@ async def delete_system_job_log(request: Request, job_log_ids: str, query_db: As @jobController.post('/jobLog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) -@log_decorator(title='定时任务日志管理', business_type=BusinessType.EXPORT) +@Log(title='定时任务调度日志', business_type=BusinessType.EXPORT) async def export_system_job_log_list( request: Request, job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_form), diff --git a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py index 328d5c2..4d0b55c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py @@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, Request from sqlalchemy.ext.asyncio import AsyncSession from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.log_vo import ( DeleteLoginLogModel, @@ -42,7 +42,7 @@ async def get_system_operation_log_list( @logController.delete('/operlog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) -@log_decorator(title='操作日志管理', business_type=BusinessType.CLEAN) +@Log(title='操作日志', business_type=BusinessType.CLEAN) async def clear_system_operation_log(request: Request, query_db: AsyncSession = Depends(get_db)): clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db) logger.info(clear_operation_log_result.message) @@ -51,7 +51,7 @@ async def clear_system_operation_log(request: Request, query_db: AsyncSession = @logController.delete('/operlog/{oper_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) -@log_decorator(title='操作日志管理', business_type=BusinessType.DELETE) +@Log(title='操作日志', business_type=BusinessType.DELETE) async def delete_system_operation_log(request: Request, oper_ids: str, query_db: AsyncSession = Depends(get_db)): delete_operation_log = DeleteOperLogModel(operIds=oper_ids) delete_operation_log_result = await OperationLogService.delete_operation_log_services( @@ -63,7 +63,7 @@ async def delete_system_operation_log(request: Request, oper_ids: str, query_db: @logController.post('/operlog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))]) -@log_decorator(title='操作日志管理', business_type=BusinessType.EXPORT) +@Log(title='操作日志', business_type=BusinessType.EXPORT) async def export_system_operation_log_list( request: Request, operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_form), @@ -101,7 +101,7 @@ async def get_system_login_log_list( @logController.delete('/logininfor/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) -@log_decorator(title='登录日志管理', business_type=BusinessType.CLEAN) +@Log(title='登录日志', business_type=BusinessType.CLEAN) async def clear_system_login_log(request: Request, query_db: AsyncSession = Depends(get_db)): clear_login_log_result = await LoginLogService.clear_login_log_services(query_db) logger.info(clear_login_log_result.message) @@ -112,7 +112,7 @@ async def clear_system_login_log(request: Request, query_db: AsyncSession = Depe @logController.delete( '/logininfor/{info_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))] ) -@log_decorator(title='登录日志管理', business_type=BusinessType.DELETE) +@Log(title='登录日志', business_type=BusinessType.DELETE) async def delete_system_login_log(request: Request, info_ids: str, query_db: AsyncSession = Depends(get_db)): delete_login_log = DeleteLoginLogModel(infoIds=info_ids) delete_login_log_result = await LoginLogService.delete_login_log_services(query_db, delete_login_log) @@ -124,7 +124,7 @@ async def delete_system_login_log(request: Request, info_ids: str, query_db: Asy @logController.get( '/logininfor/unlock/{user_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:unlock'))] ) -@log_decorator(title='登录日志管理', business_type=BusinessType.OTHER) +@Log(title='账户解锁', business_type=BusinessType.OTHER) async def unlock_system_user(request: Request, user_name: str, query_db: AsyncSession = Depends(get_db)): unlock_user = UnlockUser(userName=user_name) unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user) @@ -134,7 +134,7 @@ async def unlock_system_user(request: Request, user_name: str, query_db: AsyncSe @logController.post('/logininfor/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))]) -@log_decorator(title='登录日志管理', business_type=BusinessType.EXPORT) +@Log(title='登录日志', business_type=BusinessType.EXPORT) async def export_system_login_log_list( request: Request, login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_form), diff --git a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py index b8b3133..63028cc 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py @@ -7,7 +7,7 @@ from typing import Optional from config.enums import BusinessType from config.env import AppConfig, JwtConfig, RedisInitKeyConfig from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.entity.vo.login_vo import UserLogin, UserRegister, Token from module_admin.entity.vo.user_vo import CurrentUserModel, EditUserModel @@ -21,7 +21,7 @@ loginController = APIRouter() @loginController.post('/login', response_model=Token) -@log_decorator(title='用户登录', business_type=BusinessType.OTHER, log_type='login') +@Log(title='用户登录', business_type=BusinessType.OTHER, log_type='login') async def login( request: Request, form_data: CustomOAuth2PasswordRequestForm = Depends(), query_db: AsyncSession = Depends(get_db) ): diff --git a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py index d47f30a..0e3124e 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py @@ -5,7 +5,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from typing import List from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuModel, MenuQueryModel from module_admin.entity.vo.user_vo import CurrentUserModel @@ -60,7 +60,7 @@ async def get_system_menu_list( @menuController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) @ValidateFields(validate_model='add_menu') -@log_decorator(title='菜单管理', business_type=BusinessType.INSERT) +@Log(title='菜单管理', business_type=BusinessType.INSERT) async def add_system_menu( request: Request, add_menu: MenuModel, @@ -79,7 +79,7 @@ async def add_system_menu( @menuController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) @ValidateFields(validate_model='edit_menu') -@log_decorator(title='菜单管理', business_type=BusinessType.UPDATE) +@Log(title='菜单管理', business_type=BusinessType.UPDATE) async def edit_system_menu( request: Request, edit_menu: MenuModel, @@ -95,7 +95,7 @@ async def edit_system_menu( @menuController.delete('/{menu_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) -@log_decorator(title='菜单管理', business_type=BusinessType.DELETE) +@Log(title='菜单管理', business_type=BusinessType.DELETE) async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSession = Depends(get_db)): delete_menu = DeleteMenuModel(menuIds=menu_ids) delete_menu_result = await MenuService.delete_menu_services(query_db, delete_menu) diff --git a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py index 4dbef45..e1e4aa1 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py @@ -4,7 +4,7 @@ from pydantic_validation_decorator import ValidateFields from sqlalchemy.ext.asyncio import AsyncSession from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.notice_vo import DeleteNoticeModel, NoticeModel, NoticePageQueryModel from module_admin.entity.vo.user_vo import CurrentUserModel @@ -35,7 +35,7 @@ async def get_system_notice_list( @noticeController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))]) @ValidateFields(validate_model='add_notice') -@log_decorator(title='通知公告管理', business_type=BusinessType.INSERT) +@Log(title='通知公告', business_type=BusinessType.INSERT) async def add_system_notice( request: Request, add_notice: NoticeModel, @@ -54,7 +54,7 @@ async def add_system_notice( @noticeController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))]) @ValidateFields(validate_model='edit_notice') -@log_decorator(title='通知公告管理', business_type=BusinessType.UPDATE) +@Log(title='通知公告', business_type=BusinessType.UPDATE) async def edit_system_notice( request: Request, edit_notice: NoticeModel, @@ -70,7 +70,7 @@ async def edit_system_notice( @noticeController.delete('/{notice_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))]) -@log_decorator(title='通知公告管理', business_type=BusinessType.DELETE) +@Log(title='通知公告', business_type=BusinessType.DELETE) async def delete_system_notice(request: Request, notice_ids: str, query_db: AsyncSession = Depends(get_db)): delete_notice = DeleteNoticeModel(noticeIds=notice_ids) delete_notice_result = await NoticeService.delete_notice_services(query_db, delete_notice) diff --git a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py index c4b3897..bf65c8f 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py @@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, Request from sqlalchemy.ext.asyncio import AsyncSession from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.online_vo import DeleteOnlineModel, OnlineQueryModel from module_admin.service.login_service import LoginService @@ -31,7 +31,7 @@ async def get_monitor_online_list( @onlineController.delete('/{token_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))]) -@log_decorator(title='在线用户', business_type=BusinessType.FORCE) +@Log(title='在线用户', business_type=BusinessType.FORCE) async def delete_monitor_online(request: Request, token_ids: str, query_db: AsyncSession = Depends(get_db)): delete_online = DeleteOnlineModel(tokenIds=token_ids) delete_online_result = await OnlineService.delete_online_services(request, delete_online) diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py index f6f2fce..4219076 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py @@ -4,7 +4,7 @@ from pydantic_validation_decorator import ValidateFields from sqlalchemy.ext.asyncio import AsyncSession from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.service.login_service import LoginService from module_admin.service.post_service import PostService @@ -36,7 +36,7 @@ async def get_system_post_list( @postController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))]) @ValidateFields(validate_model='add_post') -@log_decorator(title='岗位管理', business_type=BusinessType.INSERT) +@Log(title='岗位管理', business_type=BusinessType.INSERT) async def add_system_post( request: Request, add_post: PostModel, @@ -55,7 +55,7 @@ async def add_system_post( @postController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))]) @ValidateFields(validate_model='edit_post') -@log_decorator(title='岗位管理', business_type=BusinessType.UPDATE) +@Log(title='岗位管理', business_type=BusinessType.UPDATE) async def edit_system_post( request: Request, edit_post: PostModel, @@ -71,7 +71,7 @@ async def edit_system_post( @postController.delete('/{post_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))]) -@log_decorator(title='岗位管理', business_type=BusinessType.DELETE) +@Log(title='岗位管理', business_type=BusinessType.DELETE) async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSession = Depends(get_db)): delete_post = DeletePostModel(postIds=post_ids) delete_post_result = await PostService.delete_post_services(query_db, delete_post) @@ -91,7 +91,7 @@ async def query_detail_system_post(request: Request, post_id: int, query_db: Asy @postController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:post:export'))]) -@log_decorator(title='岗位管理', business_type=BusinessType.EXPORT) +@Log(title='岗位管理', business_type=BusinessType.EXPORT) async def export_system_post_list( request: Request, post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_form), diff --git a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index d764414..797fd8e 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -4,7 +4,7 @@ from pydantic_validation_decorator import ValidateFields from sqlalchemy.ext.asyncio import AsyncSession from config.enums import BusinessType from config.get_db import get_db -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.data_scope import GetDataScope from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.dept_vo import DeptModel @@ -57,7 +57,7 @@ async def get_system_role_list( @roleController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))]) @ValidateFields(validate_model='add_role') -@log_decorator(title='角色管理', business_type=BusinessType.INSERT) +@Log(title='角色管理', business_type=BusinessType.INSERT) async def add_system_role( request: Request, add_role: AddRoleModel, @@ -76,7 +76,7 @@ async def add_system_role( @roleController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @ValidateFields(validate_model='edit_role') -@log_decorator(title='角色管理', business_type=BusinessType.UPDATE) +@Log(title='角色管理', business_type=BusinessType.UPDATE) async def edit_system_role( request: Request, edit_role: AddRoleModel, @@ -96,7 +96,7 @@ async def edit_system_role( @roleController.put('/dataScope', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=BusinessType.GRANT) +@Log(title='角色管理', business_type=BusinessType.GRANT) async def edit_system_role_datascope( request: Request, role_data_scope: AddRoleModel, @@ -122,7 +122,7 @@ async def edit_system_role_datascope( @roleController.delete('/{role_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))]) -@log_decorator(title='角色管理', business_type=BusinessType.DELETE) +@Log(title='角色管理', business_type=BusinessType.DELETE) async def delete_system_role( request: Request, role_ids: str, @@ -161,7 +161,7 @@ async def query_detail_system_role( @roleController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))]) -@log_decorator(title='角色管理', business_type=BusinessType.EXPORT) +@Log(title='角色管理', business_type=BusinessType.EXPORT) async def export_system_role_list( request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), @@ -179,7 +179,7 @@ async def export_system_role_list( @roleController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=BusinessType.UPDATE) +@Log(title='角色管理', business_type=BusinessType.UPDATE) async def reset_system_role_status( request: Request, change_role: AddRoleModel, @@ -242,7 +242,7 @@ async def get_system_unallocated_user_list( @roleController.put('/authUser/selectAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=BusinessType.GRANT) +@Log(title='角色管理', business_type=BusinessType.GRANT) async def add_system_role_user( request: Request, add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), @@ -259,7 +259,7 @@ async def add_system_role_user( @roleController.put('/authUser/cancel', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=BusinessType.GRANT) +@Log(title='角色管理', business_type=BusinessType.GRANT) async def cancel_system_role_user( request: Request, cancel_user_role: CrudUserRoleModel, query_db: AsyncSession = Depends(get_db) ): @@ -270,7 +270,7 @@ async def cancel_system_role_user( @roleController.put('/authUser/cancelAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) -@log_decorator(title='角色管理', business_type=BusinessType.GRANT) +@Log(title='角色管理', business_type=BusinessType.GRANT) async def batch_cancel_system_role_user( request: Request, batch_cancel_user_role: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query), diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index 2ee6e70..72d06f4 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -6,7 +6,7 @@ from typing import Optional, Union from pydantic_validation_decorator import ValidateFields from config.get_db import get_db from config.env import UploadConfig -from module_admin.annotation.log_annotation import log_decorator +from module_admin.annotation.log_annotation import Log from module_admin.aspect.data_scope import GetDataScope from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.dept_vo import DeptModel @@ -72,7 +72,7 @@ async def get_system_user_list( @userController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) @ValidateFields(validate_model='add_user') -@log_decorator(title='用户管理', business_type=BusinessType.INSERT) +@Log(title='用户管理', business_type=BusinessType.INSERT) async def add_system_user( request: Request, add_user: AddUserModel, @@ -97,7 +97,7 @@ async def add_system_user( @userController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @ValidateFields(validate_model='edit_user') -@log_decorator(title='用户管理', business_type=BusinessType.UPDATE) +@Log(title='用户管理', business_type=BusinessType.UPDATE) async def edit_system_user( request: Request, edit_user: EditUserModel, @@ -121,7 +121,7 @@ async def edit_system_user( @userController.delete('/{user_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))]) -@log_decorator(title='用户管理', business_type=BusinessType.DELETE) +@Log(title='用户管理', business_type=BusinessType.DELETE) async def delete_system_user( request: Request, user_ids: str, @@ -146,7 +146,7 @@ async def delete_system_user( @userController.put('/resetPwd', dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))]) -@log_decorator(title='用户管理', business_type=BusinessType.UPDATE) +@Log(title='用户管理', business_type=BusinessType.UPDATE) async def reset_system_user_pwd( request: Request, reset_user: EditUserModel, @@ -171,7 +171,7 @@ async def reset_system_user_pwd( @userController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) -@log_decorator(title='用户管理', business_type=BusinessType.UPDATE) +@Log(title='用户管理', business_type=BusinessType.UPDATE) async def change_system_user_status( request: Request, change_user: EditUserModel, @@ -229,7 +229,7 @@ async def query_detail_system_user( @userController.post('/profile/avatar') -@log_decorator(title='个人信息', business_type=BusinessType.UPDATE) +@Log(title='个人信息', business_type=BusinessType.UPDATE) async def change_system_user_profile_avatar( request: Request, avatarfile: bytes = File(), @@ -264,7 +264,7 @@ async def change_system_user_profile_avatar( @userController.put('/profile') -@log_decorator(title='个人信息', business_type=BusinessType.UPDATE) +@Log(title='个人信息', business_type=BusinessType.UPDATE) async def change_system_user_profile_info( request: Request, user_info: UserInfoModel, @@ -288,7 +288,7 @@ async def change_system_user_profile_info( @userController.put('/profile/updatePwd') -@log_decorator(title='个人信息', business_type=BusinessType.UPDATE) +@Log(title='个人信息', business_type=BusinessType.UPDATE) async def reset_system_user_password( request: Request, reset_password: ResetPasswordModel = Depends(ResetPasswordModel.as_query), @@ -309,7 +309,7 @@ async def reset_system_user_password( @userController.post('/importData', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) -@log_decorator(title='用户管理', business_type=BusinessType.IMPORT) +@Log(title='用户管理', business_type=BusinessType.IMPORT) async def batch_import_system_user( request: Request, file: UploadFile = File(...), @@ -336,7 +336,7 @@ async def export_system_user_template(request: Request, query_db: AsyncSession = @userController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:user:export'))]) -@log_decorator(title='用户管理', business_type=BusinessType.EXPORT) +@Log(title='用户管理', business_type=BusinessType.EXPORT) async def export_system_user_list( request: Request, user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_form), @@ -373,7 +373,7 @@ async def get_system_allocated_role_list(request: Request, user_id: int, query_d response_model=UserRoleResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))], ) -@log_decorator(title='用户管理', business_type=BusinessType.GRANT) +@Log(title='用户管理', business_type=BusinessType.GRANT) async def update_system_role_user( request: Request, user_id: int = Query(alias='userId'), -- Gitee From 1d4fb2cdb200469f3ce14c2f67f2fb1862e74707 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 15 Jul 2024 11:36:34 +0800 Subject: [PATCH 111/129] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dvalidate=5Fsec?= =?UTF-8?q?ond=5For=5Fminute=E5=8F=82=E6=95=B0=E4=B8=A2=E5=A4=B1=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/utils/cron_util.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ruoyi-fastapi-backend/utils/cron_util.py b/ruoyi-fastapi-backend/utils/cron_util.py index 09050e5..6232962 100644 --- a/ruoyi-fastapi-backend/utils/cron_util.py +++ b/ruoyi-fastapi-backend/utils/cron_util.py @@ -40,7 +40,7 @@ class CronUtil: if ( second_or_minute == '*' or ('-' in second_or_minute and cls.__valid_range(second_or_minute, 0, 59)) - or ('/' in second_or_minute and cls.__valid_sum(second_or_minute, 0, 58, 1, 59)) + or ('/' in second_or_minute and cls.__valid_sum(second_or_minute, 0, 58, 1, 59, 59)) or re.match(r'^(?:[0-5]?\d|59)(?:,[0-5]?\d|59)*$', second_or_minute) ): return True @@ -109,8 +109,8 @@ class CronUtil: if ( week in ['*', '?'] or ('-' in week and cls.__valid_range(week, 1, 7)) - or re.match(r'^[1-7]#[1-4]$', week) - or re.match(r'^[1-7]L$', week) + or ('#' in week and re.match(r'^[1-7]#[1-4]$', week)) + or ('L' in week and re.match(r'^[1-7]L$', week)) or re.match(r'^[1-7](?:(,[1-7]))*$', week) ): return True @@ -130,8 +130,8 @@ class CronUtil: year == '*' or ('-' in year and cls.__valid_range(year, current_year, 2099)) or ('/' in year and cls.__valid_sum(year, current_year, 2098, 1, 2099 - current_year, 2099)) - or re.match(r'^[1-7]#[1-4]$', year) - or re.match(r'^[1-7]L$', year) + or ('#' in year and re.match(r'^[1-7]#[1-4]$', year)) + or ('L' in year and re.match(r'^[1-7]L$', year)) or ( (len(year) == 4 or ',' in year) and all(int(item) in future_years and current_year <= int(item) <= 2099 for item in year.split(',')) -- Gitee From 753403b0f857b37c065fe1c138c6b22e13d1110b Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 15 Jul 2024 11:37:28 +0800 Subject: [PATCH 112/129] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dcheck=5Frole?= =?UTF-8?q?=5Fdata=5Fscope=5Fservices=E5=8F=82=E6=95=B0=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E4=B8=8D=E5=8C=B9=E9=85=8D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module_admin/controller/user_controller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index 72d06f4..86af1a7 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -83,7 +83,7 @@ async def add_system_user( ): if not current_user.user.admin: await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql) - await RoleService.check_role_data_scope_services(query_db, ','.join(add_user.role_ids), role_data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, ','.join([str(item) for item in add_user.role_ids]), role_data_scope_sql) add_user.password = PwdUtil.get_password_hash(add_user.password) add_user.create_by = current_user.user.user_name add_user.create_time = datetime.now() @@ -111,7 +111,7 @@ async def edit_system_user( if not current_user.user.admin: await UserService.check_user_data_scope_services(query_db, edit_user.user_id, user_data_scope_sql) await DeptService.check_dept_data_scope_services(query_db, edit_user.dept_id, dept_data_scope_sql) - await RoleService.check_role_data_scope_services(query_db, ','.join(edit_user.role_ids), role_data_scope_sql) + await RoleService.check_role_data_scope_services(query_db, ','.join([str(item) for item in edit_user.role_ids]), role_data_scope_sql) edit_user.update_by = current_user.user.user_name edit_user.update_time = datetime.now() edit_user_result = await UserService.edit_user_services(query_db, edit_user) -- Gitee From 997a3068aca3256587d9ee69750911f53a593484 Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Mon, 15 Jul 2024 11:38:29 +0800 Subject: [PATCH 113/129] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=8D=87?= =?UTF-8?q?=E7=BA=A7element-plus=E5=90=8Eel-radio=E4=BD=BF=E7=94=A8label?= =?UTF-8?q?=E8=BF=87=E6=9C=9F=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/Crontab/day.vue | 14 +++++++------- .../src/components/Crontab/hour.vue | 8 ++++---- .../src/components/Crontab/min.vue | 8 ++++---- .../src/components/Crontab/month.vue | 8 ++++---- .../src/components/Crontab/second.vue | 8 ++++---- .../src/components/Crontab/week.vue | 12 ++++++------ .../src/components/Crontab/year.vue | 10 +++++----- .../src/views/monitor/job/index.vue | 12 ++++++------ .../src/views/system/config/index.vue | 2 +- .../src/views/system/dept/index.vue | 2 +- .../src/views/system/dict/data.vue | 2 +- .../src/views/system/dict/index.vue | 2 +- .../src/views/system/menu/index.vue | 18 +++++++++--------- .../src/views/system/notice/index.vue | 2 +- .../src/views/system/post/index.vue | 2 +- .../src/views/system/role/index.vue | 2 +- .../src/views/system/user/index.vue | 2 +- .../src/views/system/user/profile/userInfo.vue | 4 ++-- .../src/views/tool/gen/genInfoForm.vue | 4 ++-- 19 files changed, 61 insertions(+), 61 deletions(-) diff --git a/ruoyi-fastapi-frontend/src/components/Crontab/day.vue b/ruoyi-fastapi-frontend/src/components/Crontab/day.vue index 25c4f79..39263f5 100644 --- a/ruoyi-fastapi-frontend/src/components/Crontab/day.vue +++ b/ruoyi-fastapi-frontend/src/components/Crontab/day.vue @@ -1,19 +1,19 @@