From 1516c1a941956ed5cdd7e58c82994be97f99ecba Mon Sep 17 00:00:00 2001 From: insistence <3055204202@qq.com> Date: Fri, 5 Dec 2025 10:00:25 +0800 Subject: [PATCH] =?UTF-8?q?refactor&perf:=20=E5=A2=9E=E5=BC=BAruff?= =?UTF-8?q?=E8=A7=84=E5=88=99=EF=BC=8C=E5=AE=8C=E5=96=84=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-fastapi-backend/alembic/env.py | 17 +- ruoyi-fastapi-backend/app.py | 2 +- ruoyi-fastapi-backend/config/constant.py | 2 + ruoyi-fastapi-backend/config/database.py | 8 +- ruoyi-fastapi-backend/config/enums.py | 5 +- ruoyi-fastapi-backend/config/env.py | 32 +- ruoyi-fastapi-backend/config/get_db.py | 10 +- ruoyi-fastapi-backend/config/get_redis.py | 13 +- ruoyi-fastapi-backend/config/get_scheduler.py | 87 ++--- ruoyi-fastapi-backend/exceptions/exception.py | 15 +- ruoyi-fastapi-backend/exceptions/handle.py | 25 +- .../middlewares/cors_middleware.py | 2 +- .../middlewares/gzip_middleware.py | 2 +- ruoyi-fastapi-backend/middlewares/handle.py | 3 +- .../middlewares/trace_middleware/__init__.py | 3 +- .../middlewares/trace_middleware/ctx.py | 11 +- .../middlewares/trace_middleware/middle.py | 15 +- .../middlewares/trace_middleware/span.py | 22 +- .../module_admin/annotation/log_annotation.py | 345 +++++++++++++----- .../annotation/pydantic_annotation.py | 30 +- .../module_admin/aspect/data_scope.py | 12 +- .../module_admin/aspect/interface_auth.py | 36 +- .../controller/cache_controller.py | 47 ++- .../controller/captcha_controller.py | 24 +- .../controller/common_controller.py | 23 +- .../controller/config_controller.py | 67 ++-- .../controller/dept_controller.py | 75 ++-- .../controller/dict_controller.py | 125 ++++--- .../module_admin/controller/job_controller.py | 103 +++--- .../module_admin/controller/log_controller.py | 72 ++-- .../controller/login_controller.py | 56 +-- .../controller/menu_controller.py | 71 ++-- .../controller/notice_controller.py | 48 ++- .../controller/online_controller.py | 23 +- .../{post_controler.py => post_controller.py} | 60 +-- .../controller/role_controller.py | 150 ++++---- .../controller/server_controller.py | 14 +- .../controller/user_controller.py | 202 +++++----- .../module_admin/dao/config_dao.py | 23 +- .../module_admin/dao/dept_dao.py | 39 +- .../module_admin/dao/dict_dao.py | 50 ++- .../module_admin/dao/job_dao.py | 26 +- .../module_admin/dao/job_log_dao.py | 19 +- .../module_admin/dao/log_dao.py | 33 +- .../module_admin/dao/login_dao.py | 7 +- .../module_admin/dao/menu_dao.py | 24 +- .../module_admin/dao/notice_dao.py | 23 +- .../module_admin/dao/post_dao.py | 27 +- .../module_admin/dao/role_dao.py | 44 ++- .../module_admin/dao/user_dao.py | 82 +++-- .../module_admin/entity/do/config_do.py | 2 + .../module_admin/entity/do/dept_do.py | 4 +- .../module_admin/entity/do/dict_do.py | 4 +- .../module_admin/entity/do/job_do.py | 4 +- .../module_admin/entity/do/log_do.py | 8 +- .../module_admin/entity/do/menu_do.py | 4 +- .../module_admin/entity/do/notice_do.py | 2 + .../module_admin/entity/do/post_do.py | 4 +- .../module_admin/entity/do/role_do.py | 4 +- .../module_admin/entity/do/user_do.py | 4 +- .../module_admin/entity/vo/cache_vo.py | 5 +- .../module_admin/entity/vo/common_vo.py | 3 +- .../module_admin/entity/vo/config_vo.py | 13 +- .../module_admin/entity/vo/dept_vo.py | 15 +- .../module_admin/entity/vo/dict_vo.py | 22 +- .../module_admin/entity/vo/job_vo.py | 12 +- .../module_admin/entity/vo/log_vo.py | 6 +- .../module_admin/entity/vo/login_vo.py | 11 +- .../module_admin/entity/vo/menu_vo.py | 19 +- .../module_admin/entity/vo/notice_vo.py | 9 +- .../module_admin/entity/vo/online_vo.py | 5 +- .../module_admin/entity/vo/post_vo.py | 13 +- .../module_admin/entity/vo/role_vo.py | 27 +- .../module_admin/entity/vo/server_vo.py | 5 +- .../module_admin/entity/vo/user_vo.py | 46 ++- .../module_admin/service/cache_service.py | 38 +- .../module_admin/service/captcha_service.py | 3 +- .../module_admin/service/common_service.py | 75 ++-- .../module_admin/service/config_service.py | 94 ++--- .../module_admin/service/dept_service.py | 70 ++-- .../module_admin/service/dict_service.py | 182 ++++----- .../module_admin/service/job_log_service.py | 33 +- .../module_admin/service/job_service.py | 98 ++--- .../module_admin/service/log_service.py | 38 +- .../module_admin/service/login_service.py | 123 ++++--- .../module_admin/service/menu_service.py | 85 ++--- .../module_admin/service/notice_service.py | 51 ++- .../module_admin/service/online_service.py | 30 +- .../module_admin/service/post_service.py | 60 ++- .../module_admin/service/role_service.py | 84 +++-- .../module_admin/service/server_service.py | 6 +- .../module_admin/service/user_service.py | 187 ++++++---- .../controller/gen_controller.py | 104 ++++-- .../module_generator/dao/gen_dao.py | 152 ++++---- .../module_generator/entity/do/gen_do.py | 4 +- .../module_generator/entity/vo/gen_vo.py | 63 ++-- .../module_generator/service/gen_service.py | 104 +++--- .../templates/python/controller.py.jinja2 | 57 +-- .../templates/python/dao.py.jinja2 | 29 +- .../templates/python/do.py.jinja2 | 1 + .../templates/python/service.py.jinja2 | 32 +- .../templates/python/vo.py.jinja2 | 25 +- .../module_task/scheduler_test.py | 4 +- ruoyi-fastapi-backend/requirements-pg.txt | 4 +- ruoyi-fastapi-backend/requirements.txt | 4 +- ruoyi-fastapi-backend/ruff.toml | 64 ++++ ruoyi-fastapi-backend/server.py | 73 ++-- .../sub_applications/handle.py | 3 +- .../sub_applications/staticfiles.py | 3 +- ruoyi-fastapi-backend/utils/common_util.py | 178 +++++++-- ruoyi-fastapi-backend/utils/cron_util.py | 74 ++-- ruoyi-fastapi-backend/utils/excel_util.py | 8 +- ruoyi-fastapi-backend/utils/gen_util.py | 15 +- ruoyi-fastapi-backend/utils/import_util.py | 14 +- ruoyi-fastapi-backend/utils/log_util.py | 12 +- ruoyi-fastapi-backend/utils/message_util.py | 2 +- ruoyi-fastapi-backend/utils/page_util.py | 24 +- ruoyi-fastapi-backend/utils/pwd_util.py | 2 +- ruoyi-fastapi-backend/utils/response_util.py | 15 +- ruoyi-fastapi-backend/utils/string_util.py | 39 +- ruoyi-fastapi-backend/utils/template_util.py | 62 ++-- .../utils/time_format_util.py | 41 ++- ruoyi-fastapi-backend/utils/upload_util.py | 39 +- 123 files changed, 2871 insertions(+), 2142 deletions(-) rename ruoyi-fastapi-backend/module_admin/controller/{post_controler.py => post_controller.py} (67%) diff --git a/ruoyi-fastapi-backend/alembic/env.py b/ruoyi-fastapi-backend/alembic/env.py index 98828e6..88469e0 100644 --- a/ruoyi-fastapi-backend/alembic/env.py +++ b/ruoyi-fastapi-backend/alembic/env.py @@ -1,13 +1,18 @@ import asyncio import os -from alembic import context +from collections.abc import Iterable from logging.config import fileConfig +from typing import Optional, Union + +from alembic import context +from alembic.migration import MigrationContext +from alembic.operations.ops import MigrationScript from sqlalchemy import pool from sqlalchemy.engine import Connection from sqlalchemy.ext.asyncio import async_engine_from_config -from config.database import Base, ASYNC_SQLALCHEMY_DATABASE_URL -from utils.import_util import ImportUtil +from config.database import ASYNC_SQLALCHEMY_DATABASE_URL, Base +from utils.import_util import ImportUtil # 判断vesrions目录是否存在,如果不存在则创建 alembic_veresions_path = 'alembic/versions' @@ -60,7 +65,11 @@ def run_migrations_offline() -> None: def do_run_migrations(connection: Connection) -> None: - def process_revision_directives(context, revision, directives): + def process_revision_directives( + context: MigrationContext, + revision: Union[str, Iterable[Optional[str]], Iterable[str]], + directives: list[MigrationScript], + ) -> None: script = directives[0] # 检查所有操作集是否为空 diff --git a/ruoyi-fastapi-backend/app.py b/ruoyi-fastapi-backend/app.py index 1ee7695..9c7e7d5 100644 --- a/ruoyi-fastapi-backend/app.py +++ b/ruoyi-fastapi-backend/app.py @@ -1,6 +1,6 @@ import uvicorn -from server import app, AppConfig # noqa: F401 +from server import AppConfig, app # noqa: F401 if __name__ == '__main__': uvicorn.run( diff --git a/ruoyi-fastapi-backend/config/constant.py b/ruoyi-fastapi-backend/config/constant.py index eb77464..da70e15 100644 --- a/ruoyi-fastapi-backend/config/constant.py +++ b/ruoyi-fastapi-backend/config/constant.py @@ -5,6 +5,7 @@ class CommonConstant: """ 常用常量 + PASSWORD_ERROR_COUNT: 密码错误次数 WWW: www主域 HTTP: http请求 HTTPS: https请求 @@ -19,6 +20,7 @@ class CommonConstant: NOT_UNIQUE: 校验是否唯一的返回标识(否) """ + PASSWORD_ERROR_COUNT = 5 WWW = 'www.' HTTP = 'http://' HTTPS = 'https://' diff --git a/ruoyi-fastapi-backend/config/database.py b/ruoyi-fastapi-backend/config/database.py index 006b6a5..72e0ce4 100644 --- a/ruoyi-fastapi-backend/config/database.py +++ b/ruoyi-fastapi-backend/config/database.py @@ -1,8 +1,8 @@ -from sqlalchemy.ext.asyncio import create_async_engine -from sqlalchemy.ext.asyncio import async_sessionmaker -from sqlalchemy.ext.asyncio import AsyncAttrs -from sqlalchemy.orm import DeclarativeBase from urllib.parse import quote_plus + +from sqlalchemy.ext.asyncio import AsyncAttrs, async_sessionmaker, create_async_engine +from sqlalchemy.orm import DeclarativeBase + from config.env import DataBaseConfig ASYNC_SQLALCHEMY_DATABASE_URL = ( diff --git a/ruoyi-fastapi-backend/config/enums.py b/ruoyi-fastapi-backend/config/enums.py index 0df6238..b6c3fda 100644 --- a/ruoyi-fastapi-backend/config/enums.py +++ b/ruoyi-fastapi-backend/config/enums.py @@ -1,4 +1,5 @@ from enum import Enum +from typing import Union class BusinessType(Enum): @@ -35,11 +36,11 @@ class RedisInitKeyConfig(Enum): """ @property - def key(self): + def key(self) -> Union[str, None]: return self.value.get('key') @property - def remark(self): + def remark(self) -> Union[str, None]: return self.value.get('remark') ACCESS_TOKEN = {'key': 'access_token', 'remark': '登录令牌信息'} diff --git a/ruoyi-fastapi-backend/config/env.py b/ruoyi-fastapi-backend/config/env.py index 3a2b3af..153b7a1 100644 --- a/ruoyi-fastapi-backend/config/env.py +++ b/ruoyi-fastapi-backend/config/env.py @@ -2,11 +2,11 @@ import argparse import configparser import os import sys +from typing import Literal + from dotenv import load_dotenv -from functools import lru_cache from pydantic import computed_field from pydantic_settings import BaseSettings -from typing import Literal class AppSettings(BaseSettings): @@ -86,7 +86,7 @@ class GenSettings: GEN_PATH = 'vf_admin/gen_path' - def __init__(self): + def __init__(self) -> None: if not os.path.exists(self.GEN_PATH): os.makedirs(self.GEN_PATH) @@ -130,7 +130,7 @@ class UploadSettings: ] DOWNLOAD_PATH = 'vf_admin/download_path' - def __init__(self): + def __init__(self) -> None: if not os.path.exists(self.UPLOAD_PATH): os.makedirs(self.UPLOAD_PATH) if not os.path.exists(self.DOWNLOAD_PATH): @@ -151,59 +151,53 @@ class GetConfig: 获取配置 """ - def __init__(self): + def __init__(self) -> None: self.parse_cli_args() - @lru_cache() - def get_app_config(self): + def get_app_config(self) -> AppSettings: """ 获取应用配置 """ # 实例化应用配置模型 return AppSettings() - @lru_cache() - def get_jwt_config(self): + def get_jwt_config(self) -> JwtSettings: """ 获取Jwt配置 """ # 实例化Jwt配置模型 return JwtSettings() - @lru_cache() - def get_database_config(self): + def get_database_config(self) -> DataBaseSettings: """ 获取数据库配置 """ # 实例化数据库配置模型 return DataBaseSettings() - @lru_cache() - def get_redis_config(self): + def get_redis_config(self) -> RedisSettings: """ 获取Redis配置 """ # 实例化Redis配置模型 return RedisSettings() - @lru_cache() - def get_gen_config(self): + def get_gen_config(self) -> GenSettings: """ 获取代码生成配置 """ # 实例化代码生成配置 return GenSettings() - @lru_cache() - def get_upload_config(self): + def get_upload_config(self) -> UploadSettings: """ - 获取数据库配置 + 获取上传配置 """ # 实例上传配置 return UploadSettings() @staticmethod - def parse_cli_args(): + def parse_cli_args() -> None: """ 解析命令行参数 """ diff --git a/ruoyi-fastapi-backend/config/get_db.py b/ruoyi-fastapi-backend/config/get_db.py index e5930c7..16df0ab 100644 --- a/ruoyi-fastapi-backend/config/get_db.py +++ b/ruoyi-fastapi-backend/config/get_db.py @@ -1,8 +1,12 @@ -from config.database import async_engine, AsyncSessionLocal, Base +from collections.abc import AsyncGenerator + +from sqlalchemy.ext.asyncio import AsyncSession + +from config.database import AsyncSessionLocal, Base, async_engine from utils.log_util import logger -async def get_db(): +async def get_db() -> AsyncGenerator[AsyncSession, None]: """ 每一个请求处理完毕后会关闭当前连接,不同的请求使用不同的连接 @@ -12,7 +16,7 @@ async def get_db(): yield current_db -async def init_create_table(): +async def init_create_table() -> None: """ 应用启动时初始化数据库连接 diff --git a/ruoyi-fastapi-backend/config/get_redis.py b/ruoyi-fastapi-backend/config/get_redis.py index ee4b6bd..e477784 100644 --- a/ruoyi-fastapi-backend/config/get_redis.py +++ b/ruoyi-fastapi-backend/config/get_redis.py @@ -1,5 +1,8 @@ +from fastapi import FastAPI from redis import asyncio as aioredis -from redis.exceptions import AuthenticationError, TimeoutError, RedisError +from redis.exceptions import AuthenticationError, RedisError +from redis.exceptions import TimeoutError as RedisTimeoutError + from config.database import AsyncSessionLocal from config.env import RedisConfig from module_admin.service.config_service import ConfigService @@ -37,14 +40,14 @@ class RedisUtil: logger.error('❌️ redis连接失败') except AuthenticationError as e: logger.error(f'❌️ redis用户名或密码错误,详细错误信息:{e}') - except TimeoutError as e: + except RedisTimeoutError as e: logger.error(f'❌️ redis连接超时,详细错误信息:{e}') except RedisError as e: logger.error(f'❌️ redis连接错误,详细错误信息:{e}') return redis @classmethod - async def close_redis_pool(cls, app): + async def close_redis_pool(cls, app: FastAPI) -> None: """ 应用关闭时关闭redis连接 @@ -55,7 +58,7 @@ class RedisUtil: logger.info('✅️ 关闭redis连接成功') @classmethod - async def init_sys_dict(cls, redis): + async def init_sys_dict(cls, redis: FastAPI) -> None: """ 应用启动时缓存字典表 @@ -66,7 +69,7 @@ class RedisUtil: await DictDataService.init_cache_sys_dict_services(session, redis) @classmethod - async def init_sys_config(cls, redis): + async def init_sys_config(cls, redis: aioredis.Redis) -> None: """ 应用启动时缓存参数配置表 diff --git a/ruoyi-fastapi-backend/config/get_scheduler.py b/ruoyi-fastapi-backend/config/get_scheduler.py index fadcf02..204adb4 100644 --- a/ruoyi-fastapi-backend/config/get_scheduler.py +++ b/ruoyi-fastapi-backend/config/get_scheduler.py @@ -1,7 +1,12 @@ import json -from apscheduler.events import EVENT_ALL +from asyncio import iscoroutinefunction +from datetime import datetime, timedelta +from typing import Optional, Union + +from apscheduler.events import EVENT_ALL, SchedulerEvent from apscheduler.executors.asyncio import AsyncIOExecutor from apscheduler.executors.pool import ProcessPoolExecutor +from apscheduler.job import Job from apscheduler.jobstores.memory import MemoryJobStore from apscheduler.jobstores.redis import RedisJobStore from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore @@ -9,27 +14,29 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.triggers.combining import OrTrigger from apscheduler.triggers.cron import CronTrigger from apscheduler.triggers.date import DateTrigger -from asyncio import iscoroutinefunction -from datetime import datetime, timedelta from sqlalchemy.engine import create_engine from sqlalchemy.orm import sessionmaker -from typing import Union + +import module_task # noqa: F401 from config.database import AsyncSessionLocal, quote_plus from config.env import DataBaseConfig, RedisConfig 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 from utils.log_util import logger -import module_task # noqa: F401 # 重写Cron定时 class MyCronTrigger(CronTrigger): + CRON_EXPRESSION_LENGTH_MIN = 6 + CRON_EXPRESSION_LENGTH_MAX = 7 + WEEKDAY_COUNT = 5 + @classmethod - def from_crontab(cls, expr: str, timezone=None): + def from_crontab(cls, expr: str, timezone: Optional[str] = None) -> 'MyCronTrigger': 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))) + if len(values) != cls.CRON_EXPRESSION_LENGTH_MIN and len(values) != cls.CRON_EXPRESSION_LENGTH_MAX: + raise ValueError(f'Wrong number of fields; got {len(values)}, expected 6 or 7') second = values[0] minute = values[1] @@ -37,7 +44,7 @@ class MyCronTrigger(CronTrigger): if '?' in values[3]: day = None elif 'L' in values[5]: - day = f"last {values[5].replace('L', '')}" + day = f'last {values[5].replace("L", "")}' elif 'W' in values[3]: day = cls.__find_recent_workday(int(values[3].split('W')[0])) else: @@ -49,11 +56,8 @@ class MyCronTrigger(CronTrigger): week = int(values[5].split('#')[1]) else: week = values[5] - if '#' in values[5]: - day_of_week = int(values[5].split('#')[0]) - 1 - else: - day_of_week = None - year = values[6] if len(values) == 7 else None + day_of_week = int(values[5].split('#')[0]) - 1 if '#' in values[5] else None + year = values[6] if len(values) == cls.CRON_EXPRESSION_LENGTH_MAX else None return cls( second=second, minute=minute, @@ -67,19 +71,17 @@ class MyCronTrigger(CronTrigger): ) @classmethod - def __find_recent_workday(cls, day: int): + def __find_recent_workday(cls, day: int) -> int: now = datetime.now() date = datetime(now.year, now.month, day) - if date.weekday() < 5: + if date.weekday() < cls.WEEKDAY_COUNT: return date.day - else: - diff = 1 - while True: - previous_day = date - timedelta(days=diff) - if previous_day.weekday() < 5: - return previous_day.day - else: - diff += 1 + diff = 1 + while True: + previous_day = date - timedelta(days=diff) + if previous_day.weekday() < cls.WEEKDAY_COUNT: + return previous_day.day + diff += 1 SQLALCHEMY_DATABASE_URL = ( @@ -100,18 +102,17 @@ engine = create_engine( pool_timeout=DataBaseConfig.db_pool_timeout, ) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +redis_config = { + 'host': RedisConfig.redis_host, + 'port': RedisConfig.redis_port, + 'username': RedisConfig.redis_username, + 'password': RedisConfig.redis_password, + 'db': RedisConfig.redis_database, +} job_stores = { 'default': MemoryJobStore(), 'sqlalchemy': SQLAlchemyJobStore(url=SQLALCHEMY_DATABASE_URL, engine=engine), - 'redis': RedisJobStore( - **dict( - host=RedisConfig.redis_host, - port=RedisConfig.redis_port, - username=RedisConfig.redis_username, - password=RedisConfig.redis_password, - db=RedisConfig.redis_database, - ) - ), + 'redis': RedisJobStore(**redis_config), } executors = {'default': AsyncIOExecutor(), 'processpool': ProcessPoolExecutor(5)} job_defaults = {'coalesce': False, 'max_instance': 1} @@ -125,7 +126,7 @@ class SchedulerUtil: """ @classmethod - async def init_system_scheduler(cls): + async def init_system_scheduler(cls) -> None: """ 应用启动时初始化定时任务 @@ -142,7 +143,7 @@ class SchedulerUtil: logger.info('✅️ 系统初始定时任务加载成功') @classmethod - async def close_system_scheduler(cls): + async def close_system_scheduler(cls) -> None: """ 应用关闭时关闭定时任务 @@ -152,7 +153,7 @@ class SchedulerUtil: logger.info('✅️ 关闭定时任务成功') @classmethod - def get_scheduler_job(cls, job_id: Union[str, int]): + def get_scheduler_job(cls, job_id: Union[str, int]) -> Job: """ 根据任务id获取任务对象 @@ -164,7 +165,7 @@ class SchedulerUtil: return query_job @classmethod - def add_scheduler_job(cls, job_info: JobModel): + def add_scheduler_job(cls, job_info: JobModel) -> None: """ 根据输入的任务对象信息添加任务 @@ -183,14 +184,14 @@ class SchedulerUtil: id=str(job_info.job_id), name=job_info.job_name, misfire_grace_time=1000000000000 if job_info.misfire_policy == '3' else None, - coalesce=True if job_info.misfire_policy == '2' else False, + coalesce=job_info.misfire_policy == '2', max_instances=3 if job_info.concurrent == '0' else 1, jobstore=job_info.job_group, executor=job_executor, ) @classmethod - def execute_scheduler_job_once(cls, job_info: JobModel): + def execute_scheduler_job_once(cls, job_info: JobModel) -> None: """ 根据输入的任务对象执行一次任务 @@ -212,14 +213,14 @@ class SchedulerUtil: id=str(job_info.job_id), name=job_info.job_name, misfire_grace_time=1000000000000 if job_info.misfire_policy == '3' else None, - coalesce=True if job_info.misfire_policy == '2' else False, + coalesce=job_info.misfire_policy == '2', max_instances=3 if job_info.concurrent == '0' else 1, jobstore=job_info.job_group, executor=job_executor, ) @classmethod - def remove_scheduler_job(cls, job_id: Union[str, int]): + def remove_scheduler_job(cls, job_id: Union[str, int]) -> None: """ 根据任务id移除任务 @@ -231,7 +232,7 @@ class SchedulerUtil: scheduler.remove_job(job_id=str(job_id)) @classmethod - def scheduler_event_listener(cls, event): + def scheduler_event_listener(cls, event: SchedulerEvent) -> None: # 获取事件类型和任务ID event_type = event.__class__.__name__ # 获取任务执行异常信息 @@ -260,7 +261,7 @@ class SchedulerUtil: # 获取任务触发器 job_trigger = str(query_job_info.get('trigger')) # 构造日志消息 - job_message = f"事件类型: {event_type}, 任务ID: {job_id}, 任务名称: {job_name}, 执行于{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" + job_message = f'事件类型: {event_type}, 任务ID: {job_id}, 任务名称: {job_name}, 执行于{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}' job_log = JobLogModel( jobName=job_name, jobGroup=job_group, diff --git a/ruoyi-fastapi-backend/exceptions/exception.py b/ruoyi-fastapi-backend/exceptions/exception.py index b86f50d..effaa9e 100644 --- a/ruoyi-fastapi-backend/exceptions/exception.py +++ b/ruoyi-fastapi-backend/exceptions/exception.py @@ -1,9 +1,12 @@ +from typing import Optional + + class LoginException(Exception): """ 自定义登录异常LoginException """ - def __init__(self, data: str = None, message: str = None): + def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None: self.data = data self.message = message @@ -13,7 +16,7 @@ class AuthException(Exception): 自定义令牌异常AuthException """ - def __init__(self, data: str = None, message: str = None): + def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None: self.data = data self.message = message @@ -23,7 +26,7 @@ class PermissionException(Exception): 自定义权限异常PermissionException """ - def __init__(self, data: str = None, message: str = None): + def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None: self.data = data self.message = message @@ -33,7 +36,7 @@ class ServiceException(Exception): 自定义服务异常ServiceException """ - def __init__(self, data: str = None, message: str = None): + def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None: self.data = data self.message = message @@ -43,7 +46,7 @@ class ServiceWarning(Exception): 自定义服务警告ServiceWarning """ - def __init__(self, data: str = None, message: str = None): + def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None: self.data = data self.message = message @@ -53,6 +56,6 @@ class ModelValidatorException(Exception): 自定义模型校验异常ModelValidatorException """ - def __init__(self, data: str = None, message: str = None): + def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None: self.data = data self.message = message diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py index dec516a..3e8e590 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 import FastAPI, Request, Response from fastapi.exceptions import HTTPException from pydantic_validation_decorator import FieldValidationError + from exceptions.exception import ( AuthException, LoginException, @@ -10,62 +11,62 @@ from exceptions.exception import ( ServiceWarning, ) from utils.log_util import logger -from utils.response_util import jsonable_encoder, JSONResponse, ResponseUtil +from utils.response_util import JSONResponse, ResponseUtil, jsonable_encoder -def handle_exception(app: FastAPI): +def handle_exception(app: FastAPI) -> None: """ 全局异常处理 """ # 自定义token检验异常 @app.exception_handler(AuthException) - async def auth_exception_handler(request: Request, exc: AuthException): + async def auth_exception_handler(request: Request, exc: AuthException) -> Response: return ResponseUtil.unauthorized(data=exc.data, msg=exc.message) # 自定义登录检验异常 @app.exception_handler(LoginException) - async def login_exception_handler(request: Request, exc: LoginException): + async def login_exception_handler(request: Request, exc: LoginException) -> Response: return ResponseUtil.failure(data=exc.data, msg=exc.message) # 自定义模型检验异常 @app.exception_handler(ModelValidatorException) - async def model_validator_exception_handler(request: Request, exc: ModelValidatorException): + async def model_validator_exception_handler(request: Request, exc: ModelValidatorException) -> Response: 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): + async def field_validation_error_handler(request: Request, exc: FieldValidationError) -> Response: logger.warning(exc.message) return ResponseUtil.failure(msg=exc.message) # 自定义权限检验异常 @app.exception_handler(PermissionException) - async def permission_exception_handler(request: Request, exc: PermissionException): + async def permission_exception_handler(request: Request, exc: PermissionException) -> Response: return ResponseUtil.forbidden(data=exc.data, msg=exc.message) # 自定义服务异常 @app.exception_handler(ServiceException) - async def service_exception_handler(request: Request, exc: ServiceException): + async def service_exception_handler(request: Request, exc: ServiceException) -> Response: logger.error(exc.message) return ResponseUtil.error(data=exc.data, msg=exc.message) # 自定义服务警告 @app.exception_handler(ServiceWarning) - async def service_warning_handler(request: Request, exc: ServiceWarning): + async def service_warning_handler(request: Request, exc: ServiceWarning) -> Response: logger.warning(exc.message) return ResponseUtil.failure(data=exc.data, msg=exc.message) # 处理其他http请求异常 @app.exception_handler(HTTPException) - async def http_exception_handler(request: Request, exc: HTTPException): + async def http_exception_handler(request: Request, exc: HTTPException) -> Response: return JSONResponse( 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): + async def exception_handler(request: Request, exc: Exception) -> Response: logger.exception(exc) return ResponseUtil.error(msg=str(exc)) diff --git a/ruoyi-fastapi-backend/middlewares/cors_middleware.py b/ruoyi-fastapi-backend/middlewares/cors_middleware.py index 55508e7..e82ca9c 100644 --- a/ruoyi-fastapi-backend/middlewares/cors_middleware.py +++ b/ruoyi-fastapi-backend/middlewares/cors_middleware.py @@ -2,7 +2,7 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -def add_cors_middleware(app: FastAPI): +def add_cors_middleware(app: FastAPI) -> None: """ 添加跨域中间件 diff --git a/ruoyi-fastapi-backend/middlewares/gzip_middleware.py b/ruoyi-fastapi-backend/middlewares/gzip_middleware.py index eb371ce..867b786 100644 --- a/ruoyi-fastapi-backend/middlewares/gzip_middleware.py +++ b/ruoyi-fastapi-backend/middlewares/gzip_middleware.py @@ -2,7 +2,7 @@ from fastapi import FastAPI from starlette.middleware.gzip import GZipMiddleware -def add_gzip_middleware(app: FastAPI): +def add_gzip_middleware(app: FastAPI) -> None: """ 添加gzip压缩中间件 diff --git a/ruoyi-fastapi-backend/middlewares/handle.py b/ruoyi-fastapi-backend/middlewares/handle.py index abb2d0d..bc2aca9 100644 --- a/ruoyi-fastapi-backend/middlewares/handle.py +++ b/ruoyi-fastapi-backend/middlewares/handle.py @@ -1,10 +1,11 @@ from fastapi import FastAPI + from middlewares.cors_middleware import add_cors_middleware from middlewares.gzip_middleware import add_gzip_middleware from middlewares.trace_middleware import add_trace_middleware -def handle_middleware(app: FastAPI): +def handle_middleware(app: FastAPI) -> None: """ 全局中间件处理 """ diff --git a/ruoyi-fastapi-backend/middlewares/trace_middleware/__init__.py b/ruoyi-fastapi-backend/middlewares/trace_middleware/__init__.py index 76f8d85..c2ea302 100644 --- a/ruoyi-fastapi-backend/middlewares/trace_middleware/__init__.py +++ b/ruoyi-fastapi-backend/middlewares/trace_middleware/__init__.py @@ -1,4 +1,5 @@ from fastapi import FastAPI + from .ctx import TraceCtx from .middle import TraceASGIMiddleware @@ -7,7 +8,7 @@ __all__ = ('TraceASGIMiddleware', 'TraceCtx') __version__ = '0.1.0' -def add_trace_middleware(app: FastAPI): +def add_trace_middleware(app: FastAPI) -> None: """ 添加trace中间件 diff --git a/ruoyi-fastapi-backend/middlewares/trace_middleware/ctx.py b/ruoyi-fastapi-backend/middlewares/trace_middleware/ctx.py index 558a5c9..4f98008 100644 --- a/ruoyi-fastapi-backend/middlewares/trace_middleware/ctx.py +++ b/ruoyi-fastapi-backend/middlewares/trace_middleware/ctx.py @@ -1,10 +1,3 @@ -# -*- coding: utf-8 -*- -""" -@author: peng -@file: ctx.py -@time: 2025/1/17 16:57 -""" - import contextvars from uuid import uuid4 @@ -13,11 +6,11 @@ CTX_REQUEST_ID: contextvars.ContextVar[str] = contextvars.ContextVar('request-id class TraceCtx: @staticmethod - def set_id(): + def set_id() -> str: _id = uuid4().hex CTX_REQUEST_ID.set(_id) return _id @staticmethod - def get_id(): + def get_id() -> str: return CTX_REQUEST_ID.get() diff --git a/ruoyi-fastapi-backend/middlewares/trace_middleware/middle.py b/ruoyi-fastapi-backend/middlewares/trace_middleware/middle.py index a071692..42cd78c 100644 --- a/ruoyi-fastapi-backend/middlewares/trace_middleware/middle.py +++ b/ruoyi-fastapi-backend/middlewares/trace_middleware/middle.py @@ -1,13 +1,8 @@ -# -*- coding: utf-8 -*- -""" -@author: peng -@file: middle.py -@time: 2025/1/17 16:57 -""" - from functools import wraps + from starlette.types import ASGIApp, Message, Receive, Scope, Send -from .span import get_current_span, Span + +from .span import Span, get_current_span class TraceASGIMiddleware: @@ -21,11 +16,11 @@ class TraceASGIMiddleware: self.app = app @staticmethod - async def my_receive(receive: Receive, span: Span): + async def my_receive(receive: Receive, span: Span) -> Receive: await span.request_before() @wraps(receive) - async def my_receive(): + async def my_receive() -> Message: message = await receive() await span.request_after(message) return message diff --git a/ruoyi-fastapi-backend/middlewares/trace_middleware/span.py b/ruoyi-fastapi-backend/middlewares/trace_middleware/span.py index 1e38eab..ef6e46f 100644 --- a/ruoyi-fastapi-backend/middlewares/trace_middleware/span.py +++ b/ruoyi-fastapi-backend/middlewares/trace_middleware/span.py @@ -1,12 +1,8 @@ -# -*- coding: utf-8 -*- -""" -@author: peng -@file: span.py -@time: 2025/1/17 16:57 -""" - +from collections.abc import AsyncGenerator from contextlib import asynccontextmanager -from starlette.types import Scope, Message + +from starlette.types import Message, Scope + from .ctx import TraceCtx @@ -16,16 +12,16 @@ class Span: request(before) --> request(after) --> response(before) --> response(after) """ - def __init__(self, scope: Scope): + def __init__(self, scope: Scope) -> None: self.scope = scope - async def request_before(self): + async def request_before(self) -> None: """ request_before: 处理header信息等, 如记录请求体信息 """ TraceCtx.set_id() - async def request_after(self, message: Message): + async def request_after(self, message: Message) -> Message: """ request_after: 处理请求bytes, 如记录请求参数 @@ -34,7 +30,7 @@ class Span: """ return message - async def response(self, message: Message): + async def response(self, message: Message) -> Message: """ if message['type'] == "http.response.start": -----> request-before pass @@ -48,5 +44,5 @@ class Span: @asynccontextmanager -async def get_current_span(scope: Scope): +async def get_current_span(scope: Scope) -> AsyncGenerator[Span, None]: yield Span(scope) diff --git a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py index f7e938c..0c48512 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/log_annotation.py @@ -1,16 +1,20 @@ -import httpx import inspect import json -import os import time -from async_lru import alru_cache +from collections.abc import Awaitable from datetime import datetime +from functools import wraps +from typing import Any, Callable, Literal, Optional, TypeVar + +import httpx +from async_lru import alru_cache from fastapi import Request from fastapi.responses import JSONResponse, ORJSONResponse, UJSONResponse -from functools import wraps from sqlalchemy.ext.asyncio import AsyncSession -from typing import Any, Callable, Literal, Optional +from starlette.status import HTTP_200_OK +from typing_extensions import ParamSpec from user_agents import parse + from config.enums import BusinessType from config.env import AppConfig from exceptions.exception import LoginException, ServiceException, ServiceWarning @@ -20,6 +24,9 @@ from module_admin.service.login_service import LoginService from utils.log_util import logger from utils.response_util import ResponseUtil +P = ParamSpec('P') +R = TypeVar('R') + class Log: """ @@ -31,7 +38,7 @@ class Log: title: str, business_type: BusinessType, log_type: Optional[Literal['login', 'operation']] = 'operation', - ): + ) -> None: """ 日志装饰器 @@ -43,80 +50,39 @@ class Log: self.title = title self.business_type = business_type.value self.log_type = log_type + self._oper_param_len = 2000 - def __call__(self, func): + def __call__(self, func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[R]]: @wraps(func) - async def wrapper(*args, **kwargs): + async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: start_time = time.perf_counter() - # 获取被装饰函数的文件路径 - file_path = inspect.getfile(func) - # 获取项目根路径 - project_root = os.getcwd() - # 处理文件路径,去除项目根路径部分 - relative_path = os.path.relpath(file_path, start=project_root)[0:-2].replace('\\', '.').replace('/', '.') # 获取当前被装饰函数所在路径 - func_path = f'{relative_path}{func.__name__}()' + func_path = self._get_decorator_func_path(func) # 获取上下文信息 request_name_list = get_function_parameters_name_by_type(func, Request) request = get_function_parameters_value_by_name(func, request_name_list[0], *args, **kwargs) - token = request.headers.get('Authorization') session_name_list = get_function_parameters_name_by_type(func, AsyncSession) query_db = get_function_parameters_value_by_name(func, session_name_list[0], *args, **kwargs) 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 + # 获取操作类型 + operator_type = self._get_oper_type(user_agent) # 获取请求的url oper_url = request.url.path - # 获取请求的ip及ip归属区域 + # 获取请求ip oper_ip = request.headers.get('X-Forwarded-For') - oper_location = '内网IP' - if AppConfig.app_ip_location_query: - oper_location = await 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) + # 获取请求ip归属区域 + oper_location = await self._get_oper_location(oper_ip) + # 获取请求参数 + oper_param = await self._get_request_params(request) # 日志表请求参数字段长度最大为2000,因此在此处判断长度 - if len(oper_param) > 2000: + if len(oper_param) > self._oper_param_len: 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 + login_log = self._get_login_log(user_agent, oper_ip, oper_location, oper_time, kwargs) try: # 调用原始函数 result = await func(*args, **kwargs) @@ -132,35 +98,12 @@ class Log: # 获取请求耗时 cost_time = float(time.perf_counter() - start_time) * 1000 # 判断请求是否来自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_from_redoc = self._is_request_from_swagger_or_redoc(request) # 根据响应结果的类型使用不同的方法获取响应结果参数 - 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': '获取失败'} + result_dict = self._get_result_dict(result, request_from_swagger, request_from_redoc) 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') + status, error_msg = self._get_status_and_error_msg(result_dict) # 根据日志类型向对应的日志表插入数据 if self.log_type == 'login': # 登录请求来自于api文档时不记录登录日志,其余情况则记录 @@ -168,14 +111,18 @@ class Log: 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') + login_log.update( + { + 'loginTime': oper_time, + 'userName': user.username, + 'status': str(status), + 'msg': result_dict.get('msg'), + } + ) await LoginLogService.add_login_log_services(query_db, LogininforModel(**login_log)) else: + token = request.headers.get('Authorization') 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 @@ -203,9 +150,203 @@ class Log: return wrapper + def _get_decorator_func_path(self, func: Callable) -> str: + """ + 获取被装饰函数所在路径 + + :param func: 被装饰函数 + :return: 被装饰函数所在路径 + """ + # 获取被装饰函数所在的模块 + module = inspect.getmodule(func) + # 获取完整模块路径 + module_path = module.__name__ if module else '' + # 获取当前被装饰函数所在路径 + func_path = f'{module_path}.{func.__name__}()' + + return func_path + + def _get_oper_type(self, user_agent: Any) -> int: + """ + 获取操作类型 + + :param user_agent: 用户代理字符串 + :return: 操作类型 + """ + operator_type = 0 + 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 + + return operator_type + + async def _get_oper_location(self, oper_ip: str) -> str: + """ + 获取请求IP归属区域 + + :param oper_ip: 请求IP + :return: 请求IP归属区域 + """ + oper_location = '内网IP' + if AppConfig.app_ip_location_query: + oper_location = await get_ip_location(oper_ip) + + return oper_location + + async def _get_request_params(self, request: Request) -> str: + """ + 获取请求参数 + + :param request: Request对象 + :return: 格式化后的请求参数字符串 + """ + params = {} + + # 路径和查询参数 + path_params = dict(request.path_params) + query_params = dict(request.query_params) + params.update({k: v for k, v in {'path_params': path_params, 'query_params': query_params}.items() if v}) + + # 请求体处理 + content_type = request.headers.get('Content-Type', '') + + # JSON请求 + if 'application/json' in content_type: + json_body = await request.json() + if json_body: + params['json_body'] = json_body + + # 表单数据 + elif 'multipart/form-data' in content_type or 'application/x-www-form-urlencoded' in content_type: + form_data = await request.form() + if form_data: + # 过滤掉文件对象,只保留普通表单字段 + form_dict = {key: value for key, value in form_data.items() if not hasattr(value, 'filename')} + if form_dict: + params['form_data'] = form_dict + + # 仅在multipart时尝试处理文件 + if 'multipart/form-data' in content_type: + file_info = {} + for key, value in form_data.items(): + if hasattr(value, 'filename'): + file_info[key] = { + 'filename': value.filename, + 'content_type': value.content_type, + 'size': value.size, + 'headers': dict(value.headers), + } + if file_info: + params['files'] = file_info + + # 其他文本请求 + elif 'application/octet-stream' not in content_type: + body = await request.body() + if body: + params['raw_body'] = body.decode('utf-8') + + return json.dumps(params, ensure_ascii=False, indent=2) if params else '' + + def _get_login_log( + self, user_agent: Any, oper_ip: str, oper_location: str, oper_time: datetime, origin_kwargs: dict + ) -> dict: + """ + 获取登录日志信息 + + :param user_agent: 用户代理字符串 + :param oper_ip: 操作ip + :param oper_location: 操作区域 + :param oper_time: 操作时间 + :param origin_kwargs: 原始函数参数 + :return: 登录日志信息 + """ + 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 = { + 'ipaddr': oper_ip, + 'loginLocation': oper_location, + 'browser': browser, + 'os': system_os, + 'loginTime': oper_time.strftime('%Y-%m-%d %H:%M:%S'), + } + self._set_login_data(login_log, origin_kwargs) + + return login_log + + def _set_login_data(self, login_log: dict, origin_kwargs: dict) -> None: + """ + 设置登录日志数据 + + :param login_log: 登录日志信息 + :param origin_kwargs: 原始函数参数 + :return: None + """ + if 'form_data' in origin_kwargs: + origin_kwargs['form_data'].login_info = login_log + + def _get_status_and_error_msg(self, result_dict: dict) -> tuple[int, str]: + """ + 获取操作状态和错误信息 + + :param result_dict: 操作结果字典 + :return: 操作状态和错误信息元组 + """ + status = 1 + error_msg = '' + if result_dict.get('code') == HTTP_200_OK: + status = 0 + else: + error_msg = result_dict.get('msg') + + return status, error_msg + + def _is_request_from_swagger_or_redoc(self, request: Request) -> tuple[bool, bool]: + """ + 判断请求是否来自swagger或redoc + + :param request: Request对象 + :return: 是否来自swagger请求和是否来自redoc请求元组 + """ + 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 + ) + + return request_from_swagger, request_from_redoc + + def _get_result_dict(self, result: Any, request_from_swagger: bool, request_from_redoc: bool) -> dict: + """ + 获取操作结果字典 + + :param result: 操作结果 + :param request_from_swagger: 是否来自swagger请求 + :param request_from_redoc: 是否来自redoc请求 + :return: 操作结果字典 + """ + if isinstance(result, (JSONResponse, ORJSONResponse, UJSONResponse)): + result_dict = json.loads(str(result.body, 'utf-8')) + elif request_from_swagger or request_from_redoc: + result_dict = {} + elif result.status_code == HTTP_200_OK: + result_dict = {'code': result.status_code, 'message': '获取成功'} + else: + result_dict = {'code': result.status_code, 'message': '获取失败'} + + return result_dict + @alru_cache() -async def get_ip_location(oper_ip: str): +async def get_ip_location(oper_ip: str) -> str: """ 查询ip归属区域 @@ -214,11 +355,11 @@ async def get_ip_location(oper_ip: str): """ oper_location = '内网IP' try: - if oper_ip != '127.0.0.1' and oper_ip != 'localhost': + if oper_ip not in ['127.0.0.1', 'localhost']: oper_location = '未知' async with httpx.AsyncClient() as client: ip_result = await client.get(f'https://qifu-api.baidubce.com/ip/geo/v1/district?ip={oper_ip}') - if ip_result.status_code == 200: + if ip_result.status_code == HTTP_200_OK: prov = ip_result.json().get('data', {}).get('prov') city = ip_result.json().get('data', {}).get('city') if prov or city: @@ -229,7 +370,7 @@ async def get_ip_location(oper_ip: str): return oper_location -def get_function_parameters_name_by_type(func: Callable, param_type: Any): +def get_function_parameters_name_by_type(func: Callable, param_type: Any) -> list: """ 获取函数指定类型的参数名称 @@ -241,13 +382,23 @@ def get_function_parameters_name_by_type(func: Callable, param_type: Any): parameters = inspect.signature(func).parameters # 找到指定类型的参数名称 parameters_name_list = [] + # 遍历所有参数 for name, param in parameters.items(): - if param.annotation == param_type: + # 处理参数注解 + annotation = param.annotation + # 检查参数类型是否匹配 + # 1. 直接匹配 + # 2. 检查是否为Annotated类型(通过类型名称判断) + if annotation == param_type or ( + hasattr(annotation, '__class__') + and annotation.__class__.__name__ == '_AnnotatedAlias' + and annotation.__origin__ == param_type + ): parameters_name_list.append(name) return parameters_name_list -def get_function_parameters_value_by_name(func: Callable, name: str, *args, **kwargs): +def get_function_parameters_value_by_name(func: Callable, name: str, *args, **kwargs) -> Any: """ 获取函数指定参数的值 diff --git a/ruoyi-fastapi-backend/module_admin/annotation/pydantic_annotation.py b/ruoyi-fastapi-backend/module_admin/annotation/pydantic_annotation.py index 11e8d7f..9dde679 100644 --- a/ruoyi-fastapi-backend/module_admin/annotation/pydantic_annotation.py +++ b/ruoyi-fastapi-backend/module_admin/annotation/pydantic_annotation.py @@ -1,21 +1,23 @@ import inspect +from typing import TYPE_CHECKING, TypeVar + from fastapi import Form, Query from pydantic import BaseModel -from pydantic.fields import FieldInfo -from typing import Type, TypeVar +if TYPE_CHECKING: + from pydantic.fields import FieldInfo BaseModelVar = TypeVar('BaseModelVar', bound=BaseModel) -def as_query(cls: Type[BaseModelVar]) -> Type[BaseModelVar]: +def as_query(cls: type[BaseModelVar]) -> type[BaseModelVar]: """ pydantic模型查询参数装饰器,将pydantic模型用于接收查询参数 """ new_parameters = [] - for field_name, model_field in cls.model_fields.items(): - model_field: FieldInfo # type: ignore + for model_field in cls.model_fields.values(): + model_field: FieldInfo if not model_field.is_required(): new_parameters.append( @@ -36,24 +38,24 @@ def as_query(cls: Type[BaseModelVar]) -> Type[BaseModelVar]: ) ) - async def as_query_func(**data): + async def as_query_func(**data) -> type[BaseModelVar]: return cls(**data) sig = inspect.signature(as_query_func) sig = sig.replace(parameters=new_parameters) - as_query_func.__signature__ = sig # type: ignore - setattr(cls, 'as_query', as_query_func) + as_query_func.__signature__ = sig + cls.as_query = as_query_func return cls -def as_form(cls: Type[BaseModelVar]) -> Type[BaseModelVar]: +def as_form(cls: type[BaseModelVar]) -> type[BaseModelVar]: """ pydantic模型表单参数装饰器,将pydantic模型用于接收表单参数 """ new_parameters = [] - for field_name, model_field in cls.model_fields.items(): - model_field: FieldInfo # type: ignore + for model_field in cls.model_fields.values(): + model_field: FieldInfo if not model_field.is_required(): new_parameters.append( @@ -74,11 +76,11 @@ def as_form(cls: Type[BaseModelVar]) -> Type[BaseModelVar]: ) ) - async def as_form_func(**data): + async def as_form_func(**data) -> type[BaseModelVar]: return cls(**data) sig = inspect.signature(as_form_func) sig = sig.replace(parameters=new_parameters) - as_form_func.__signature__ = sig # type: ignore - setattr(cls, 'as_form', as_form_func) + as_form_func.__signature__ = sig + cls.as_form = as_form_func return cls diff --git a/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py b/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py index 5a7afbb..fe52363 100644 --- a/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py +++ b/ruoyi-fastapi-backend/module_admin/aspect/data_scope.py @@ -1,5 +1,7 @@ -from fastapi import Depends from typing import Optional + +from fastapi import Depends + from module_admin.entity.vo.user_vo import CurrentUserModel from module_admin.service.login_service import LoginService @@ -21,7 +23,7 @@ class GetDataScope: db_alias: Optional[str] = 'db', user_alias: Optional[str] = 'user_id', dept_alias: Optional[str] = 'dept_id', - ): + ) -> None: """ 获取当前用户数据权限对应的查询sql语句 @@ -35,7 +37,7 @@ class GetDataScope: self.user_alias = user_alias self.dept_alias = dept_alias - def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)) -> str: user_id = current_user.user.user_id dept_id = current_user.user.dept_id custom_data_scope_role_id_list = [ @@ -46,7 +48,7 @@ class GetDataScope: if current_user.user.admin or role.data_scope == self.DATA_SCOPE_ALL: param_sql_list = ['1 == 1'] break - elif role.data_scope == self.DATA_SCOPE_CUSTOM: + if role.data_scope == self.DATA_SCOPE_CUSTOM: if len(custom_data_scope_role_id_list) > 1: param_sql_list.append( f"{self.query_alias}.{self.dept_alias}.in_(select(SysRoleDept.dept_id).where(SysRoleDept.role_id.in_({custom_data_scope_role_id_list}))) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0" @@ -70,6 +72,6 @@ class GetDataScope: else: param_sql_list.append('1 == 0') param_sql_list = list(dict.fromkeys(param_sql_list)) - param_sql = f"or_({', '.join(param_sql_list)})" + param_sql = f'or_({", ".join(param_sql_list)})' return param_sql diff --git a/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py b/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py index 8f8349d..db81952 100644 --- a/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py +++ b/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py @@ -1,5 +1,7 @@ +from typing import Union + from fastapi import Depends -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 @@ -10,7 +12,7 @@ class CheckUserInterfaceAuth: 校验当前用户是否具有相应的接口权限 """ - def __init__(self, perm: Union[str, List], is_strict: bool = False): + def __init__(self, perm: Union[str, list], is_strict: bool = False) -> None: """ 校验当前用户是否具有相应的接口权限 @@ -20,20 +22,18 @@ class CheckUserInterfaceAuth: self.perm = perm self.is_strict = is_strict - def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)) -> bool: user_auth_list = current_user.permissions if '*:*:*' in user_auth_list: return True - if isinstance(self.perm, str): - if self.perm in user_auth_list: - return True + if isinstance(self.perm, str) and self.perm in user_auth_list: + return True if isinstance(self.perm, list): if self.is_strict: - if all([perm_str in user_auth_list for perm_str in self.perm]): - return True - else: - if any([perm_str in user_auth_list for perm_str in self.perm]): + if all(perm_str in user_auth_list for perm_str in self.perm): return True + elif any(perm_str in user_auth_list for perm_str in self.perm): + return True raise PermissionException(data='', message='该用户无此接口权限') @@ -42,7 +42,7 @@ class CheckRoleInterfaceAuth: 根据角色校验当前用户是否具有相应的接口权限 """ - def __init__(self, role_key: Union[str, List], is_strict: bool = False): + def __init__(self, role_key: Union[str, list], is_strict: bool = False) -> None: """ 根据角色校验当前用户是否具有相应的接口权限 @@ -52,17 +52,15 @@ class CheckRoleInterfaceAuth: self.role_key = role_key self.is_strict = is_strict - def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)) -> bool: user_role_list = current_user.user.role user_role_key_list = [role.role_key for role in user_role_list] - if isinstance(self.role_key, str): - if self.role_key in user_role_key_list: - return True + if isinstance(self.role_key, str) and self.role_key in user_role_key_list: + return True if isinstance(self.role_key, list): if self.is_strict: - if all([role_key_str in user_role_key_list for role_key_str in self.role_key]): - return True - else: - if any([role_key_str in user_role_key_list for role_key_str in self.role_key]): + if all(role_key_str in user_role_key_list for role_key_str in self.role_key): return True + elif any(role_key_str in user_role_key_list for role_key_str in self.role_key): + return True raise PermissionException(data='', message='该用户无此接口权限') diff --git a/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py b/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py index 9e72713..7ade706 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/cache_controller.py @@ -1,5 +1,7 @@ -from fastapi import APIRouter, Depends, Request -from typing import List +from typing import Annotated + +from fastapi import APIRouter, Depends, Path, Request, Response + from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel from module_admin.service.cache_service import CacheService @@ -7,14 +9,13 @@ 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)]) +cache_controller = APIRouter(prefix='/monitor/cache', dependencies=[Depends(LoginService.get_current_user)]) -@cacheController.get( +@cache_controller.get( '', response_model=CacheMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))] ) -async def get_monitor_cache_info(request: Request): +async def get_monitor_cache_info(request: Request) -> Response: # 获取全量数据 cache_info_query_result = await CacheService.get_cache_monitor_statistical_info_services(request) logger.info('获取成功') @@ -22,12 +23,12 @@ async def get_monitor_cache_info(request: Request): return ResponseUtil.success(data=cache_info_query_result) -@cacheController.get( +@cache_controller.get( '/getNames', - response_model=List[CacheInfoModel], + response_model=list[CacheInfoModel], dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))], ) -async def get_monitor_cache_name(request: Request): +async def get_monitor_cache_name(request: Request) -> Response: # 获取全量数据 cache_name_list_result = await CacheService.get_cache_monitor_cache_name_services() logger.info('获取成功') @@ -35,12 +36,12 @@ async def get_monitor_cache_name(request: Request): return ResponseUtil.success(data=cache_name_list_result) -@cacheController.get( +@cache_controller.get( '/getKeys/{cache_name}', - response_model=List[str], + response_model=list[str], dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))], ) -async def get_monitor_cache_key(request: Request, cache_name: str): +async def get_monitor_cache_key(request: Request, cache_name: Annotated[str, Path(description='缓存名称')]) -> Response: # 获取全量数据 cache_key_list_result = await CacheService.get_cache_monitor_cache_key_services(request, cache_name) logger.info('获取成功') @@ -48,12 +49,16 @@ async def get_monitor_cache_key(request: Request, cache_name: str): return ResponseUtil.success(data=cache_key_list_result) -@cacheController.get( +@cache_controller.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): +async def get_monitor_cache_value( + request: Request, + cache_name: Annotated[str, Path(description='缓存名称')], + cache_key: Annotated[str, Path(description='缓存键')], +) -> Response: # 获取全量数据 cache_value_list_result = await CacheService.get_cache_monitor_cache_value_services(request, cache_name, cache_key) logger.info('获取成功') @@ -61,28 +66,30 @@ async def get_monitor_cache_value(request: Request, cache_name: str, cache_key: return ResponseUtil.success(data=cache_value_list_result) -@cacheController.delete( +@cache_controller.delete( '/clearCacheName/{cache_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))] ) -async def clear_monitor_cache_name(request: Request, cache_name: str): +async def clear_monitor_cache_name( + request: Request, cache_name: Annotated[str, Path(description='缓存名称')] +) -> Response: 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( +@cache_controller.delete( '/clearCacheKey/{cache_key}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))] ) -async def clear_monitor_cache_key(request: Request, cache_key: str): +async def clear_monitor_cache_key(request: Request, cache_key: Annotated[str, Path(description='缓存键')]) -> Response: 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): +@cache_controller.delete('/clearCacheAll', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]) +async def clear_monitor_cache_all(request: Request) -> Response: 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/controller/captcha_controller.py b/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py index 83d35b8..479375c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py @@ -1,28 +1,24 @@ import uuid from datetime import timedelta -from fastapi import APIRouter, Request + +from fastapi import APIRouter, Request, Response + from config.enums import RedisInitKeyConfig from module_admin.entity.vo.login_vo import CaptchaCode from module_admin.service.captcha_service import CaptchaService -from utils.response_util import ResponseUtil from utils.log_util import logger +from utils.response_util import ResponseUtil + +captcha_controller = APIRouter() -captchaController = APIRouter() - - -@captchaController.get('/captchaImage') -async def get_captcha_image(request: Request): +@captcha_controller.get('/captchaImage') +async def get_captcha_image(request: Request) -> Response: captcha_enabled = ( - True - if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') - == 'true' - else False + await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') == 'true' ) register_enabled = ( - True - if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.registerUser') == 'true' - else False + await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.registerUser') == 'true' ) session_id = str(uuid.uuid4()) captcha_result = await CaptchaService.create_captcha_image_service() diff --git a/ruoyi-fastapi-backend/module_admin/controller/common_controller.py b/ruoyi-fastapi-backend/module_admin/controller/common_controller.py index d2fd621..714ecbd 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/common_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/common_controller.py @@ -1,35 +1,38 @@ -from fastapi import APIRouter, BackgroundTasks, Depends, File, Query, Request, UploadFile +from typing import Annotated + +from fastapi import APIRouter, BackgroundTasks, Depends, File, Query, Request, Response, UploadFile + from module_admin.service.common_service import CommonService from module_admin.service.login_service import LoginService from utils.log_util import logger from utils.response_util import ResponseUtil -commonController = APIRouter(prefix='/common', dependencies=[Depends(LoginService.get_current_user)]) +common_controller = APIRouter(prefix='/common', dependencies=[Depends(LoginService.get_current_user)]) -@commonController.post('/upload') -async def common_upload(request: Request, file: UploadFile = File(...)): +@common_controller.post('/upload') +async def common_upload(request: Request, file: Annotated[UploadFile, File(...)]) -> Response: upload_result = await CommonService.upload_service(request, file) logger.info('上传成功') return ResponseUtil.success(model_content=upload_result.result) -@commonController.get('/download') +@common_controller.get('/download') async def common_download( request: Request, background_tasks: BackgroundTasks, - file_name: str = Query(alias='fileName'), - delete: bool = Query(), -): + file_name: Annotated[str, Query(alias='fileName')], + delete: Annotated[bool, Query()], +) -> Response: 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_resource(request: Request, resource: str = Query()): +@common_controller.get('/download/resource') +async def common_download_resource(request: Request, resource: Annotated[str, Query()]) -> Response: download_resource_result = await CommonService.download_resource_services(resource) logger.info(download_resource_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py index 747dff2..640966c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py @@ -1,7 +1,10 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Form, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Form, Path, Query, Request, Response 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 @@ -15,18 +18,17 @@ 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)]) +config_controller = APIRouter(prefix='/system/config', dependencies=[Depends(LoginService.get_current_user)]) -@configController.get( +@config_controller.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: Annotated[ConfigPageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 config_page_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=True) logger.info('获取成功') @@ -34,15 +36,15 @@ async def get_system_config_list( return ResponseUtil.success(model_content=config_page_query_result) -@configController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))]) +@config_controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))]) @ValidateFields(validate_model='add_config') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: add_config.create_by = current_user.user.user_name add_config.create_time = datetime.now() add_config.update_by = current_user.user.user_name @@ -53,15 +55,15 @@ async def add_system_config( return ResponseUtil.success(msg=add_config_result.message) -@configController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))]) +@config_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))]) @ValidateFields(validate_model='edit_config') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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) @@ -70,18 +72,25 @@ async def edit_system_config( return ResponseUtil.success(msg=edit_config_result.message) -@configController.delete('/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) +@config_controller.delete('/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) @Log(title='参数管理', business_type=BusinessType.UPDATE) -async def refresh_system_config(request: Request, query_db: AsyncSession = Depends(get_db)): +async def refresh_system_config( + request: Request, + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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'))]) +@config_controller.delete('/{config_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))]) @Log(title='参数管理', business_type=BusinessType.DELETE) -async def delete_system_config(request: Request, config_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_config( + request: Request, + config_ids: Annotated[str, Path(description='需要删除的参数主键')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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) @@ -89,18 +98,22 @@ async def delete_system_config(request: Request, config_ids: str, query_db: Asyn return ResponseUtil.success(msg=delete_config_result.message) -@configController.get( +@config_controller.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)): +async def query_detail_system_config( + request: Request, + config_id: Annotated[int, Path(description='参数主键')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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): +@config_controller.get('/configKey/{config_key}') +async def query_system_config(request: Request, config_key: str) -> Response: # 获取全量数据 config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key) logger.info('获取成功') @@ -108,13 +121,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'))]) +@config_controller.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))]) @Log(title='参数管理', business_type=BusinessType.EXPORT) async def export_system_config_list( request: Request, - config_page_query: ConfigPageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + config_page_query: Annotated[ConfigPageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 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/controller/dept_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py index 2943206..d5638c7 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dept_controller.py @@ -1,8 +1,10 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Path, Query, Request, Response 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.annotation.log_annotation import Log @@ -15,21 +17,20 @@ 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)]) +dept_controller = APIRouter(prefix='/system/dept', dependencies=[Depends(LoginService.get_current_user)]) -@deptController.get( +@dept_controller.get( '/list/exclude/{dept_id}', - response_model=List[DeptModel], + 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_id: Annotated[int, Path(description='部门id')], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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('获取成功') @@ -37,30 +38,30 @@ async def get_system_dept_tree_for_edit_option( return ResponseUtil.success(data=dept_query_result) -@deptController.get( - '/list', response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))] +@dept_controller.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: Annotated[DeptQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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'))]) +@dept_controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))]) @ValidateFields(validate_model='add_dept') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: add_dept.create_by = current_user.user.user_name add_dept.create_time = datetime.now() add_dept.update_by = current_user.user.user_name @@ -71,16 +72,16 @@ async def add_system_dept( return ResponseUtil.success(data=add_dept_result) -@deptController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) +@dept_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))]) @ValidateFields(validate_model='edit_dept') @Log(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')), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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 @@ -91,15 +92,15 @@ async def edit_system_dept( return ResponseUtil.success(msg=edit_dept_result.message) -@deptController.delete('/{dept_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) +@dept_controller.delete('/{dept_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))]) @Log(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')), -): + dept_ids: Annotated[str, Path(description='需要删除的部门id')], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: dept_id_list = dept_ids.split(',') if dept_ids else [] if dept_id_list: for dept_id in dept_id_list: @@ -114,16 +115,16 @@ async def delete_system_dept( return ResponseUtil.success(msg=delete_dept_result.message) -@deptController.get( +@dept_controller.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')), -): + dept_id: Annotated[int, Path(description='部门id')], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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/controller/dict_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py index 27fa24c..2822591 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py @@ -1,8 +1,10 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Form, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Form, Path, Query, Request, Response 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.annotation.log_annotation import Log @@ -23,18 +25,17 @@ 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)]) +dict_controller = APIRouter(prefix='/system/dict', dependencies=[Depends(LoginService.get_current_user)]) -@dictController.get( +@dict_controller.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: Annotated[DictTypePageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 dict_type_page_query_result = await DictTypeService.get_dict_type_list_services( query_db, dict_type_page_query, is_page=True @@ -44,15 +45,15 @@ async def get_system_dict_type_list( return ResponseUtil.success(model_content=dict_type_page_query_result) -@dictController.post('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) +@dict_controller.post('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) @ValidateFields(validate_model='add_dict_type') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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 @@ -63,15 +64,15 @@ async def add_system_dict_type( return ResponseUtil.success(msg=add_dict_type_result.message) -@dictController.put('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) +@dict_controller.put('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) @ValidateFields(validate_model='edit_dict_type') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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) @@ -80,18 +81,22 @@ async def edit_system_dict_type( return ResponseUtil.success(msg=edit_dict_type_result.message) -@dictController.delete('/type/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) +@dict_controller.delete('/type/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @Log(title='字典类型', business_type=BusinessType.UPDATE) -async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends(get_db)): +async def refresh_system_dict(request: Request, query_db: Annotated[AsyncSession, Depends(get_db)]) -> Response: 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'))]) +@dict_controller.delete('/type/{dict_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @Log(title='字典类型', business_type=BusinessType.DELETE) -async def delete_system_dict_type(request: Request, dict_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_dict_type( + request: Request, + dict_ids: Annotated[str, Path(description='需要删除的字典主键')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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) @@ -99,33 +104,39 @@ 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]) -async def query_system_dict_type_options(request: Request, query_db: AsyncSession = Depends(get_db)): +@dict_controller.get('/type/optionselect', response_model=list[DictTypeModel]) +async def query_system_dict_type_options( + request: Request, query_db: Annotated[AsyncSession, Depends(get_db)] +) -> Response: dict_type_query_result = await DictTypeService.get_dict_type_list_services( - query_db, DictTypePageQueryModel(**dict()), is_page=False + query_db, DictTypePageQueryModel(), is_page=False ) logger.info('获取成功') return ResponseUtil.success(data=dict_type_query_result) -@dictController.get( +@dict_controller.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)): +async def query_detail_system_dict_type( + request: Request, + dict_id: Annotated[int, Path(description='字典主键')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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'))]) +@dict_controller.post('/type/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) @Log(title='字典类型', business_type=BusinessType.EXPORT) async def export_system_dict_type_list( request: Request, - dict_type_page_query: DictTypePageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + dict_type_page_query: Annotated[DictTypePageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 dict_type_query_result = await DictTypeService.get_dict_type_list_services( query_db, dict_type_page_query, is_page=False @@ -136,8 +147,12 @@ async def export_system_dict_type_list( 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)): +@dict_controller.get('/data/type/{dict_type}') +async def query_system_dict_type_data( + request: Request, + dict_type: Annotated[str, Path(description='字典类型')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services( request.app.state.redis, dict_type @@ -147,14 +162,14 @@ async def query_system_dict_type_data(request: Request, dict_type: str, query_db return ResponseUtil.success(data=dict_data_query_result) -@dictController.get( +@dict_controller.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: Annotated[DictDataPageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 dict_data_page_query_result = await DictDataService.get_dict_data_list_services( query_db, dict_data_page_query, is_page=True @@ -164,15 +179,15 @@ async def get_system_dict_data_list( return ResponseUtil.success(model_content=dict_data_page_query_result) -@dictController.post('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) +@dict_controller.post('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))]) @ValidateFields(validate_model='add_dict_data') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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 @@ -183,15 +198,15 @@ async def add_system_dict_data( return ResponseUtil.success(msg=add_dict_data_result.message) -@dictController.put('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) +@dict_controller.put('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))]) @ValidateFields(validate_model='edit_dict_data') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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) @@ -200,9 +215,13 @@ async def edit_system_dict_data( return ResponseUtil.success(msg=edit_dict_data_result.message) -@dictController.delete('/data/{dict_codes}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) +@dict_controller.delete('/data/{dict_codes}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))]) @Log(title='字典数据', business_type=BusinessType.DELETE) -async def delete_system_dict_data(request: Request, dict_codes: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_dict_data( + request: Request, + dict_codes: Annotated[str, Path(description='需要删除的字典编码')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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) @@ -210,25 +229,29 @@ 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( +@dict_controller.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)): +async def query_detail_system_dict_data( + request: Request, + dict_code: Annotated[int, Path(description='字典编码')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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'))]) +@dict_controller.post('/data/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))]) @Log(title='字典数据', business_type=BusinessType.EXPORT) async def export_system_dict_data_list( request: Request, - dict_data_page_query: DictDataPageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + dict_data_page_query: Annotated[DictDataPageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 dict_data_query_result = await DictDataService.get_dict_data_list_services( query_db, dict_data_page_query, is_page=False diff --git a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py index c930569..0b4306d 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py @@ -1,7 +1,10 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Form, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Form, Path, Query, Request, Response 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 @@ -23,18 +26,17 @@ 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)]) +job_controller = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)]) -@jobController.get( +@job_controller.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), -): + job_page_query: Annotated[JobPageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 notice_page_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=True) logger.info('获取成功') @@ -42,15 +44,15 @@ async def get_system_job_list( return ResponseUtil.success(model_content=notice_page_query_result) -@jobController.post('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))]) +@job_controller.post('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))]) @ValidateFields(validate_model='add_job') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: add_job.create_by = current_user.user.user_name add_job.create_time = datetime.now() add_job.update_by = current_user.user.user_name @@ -61,15 +63,15 @@ async def add_system_job( return ResponseUtil.success(msg=add_job_result.message) -@jobController.put('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))]) +@job_controller.put('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))]) @ValidateFields(validate_model='edit_job') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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) @@ -78,14 +80,14 @@ async def edit_system_job( return ResponseUtil.success(msg=edit_job_result.message) -@jobController.put('/job/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) +@job_controller.put('/job/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) @Log(title='定时任务', business_type=BusinessType.UPDATE) async def change_system_job_status( request: Request, change_job: EditJobModel, - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: edit_job = EditJobModel( jobId=change_job.job_id, status=change_job.status, @@ -99,18 +101,26 @@ async def change_system_job_status( return ResponseUtil.success(msg=edit_job_result.message) -@jobController.put('/job/run', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) +@job_controller.put('/job/run', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))]) @Log(title='定时任务', business_type=BusinessType.UPDATE) -async def execute_system_job(request: Request, execute_job: JobModel, query_db: AsyncSession = Depends(get_db)): +async def execute_system_job( + request: Request, + execute_job: JobModel, + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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'))]) +@job_controller.delete('/job/{job_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @Log(title='定时任务', business_type=BusinessType.DELETE) -async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_job( + request: Request, + job_ids: Annotated[str, Path(description='需要删除的定时任务ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: delete_job = DeleteJobModel(jobIds=job_ids) delete_job_result = await JobService.delete_job_services(query_db, delete_job) logger.info(delete_job_result.message) @@ -118,23 +128,27 @@ async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSessi return ResponseUtil.success(msg=delete_job_result.message) -@jobController.get( +@job_controller.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)): +async def query_detail_system_job( + request: Request, + job_id: Annotated[int, Path(description='任务ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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'))]) +@job_controller.post('/job/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) @Log(title='定时任务', business_type=BusinessType.EXPORT) async def export_system_job_list( request: Request, - job_page_query: JobPageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + job_page_query: Annotated[JobPageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 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) @@ -143,14 +157,14 @@ async def export_system_job_list( return ResponseUtil.streaming(data=bytes2file_response(job_export_result)) -@jobController.get( +@job_controller.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), -): + job_log_page_query: Annotated[JobLogPageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 job_log_page_query_result = await JobLogService.get_job_log_list_services( query_db, job_log_page_query, is_page=True @@ -160,18 +174,25 @@ async def get_system_job_log_list( return ResponseUtil.success(model_content=job_log_page_query_result) -@jobController.delete('/jobLog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) +@job_controller.delete('/jobLog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @Log(title='定时任务调度日志', business_type=BusinessType.CLEAN) -async def clear_system_job_log(request: Request, query_db: AsyncSession = Depends(get_db)): +async def clear_system_job_log( + request: Request, + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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'))]) +@job_controller.delete('/jobLog/{job_log_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))]) @Log(title='定时任务调度日志', business_type=BusinessType.DELETE) -async def delete_system_job_log(request: Request, job_log_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_job_log( + request: Request, + job_log_ids: Annotated[str, Path(description='需要删除的定时任务日志ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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) @@ -179,13 +200,13 @@ async def delete_system_job_log(request: Request, job_log_ids: str, query_db: As return ResponseUtil.success(msg=delete_job_log_result.message) -@jobController.post('/jobLog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) +@job_controller.post('/jobLog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))]) @Log(title='定时任务调度日志', business_type=BusinessType.EXPORT) async def export_system_job_log_list( request: Request, - job_log_page_query: JobLogPageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + job_log_page_query: Annotated[JobLogPageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 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) diff --git a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py index a01ba94..39541be 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py @@ -1,5 +1,8 @@ -from fastapi import APIRouter, Depends, Form, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Form, Path, Query, Request, Response 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 @@ -18,20 +21,19 @@ 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)]) +log_controller = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)]) -@logController.get( +@log_controller.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: Annotated[OperLogPageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 operation_log_page_query_result = await OperationLogService.get_operation_log_list_services( query_db, operation_log_page_query, is_page=True @@ -41,18 +43,22 @@ async def get_system_operation_log_list( return ResponseUtil.success(model_content=operation_log_page_query_result) -@logController.delete('/operlog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) +@log_controller.delete('/operlog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) @Log(title='操作日志', business_type=BusinessType.CLEAN) -async def clear_system_operation_log(request: Request, query_db: AsyncSession = Depends(get_db)): +async def clear_system_operation_log(request: Request, query_db: Annotated[AsyncSession, Depends(get_db)]) -> Response: 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_controller.delete('/operlog/{oper_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))]) @Log(title='操作日志', business_type=BusinessType.DELETE) -async def delete_system_operation_log(request: Request, oper_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_operation_log( + request: Request, + oper_ids: Annotated[str, Path(description='需要删除的日志主键')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: delete_operation_log = DeleteOperLogModel(operIds=oper_ids) delete_operation_log_result = await OperationLogService.delete_operation_log_services( query_db, delete_operation_log @@ -62,13 +68,13 @@ async def delete_system_operation_log(request: Request, oper_ids: str, query_db: return ResponseUtil.success(msg=delete_operation_log_result.message) -@logController.post('/operlog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))]) +@log_controller.post('/operlog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))]) @Log(title='操作日志', business_type=BusinessType.EXPORT) async def export_system_operation_log_list( request: Request, - operation_log_page_query: OperLogPageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + operation_log_page_query: Annotated[OperLogPageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 operation_log_query_result = await OperationLogService.get_operation_log_list_services( query_db, operation_log_page_query, is_page=False @@ -81,16 +87,16 @@ async def export_system_operation_log_list( return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result)) -@logController.get( +@log_controller.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: Annotated[LoginLogPageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 login_log_page_query_result = await LoginLogService.get_login_log_list_services( query_db, login_log_page_query, is_page=True @@ -100,20 +106,24 @@ async def get_system_login_log_list( return ResponseUtil.success(model_content=login_log_page_query_result) -@logController.delete('/logininfor/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) +@log_controller.delete('/logininfor/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]) @Log(title='登录日志', business_type=BusinessType.CLEAN) -async def clear_system_login_log(request: Request, query_db: AsyncSession = Depends(get_db)): +async def clear_system_login_log(request: Request, query_db: Annotated[AsyncSession, Depends(get_db)]) -> Response: 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( +@log_controller.delete( '/logininfor/{info_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))] ) @Log(title='登录日志', business_type=BusinessType.DELETE) -async def delete_system_login_log(request: Request, info_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_login_log( + request: Request, + info_ids: Annotated[str, Path(description='需要删除的访问ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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) @@ -121,11 +131,15 @@ 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( +@log_controller.get( '/logininfor/unlock/{user_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:unlock'))] ) @Log(title='账户解锁', business_type=BusinessType.OTHER) -async def unlock_system_user(request: Request, user_name: str, query_db: AsyncSession = Depends(get_db)): +async def unlock_system_user( + request: Request, + user_name: Annotated[str, Path(description='用户名称')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: unlock_user = UnlockUser(userName=user_name) unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user) logger.info(unlock_user_result.message) @@ -133,13 +147,13 @@ async def unlock_system_user(request: Request, user_name: str, query_db: AsyncSe return ResponseUtil.success(msg=unlock_user_result.message) -@logController.post('/logininfor/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))]) +@log_controller.post('/logininfor/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))]) @Log(title='登录日志', business_type=BusinessType.EXPORT) async def export_system_login_log_list( request: Request, - login_log_page_query: LoginLogPageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + login_log_page_query: Annotated[LoginLogPageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 login_log_query_result = await LoginLogService.get_login_log_list_services( query_db, login_log_page_query, is_page=False diff --git a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py index 1a3c198..0accf07 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py @@ -1,35 +1,35 @@ -import jwt import uuid from datetime import datetime, timedelta -from fastapi import APIRouter, Depends, Request +from typing import Annotated, Optional + +import jwt +from fastapi import APIRouter, Depends, Request, Response from sqlalchemy.ext.asyncio import AsyncSession -from typing import Optional + from config.enums import BusinessType, RedisInitKeyConfig from config.env import AppConfig, JwtConfig from config.get_db import get_db 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.login_vo import Token, UserLogin, UserRegister 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 - -loginController = APIRouter() +login_controller = APIRouter() -@loginController.post('/login', response_model=Token) +@login_controller.post('/login', response_model=Token) @Log(title='用户登录', business_type=BusinessType.OTHER, log_type='login') async def login( - request: Request, form_data: CustomOAuth2PasswordRequestForm = Depends(), query_db: AsyncSession = Depends(get_db) -): + request: Request, + form_data: Annotated[CustomOAuth2PasswordRequestForm, Depends()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: captcha_enabled = ( - True - if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') - == 'true' - else False + await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') == 'true' ) user = UserLogin( userName=form_data.username, @@ -77,36 +77,40 @@ async def login( return ResponseUtil.success(msg='登录成功', dict_content={'token': access_token}) -@loginController.get('/getInfo', response_model=CurrentUserModel) +@login_controller.get('/getInfo', response_model=CurrentUserModel) async def get_login_user_info( - request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user) -): + request: Request, current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)] +) -> Response: logger.info('获取成功') return ResponseUtil.success(model_content=current_user) -@loginController.get('/getRouters') +@login_controller.get('/getRouters') async def get_login_user_routers( request: Request, - current_user: CurrentUserModel = Depends(LoginService.get_current_user), - query_db: AsyncSession = Depends(get_db), -): + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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)): +@login_controller.post('/register', response_model=CrudResponseModel) +async def register_user( + request: Request, + user_register: UserRegister, + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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) +# @login_controller.post("/getSmsCode", response_model=SmsCode) # async def get_sms_code(request: Request, user: ResetUserModel, query_db: AsyncSession = Depends(get_db)): # try: # sms_result = await LoginService.get_sms_code_services(request, query_db, user) @@ -121,7 +125,7 @@ async def register_user(request: Request, user_register: UserRegister, query_db: # return ResponseUtil.error(msg=str(e)) # # -# @loginController.post("/forgetPwd", response_model=CrudResponseModel) +# @login_controller.post("/forgetPwd", response_model=CrudResponseModel) # async def forget_user_pwd(request: Request, forget_user: ResetUserModel, query_db: AsyncSession = Depends(get_db)): # try: # forget_user_result = await LoginService.forget_user_services(request, query_db, forget_user) @@ -136,8 +140,8 @@ async def register_user(request: Request, user_register: UserRegister, query_db: # return ResponseUtil.error(msg=str(e)) -@loginController.post('/logout') -async def logout(request: Request, token: Optional[str] = Depends(oauth2_scheme)): +@login_controller.post('/logout') +async def logout(request: Request, token: Annotated[Optional[str], Depends(oauth2_scheme)]) -> Response: payload = jwt.decode( token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False} ) diff --git a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py index 0e3124e..4cf4d76 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/menu_controller.py @@ -1,8 +1,10 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Path, Query, Request, Response 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.annotation.log_annotation import Log @@ -14,59 +16,58 @@ 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)]) +menu_controller = APIRouter(prefix='/system/menu', dependencies=[Depends(LoginService.get_current_user)]) -@menuController.get('/treeselect') +@menu_controller.get('/treeselect') async def get_system_menu_tree( request: Request, - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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}') +@menu_controller.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_id: Annotated[int, Path(description='角色ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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'))] +@menu_controller.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: Annotated[MenuQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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'))]) +@menu_controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))]) @ValidateFields(validate_model='add_menu') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: add_menu.create_by = current_user.user.user_name add_menu.create_time = datetime.now() add_menu.update_by = current_user.user.user_name @@ -77,15 +78,15 @@ async def add_system_menu( return ResponseUtil.success(msg=add_menu_result.message) -@menuController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) +@menu_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))]) @ValidateFields(validate_model='edit_menu') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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) @@ -94,9 +95,13 @@ async def edit_system_menu( return ResponseUtil.success(msg=edit_menu_result.message) -@menuController.delete('/{menu_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) +@menu_controller.delete('/{menu_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))]) @Log(title='菜单管理', business_type=BusinessType.DELETE) -async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_menu( + request: Request, + menu_ids: Annotated[str, Path(description='需要删除的菜单ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: delete_menu = DeleteMenuModel(menuIds=menu_ids) delete_menu_result = await MenuService.delete_menu_services(query_db, delete_menu) logger.info(delete_menu_result.message) @@ -104,10 +109,14 @@ async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSes return ResponseUtil.success(msg=delete_menu_result.message) -@menuController.get( +@menu_controller.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)): +async def query_detail_system_menu( + request: Request, + menu_id: Annotated[int, Path(description='菜单ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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/controller/notice_controller.py b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py index e1e4aa1..9a01737 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py @@ -1,7 +1,10 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Path, Query, Request, Response 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 @@ -14,18 +17,17 @@ 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)]) +notice_controller = APIRouter(prefix='/system/notice', dependencies=[Depends(LoginService.get_current_user)]) -@noticeController.get( +@notice_controller.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: Annotated[NoticePageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 notice_page_query_result = await NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True) logger.info('获取成功') @@ -33,15 +35,15 @@ async def get_system_notice_list( return ResponseUtil.success(model_content=notice_page_query_result) -@noticeController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))]) +@notice_controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))]) @ValidateFields(validate_model='add_notice') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: add_notice.create_by = current_user.user.user_name add_notice.create_time = datetime.now() add_notice.update_by = current_user.user.user_name @@ -52,15 +54,15 @@ async def add_system_notice( return ResponseUtil.success(msg=add_notice_result.message) -@noticeController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))]) +@notice_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))]) @ValidateFields(validate_model='edit_notice') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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) @@ -69,9 +71,13 @@ async def edit_system_notice( return ResponseUtil.success(msg=edit_notice_result.message) -@noticeController.delete('/{notice_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))]) +@notice_controller.delete('/{notice_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))]) @Log(title='通知公告', business_type=BusinessType.DELETE) -async def delete_system_notice(request: Request, notice_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_notice( + request: Request, + notice_ids: Annotated[str, Path(description='需要删除的公告ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: delete_notice = DeleteNoticeModel(noticeIds=notice_ids) delete_notice_result = await NoticeService.delete_notice_services(query_db, delete_notice) logger.info(delete_notice_result.message) @@ -79,10 +85,14 @@ async def delete_system_notice(request: Request, notice_ids: str, query_db: Asyn return ResponseUtil.success(msg=delete_notice_result.message) -@noticeController.get( +@notice_controller.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)): +async def query_detail_system_post( + request: Request, + notice_id: Annotated[int, Path(description='公告ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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/controller/online_controller.py b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py index bf65c8f..70c731c 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/online_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/online_controller.py @@ -1,5 +1,8 @@ -from fastapi import APIRouter, Depends, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Path, Query, Request, Response 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 @@ -11,16 +14,16 @@ 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)]) +online_controller = APIRouter(prefix='/monitor/online', dependencies=[Depends(LoginService.get_current_user)]) -@onlineController.get( +@online_controller.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) -): + request: Request, + online_page_query: Annotated[OnlineQueryModel, Query()], +) -> Response: # 获取全量数据 online_query_result = await OnlineService.get_online_list_services(request, online_page_query) logger.info('获取成功') @@ -30,9 +33,13 @@ async def get_monitor_online_list( ) -@onlineController.delete('/{token_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))]) +@online_controller.delete('/{token_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))]) @Log(title='在线用户', business_type=BusinessType.FORCE) -async def delete_monitor_online(request: Request, token_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_monitor_online( + request: Request, + token_ids: Annotated[str, Path(description='需要强退的会话编号')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: delete_online = DeleteOnlineModel(tokenIds=token_ids) delete_online_result = await OnlineService.delete_online_services(request, delete_online) logger.info(delete_online_result.message) diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controller.py similarity index 67% rename from ruoyi-fastapi-backend/module_admin/controller/post_controler.py rename to ruoyi-fastapi-backend/module_admin/controller/post_controller.py index e9c69c4..475849d 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controller.py @@ -1,32 +1,34 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Form, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Form, Path, Query, Request, Response 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 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 module_admin.service.login_service import LoginService +from module_admin.service.post_service import PostService 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)]) +post_controller = APIRouter(prefix='/system/post', dependencies=[Depends(LoginService.get_current_user)]) -@postController.get( +@post_controller.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: Annotated[PostPageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 post_page_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=True) logger.info('获取成功') @@ -34,15 +36,15 @@ async def get_system_post_list( return ResponseUtil.success(model_content=post_page_query_result) -@postController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))]) +@post_controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))]) @ValidateFields(validate_model='add_post') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: add_post.create_by = current_user.user.user_name add_post.create_time = datetime.now() add_post.update_by = current_user.user.user_name @@ -53,15 +55,15 @@ async def add_system_post( return ResponseUtil.success(msg=add_post_result.message) -@postController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))]) +@post_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))]) @ValidateFields(validate_model='edit_post') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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) @@ -70,9 +72,13 @@ async def edit_system_post( return ResponseUtil.success(msg=edit_post_result.message) -@postController.delete('/{post_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))]) +@post_controller.delete('/{post_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))]) @Log(title='岗位管理', business_type=BusinessType.DELETE) -async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_system_post( + request: Request, + post_ids: Annotated[str, Path(description='需要删除的岗位ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: delete_post = DeletePostModel(postIds=post_ids) delete_post_result = await PostService.delete_post_services(query_db, delete_post) logger.info(delete_post_result.message) @@ -80,23 +86,27 @@ async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSes return ResponseUtil.success(msg=delete_post_result.message) -@postController.get( +@post_controller.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)): +async def query_detail_system_post( + request: Request, + post_id: Annotated[int, Path(description='岗位ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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'))]) +@post_controller.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:post:export'))]) @Log(title='岗位管理', business_type=BusinessType.EXPORT) async def export_system_post_list( request: Request, - post_page_query: PostPageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + post_page_query: Annotated[PostPageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 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/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index d4ab531..5e52133 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -1,7 +1,10 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Form, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Form, Path, Query, Request, Response 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 @@ -19,18 +22,17 @@ 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)]) +role_controller = APIRouter(prefix='/system/role', dependencies=[Depends(LoginService.get_current_user)]) -@roleController.get('/deptTree/{role_id}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]) +@role_controller.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_id: Annotated[int, Path(description='角色ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: + 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('获取成功') @@ -38,15 +40,15 @@ async def get_system_role_dept_tree( return ResponseUtil.success(model_content=role_dept_query_result) -@roleController.get( +@role_controller.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: Annotated[RolePageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: role_page_query_result = await RoleService.get_role_list_services( query_db, role_page_query, data_scope_sql, is_page=True ) @@ -55,15 +57,15 @@ async def get_system_role_list( return ResponseUtil.success(model_content=role_page_query_result) -@roleController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))]) +@role_controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))]) @ValidateFields(validate_model='add_role') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: add_role.create_by = current_user.user.user_name add_role.create_time = datetime.now() add_role.update_by = current_user.user.user_name @@ -74,16 +76,16 @@ async def add_system_role( return ResponseUtil.success(msg=add_role_result.message) -@roleController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@role_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @ValidateFields(validate_model='edit_role') @Log(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')), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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) @@ -95,15 +97,15 @@ async def edit_system_role( return ResponseUtil.success(msg=edit_role_result.message) -@roleController.put('/dataScope', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@role_controller.put('/dataScope', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @Log(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')), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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) @@ -121,15 +123,15 @@ async def edit_system_role_datascope( return ResponseUtil.success(msg=role_data_scope_result.message) -@roleController.delete('/{role_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))]) +@role_controller.delete('/{role_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))]) @Log(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')), -): + role_ids: Annotated[str, Path(description='需要删除的角色ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: role_id_list = role_ids.split(',') if role_ids else [] if role_id_list: for role_id in role_id_list: @@ -143,16 +145,16 @@ async def delete_system_role( return ResponseUtil.success(msg=delete_role_result.message) -@roleController.get( +@role_controller.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')), -): + role_id: Annotated[int, Path(description='角色ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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) @@ -161,14 +163,14 @@ async def query_detail_system_role( return ResponseUtil.success(data=role_detail_result.model_dump(by_alias=True)) -@roleController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))]) +@role_controller.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))]) @Log(title='角色管理', business_type=BusinessType.EXPORT) async def export_system_role_list( request: Request, - role_page_query: RolePageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), - data_scope_sql: str = Depends(GetDataScope('SysDept')), -): + role_page_query: Annotated[RolePageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: # 获取全量数据 role_query_result = await RoleService.get_role_list_services( query_db, role_page_query, data_scope_sql, is_page=False @@ -179,15 +181,15 @@ async def export_system_role_list( return ResponseUtil.streaming(data=bytes2file_response(role_export_result)) -@roleController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@role_controller.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @Log(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')), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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) @@ -204,17 +206,17 @@ async def reset_system_role_status( return ResponseUtil.success(msg=edit_role_result.message) -@roleController.get( +@role_controller.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')), -): + user_role: Annotated[UserRolePageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], +) -> Response: role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services( query_db, user_role, data_scope_sql, is_page=True ) @@ -223,17 +225,17 @@ async def get_system_allocated_user_list( return ResponseUtil.success(model_content=role_user_allocated_page_query_result) -@roleController.get( +@role_controller.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')), -): + user_role: Annotated[UserRolePageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], +) -> Response: role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services( query_db, user_role, data_scope_sql, is_page=True ) @@ -242,15 +244,15 @@ async def get_system_unallocated_user_list( return ResponseUtil.success(model_content=role_user_unallocated_page_query_result) -@roleController.put('/authUser/selectAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@role_controller.put('/authUser/selectAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @Log(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')), -): + add_role_user: Annotated[CrudUserRoleModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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) @@ -259,24 +261,26 @@ async def add_system_role_user( return ResponseUtil.success(msg=add_role_user_result.message) -@roleController.put('/authUser/cancel', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) +@role_controller.put('/authUser/cancel', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @Log(title='角色管理', business_type=BusinessType.GRANT) async def cancel_system_role_user( - request: Request, cancel_user_role: CrudUserRoleModel, query_db: AsyncSession = Depends(get_db) -): + request: Request, + cancel_user_role: CrudUserRoleModel, + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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'))]) +@role_controller.put('/authUser/cancelAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))]) @Log(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), -): + batch_cancel_user_role: Annotated[CrudUserRoleModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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/controller/server_controller.py b/ruoyi-fastapi-backend/module_admin/controller/server_controller.py index f63fdf8..2258e83 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/server_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/server_controller.py @@ -1,19 +1,19 @@ -from fastapi import APIRouter, Depends, Request +from fastapi import APIRouter, Depends, Request, Response + from module_admin.aspect.interface_auth import CheckUserInterfaceAuth 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 +from utils.response_util import ResponseUtil + +server_controller = APIRouter(prefix='/monitor/server', dependencies=[Depends(LoginService.get_current_user)]) -serverController = APIRouter(prefix='/monitor/server', dependencies=[Depends(LoginService.get_current_user)]) - - -@serverController.get( +@server_controller.get( '', response_model=ServerMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:server:list'))] ) -async def get_monitor_server_info(request: Request): +async def get_monitor_server_info(request: Request) -> Response: # 获取全量数据 server_info_query_result = await ServerService.get_server_monitor_info() logger.info('获取成功') diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index 91d6611..c36604b 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -1,12 +1,15 @@ import os from datetime import datetime -from fastapi import APIRouter, Depends, File, Form, Query, Request, UploadFile -from sqlalchemy.ext.asyncio import AsyncSession -from typing import Literal, Optional, Union +from typing import Annotated, Literal, Optional, Union + +import aiofiles +from fastapi import APIRouter, Depends, File, Form, Path, Query, Request, Response, UploadFile from pydantic_validation_decorator import ValidateFields -from config.get_db import get_db +from sqlalchemy.ext.asyncio import AsyncSession + from config.enums import BusinessType from config.env import UploadConfig +from config.get_db import get_db from module_admin.annotation.log_annotation import Log from module_admin.aspect.data_scope import GetDataScope from module_admin.aspect.interface_auth import CheckUserInterfaceAuth @@ -27,10 +30,10 @@ from module_admin.entity.vo.user_vo import ( UserRoleQueryModel, UserRoleResponseModel, ) -from module_admin.service.login_service import LoginService -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.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 @@ -38,29 +41,30 @@ 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)]) +user_controller = APIRouter(prefix='/system/user', dependencies=[Depends(LoginService.get_current_user)]) -@userController.get('/deptTree', dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]) +@user_controller.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) + request: Request, + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: + 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( +@user_controller.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: Annotated[UserPageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], +) -> Response: # 获取分页数据 user_page_query_result = await UserService.get_user_list_services( query_db, user_page_query, data_scope_sql, is_page=True @@ -70,17 +74,17 @@ async def get_system_user_list( return ResponseUtil.success(model_content=user_page_query_result) -@userController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) +@user_controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))]) @ValidateFields(validate_model='add_user') @Log(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')), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + dept_data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], + role_data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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( @@ -97,18 +101,18 @@ async def add_system_user( return ResponseUtil.success(msg=add_user_result.message) -@userController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) +@user_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @ValidateFields(validate_model='edit_user') @Log(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')), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + user_data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], + dept_data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], + role_data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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) @@ -124,15 +128,15 @@ async def edit_system_user( return ResponseUtil.success(msg=edit_user_result.message) -@userController.delete('/{user_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))]) +@user_controller.delete('/{user_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))]) @Log(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')), -): + user_ids: Annotated[str, Path(description='需要删除的用户ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], +) -> Response: user_id_list = user_ids.split(',') if user_ids else [] if user_id_list: if current_user.user.user_id in list(map(int, user_id_list)): @@ -150,15 +154,15 @@ async def delete_system_user( return ResponseUtil.success(msg=delete_user_result.message) -@userController.put('/resetPwd', dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))]) +@user_controller.put('/resetPwd', dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))]) @Log(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')), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], +) -> Response: 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) @@ -176,15 +180,15 @@ async def reset_system_user_pwd( return ResponseUtil.success(msg=edit_user_result.message) -@userController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) +@user_controller.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))]) @Log(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')), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], +) -> Response: 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) @@ -201,31 +205,31 @@ async def change_system_user_status( return ResponseUtil.success(msg=edit_user_result.message) -@userController.get('/profile', response_model=UserProfileModel) +@user_controller.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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: 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_controller.get( '/{user_id}', response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))] ) -@userController.get( +@user_controller.get( '/', response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))] ) async def query_detail_system_user( request: Request, + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], user_id: Optional[Union[int, Literal['']]] = '', - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), - data_scope_sql: str = Depends(GetDataScope('SysUser')), -): +) -> Response: 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) @@ -234,14 +238,14 @@ async def query_detail_system_user( return ResponseUtil.success(model_content=detail_user_result) -@userController.post('/profile/avatar') +@user_controller.post('/profile/avatar') @Log(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), -): + avatarfile: Annotated[bytes, File()], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: if avatarfile: relative_path = ( f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}' @@ -253,8 +257,8 @@ async def change_system_user_profile_avatar( pass avatar_name = f'avatar_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.png' avatar_path = os.path.join(dir_path, avatar_name) - with open(avatar_path, 'wb') as f: - f.write(avatarfile) + async with aiofiles.open(avatar_path, 'wb') as f: + await f.write(avatarfile) edit_user = EditUserModel( userId=current_user.user.user_id, avatar=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{avatar_name}', @@ -269,14 +273,14 @@ async def change_system_user_profile_avatar( return ResponseUtil.failure(msg='上传图片异常,请联系管理员') -@userController.put('/profile') +@user_controller.put('/profile') @Log(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), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: edit_user = EditUserModel( **user_info.model_dump(exclude_unset=True, by_alias=True, exclude={'role_ids', 'post_ids'}), userId=current_user.user.user_id, @@ -293,14 +297,14 @@ async def change_system_user_profile_info( return ResponseUtil.success(msg=edit_user_result.message) -@userController.put('/profile/updatePwd') +@user_controller.put('/profile/updatePwd') @Log(title='个人信息', business_type=BusinessType.UPDATE) async def reset_system_user_password( request: Request, reset_password: ResetPasswordModel, - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: reset_user = ResetUserModel( userId=current_user.user.user_id, oldPassword=reset_password.old_password, @@ -315,17 +319,17 @@ async def reset_system_user_password( return ResponseUtil.success(msg=reset_user_result.message) -@userController.post('/importData', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) +@user_controller.post('/importData', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) @Log(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')), -): + file: Annotated[UploadFile, File(...)], + update_support: Annotated[bool, Query(alias='updateSupport')], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + user_data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], + dept_data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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 ) @@ -334,22 +338,22 @@ async def batch_import_system_user( 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)): +@user_controller.post('/importTemplate', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))]) +async def export_system_user_template(request: Request, query_db: Annotated[AsyncSession, Depends(get_db)]) -> Response: 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'))]) +@user_controller.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:user:export'))]) @Log(title='用户管理', business_type=BusinessType.EXPORT) async def export_system_user_list( request: Request, - user_page_query: UserPageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), - data_scope_sql: str = Depends(GetDataScope('SysUser')), -): + user_page_query: Annotated[UserPageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], + data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], +) -> Response: # 获取全量数据 user_query_result = await UserService.get_user_list_services( query_db, user_page_query, data_scope_sql, is_page=False @@ -360,12 +364,16 @@ async def export_system_user_list( return ResponseUtil.streaming(data=bytes2file_response(user_export_result)) -@userController.get( +@user_controller.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)): +async def get_system_allocated_role_list( + request: Request, + user_id: Annotated[int, Path(description='用户ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: 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 @@ -375,7 +383,7 @@ async def get_system_allocated_role_list(request: Request, user_id: int, query_d return ResponseUtil.success(model_content=user_role_allocated_query_result) -@userController.put( +@user_controller.put( '/authRole', response_model=UserRoleResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))], @@ -383,13 +391,13 @@ async def get_system_allocated_role_list(request: Request, user_id: int, query_d @Log(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')), -): + user_id: Annotated[int, Query(alias='userId')], + role_ids: Annotated[str, Query(alias='roleIds')], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], + user_data_scope_sql: Annotated[str, Depends(GetDataScope('SysUser'))], + role_data_scope_sql: Annotated[str, Depends(GetDataScope('SysDept'))], +) -> Response: 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) diff --git a/ruoyi-fastapi-backend/module_admin/dao/config_dao.py b/ruoyi-fastapi-backend/module_admin/dao/config_dao.py index 4f34a2f..0e63ed3 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/config_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/config_dao.py @@ -1,9 +1,12 @@ from datetime import datetime, time +from typing import Any, Union + 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 ConfigModel, ConfigPageQueryModel -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil class ConfigDao: @@ -12,7 +15,7 @@ class ConfigDao: """ @classmethod - async def get_config_detail_by_id(cls, db: AsyncSession, config_id: int): + async def get_config_detail_by_id(cls, db: AsyncSession, config_id: int) -> Union[SysConfig, None]: """ 根据参数配置id获取参数配置详细信息 @@ -25,7 +28,7 @@ class ConfigDao: return config_info @classmethod - async def get_config_detail_by_info(cls, db: AsyncSession, config: ConfigModel): + async def get_config_detail_by_info(cls, db: AsyncSession, config: ConfigModel) -> Union[SysConfig, None]: """ 根据参数配置参数获取参数配置信息 @@ -49,7 +52,9 @@ class ConfigDao: return config_info @classmethod - async def get_config_list(cls, db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False): + async def get_config_list( + cls, db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取参数配置列表信息 @@ -74,12 +79,14 @@ class ConfigDao: .order_by(SysConfig.config_id) .distinct() ) - config_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + config_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return config_list @classmethod - async def add_config_dao(cls, db: AsyncSession, config: ConfigModel): + async def add_config_dao(cls, db: AsyncSession, config: ConfigModel) -> SysConfig: """ 新增参数配置数据库操作 @@ -94,7 +101,7 @@ class ConfigDao: return db_config @classmethod - async def edit_config_dao(cls, db: AsyncSession, config: dict): + async def edit_config_dao(cls, db: AsyncSession, config: dict) -> None: """ 编辑参数配置数据库操作 @@ -105,7 +112,7 @@ class ConfigDao: await db.execute(update(SysConfig), [config]) @classmethod - async def delete_config_dao(cls, db: AsyncSession, config: ConfigModel): + async def delete_config_dao(cls, db: AsyncSession, config: ConfigModel) -> None: """ 删除参数配置数据库操作 diff --git a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py index f450210..8fc7581 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dept_dao.py @@ -1,7 +1,10 @@ +from collections.abc import Sequence +from typing import Union + 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 @@ -14,7 +17,7 @@ class DeptDao: """ @classmethod - async def get_dept_by_id(cls, db: AsyncSession, dept_id: int): + async def get_dept_by_id(cls, db: AsyncSession, dept_id: int) -> Union[SysDept, None]: """ 根据部门id获取在用部门信息 @@ -27,7 +30,7 @@ class DeptDao: return dept_info @classmethod - async def get_dept_detail_by_id(cls, db: AsyncSession, dept_id: int): + async def get_dept_detail_by_id(cls, db: AsyncSession, dept_id: int) -> Union[SysDept, None]: """ 根据部门id获取部门详细信息 @@ -44,7 +47,7 @@ class DeptDao: return dept_info @classmethod - async def get_dept_detail_by_info(cls, db: AsyncSession, dept: DeptModel): + async def get_dept_detail_by_info(cls, db: AsyncSession, dept: DeptModel) -> Union[SysDept, None]: """ 根据部门参数获取部门信息 @@ -68,7 +71,9 @@ class DeptDao: return dept_info @classmethod - async def get_dept_info_for_edit_option(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str): + async def get_dept_info_for_edit_option( + cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str + ) -> Sequence[SysDept]: """ 获取部门编辑对应的在用部门列表信息 @@ -101,7 +106,7 @@ class DeptDao: return dept_result @classmethod - async def get_children_dept_dao(cls, db: AsyncSession, dept_id: int): + async def get_children_dept_dao(cls, db: AsyncSession, dept_id: int) -> Sequence[SysDept]: """ 根据部门id查询当前部门的子部门列表信息 @@ -116,7 +121,9 @@ class DeptDao: return dept_result @classmethod - async def get_dept_list_for_tree(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str): + async def get_dept_list_for_tree( + cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str + ) -> Sequence[SysDept]: """ 获取所有在用部门列表信息 @@ -146,7 +153,7 @@ class DeptDao: return dept_result @classmethod - async def get_dept_list(cls, db: AsyncSession, page_object: DeptModel, data_scope_sql: str): + async def get_dept_list(cls, db: AsyncSession, page_object: DeptModel, data_scope_sql: str) -> Sequence[SysDept]: """ 根据查询参数获取部门列表信息 @@ -177,7 +184,7 @@ class DeptDao: return dept_result @classmethod - async def add_dept_dao(cls, db: AsyncSession, dept: DeptModel): + async def add_dept_dao(cls, db: AsyncSession, dept: DeptModel) -> SysDept: """ 新增部门数据库操作 @@ -192,7 +199,7 @@ class DeptDao: return db_dept @classmethod - async def edit_dept_dao(cls, db: AsyncSession, dept: dict): + async def edit_dept_dao(cls, db: AsyncSession, dept: dict) -> None: """ 编辑部门数据库操作 @@ -203,7 +210,7 @@ class DeptDao: await db.execute(update(SysDept), [dept]) @classmethod - async def update_dept_children_dao(cls, db: AsyncSession, update_dept: List): + async def update_dept_children_dao(cls, db: AsyncSession, update_dept: list) -> None: """ 更新子部门信息 @@ -225,7 +232,7 @@ class DeptDao: ) @classmethod - async def update_dept_status_normal_dao(cls, db: AsyncSession, dept_id_list: List): + async def update_dept_status_normal_dao(cls, db: AsyncSession, dept_id_list: list) -> None: """ 批量更新部门状态为正常 @@ -236,7 +243,7 @@ class DeptDao: 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): + async def delete_dept_dao(cls, db: AsyncSession, dept: DeptModel) -> None: """ 删除部门数据库操作 @@ -251,7 +258,7 @@ class DeptDao: ) @classmethod - async def count_normal_children_dept_dao(cls, db: AsyncSession, dept_id: int): + async def count_normal_children_dept_dao(cls, db: AsyncSession, dept_id: int) -> Union[int, None]: """ 根据部门id查询查询所有子部门(正常状态)的数量 @@ -270,7 +277,7 @@ class DeptDao: return normal_children_dept_count @classmethod - async def count_children_dept_dao(cls, db: AsyncSession, dept_id: int): + async def count_children_dept_dao(cls, db: AsyncSession, dept_id: int) -> Union[int, None]: """ 根据部门id查询查询所有子部门(所有状态)的数量 @@ -290,7 +297,7 @@ class DeptDao: return children_dept_count @classmethod - async def count_dept_user_dao(cls, db: AsyncSession, dept_id: int): + async def count_dept_user_dao(cls, db: AsyncSession, dept_id: int) -> Union[int, None]: """ 根据部门id查询查询部门下的用户数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py index c5a8ed5..eee5236 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py @@ -1,9 +1,13 @@ +from collections.abc import Sequence from datetime import datetime, time +from typing import Any, Union + 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.do.dict_do import SysDictData, SysDictType from module_admin.entity.vo.dict_vo import DictDataModel, DictDataPageQueryModel, DictTypeModel, DictTypePageQueryModel -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil from utils.time_format_util import list_format_datetime @@ -13,7 +17,7 @@ class DictTypeDao: """ @classmethod - async def get_dict_type_detail_by_id(cls, db: AsyncSession, dict_id: int): + async def get_dict_type_detail_by_id(cls, db: AsyncSession, dict_id: int) -> Union[SysDictType, None]: """ 根据字典类型id获取字典类型详细信息 @@ -26,7 +30,7 @@ class DictTypeDao: return dict_type_info @classmethod - async def get_dict_type_detail_by_info(cls, db: AsyncSession, dict_type: DictTypeModel): + async def get_dict_type_detail_by_info(cls, db: AsyncSession, dict_type: DictTypeModel) -> Union[SysDictType, None]: """ 根据字典类型参数获取字典类型信息 @@ -50,7 +54,7 @@ class DictTypeDao: return dict_type_info @classmethod - async def get_all_dict_type(cls, db: AsyncSession): + async def get_all_dict_type(cls, db: AsyncSession) -> list[Any]: """ 获取所有的字典类型信息 @@ -62,7 +66,9 @@ class DictTypeDao: return list_format_datetime(dict_type_info) @classmethod - async def get_dict_type_list(cls, db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False): + async def get_dict_type_list( + cls, db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取字典类型列表信息 @@ -87,12 +93,14 @@ class DictTypeDao: .order_by(SysDictType.dict_id) .distinct() ) - dict_type_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + dict_type_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return dict_type_list @classmethod - async def add_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel): + async def add_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel) -> SysDictType: """ 新增字典类型数据库操作 @@ -107,7 +115,7 @@ class DictTypeDao: return db_dict_type @classmethod - async def edit_dict_type_dao(cls, db: AsyncSession, dict_type: dict): + async def edit_dict_type_dao(cls, db: AsyncSession, dict_type: dict) -> None: """ 编辑字典类型数据库操作 @@ -118,7 +126,7 @@ class DictTypeDao: await db.execute(update(SysDictType), [dict_type]) @classmethod - async def delete_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel): + async def delete_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel) -> None: """ 删除字典类型数据库操作 @@ -135,7 +143,7 @@ class DictDataDao: """ @classmethod - async def get_dict_data_detail_by_id(cls, db: AsyncSession, dict_code: int): + async def get_dict_data_detail_by_id(cls, db: AsyncSession, dict_code: int) -> Union[SysDictData, None]: """ 根据字典数据id获取字典数据详细信息 @@ -150,7 +158,7 @@ class DictDataDao: return dict_data_info @classmethod - async def get_dict_data_detail_by_info(cls, db: AsyncSession, dict_data: DictDataModel): + async def get_dict_data_detail_by_info(cls, db: AsyncSession, dict_data: DictDataModel) -> Union[SysDictData, None]: """ 根据字典数据参数获取字典数据信息 @@ -175,7 +183,9 @@ class DictDataDao: return dict_data_info @classmethod - async def get_dict_data_list(cls, db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False): + async def get_dict_data_list( + cls, db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取字典数据列表信息 @@ -194,12 +204,14 @@ class DictDataDao: .order_by(SysDictData.dict_sort) .distinct() ) - dict_data_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + dict_data_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return dict_data_list @classmethod - async def query_dict_data_list(cls, db: AsyncSession, dict_type: str): + async def query_dict_data_list(cls, db: AsyncSession, dict_type: str) -> Sequence[SysDictData]: """ 根据查询参数获取字典数据列表信息 @@ -229,7 +241,7 @@ class DictDataDao: return dict_data_list @classmethod - async def add_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel): + async def add_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel) -> SysDictData: """ 新增字典数据数据库操作 @@ -244,7 +256,7 @@ class DictDataDao: return db_data_type @classmethod - async def edit_dict_data_dao(cls, db: AsyncSession, dict_data: dict): + async def edit_dict_data_dao(cls, db: AsyncSession, dict_data: dict) -> None: """ 编辑字典数据数据库操作 @@ -255,7 +267,7 @@ class DictDataDao: await db.execute(update(SysDictData), [dict_data]) @classmethod - async def delete_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel): + async def delete_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel) -> None: """ 删除字典数据数据库操作 @@ -266,7 +278,7 @@ class DictDataDao: 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): + async def count_dict_data_dao(cls, db: AsyncSession, dict_type: str) -> Union[int, None]: """ 根据字典类型查询字典类型关联的字典数据数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py index fc30048..2b73d74 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py @@ -1,8 +1,12 @@ +from collections.abc import Sequence +from typing import Any, Union + 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 JobModel, JobPageQueryModel -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil class JobDao: @@ -11,7 +15,7 @@ class JobDao: """ @classmethod - async def get_job_detail_by_id(cls, db: AsyncSession, job_id: int): + async def get_job_detail_by_id(cls, db: AsyncSession, job_id: int) -> Union[SysJob, None]: """ 根据定时任务id获取定时任务详细信息 @@ -24,7 +28,7 @@ class JobDao: return job_info @classmethod - async def get_job_detail_by_info(cls, db: AsyncSession, job: JobModel): + async def get_job_detail_by_info(cls, db: AsyncSession, job: JobModel) -> Union[SysJob, None]: """ 根据定时任务参数获取定时任务信息 @@ -53,7 +57,9 @@ class JobDao: return job_info @classmethod - async def get_job_list(cls, db: AsyncSession, query_object: JobPageQueryModel, is_page: bool = False): + async def get_job_list( + cls, db: AsyncSession, query_object: JobPageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取定时任务列表信息 @@ -72,12 +78,14 @@ class JobDao: .order_by(SysJob.job_id) .distinct() ) - job_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + job_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return job_list @classmethod - async def get_job_list_for_scheduler(cls, db: AsyncSession): + async def get_job_list_for_scheduler(cls, db: AsyncSession) -> Sequence[SysJob]: """ 获取定时任务列表信息 @@ -89,7 +97,7 @@ class JobDao: return job_list @classmethod - async def add_job_dao(cls, db: AsyncSession, job: JobModel): + async def add_job_dao(cls, db: AsyncSession, job: JobModel) -> SysJob: """ 新增定时任务数据库操作 @@ -104,7 +112,7 @@ class JobDao: return db_job @classmethod - async def edit_job_dao(cls, db: AsyncSession, job: dict, old_job: JobModel): + async def edit_job_dao(cls, db: AsyncSession, job: dict, old_job: JobModel) -> None: """ 编辑定时任务数据库操作 @@ -124,7 +132,7 @@ class JobDao: ) @classmethod - async def delete_job_dao(cls, db: AsyncSession, job: JobModel): + async def delete_job_dao(cls, db: AsyncSession, job: JobModel) -> None: """ 删除定时任务数据库操作 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 586a3d6..604a7fe 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,13 @@ from datetime import datetime, time +from typing import Any, Union + from sqlalchemy import delete, desc, 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 JobLogModel, JobLogPageQueryModel -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil class JobLogDao: @@ -13,7 +16,9 @@ class JobLogDao: """ @classmethod - async def get_job_log_list(cls, db: AsyncSession, query_object: JobLogPageQueryModel, is_page: bool = False): + async def get_job_log_list( + cls, db: AsyncSession, query_object: JobLogPageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取定时任务日志列表信息 @@ -38,12 +43,14 @@ class JobLogDao: .order_by(desc(SysJobLog.create_time)) .distinct() ) - job_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + job_log_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return job_log_list @classmethod - def add_job_log_dao(cls, db: Session, job_log: JobLogModel): + def add_job_log_dao(cls, db: Session, job_log: JobLogModel) -> SysJobLog: """ 新增定时任务日志数据库操作 @@ -58,7 +65,7 @@ class JobLogDao: return db_job_log @classmethod - async def delete_job_log_dao(cls, db: AsyncSession, job_log: JobLogModel): + async def delete_job_log_dao(cls, db: AsyncSession, job_log: JobLogModel) -> None: """ 删除定时任务日志数据库操作 @@ -69,7 +76,7 @@ class JobLogDao: 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): + async def clear_job_log_dao(cls, db: AsyncSession) -> None: """ 清除定时任务日志数据库操作 diff --git a/ruoyi-fastapi-backend/module_admin/dao/log_dao.py b/ruoyi-fastapi-backend/module_admin/dao/log_dao.py index 684f3d7..385b155 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/log_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/log_dao.py @@ -1,10 +1,13 @@ from datetime import datetime, time +from typing import Any, Union + from sqlalchemy import asc, delete, desc, select from sqlalchemy.ext.asyncio import AsyncSession + 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 utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil from utils.time_format_util import TimeFormatUtil @@ -14,7 +17,9 @@ class OperationLogDao: """ @classmethod - async def get_operation_log_list(cls, db: AsyncSession, query_object: OperLogPageQueryModel, is_page: bool = False): + async def get_operation_log_list( + cls, db: AsyncSession, query_object: OperLogPageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取操作日志列表信息 @@ -48,12 +53,14 @@ class OperationLogDao: .distinct() .order_by(order_by_column) ) - operation_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + operation_log_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return operation_log_list @classmethod - async def add_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel): + async def add_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel) -> SysOperLog: """ 新增操作日志数据库操作 @@ -68,7 +75,7 @@ class OperationLogDao: return db_operation_log @classmethod - async def delete_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel): + async def delete_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel) -> None: """ 删除操作日志数据库操作 @@ -79,7 +86,7 @@ class OperationLogDao: await db.execute(delete(SysOperLog).where(SysOperLog.oper_id.in_([operation_log.oper_id]))) @classmethod - async def clear_operation_log_dao(cls, db: AsyncSession): + async def clear_operation_log_dao(cls, db: AsyncSession) -> None: """ 清除操作日志数据库操作 @@ -95,7 +102,9 @@ class LoginLogDao: """ @classmethod - async def get_login_log_list(cls, db: AsyncSession, query_object: LoginLogPageQueryModel, is_page: bool = False): + async def get_login_log_list( + cls, db: AsyncSession, query_object: LoginLogPageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取登录日志列表信息 @@ -130,12 +139,14 @@ class LoginLogDao: .distinct() .order_by(order_by_column) ) - login_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + login_log_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return login_log_list @classmethod - async def add_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel): + async def add_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel) -> SysLogininfor: """ 新增登录日志数据库操作 @@ -150,7 +161,7 @@ class LoginLogDao: return db_login_log @classmethod - async def delete_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel): + async def delete_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel) -> None: """ 删除登录日志数据库操作 @@ -161,7 +172,7 @@ class LoginLogDao: await db.execute(delete(SysLogininfor).where(SysLogininfor.info_id.in_([login_log.info_id]))) @classmethod - async def clear_login_log_dao(cls, db: AsyncSession): + async def clear_login_log_dao(cls, db: AsyncSession) -> None: """ 清除登录日志数据库操作 diff --git a/ruoyi-fastapi-backend/module_admin/dao/login_dao.py b/ruoyi-fastapi-backend/module_admin/dao/login_dao.py index 9764a4a..322c1c8 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/login_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/login_dao.py @@ -1,10 +1,13 @@ -from sqlalchemy import and_, select +from typing import Union + +from sqlalchemy import Row, and_, select from sqlalchemy.ext.asyncio import AsyncSession + 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): +async def login_by_account(db: AsyncSession, user_name: str) -> Union[Row[tuple[SysUser, SysDept]], None]: """ 根据用户名查询用户信息 diff --git a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py index 19831e0..6343606 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/menu_dao.py @@ -1,5 +1,9 @@ +from collections.abc import Sequence +from typing import Union + 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.role_do import SysRole, SysRoleMenu from module_admin.entity.do.user_do import SysUser, SysUserRole @@ -12,7 +16,7 @@ class MenuDao: """ @classmethod - async def get_menu_detail_by_id(cls, db: AsyncSession, menu_id: int): + async def get_menu_detail_by_id(cls, db: AsyncSession, menu_id: int) -> Union[SysMenu, None]: """ 根据菜单id获取菜单详细信息 @@ -25,7 +29,7 @@ class MenuDao: return menu_info @classmethod - async def get_menu_detail_by_info(cls, db: AsyncSession, menu: MenuModel): + async def get_menu_detail_by_info(cls, db: AsyncSession, menu: MenuModel) -> Union[SysMenu, None]: """ 根据菜单参数获取菜单信息 @@ -50,7 +54,7 @@ class MenuDao: return menu_info @classmethod - async def get_menu_list_for_tree(cls, db: AsyncSession, user_id: int, role: list): + async def get_menu_list_for_tree(cls, db: AsyncSession, user_id: int, role: list) -> Sequence[SysMenu]: """ 根据角色信息获取所有在用菜单列表信息 @@ -94,7 +98,9 @@ class MenuDao: return menu_query_all @classmethod - async def get_menu_list(cls, db: AsyncSession, page_object: MenuQueryModel, user_id: int, role: list): + async def get_menu_list( + cls, db: AsyncSession, page_object: MenuQueryModel, user_id: int, role: list + ) -> Sequence[SysMenu]: """ 根据查询参数获取菜单列表信息 @@ -156,7 +162,7 @@ class MenuDao: return menu_query_all @classmethod - async def add_menu_dao(cls, db: AsyncSession, menu: MenuModel): + async def add_menu_dao(cls, db: AsyncSession, menu: MenuModel) -> SysMenu: """ 新增菜单数据库操作 @@ -171,7 +177,7 @@ class MenuDao: return db_menu @classmethod - async def edit_menu_dao(cls, db: AsyncSession, menu: dict): + async def edit_menu_dao(cls, db: AsyncSession, menu: dict) -> None: """ 编辑菜单数据库操作 @@ -182,7 +188,7 @@ class MenuDao: await db.execute(update(SysMenu), [menu]) @classmethod - async def delete_menu_dao(cls, db: AsyncSession, menu: MenuModel): + async def delete_menu_dao(cls, db: AsyncSession, menu: MenuModel) -> None: """ 删除菜单数据库操作 @@ -193,7 +199,7 @@ class MenuDao: 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): + async def has_child_by_menu_id_dao(cls, db: AsyncSession, menu_id: int) -> Union[int, None]: """ 根据菜单id查询菜单关联子菜单的数量 @@ -208,7 +214,7 @@ class MenuDao: return menu_count @classmethod - async def check_menu_exist_role_dao(cls, db: AsyncSession, menu_id: int): + async def check_menu_exist_role_dao(cls, db: AsyncSession, menu_id: int) -> Union[int, None]: """ 根据菜单id查询菜单关联角色数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py index 9f48a14..b078555 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py @@ -1,9 +1,12 @@ from datetime import datetime, time +from typing import Any, Union + 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 NoticeModel, NoticePageQueryModel -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil class NoticeDao: @@ -12,7 +15,7 @@ class NoticeDao: """ @classmethod - async def get_notice_detail_by_id(cls, db: AsyncSession, notice_id: int): + async def get_notice_detail_by_id(cls, db: AsyncSession, notice_id: int) -> Union[SysNotice, None]: """ 根据通知公告id获取通知公告详细信息 @@ -25,7 +28,7 @@ class NoticeDao: return notice_info @classmethod - async def get_notice_detail_by_info(cls, db: AsyncSession, notice: NoticeModel): + async def get_notice_detail_by_info(cls, db: AsyncSession, notice: NoticeModel) -> Union[SysNotice, None]: """ 根据通知公告参数获取通知公告信息 @@ -50,7 +53,9 @@ class NoticeDao: return notice_info @classmethod - async def get_notice_list(cls, db: AsyncSession, query_object: NoticePageQueryModel, is_page: bool = False): + async def get_notice_list( + cls, db: AsyncSession, query_object: NoticePageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取通知公告列表信息 @@ -75,12 +80,14 @@ class NoticeDao: .order_by(SysNotice.notice_id) .distinct() ) - notice_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + notice_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return notice_list @classmethod - async def add_notice_dao(cls, db: AsyncSession, notice: NoticeModel): + async def add_notice_dao(cls, db: AsyncSession, notice: NoticeModel) -> SysNotice: """ 新增通知公告数据库操作 @@ -95,7 +102,7 @@ class NoticeDao: return db_notice @classmethod - async def edit_notice_dao(cls, db: AsyncSession, notice: dict): + async def edit_notice_dao(cls, db: AsyncSession, notice: dict) -> None: """ 编辑通知公告数据库操作 @@ -106,7 +113,7 @@ class NoticeDao: await db.execute(update(SysNotice), [notice]) @classmethod - async def delete_notice_dao(cls, db: AsyncSession, notice: NoticeModel): + async def delete_notice_dao(cls, db: AsyncSession, notice: NoticeModel) -> None: """ 删除通知公告数据库操作 diff --git a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py index 7d90088..3ea0b22 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py @@ -1,9 +1,12 @@ +from typing import Any, Union + 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 PostModel, PostPageQueryModel -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil class PostDao: @@ -12,7 +15,7 @@ class PostDao: """ @classmethod - async def get_post_by_id(cls, db: AsyncSession, post_id: int): + async def get_post_by_id(cls, db: AsyncSession, post_id: int) -> Union[SysPost, None]: """ 根据岗位id获取在用岗位详细信息 @@ -29,7 +32,7 @@ class PostDao: return post_info @classmethod - async def get_post_detail_by_id(cls, db: AsyncSession, post_id: int): + async def get_post_detail_by_id(cls, db: AsyncSession, post_id: int) -> Union[SysPost, None]: """ 根据岗位id获取岗位详细信息 @@ -42,7 +45,7 @@ class PostDao: return post_info @classmethod - async def get_post_detail_by_info(cls, db: AsyncSession, post: PostModel): + async def get_post_detail_by_info(cls, db: AsyncSession, post: PostModel) -> Union[SysPost, None]: """ 根据岗位参数获取岗位信息 @@ -67,7 +70,9 @@ class PostDao: return post_info @classmethod - async def get_post_list(cls, db: AsyncSession, query_object: PostPageQueryModel, is_page: bool = False): + async def get_post_list( + cls, db: AsyncSession, query_object: PostPageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取岗位列表信息 @@ -86,12 +91,14 @@ class PostDao: .order_by(SysPost.post_sort) .distinct() ) - post_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + post_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return post_list @classmethod - async def add_post_dao(cls, db: AsyncSession, post: PostModel): + async def add_post_dao(cls, db: AsyncSession, post: PostModel) -> SysPost: """ 新增岗位数据库操作 @@ -106,7 +113,7 @@ class PostDao: return db_post @classmethod - async def edit_post_dao(cls, db: AsyncSession, post: dict): + async def edit_post_dao(cls, db: AsyncSession, post: dict) -> None: """ 编辑岗位数据库操作 @@ -117,7 +124,7 @@ class PostDao: await db.execute(update(SysPost), [post]) @classmethod - async def delete_post_dao(cls, db: AsyncSession, post: PostModel): + async def delete_post_dao(cls, db: AsyncSession, post: PostModel) -> None: """ 删除岗位数据库操作 @@ -128,7 +135,7 @@ class PostDao: 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): + async def count_user_post_dao(cls, db: AsyncSession, post_id: int) -> Union[int, None]: """ 根据岗位id查询岗位关联的用户数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py index 534c7f3..cc9366c 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py @@ -1,12 +1,16 @@ +from collections.abc import Sequence from datetime import datetime, time +from typing import Any, Union + from sqlalchemy import and_, delete, desc, func, or_, select, update # noqa: F401 from sqlalchemy.ext.asyncio import AsyncSession + from module_admin.entity.do.dept_do import SysDept from module_admin.entity.do.menu_do import SysMenu -from module_admin.entity.do.role_do import SysRole, SysRoleMenu, SysRoleDept +from module_admin.entity.do.role_do import SysRole, SysRoleDept, SysRoleMenu 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 utils.page_util import PageResponseModel, PageUtil class RoleDao: @@ -15,7 +19,7 @@ class RoleDao: """ @classmethod - async def get_role_by_name(cls, db: AsyncSession, role_name: str): + async def get_role_by_name(cls, db: AsyncSession, role_name: str) -> Union[SysRole, None]: """ 根据角色名获取在用角色信息 @@ -39,7 +43,7 @@ class RoleDao: return query_role_info @classmethod - async def get_role_by_info(cls, db: AsyncSession, role: RoleModel): + async def get_role_by_info(cls, db: AsyncSession, role: RoleModel) -> Union[SysRole, None]: """ 根据角色参数获取角色信息 @@ -67,7 +71,7 @@ class RoleDao: return query_role_info @classmethod - async def get_role_by_id(cls, db: AsyncSession, role_id: int): + async def get_role_by_id(cls, db: AsyncSession, role_id: int) -> Union[SysRole, None]: """ 根据角色id获取在用角色信息 @@ -88,7 +92,7 @@ class RoleDao: return role_info @classmethod - async def get_role_detail_by_id(cls, db: AsyncSession, role_id: int): + async def get_role_detail_by_id(cls, db: AsyncSession, role_id: int) -> Union[SysRole, None]: """ 根据role_id获取角色详细信息 @@ -105,7 +109,7 @@ class RoleDao: return query_role_info @classmethod - async def get_role_select_option_dao(cls, db: AsyncSession): + async def get_role_select_option_dao(cls, db: AsyncSession) -> Sequence[SysRole]: """ 获取编辑页面对应的在用角色列表信息 @@ -127,7 +131,7 @@ class RoleDao: @classmethod async def get_role_list( cls, db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取角色列表信息 @@ -159,12 +163,14 @@ class RoleDao: .order_by(SysRole.role_sort) .distinct() ) - role_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + role_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return role_list @classmethod - async def add_role_dao(cls, db: AsyncSession, role: RoleModel): + async def add_role_dao(cls, db: AsyncSession, role: RoleModel) -> SysRole: """ 新增角色数据库操作 @@ -179,7 +185,7 @@ class RoleDao: return db_role @classmethod - async def edit_role_dao(cls, db: AsyncSession, role: dict): + async def edit_role_dao(cls, db: AsyncSession, role: dict) -> None: """ 编辑角色数据库操作 @@ -190,7 +196,7 @@ class RoleDao: await db.execute(update(SysRole), [role]) @classmethod - async def delete_role_dao(cls, db: AsyncSession, role: RoleModel): + async def delete_role_dao(cls, db: AsyncSession, role: RoleModel) -> None: """ 删除角色数据库操作 @@ -205,7 +211,7 @@ class RoleDao: ) @classmethod - async def get_role_menu_dao(cls, db: AsyncSession, role: RoleModel): + async def get_role_menu_dao(cls, db: AsyncSession, role: RoleModel) -> Sequence[SysMenu]: """ 根据角色id获取角色菜单关联列表信息 @@ -241,7 +247,7 @@ class RoleDao: return role_menu_query_all @classmethod - async def add_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel): + async def add_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel) -> None: """ 新增角色菜单关联信息数据库操作 @@ -253,7 +259,7 @@ class RoleDao: db.add(db_role_menu) @classmethod - async def delete_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel): + async def delete_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel) -> None: """ 删除角色菜单关联信息数据库操作 @@ -264,7 +270,7 @@ class RoleDao: 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): + async def get_role_dept_dao(cls, db: AsyncSession, role: RoleModel) -> Sequence[SysDept]: """ 根据角色id获取角色部门关联列表信息 @@ -300,7 +306,7 @@ class RoleDao: return role_dept_query_all @classmethod - async def add_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel): + async def add_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel) -> None: """ 新增角色部门关联信息数据库操作 @@ -312,7 +318,7 @@ class RoleDao: db.add(db_role_dept) @classmethod - async def delete_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel): + async def delete_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel) -> None: """ 删除角色部门关联信息数据库操作 @@ -323,7 +329,7 @@ class RoleDao: 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): + async def count_user_role_dao(cls, db: AsyncSession, role_id: int) -> Union[int, None]: """ 根据角色id查询角色关联用户数量 diff --git a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py index cc53566..0442426 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py @@ -1,6 +1,10 @@ +from collections.abc import Sequence from datetime import datetime, time +from typing import Any, Union + from sqlalchemy import and_, delete, desc, func, or_, select, update from sqlalchemy.ext.asyncio import AsyncSession + from module_admin.entity.do.dept_do import SysDept from module_admin.entity.do.menu_do import SysMenu from module_admin.entity.do.post_do import SysPost @@ -14,7 +18,7 @@ from module_admin.entity.vo.user_vo import ( UserRolePageQueryModel, UserRoleQueryModel, ) -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil class UserDao: @@ -23,7 +27,7 @@ class UserDao: """ @classmethod - async def get_user_by_name(cls, db: AsyncSession, user_name: str): + async def get_user_by_name(cls, db: AsyncSession, user_name: str) -> Union[SysUser, None]: """ 根据用户名获取用户信息 @@ -47,7 +51,7 @@ class UserDao: return query_user_info @classmethod - async def get_user_by_info(cls, db: AsyncSession, user: UserModel): + async def get_user_by_info(cls, db: AsyncSession, user: UserModel) -> Union[SysUser, None]: """ 根据用户参数获取用户信息 @@ -76,7 +80,7 @@ class UserDao: return query_user_info @classmethod - async def get_user_by_id(cls, db: AsyncSession, user_id: int): + async def get_user_by_id(cls, db: AsyncSession, user_id: int) -> dict[str, Any]: """ 根据user_id获取用户信息 @@ -172,18 +176,18 @@ class UserDao: .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, - ) + results = { + '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, + } return results @classmethod - async def get_user_detail_by_id(cls, db: AsyncSession, user_id: int): + async def get_user_detail_by_id(cls, db: AsyncSession, user_id: int) -> dict[str, Any]: """ 根据user_id获取用户详细信息 @@ -263,20 +267,20 @@ class UserDao: .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, - ) + results = { + '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, + } return results @classmethod async def get_user_list( cls, db: AsyncSession, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[list[dict[str, Any]]]]: """ 根据查询参数获取用户列表信息 @@ -321,12 +325,14 @@ class UserDao: .order_by(SysUser.user_id) .distinct() ) - user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + user_list: Union[PageResponseModel, list[list[dict[str, Any]]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return user_list @classmethod - async def add_user_dao(cls, db: AsyncSession, user: UserModel): + async def add_user_dao(cls, db: AsyncSession, user: UserModel) -> SysUser: """ 新增用户数据库操作 @@ -341,7 +347,7 @@ class UserDao: return db_user @classmethod - async def edit_user_dao(cls, db: AsyncSession, user: dict): + async def edit_user_dao(cls, db: AsyncSession, user: dict) -> None: """ 编辑用户数据库操作 @@ -352,7 +358,7 @@ class UserDao: await db.execute(update(SysUser), [user]) @classmethod - async def delete_user_dao(cls, db: AsyncSession, user: UserModel): + async def delete_user_dao(cls, db: AsyncSession, user: UserModel) -> None: """ 删除用户数据库操作 @@ -367,7 +373,9 @@ class UserDao: ) @classmethod - async def get_user_role_allocated_list_by_user_id(cls, db: AsyncSession, query_object: UserRoleQueryModel): + async def get_user_role_allocated_list_by_user_id( + cls, db: AsyncSession, query_object: UserRoleQueryModel + ) -> Sequence[SysRole]: """ 根据用户id获取用户已分配的角色列表信息数据库操作 @@ -400,7 +408,7 @@ class UserDao: @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 - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据角色id获取已分配的用户列表信息 @@ -424,14 +432,16 @@ class UserDao: ) .distinct() ) - allocated_user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + allocated_user_list: Union[PageResponseModel, list[dict[str, Any]]] = 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 - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据角色id获取未分配的用户列表信息 @@ -463,14 +473,14 @@ class UserDao: ) .distinct() ) - unallocated_user_list = await PageUtil.paginate( + unallocated_user_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( db, query, query_object.page_num, query_object.page_size, is_page ) return unallocated_user_list @classmethod - async def add_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel): + async def add_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel) -> None: """ 新增用户角色关联信息数据库操作 @@ -482,7 +492,7 @@ class UserDao: db.add(db_user_role) @classmethod - async def delete_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel): + async def delete_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel) -> None: """ 删除用户角色关联信息数据库操作 @@ -493,7 +503,7 @@ class UserDao: 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): + async def delete_user_role_by_user_and_role_dao(cls, db: AsyncSession, user_role: UserRoleModel) -> None: """ 根据用户id及角色id删除用户角色关联信息数据库操作 @@ -509,7 +519,7 @@ class UserDao: ) @classmethod - async def get_user_role_detail(cls, db: AsyncSession, user_role: UserRoleModel): + async def get_user_role_detail(cls, db: AsyncSession, user_role: UserRoleModel) -> Union[SysUserRole, None]: """ 根据用户角色关联获取用户角色关联详细信息 @@ -532,7 +542,7 @@ class UserDao: return user_role_info @classmethod - async def add_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel): + async def add_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel) -> None: """ 新增用户岗位关联信息数据库操作 @@ -544,7 +554,7 @@ class UserDao: db.add(db_user_post) @classmethod - async def delete_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel): + async def delete_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel) -> None: """ 删除用户岗位关联信息数据库操作 @@ -555,7 +565,7 @@ class UserDao: 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): + async def get_user_dept_info(cls, db: AsyncSession, dept_id: int) -> Union[SysDept, None]: dept_basic_info = ( ( await db.execute( 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 8a3235d..0c40b8d 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/config_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/config_do.py @@ -1,5 +1,7 @@ from datetime import datetime + from sqlalchemy import CHAR, Column, DateTime, Integer, String + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 48baf8d..c745b56 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/dept_do.py @@ -1,5 +1,7 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, String + +from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, String + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 de6a9c4..37b2b7b 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/dict_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/dict_do.py @@ -1,5 +1,7 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, String + +from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, String + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 b966066..6a19665 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/job_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/job_do.py @@ -1,5 +1,7 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, DOUBLE, Index, LargeBinary, String + +from sqlalchemy import CHAR, DOUBLE, BigInteger, Column, DateTime, Index, LargeBinary, String + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 981b026..298921c 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/log_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/log_do.py @@ -1,5 +1,7 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, Index, Integer, String + +from sqlalchemy import CHAR, BigInteger, Column, DateTime, Index, Integer, String + from config.database import Base @@ -38,7 +40,9 @@ class SysOperLog(Base): business_type = Column(Integer, nullable=True, server_default='0', comment='业务类型(0其它 1新增 2修改 3删除)') method = Column(String(100), nullable=True, server_default="''", comment='方法名称') request_method = Column(String(10), nullable=True, server_default="''", comment='请求方式') - operator_type = Column(Integer, nullable=True, server_default='0', comment='操作类别(0其它 1后台用户 2手机端用户)') + operator_type = Column( + Integer, nullable=True, server_default='0', comment='操作类别(0其它 1后台用户 2手机端用户)' + ) oper_name = Column(String(50), nullable=True, server_default="''", comment='操作人员') dept_name = Column(String(50), nullable=True, server_default="''", comment='部门名称') oper_url = Column(String(255), nullable=True, server_default="''", comment='请求URL') 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 0a8a836..b7aa4c7 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/menu_do.py @@ -1,5 +1,7 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, String + +from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, String + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 0d60854..468f599 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/notice_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/notice_do.py @@ -1,6 +1,8 @@ from datetime import datetime + from sqlalchemy import CHAR, Column, DateTime, Integer, LargeBinary, String from sqlalchemy.dialects import mysql + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 442d0f3..5b18596 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/post_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/post_do.py @@ -1,5 +1,7 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, String + +from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, String + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 fecf9d1..39b0866 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/role_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/role_do.py @@ -1,6 +1,8 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, SmallInteger, String + +from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, SmallInteger, String from sqlalchemy.dialects import mysql + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 c71b5b7..4d1cfe1 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/do/user_do.py +++ b/ruoyi-fastapi-backend/module_admin/entity/do/user_do.py @@ -1,5 +1,7 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, String + +from sqlalchemy import CHAR, BigInteger, Column, DateTime, String + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil 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 79b49fb..dfd4669 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/cache_vo.py @@ -1,6 +1,7 @@ +from typing import Any, Optional + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Any, List, Optional class CacheMonitorModel(BaseModel): @@ -10,7 +11,7 @@ class CacheMonitorModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - command_stats: Optional[List] = Field(default=[], description='命令统计') + command_stats: Optional[list] = Field(default=[], description='命令统计') db_size: Optional[int] = Field(default=None, description='Key数量') info: Optional[dict] = Field(default={}, description='Redis信息') 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 258be5d..f885c31 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/common_vo.py @@ -1,6 +1,7 @@ +from typing import Any, Optional + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Any, Optional class CrudResponseModel(BaseModel): 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 917d7d6..395c608 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 datetime import datetime +from typing import Literal, Optional, Union + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from typing import Literal, Optional -from module_admin.annotation.pydantic_annotation import as_query class ConfigModel(BaseModel): @@ -26,20 +26,20 @@ class ConfigModel(BaseModel): @NotBlank(field_name='config_key', message='参数名称不能为空') @Size(field_name='config_key', min_length=0, max_length=100, message='参数名称长度不能超过100个字符') - def get_config_key(self): + def get_config_key(self) -> Union[str, None]: 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): + def get_config_name(self) -> Union[str, None]: 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): + def get_config_value(self) -> Union[str, None]: return self.config_value - def validate_fields(self): + def validate_fields(self) -> None: self.get_config_key() self.get_config_name() self.get_config_value() @@ -54,7 +54,6 @@ class ConfigQueryModel(ConfigModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class ConfigPageQueryModel(ConfigQueryModel): """ 参数配置管理分页查询模型 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 dcad117..930f820 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 datetime import datetime +from typing import Literal, Optional, Union + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import Network, NotBlank, Size -from typing import Literal, Optional -from module_admin.annotation.pydantic_annotation import as_query class DeptModel(BaseModel): @@ -30,30 +30,29 @@ class DeptModel(BaseModel): @NotBlank(field_name='dept_name', message='部门名称不能为空') @Size(field_name='dept_name', min_length=0, max_length=30, message='部门名称长度不能超过30个字符') - def get_dept_name(self): + def get_dept_name(self) -> Union[str, None]: return self.dept_name @NotBlank(field_name='order_num', message='显示顺序不能为空') - def get_order_num(self): + def get_order_num(self) -> Union[int, None]: return self.order_num @Size(field_name='phone', min_length=0, max_length=11, message='联系电话长度不能超过11个字符') - def get_phone(self): + def get_phone(self) -> Union[str, None]: 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): + def get_email(self) -> Union[str, None]: return self.email - def validate_fields(self): + def validate_fields(self) -> None: self.get_dept_name() self.get_order_num() self.get_phone() self.get_email() -@as_query class DeptQueryModel(DeptModel): """ 部门管理不分页查询模型 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 3251f08..3d9a463 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 datetime import datetime +from typing import Literal, Optional, Union + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Pattern, Size -from typing import Literal, Optional -from module_admin.annotation.pydantic_annotation import as_query class DictTypeModel(BaseModel): @@ -25,7 +25,7 @@ class DictTypeModel(BaseModel): @NotBlank(field_name='dict_name', message='字典名称不能为空') @Size(field_name='dict_name', min_length=0, max_length=100, message='字典类型名称长度不能超过100个字符') - def get_dict_name(self): + def get_dict_name(self) -> Union[str, None]: return self.dict_name @NotBlank(field_name='dict_type', message='字典类型不能为空') @@ -35,10 +35,10 @@ class DictTypeModel(BaseModel): regexp='^[a-z][a-z0-9_]*$', message='字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)', ) - def get_dict_type(self): + def get_dict_type(self) -> Union[str, None]: return self.dict_type - def validate_fields(self): + def validate_fields(self) -> None: self.get_dict_name() self.get_dict_type() @@ -67,24 +67,24 @@ class DictDataModel(BaseModel): @NotBlank(field_name='dict_label', message='字典标签不能为空') @Size(field_name='dict_label', min_length=0, max_length=100, message='字典标签长度不能超过100个字符') - def get_dict_label(self): + def get_dict_label(self) -> Union[str, None]: 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): + def get_dict_value(self) -> Union[str, None]: 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): + def get_dict_type(self) -> Union[str, None]: return self.dict_type @Size(field_name='css_class', min_length=0, max_length=100, message='样式属性长度不能超过100个字符') - def get_css_class(self): + def get_css_class(self) -> Union[str, None]: return self.css_class - def validate_fields(self): + def validate_fields(self) -> None: self.get_dict_label() self.get_dict_value() self.get_dict_type() @@ -100,7 +100,6 @@ class DictTypeQueryModel(DictTypeModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class DictTypePageQueryModel(DictTypeQueryModel): """ 字典类型管理分页查询模型 @@ -129,7 +128,6 @@ class DictDataQueryModel(DictDataModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class DictDataPageQueryModel(DictDataQueryModel): """ 字典数据管理分页查询模型 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 960a837..732ba8e 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 datetime import datetime +from typing import Literal, Optional, Union + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from typing import Literal, Optional -from module_admin.annotation.pydantic_annotation import as_query class JobModel(BaseModel): @@ -34,15 +34,15 @@ class JobModel(BaseModel): @NotBlank(field_name='invoke_target', message='调用目标字符串不能为空') @Size(field_name='invoke_target', min_length=0, max_length=500, message='调用目标字符串长度不能超过500个字符') - def get_invoke_target(self): + def get_invoke_target(self) -> Union[str, None]: 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): + def get_cron_expression(self) -> Union[str, None]: return self.cron_expression - def validate_fields(self): + def validate_fields(self) -> None: self.get_invoke_target() self.get_cron_expression() @@ -77,7 +77,6 @@ class JobQueryModel(JobModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class JobPageQueryModel(JobQueryModel): """ 定时任务管理分页查询模型 @@ -114,7 +113,6 @@ class JobLogQueryModel(JobLogModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class JobLogPageQueryModel(JobLogQueryModel): """ 定时任务日志管理分页查询模型 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 739ad6c..3ad871a 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py @@ -1,8 +1,8 @@ from datetime import datetime +from typing import Literal, Optional + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Literal, Optional -from module_admin.annotation.pydantic_annotation import as_query class OperLogModel(BaseModel): @@ -68,7 +68,6 @@ class OperLogQueryModel(OperLogModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class OperLogPageQueryModel(OperLogQueryModel): """ 操作日志管理分页查询模型 @@ -101,7 +100,6 @@ class LoginLogQueryModel(LogininforModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class LoginLogPageQueryModel(LoginLogQueryModel): """ 登录日志管理分页查询模型 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 fbd6e07..c86758b 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,9 @@ import re +from typing import Optional, Union + from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel -from typing import List, Optional, Union + from exceptions.exception import ModelValidatorException from module_admin.entity.vo.menu_vo import MenuModel @@ -31,8 +33,7 @@ class UserRegister(BaseModel): 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): @@ -57,7 +58,7 @@ class SmsCode(BaseModel): class MenuTreeModel(MenuModel): - children: Optional[Union[List['MenuTreeModel'], None]] = Field(default=None, description='子菜单') + children: Optional[Union[list['MenuTreeModel'], None]] = Field(default=None, description='子菜单') class MetaModel(BaseModel): @@ -84,4 +85,4 @@ class RouterModel(BaseModel): default=None, description='当你一个路由下面的children声明的路由大于1个时,自动会变成嵌套的模式--如组件页面' ) meta: Optional[MetaModel] = Field(default=None, description='其他元素') - children: Optional[Union[List['RouterModel'], None]] = Field(default=None, description='子路由') + children: Optional[Union[list['RouterModel'], None]] = Field(default=None, description='子路由') 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 9dc8d75..b58500c 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 datetime import datetime +from typing import Literal, Optional, Union + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from typing import Literal, Optional -from module_admin.annotation.pydantic_annotation import as_query class MenuModel(BaseModel): @@ -36,30 +36,30 @@ class MenuModel(BaseModel): @NotBlank(field_name='menu_name', message='菜单名称不能为空') @Size(field_name='menu_name', min_length=0, max_length=50, message='菜单名称长度不能超过50个字符') - def get_menu_name(self): + def get_menu_name(self) -> Union[str, None]: return self.menu_name @NotBlank(field_name='order_num', message='显示顺序不能为空') - def get_order_num(self): + def get_order_num(self) -> Union[int, None]: return self.order_num @Size(field_name='path', min_length=0, max_length=200, message='路由地址长度不能超过200个字符') - def get_path(self): + def get_path(self) -> Union[str, None]: return self.path @Size(field_name='component', min_length=0, max_length=255, message='组件路径长度不能超过255个字符') - def get_component(self): + def get_component(self) -> Union[str, None]: return self.component @NotBlank(field_name='menu_type', message='菜单类型不能为空') - def get_menu_type(self): + def get_menu_type(self) -> Union[Literal['M', 'C', 'F'], None]: return self.menu_type @Size(field_name='perms', min_length=0, max_length=100, message='权限标识长度不能超过100个字符') - def get_perms(self): + def get_perms(self) -> Union[str, None]: return self.perms - def validate_fields(self): + def validate_fields(self) -> None: self.get_menu_name() self.get_order_num() self.get_path() @@ -68,7 +68,6 @@ class MenuModel(BaseModel): self.get_perms() -@as_query class MenuQueryModel(MenuModel): """ 菜单管理不分页查询模型 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 0b5d70c..155530a 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 datetime import datetime +from typing import Literal, Optional, Union + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size, Xss -from typing import Literal, Optional -from module_admin.annotation.pydantic_annotation import as_query class NoticeModel(BaseModel): @@ -27,10 +27,10 @@ class NoticeModel(BaseModel): @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): + def get_notice_title(self) -> Union[str, None]: return self.notice_title - def validate_fields(self): + def validate_fields(self) -> None: self.get_notice_title() @@ -43,7 +43,6 @@ class NoticeQueryModel(NoticeModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class NoticePageQueryModel(NoticeQueryModel): """ 通知公告管理分页查询模型 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 11bb475..68eda31 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/online_vo.py @@ -1,8 +1,8 @@ from datetime import datetime +from typing import Optional + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import Optional -from module_admin.annotation.pydantic_annotation import as_query class OnlineModel(BaseModel): @@ -22,7 +22,6 @@ class OnlineModel(BaseModel): login_time: Optional[datetime] = Field(default=None, description='登录时间') -@as_query class OnlineQueryModel(OnlineModel): """ 岗位管理不分页查询模型 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 79390c3..dcb4f3b 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 datetime import datetime +from typing import Literal, Optional, Union + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank, Size -from typing import Literal, Optional -from module_admin.annotation.pydantic_annotation import as_query class PostModel(BaseModel): @@ -26,19 +26,19 @@ class PostModel(BaseModel): @NotBlank(field_name='post_code', message='岗位编码不能为空') @Size(field_name='post_code', min_length=0, max_length=64, message='岗位编码长度不能超过64个字符') - def get_post_code(self): + def get_post_code(self) -> Union[str, None]: 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): + def get_post_name(self) -> Union[str, None]: return self.post_name @NotBlank(field_name='post_sort', message='显示顺序不能为空') - def get_post_sort(self): + def get_post_sort(self) -> Union[int, None]: return self.post_sort - def validate_fields(self): + def validate_fields(self) -> None: self.get_post_code() self.get_post_name() self.get_post_sort() @@ -53,7 +53,6 @@ class PostQueryModel(PostModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class PostPageQueryModel(PostQueryModel): """ 岗位管理分页查询模型 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 a81f8d5..5c80dd0 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 datetime import datetime +from typing import Literal, Optional, Union + 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 List, Literal, Optional, Union -from module_admin.annotation.pydantic_annotation import as_query class RoleModel(BaseModel): @@ -55,19 +55,19 @@ class RoleModel(BaseModel): @NotBlank(field_name='role_name', message='角色名称不能为空') @Size(field_name='role_name', min_length=0, max_length=30, message='角色名称长度不能超过30个字符') - def get_role_name(self): + def get_role_name(self) -> Union[str, None]: 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): + def get_role_key(self) -> Union[str, None]: return self.role_key @NotBlank(field_name='role_sort', message='显示顺序不能为空') - def get_role_sort(self): + def get_role_sort(self) -> Union[int, None]: return self.role_sort - def validate_fields(self): + def validate_fields(self) -> None: self.get_role_name() self.get_role_key() self.get_role_sort() @@ -104,7 +104,6 @@ class RoleQueryModel(RoleModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class RolePageQueryModel(RoleQueryModel): """ 角色管理分页查询模型 @@ -121,8 +120,8 @@ class RoleMenuQueryModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - menus: List = Field(default=[], description='菜单信息') - checked_keys: List[int] = Field(default=[], description='已选择的菜单ID信息') + menus: list = Field(default=[], description='菜单信息') + checked_keys: list[int] = Field(default=[], description='已选择的菜单ID信息') class RoleDeptQueryModel(BaseModel): @@ -132,8 +131,8 @@ class RoleDeptQueryModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - depts: List = Field(default=[], description='部门信息') - checked_keys: List[int] = Field(default=[], description='已选择的部门ID信息') + depts: list = Field(default=[], description='部门信息') + checked_keys: list[int] = Field(default=[], description='已选择的部门ID信息') class AddRoleModel(RoleModel): @@ -141,8 +140,8 @@ class AddRoleModel(RoleModel): 新增角色模型 """ - dept_ids: List = Field(default=[], description='部门ID信息') - menu_ids: List = Field(default=[], description='菜单ID信息') + dept_ids: list = Field(default=[], description='部门ID信息') + menu_ids: list = Field(default=[], description='菜单ID信息') type: Optional[str] = Field(default=None, description='操作类型') @@ -153,6 +152,6 @@ class DeleteRoleModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - role_ids: str = Field(description='需要删除的菜单ID') + role_ids: str = Field(description='需要删除的角色ID') update_by: Optional[str] = Field(default=None, description='更新者') update_time: Optional[datetime] = Field(default=None, description='更新时间') 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 810ecac..52c63bf 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,7 @@ +from typing import Optional + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel -from typing import List, Optional class CpuInfo(BaseModel): @@ -64,4 +65,4 @@ class ServerMonitorModel(BaseModel): py: Optional[PyInfo] = Field(description='Python相关信息') mem: Optional[MemoryInfo] = Field(description='內存相关信息') sys: Optional[SysInfo] = Field(description='服务器相关信息') - sys_files: Optional[List[SysFiles]] = Field(description='磁盘相关信息') + sys_files: Optional[list[SysFiles]] = Field(description='磁盘相关信息') 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 0230882..887b0f9 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py @@ -1,11 +1,12 @@ import re from datetime import datetime +from typing import Literal, Optional, Union + 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 List, Literal, Optional, Union + from exceptions.exception import ModelValidatorException -from module_admin.annotation.pydantic_annotation import as_query from module_admin.entity.vo.dept_vo import DeptModel from module_admin.entity.vo.post_vo import PostModel from module_admin.entity.vo.role_vo import RoleModel @@ -53,8 +54,7 @@ class UserModel(BaseModel): 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': @@ -67,24 +67,24 @@ class UserModel(BaseModel): @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): + def get_user_name(self) -> Union[str, None]: 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): + def get_nick_name(self) -> Union[str, None]: 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): + def get_email(self) -> Union[str, None]: return self.email @Size(field_name='phonenumber', min_length=0, max_length=11, message='手机号码长度不能超过11个字符') - def get_phonenumber(self): + def get_phonenumber(self) -> Union[str, None]: return self.phonenumber - def validate_fields(self): + def validate_fields(self) -> None: self.get_user_name() self.get_nick_name() self.get_email() @@ -117,14 +117,14 @@ class UserInfoModel(UserModel): 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='角色信息') + role: Optional[list[Union[RoleModel, None]]] = Field(default=[], description='角色信息') class CurrentUserModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - permissions: List = Field(description='权限信息') - roles: List = Field(description='角色信息') + permissions: list = Field(description='权限信息') + roles: list = Field(description='角色信息') user: Union[UserInfoModel, None] = Field(description='用户信息') is_default_modify_pwd: bool = Field(default=False, description='是否初始密码修改提醒') is_password_expired: bool = Field(default=False, description='密码是否过期提醒') @@ -138,10 +138,10 @@ class UserDetailModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) 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='角色信息') + 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): @@ -165,7 +165,6 @@ class UserQueryModel(UserModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class UserPageQueryModel(UserQueryModel): """ 用户管理分页查询模型 @@ -180,8 +179,8 @@ class AddUserModel(UserModel): 新增用户模型 """ - role_ids: Optional[List] = Field(default=[], description='角色ID信息') - post_ids: Optional[List] = Field(default=[], description='岗位ID信息') + role_ids: Optional[list] = Field(default=[], description='角色ID信息') + post_ids: Optional[list] = Field(default=[], description='岗位ID信息') type: Optional[str] = Field(default=None, description='操作类型') @@ -190,7 +189,7 @@ class EditUserModel(AddUserModel): 编辑用户模型 """ - role: Optional[List] = Field(default=[], description='角色信息') + role: Optional[list] = Field(default=[], description='角色信息') class ResetPasswordModel(BaseModel): @@ -208,8 +207,7 @@ class ResetPasswordModel(BaseModel): 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): @@ -242,7 +240,6 @@ class UserRoleQueryModel(UserModel): role_id: Optional[int] = Field(default=None, description='角色ID') -@as_query class UserRolePageQueryModel(UserRoleQueryModel): """ 用户角色关联管理分页查询模型 @@ -267,11 +264,10 @@ class UserRoleResponseModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - roles: List[Union[SelectedRoleModel, None]] = Field(default=[], description='角色信息') + roles: list[Union[SelectedRoleModel, None]] = Field(default=[], description='角色信息') user: UserInfoModel = Field(description='用户信息') -@as_query class CrudUserRoleModel(BaseModel): """ 新增、删除用户关联角色及角色关联用户模型 diff --git a/ruoyi-fastapi-backend/module_admin/service/cache_service.py b/ruoyi-fastapi-backend/module_admin/service/cache_service.py index 72212cb..27619a8 100644 --- a/ruoyi-fastapi-backend/module_admin/service/cache_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/cache_service.py @@ -1,4 +1,5 @@ from fastapi import Request + from config.enums import RedisInitKeyConfig from config.get_redis import RedisUtil from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel @@ -11,7 +12,7 @@ class CacheService: """ @classmethod - async def get_cache_monitor_statistical_info_services(cls, request: Request): + async def get_cache_monitor_statistical_info_services(cls, request: Request) -> CacheMonitorModel: """ 获取缓存监控信息service @@ -22,34 +23,33 @@ class CacheService: 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() + {'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 @classmethod - async def get_cache_monitor_cache_name_services(cls): + async def get_cache_monitor_cache_name_services(cls) -> list[CacheInfoModel]: """ 获取缓存名称列表信息service :return: 缓存名称列表信息 """ - name_list = [] - for key_config in RedisInitKeyConfig: - name_list.append( - CacheInfoModel( - cacheKey='', - cacheName=key_config.key, - cacheValue='', - remark=key_config.remark, - ) + name_list = [ + CacheInfoModel( + cacheKey='', + cacheName=key_config.key, + cacheValue='', + remark=key_config.remark, ) + for key_config in RedisInitKeyConfig + ] return name_list @classmethod - async def get_cache_monitor_cache_key_services(cls, request: Request, cache_name: str): + async def get_cache_monitor_cache_key_services(cls, request: Request, cache_name: str) -> list[str]: """ 获取缓存键名列表信息service @@ -57,13 +57,15 @@ class CacheService: :param cache_name: 缓存名称 :return: 缓存键名列表信息 """ - cache_keys = await request.app.state.redis.keys(f'{cache_name}*') + cache_keys: list[str] = 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 @classmethod - async def get_cache_monitor_cache_value_services(cls, request: Request, cache_name: str, cache_key: str): + async def get_cache_monitor_cache_value_services( + cls, request: Request, cache_name: str, cache_key: str + ) -> CacheInfoModel: """ 获取缓存内容信息service @@ -77,7 +79,7 @@ class CacheService: 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): + async def clear_cache_monitor_cache_name_services(cls, request: Request, cache_name: str) -> CrudResponseModel: """ 清除缓存名称对应所有键值service @@ -92,7 +94,7 @@ class CacheService: return CrudResponseModel(is_success=True, message=f'{cache_name}对应键值清除成功') @classmethod - async def clear_cache_monitor_cache_key_services(cls, request: Request, cache_key: str): + async def clear_cache_monitor_cache_key_services(cls, request: Request, cache_key: str) -> CrudResponseModel: """ 清除缓存名称对应所有键值service @@ -107,7 +109,7 @@ class CacheService: return CrudResponseModel(is_success=True, message=f'{cache_key}清除成功') @classmethod - async def clear_cache_monitor_all_services(cls, request: Request): + async def clear_cache_monitor_all_services(cls, request: Request) -> CrudResponseModel: """ 清除所有缓存service diff --git a/ruoyi-fastapi-backend/module_admin/service/captcha_service.py b/ruoyi-fastapi-backend/module_admin/service/captcha_service.py index 1be8ffb..5187d74 100644 --- a/ruoyi-fastapi-backend/module_admin/service/captcha_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/captcha_service.py @@ -2,6 +2,7 @@ import base64 import io import os import random + from PIL import Image, ImageDraw, ImageFont @@ -11,7 +12,7 @@ class CaptchaService: """ @classmethod - async def create_captcha_image_service(cls): + async def create_captcha_image_service(cls) -> list[str, int]: # 创建空白图像 image = Image.new('RGB', (160, 60), color='#EAEAEA') diff --git a/ruoyi-fastapi-backend/module_admin/service/common_service.py b/ruoyi-fastapi-backend/module_admin/service/common_service.py index 20eb868..b5832ad 100644 --- a/ruoyi-fastapi-backend/module_admin/service/common_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/common_service.py @@ -1,6 +1,9 @@ import os from datetime import datetime + +import aiofiles from fastapi import BackgroundTasks, Request, UploadFile + from config.env import UploadConfig from exceptions.exception import ServiceException from module_admin.entity.vo.common_vo import CrudResponseModel, UploadResponseModel @@ -13,7 +16,7 @@ class CommonService: """ @classmethod - async def upload_service(cls, request: Request, file: UploadFile): + async def upload_service(cls, request: Request, file: UploadFile) -> CrudResponseModel: """ 通用上传service @@ -23,33 +26,39 @@ class CommonService: """ if not UploadUtil.check_file_extension(file): 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) - try: - os.makedirs(dir_path) - except FileExistsError: - pass - filename = f'{file.filename.rsplit(".", 1)[0]}_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.{file.filename.rsplit(".")[-1]}' - filepath = os.path.join(dir_path, filename) - with open(filepath, 'wb') as f: - # 流式写出大型文件,这里的10代表10MB - for chunk in iter(lambda: file.file.read(1024 * 1024 * 10), b''): - f.write(chunk) + 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) + try: + os.makedirs(dir_path) + except FileExistsError: + pass + filename = f'{file.filename.rsplit(".", 1)[0]}_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.{file.filename.rsplit(".")[-1]}' + filepath = os.path.join(dir_path, filename) + async with aiofiles.open(filepath, 'wb') as f: + # 流式写出大型文件,这里的10代表10MB + while True: + chunk = await file.read(1024 * 1024 * 10) + if not chunk: + break + await f.write(chunk) - return CrudResponseModel( - is_success=True, - result=UploadResponseModel( - 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}', - ), - message='上传成功', - ) + return CrudResponseModel( + is_success=True, + result=UploadResponseModel( + 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}', + ), + message='上传成功', + ) @classmethod - async def download_services(cls, background_tasks: BackgroundTasks, file_name, delete: bool): + async def download_services( + cls, background_tasks: BackgroundTasks, file_name: str, delete: bool + ) -> CrudResponseModel: """ 下载下载目录文件service @@ -61,15 +70,14 @@ class CommonService: filepath = os.path.join(UploadConfig.DOWNLOAD_PATH, file_name) if '..' in file_name: raise ServiceException(message='文件名称不合法') - elif not UploadUtil.check_file_exists(filepath): + if not UploadUtil.check_file_exists(filepath): raise ServiceException(message='文件不存在') - else: - if delete: - background_tasks.add_task(UploadUtil.delete_file, filepath) - return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功') + if delete: + background_tasks.add_task(UploadUtil.delete_file, filepath) + return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功') @classmethod - async def download_resource_services(cls, resource: str): + async def download_resource_services(cls, resource: str) -> CrudResponseModel: """ 下载上传目录文件service @@ -85,7 +93,6 @@ class CommonService: or not UploadUtil.check_file_random_code(filename) ): raise ServiceException(message='文件名称不合法') - elif not UploadUtil.check_file_exists(filepath): + if not UploadUtil.check_file_exists(filepath): raise ServiceException(message='文件不存在') - else: - return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功') + return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功') diff --git a/ruoyi-fastapi-backend/module_admin/service/config_service.py b/ruoyi-fastapi-backend/module_admin/service/config_service.py index 312006d..20a4968 100644 --- a/ruoyi-fastapi-backend/module_admin/service/config_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/config_service.py @@ -1,6 +1,9 @@ +from typing import Any, Union + from fastapi import Request +from redis import asyncio as aioredis from sqlalchemy.ext.asyncio import AsyncSession -from typing import List + from config.constant import CommonConstant from config.enums import RedisInitKeyConfig from exceptions.exception import ServiceException @@ -9,6 +12,7 @@ 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 from utils.excel_util import ExcelUtil +from utils.page_util import PageResponseModel class ConfigService: @@ -19,7 +23,7 @@ class ConfigService: @classmethod async def get_config_list_services( cls, query_db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取参数配置列表信息service @@ -33,7 +37,7 @@ class ConfigService: return config_list_result @classmethod - async def init_cache_sys_config_services(cls, query_db: AsyncSession, redis): + async def init_cache_sys_config_services(cls, query_db: AsyncSession, redis: aioredis.Redis) -> None: """ 应用初始化:获取所有参数配置对应的键值对信息并缓存service @@ -46,15 +50,15 @@ class ConfigService: # 删除匹配的键 if keys: await redis.delete(*keys) - config_all = await ConfigDao.get_config_list(query_db, ConfigPageQueryModel(**dict()), is_page=False) + config_all = await ConfigDao.get_config_list(query_db, ConfigPageQueryModel(), is_page=False) for config_obj in config_all: await redis.set( - f"{RedisInitKeyConfig.SYS_CONFIG.key}:{config_obj.get('configKey')}", + f'{RedisInitKeyConfig.SYS_CONFIG.key}:{config_obj.get("configKey")}', config_obj.get('configValue'), ) @classmethod - async def query_config_list_from_cache_services(cls, redis, config_key: str): + async def query_config_list_from_cache_services(cls, redis: aioredis.Redis, config_key: str) -> Any: """ 从缓存获取参数键名对应值service @@ -67,7 +71,7 @@ class ConfigService: return result @classmethod - async def check_config_key_unique_services(cls, query_db: AsyncSession, page_object: ConfigModel): + async def check_config_key_unique_services(cls, query_db: AsyncSession, page_object: ConfigModel) -> bool: """ 校验参数键名是否唯一service @@ -82,7 +86,9 @@ class ConfigService: return CommonConstant.UNIQUE @classmethod - async def add_config_services(cls, request: Request, query_db: AsyncSession, page_object: ConfigModel): + async def add_config_services( + cls, request: Request, query_db: AsyncSession, page_object: ConfigModel + ) -> CrudResponseModel: """ 新增参数配置信息service @@ -93,20 +99,21 @@ class ConfigService: """ if not await cls.check_config_key_unique_services(query_db, page_object): 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.key}:{page_object.config_key}', page_object.config_value - ) - return CrudResponseModel(is_success=True, message='新增成功') - except Exception as e: - await query_db.rollback() - raise e + try: + await ConfigDao.add_config_dao(query_db, page_object) + await query_db.commit() + await request.app.state.redis.set( + f'{RedisInitKeyConfig.SYS_CONFIG.key}:{page_object.config_key}', page_object.config_value + ) + return CrudResponseModel(is_success=True, message='新增成功') + except Exception as e: + await query_db.rollback() + raise e @classmethod - async def edit_config_services(cls, request: Request, query_db: AsyncSession, page_object: ConfigModel): + async def edit_config_services( + cls, request: Request, query_db: AsyncSession, page_object: ConfigModel + ) -> CrudResponseModel: """ 编辑参数配置信息service @@ -120,26 +127,27 @@ class ConfigService: if config_info.config_id: if not await cls.check_config_key_unique_services(query_db, page_object): raise ServiceException(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.key}:{config_info.config_key}' - ) - await request.app.state.redis.set( - f'{RedisInitKeyConfig.SYS_CONFIG.key}:{page_object.config_key}', page_object.config_value + 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.key}:{config_info.config_key}' ) - return CrudResponseModel(is_success=True, message='更新成功') - except Exception as e: - await query_db.rollback() - raise e + await request.app.state.redis.set( + f'{RedisInitKeyConfig.SYS_CONFIG.key}:{page_object.config_key}', page_object.config_value + ) + return CrudResponseModel(is_success=True, message='更新成功') + except Exception as e: + await query_db.rollback() + raise e else: raise ServiceException(message='参数配置不存在') @classmethod - async def delete_config_services(cls, request: Request, query_db: AsyncSession, page_object: DeleteConfigModel): + async def delete_config_services( + cls, request: Request, query_db: AsyncSession, page_object: DeleteConfigModel + ) -> CrudResponseModel: """ 删除参数配置信息service @@ -156,9 +164,8 @@ class ConfigService: config_info = await cls.config_detail_services(query_db, int(config_id)) if config_info.config_type == CommonConstant.YES: 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.key}:{config_info.config_key}') + await ConfigDao.delete_config_dao(query_db, ConfigModel(configId=int(config_id))) + delete_config_key_list.append(f'{RedisInitKeyConfig.SYS_CONFIG.key}:{config_info.config_key}') await query_db.commit() if delete_config_key_list: await request.app.state.redis.delete(*delete_config_key_list) @@ -170,7 +177,7 @@ class ConfigService: raise ServiceException(message='传入参数配置id为空') @classmethod - async def config_detail_services(cls, query_db: AsyncSession, config_id: int): + async def config_detail_services(cls, query_db: AsyncSession, config_id: int) -> ConfigModel: """ 获取参数配置详细信息service @@ -179,15 +186,12 @@ class ConfigService: :return: 参数配置id对应的信息 """ config = await ConfigDao.get_config_detail_by_id(query_db, config_id=config_id) - if config: - result = ConfigModel(**CamelCaseUtil.transform_result(config)) - else: - result = ConfigModel(**dict()) + result = ConfigModel(**CamelCaseUtil.transform_result(config)) if config else ConfigModel() return result @staticmethod - async def export_config_list_services(config_list: List): + async def export_config_list_services(config_list: list) -> bytes: """ 导出参数配置信息service @@ -218,7 +222,7 @@ class ConfigService: return binary_data @classmethod - async def refresh_sys_config_services(cls, request: Request, query_db: AsyncSession): + async def refresh_sys_config_services(cls, request: Request, query_db: AsyncSession) -> CrudResponseModel: """ 刷新字典缓存信息service diff --git a/ruoyi-fastapi-backend/module_admin/service/dept_service.py b/ruoyi-fastapi-backend/module_admin/service/dept_service.py index 50594c8..247ee6b 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dept_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dept_service.py @@ -1,7 +1,12 @@ +from collections.abc import Sequence +from typing import Any + 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.do.dept_do import SysDept 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 @@ -13,7 +18,9 @@ class DeptService: """ @classmethod - async def get_dept_tree_services(cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str): + async def get_dept_tree_services( + cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str + ) -> list[dict[str, Any]]: """ 获取部门树信息service @@ -30,7 +37,7 @@ class DeptService: @classmethod async def get_dept_for_edit_option_services( cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str - ): + ) -> list[dict[str, Any]]: """ 获取部门编辑部门树信息service @@ -44,7 +51,9 @@ class DeptService: return CamelCaseUtil.transform_result(dept_list_result) @classmethod - async def get_dept_list_services(cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str): + async def get_dept_list_services( + cls, query_db: AsyncSession, page_object: DeptModel, data_scope_sql: str + ) -> list[dict[str, Any]]: """ 获取部门列表信息service @@ -58,7 +67,9 @@ 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): + async def check_dept_data_scope_services( + cls, query_db: AsyncSession, dept_id: int, data_scope_sql: str + ) -> CrudResponseModel: """ 校验部门是否有数据权限service @@ -70,11 +81,10 @@ class DeptService: 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='没有权限访问部门数据') + raise ServiceException(message='没有权限访问部门数据') @classmethod - async def check_dept_name_unique_services(cls, query_db: AsyncSession, page_object: DeptModel): + async def check_dept_name_unique_services(cls, query_db: AsyncSession, page_object: DeptModel) -> bool: """ 校验部门名称是否唯一service @@ -91,7 +101,7 @@ class DeptService: return CommonConstant.UNIQUE @classmethod - async def add_dept_services(cls, query_db: AsyncSession, page_object: DeptModel): + async def add_dept_services(cls, query_db: AsyncSession, page_object: DeptModel) -> CrudResponseModel: """ 新增部门信息service @@ -114,7 +124,7 @@ class DeptService: raise e @classmethod - async def edit_dept_services(cls, query_db: AsyncSession, page_object: DeptModel): + async def edit_dept_services(cls, query_db: AsyncSession, page_object: DeptModel) -> CrudResponseModel: """ 编辑部门信息service @@ -124,9 +134,9 @@ class DeptService: """ 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: + if page_object.dept_id == page_object.parent_id: raise ServiceException(message=f'修改部门{page_object.dept_name}失败,上级部门不能是自己') - elif ( + if ( page_object.status == CommonConstant.DEPT_DISABLE and (await DeptDao.count_normal_children_dept_dao(query_db, page_object.dept_id)) > 0 ): @@ -154,7 +164,7 @@ class DeptService: raise e @classmethod - async def delete_dept_services(cls, query_db: AsyncSession, page_object: DeleteDeptModel): + async def delete_dept_services(cls, query_db: AsyncSession, page_object: DeleteDeptModel) -> CrudResponseModel: """ 删除部门信息service @@ -168,7 +178,7 @@ class DeptService: for dept_id in dept_id_list: if (await DeptDao.count_children_dept_dao(query_db, int(dept_id))) > 0: raise ServiceWarning(message='存在下级部门,不允许删除') - elif (await DeptDao.count_dept_user_dao(query_db, int(dept_id))) > 0: + if (await DeptDao.count_dept_user_dao(query_db, int(dept_id))) > 0: raise ServiceWarning(message='部门存在用户,不允许删除') await DeptDao.delete_dept_dao(query_db, DeptModel(deptId=dept_id)) @@ -181,7 +191,7 @@ class DeptService: raise ServiceException(message='传入部门id为空') @classmethod - async def dept_detail_services(cls, query_db: AsyncSession, dept_id: int): + async def dept_detail_services(cls, query_db: AsyncSession, dept_id: int) -> DeptModel: """ 获取部门详细信息service @@ -190,37 +200,34 @@ class DeptService: :return: 部门id对应的信息 """ dept = await DeptDao.get_dept_detail_by_id(query_db, dept_id=dept_id) - if dept: - result = DeptModel(**CamelCaseUtil.transform_result(dept)) - else: - result = DeptModel(**dict()) + result = DeptModel(**CamelCaseUtil.transform_result(dept)) if dept else DeptModel() return result @classmethod - def list_to_tree(cls, permission_list: list) -> list: + def list_to_tree(cls, permission_list: Sequence[SysDept]) -> list[dict[str, Any]]: """ 工具方法:根据部门列表信息生成树形嵌套数据 :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 = [ + {'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)) + mapping: dict[int, dict[str, Any]] = dict(zip([i['id'] for i in _permission_list], _permission_list)) # 树容器 - container: list = [] + container: list[dict[str, Any]] = [] - for d in permission_list: + for d in _permission_list: # 如果找不到父级项,则是根节点 - parent: dict = mapping.get(d['parentId']) + parent = mapping.get(d['parentId']) if parent is None: container.append(d) else: - children: list = parent.get('children') + children: list[dict[str, Any]] = parent.get('children') if not children: children = [] children.append(d) @@ -229,7 +236,7 @@ class DeptService: return container @classmethod - async def replace_first(cls, original_str: str, old_str: str, new_str: str): + async def replace_first(cls, original_str: str, old_str: str, new_str: str) -> str: """ 工具方法:替换字符串 @@ -240,11 +247,10 @@ class DeptService: """ if original_str.startswith(old_str): return original_str.replace(old_str, new_str, 1) - else: - return original_str + return original_str @classmethod - async def update_parent_dept_status_normal(cls, query_db: AsyncSession, dept: DeptModel): + async def update_parent_dept_status_normal(cls, query_db: AsyncSession, dept: DeptModel) -> None: """ 更新父部门状态为正常 @@ -256,7 +262,9 @@ class DeptService: await DeptDao.update_dept_status_normal_dao(query_db, list(map(int, dept_id_list))) @classmethod - async def update_dept_children(cls, query_db: AsyncSession, dept_id: int, new_ancestors: str, old_ancestors: str): + async def update_dept_children( + cls, query_db: AsyncSession, dept_id: int, new_ancestors: str, old_ancestors: str + ) -> None: """ 更新子部门信息 diff --git a/ruoyi-fastapi-backend/module_admin/service/dict_service.py b/ruoyi-fastapi-backend/module_admin/service/dict_service.py index 0acfd73..9bd556e 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dict_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dict_service.py @@ -1,11 +1,16 @@ import json +from collections.abc import Sequence +from typing import Any, Union + from fastapi import Request +from redis import asyncio as aioredis from sqlalchemy.ext.asyncio import AsyncSession -from typing import List + from config.constant import CommonConstant from config.enums import RedisInitKeyConfig from exceptions.exception import ServiceException from module_admin.dao.dict_dao import DictDataDao, DictTypeDao +from module_admin.entity.do.dict_do import SysDictData from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.entity.vo.dict_vo import ( DeleteDictDataModel, @@ -17,6 +22,7 @@ from module_admin.entity.vo.dict_vo import ( ) from utils.common_util import CamelCaseUtil from utils.excel_util import ExcelUtil +from utils.page_util import PageResponseModel class DictTypeService: @@ -27,7 +33,7 @@ class DictTypeService: @classmethod async def get_dict_type_list_services( cls, query_db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取字典类型列表信息service @@ -41,7 +47,7 @@ class DictTypeService: return dict_type_list_result @classmethod - async def check_dict_type_unique_services(cls, query_db: AsyncSession, page_object: DictTypeModel): + async def check_dict_type_unique_services(cls, query_db: AsyncSession, page_object: DictTypeModel) -> bool: """ 校验字典类型称是否唯一service @@ -58,7 +64,9 @@ class DictTypeService: return CommonConstant.UNIQUE @classmethod - async def add_dict_type_services(cls, request: Request, query_db: AsyncSession, page_object: DictTypeModel): + async def add_dict_type_services( + cls, request: Request, query_db: AsyncSession, page_object: DictTypeModel + ) -> CrudResponseModel: """ 新增字典类型信息service @@ -69,20 +77,21 @@ class DictTypeService: """ 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 request.app.state.redis.set(f'{RedisInitKeyConfig.SYS_DICT.key}:{page_object.dict_type}', '') - result = dict(is_success=True, message='新增成功') - except Exception as e: - await query_db.rollback() - raise e + 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.key}:{page_object.dict_type}', '') + result = {'is_success': True, 'message': '新增成功'} + except Exception as e: + await query_db.rollback() + raise e return CrudResponseModel(**result) @classmethod - async def edit_dict_type_services(cls, request: Request, query_db: AsyncSession, page_object: DictTypeModel): + async def edit_dict_type_services( + cls, request: Request, query_db: AsyncSession, page_object: DictTypeModel + ) -> CrudResponseModel: """ 编辑字典类型信息service @@ -96,38 +105,37 @@ class DictTypeService: 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) - if dict_type_info.dict_type != page_object.dict_type: - for dict_data in dict_data_list: - edit_dict_data = DictDataModel( - dictCode=dict_data.get('dict_code'), - dictType=page_object.dict_type, - updateBy=page_object.update_by, - updateTime=page_object.update_time, - ).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.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 + 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) + if dict_type_info.dict_type != page_object.dict_type: + for dict_data in dict_data_list: + edit_dict_data = DictDataModel( + dictCode=dict_data.get('dict_code'), + dictType=page_object.dict_type, + updateBy=page_object.update_by, + updateTime=page_object.update_time, + ).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.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: raise ServiceException(message='字典类型不存在') @classmethod async def delete_dict_type_services( cls, request: Request, query_db: AsyncSession, page_object: DeleteDictTypeModel - ): + ) -> CrudResponseModel: """ 删除字典类型信息service @@ -157,7 +165,7 @@ class DictTypeService: raise ServiceException(message='传入字典类型id为空') @classmethod - async def dict_type_detail_services(cls, query_db: AsyncSession, dict_id: int): + async def dict_type_detail_services(cls, query_db: AsyncSession, dict_id: int) -> DictTypeModel: """ 获取字典类型详细信息service @@ -166,15 +174,12 @@ class DictTypeService: :return: 字典类型id对应的信息 """ dict_type = await DictTypeDao.get_dict_type_detail_by_id(query_db, dict_id=dict_id) - if dict_type: - result = DictTypeModel(**CamelCaseUtil.transform_result(dict_type)) - else: - result = DictTypeModel(**dict()) + result = DictTypeModel(**CamelCaseUtil.transform_result(dict_type)) if dict_type else DictTypeModel() return result @staticmethod - async def export_dict_type_list_services(dict_type_list: List): + async def export_dict_type_list_services(dict_type_list: list) -> bytes: """ 导出字典类型信息service @@ -204,7 +209,7 @@ class DictTypeService: return binary_data @classmethod - async def refresh_sys_dict_services(cls, request: Request, query_db: AsyncSession): + async def refresh_sys_dict_services(cls, request: Request, query_db: AsyncSession) -> CrudResponseModel: """ 刷新字典缓存信息service @@ -213,7 +218,7 @@ class DictTypeService: :return: 刷新字典缓存校验结果 """ await DictDataService.init_cache_sys_dict_services(query_db, request.app.state.redis) - result = dict(is_success=True, message='刷新成功') + result = {'is_success': True, 'message': '刷新成功'} return CrudResponseModel(**result) @@ -226,7 +231,7 @@ class DictDataService: @classmethod async def get_dict_data_list_services( cls, query_db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取字典数据列表信息service @@ -240,7 +245,7 @@ class DictDataService: return dict_data_list_result @classmethod - async def query_dict_data_list_services(cls, query_db: AsyncSession, dict_type: str): + async def query_dict_data_list_services(cls, query_db: AsyncSession, dict_type: str) -> Sequence[SysDictData]: """ 获取字典数据列表信息service @@ -253,7 +258,7 @@ class DictDataService: return dict_data_list_result @classmethod - async def init_cache_sys_dict_services(cls, query_db: AsyncSession, redis): + async def init_cache_sys_dict_services(cls, query_db: AsyncSession, redis: aioredis.Redis) -> None: """ 应用初始化:获取所有字典类型对应的字典数据信息并缓存service @@ -277,7 +282,9 @@ class DictDataService: ) @classmethod - async def query_dict_data_list_from_cache_services(cls, redis, dict_type: str): + async def query_dict_data_list_from_cache_services( + cls, redis: aioredis.Redis, dict_type: str + ) -> list[dict[str, Any]]: """ 从缓存获取字典数据列表信息service @@ -293,7 +300,7 @@ class DictDataService: return CamelCaseUtil.transform_result(result) @classmethod - async def check_dict_data_unique_services(cls, query_db: AsyncSession, page_object: DictDataModel): + async def check_dict_data_unique_services(cls, query_db: AsyncSession, page_object: DictDataModel) -> bool: """ 校验字典数据是否唯一service @@ -308,7 +315,9 @@ class DictDataService: return CommonConstant.UNIQUE @classmethod - async def add_dict_data_services(cls, request: Request, query_db: AsyncSession, page_object: DictDataModel): + async def add_dict_data_services( + cls, request: Request, query_db: AsyncSession, page_object: DictDataModel + ) -> CrudResponseModel: """ 新增字典数据信息service @@ -321,22 +330,23 @@ class DictDataService: 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.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 + 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.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 @classmethod - async def edit_dict_data_services(cls, request: Request, query_db: AsyncSession, page_object: DictDataModel): + async def edit_dict_data_services( + cls, request: Request, query_db: AsyncSession, page_object: DictDataModel + ) -> CrudResponseModel: """ 编辑字典数据信息service @@ -352,26 +362,25 @@ class DictDataService: 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.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 + 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.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: raise ServiceException(message='字典数据不存在') @classmethod async def delete_dict_data_services( cls, request: Request, query_db: AsyncSession, page_object: DeleteDictDataModel - ): + ) -> CrudResponseModel: """ 删除字典数据信息service @@ -403,7 +412,7 @@ class DictDataService: raise ServiceException(message='传入字典数据id为空') @classmethod - async def dict_data_detail_services(cls, query_db: AsyncSession, dict_code: int): + async def dict_data_detail_services(cls, query_db: AsyncSession, dict_code: int) -> DictDataModel: """ 获取字典数据详细信息service @@ -412,15 +421,12 @@ class DictDataService: :return: 字典数据id对应的信息 """ dict_data = await DictDataDao.get_dict_data_detail_by_id(query_db, dict_code=dict_code) - if dict_data: - result = DictDataModel(**CamelCaseUtil.transform_result(dict_data)) - else: - result = DictDataModel(**dict()) + result = DictDataModel(**CamelCaseUtil.transform_result(dict_data)) if dict_data else DictDataModel() return result @staticmethod - async def export_dict_data_list_services(dict_data_list: List): + async def export_dict_data_list_services(dict_data_list: list) -> bytes: """ 导出字典数据信息service 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 596abe7..be67b3b 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_log_service.py @@ -1,12 +1,15 @@ +from typing import Any, Union + 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.excel_util import ExcelUtil +from utils.page_util import PageResponseModel class JobLogService: @@ -17,7 +20,7 @@ class JobLogService: @classmethod async def get_job_log_list_services( cls, query_db: AsyncSession, query_object: JobLogPageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取定时任务日志列表信息service @@ -31,7 +34,7 @@ class JobLogService: return job_log_list_result @classmethod - def add_job_log_services(cls, query_db: Session, page_object: JobLogModel): + def add_job_log_services(cls, query_db: Session, page_object: JobLogModel) -> CrudResponseModel: """ 新增定时任务日志信息service @@ -42,15 +45,15 @@ class JobLogService: try: JobLogDao.add_job_log_dao(query_db, page_object) query_db.commit() - result = dict(is_success=True, message='新增成功') + result = {'is_success': True, 'message': '新增成功'} except Exception as e: query_db.rollback() - result = dict(is_success=False, message=str(e)) + result = {'is_success': False, 'message': str(e)} return CrudResponseModel(**result) @classmethod - async def delete_job_log_services(cls, query_db: AsyncSession, page_object: DeleteJobLogModel): + async def delete_job_log_services(cls, query_db: AsyncSession, page_object: DeleteJobLogModel) -> CrudResponseModel: """ 删除定时任务日志信息service @@ -64,16 +67,16 @@ class JobLogService: for job_log_id in job_log_id_list: await JobLogDao.delete_job_log_dao(query_db, JobLogModel(jobLogId=job_log_id)) await query_db.commit() - result = dict(is_success=True, message='删除成功') + result = {'is_success': True, 'message': '删除成功'} except Exception as e: await query_db.rollback() raise e else: - result = dict(is_success=False, message='传入定时任务日志id为空') + result = {'is_success': False, 'message': '传入定时任务日志id为空'} return CrudResponseModel(**result) @classmethod - async def clear_job_log_services(cls, query_db: AsyncSession): + async def clear_job_log_services(cls, query_db: AsyncSession) -> CrudResponseModel: """ 清除定时任务日志信息service @@ -83,7 +86,7 @@ class JobLogService: try: await JobLogDao.clear_job_log_dao(query_db) await query_db.commit() - result = dict(is_success=True, message='清除成功') + result = {'is_success': True, 'message': '清除成功'} except Exception as e: await query_db.rollback() raise e @@ -91,7 +94,7 @@ class JobLogService: return CrudResponseModel(**result) @staticmethod - async def export_job_log_list_services(request: Request, job_log_list: List): + async def export_job_log_list_services(request: Request, job_log_list: list) -> bytes: """ 导出定时任务日志信息service @@ -118,13 +121,13 @@ class JobLogService: 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 = [{'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 + {'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} @@ -133,9 +136,9 @@ class JobLogService: item['status'] = '正常' else: item['status'] = '暂停' - if str(item.get('jobGroup')) in job_group_option_dict.keys(): + if str(item.get('jobGroup')) in job_group_option_dict: item['jobGroup'] = job_group_option_dict.get(str(item.get('jobGroup'))).get('label') - if str(item.get('jobExecutor')) in job_executor_option_dict.keys(): + if str(item.get('jobExecutor')) in job_executor_option_dict: item['jobExecutor'] = job_executor_option_dict.get(str(item.get('jobExecutor'))).get('label') binary_data = ExcelUtil.export_list2excel(job_log_list, mapping_dict) diff --git a/ruoyi-fastapi-backend/module_admin/service/job_service.py b/ruoyi-fastapi-backend/module_admin/service/job_service.py index 2b783f0..7e584ce 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_service.py @@ -1,6 +1,8 @@ +from typing import Any, Union + 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 @@ -11,6 +13,7 @@ from module_admin.service.dict_service import DictDataService from utils.common_util import CamelCaseUtil from utils.cron_util import CronUtil from utils.excel_util import ExcelUtil +from utils.page_util import PageResponseModel from utils.string_util import StringUtil @@ -22,7 +25,7 @@ class JobService: @classmethod async def get_job_list_services( cls, query_db: AsyncSession, query_object: JobPageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取定时任务列表信息service @@ -36,7 +39,7 @@ class JobService: return job_list_result @classmethod - async def check_job_unique_services(cls, query_db: AsyncSession, page_object: JobModel): + async def check_job_unique_services(cls, query_db: AsyncSession, page_object: JobModel) -> bool: """ 校验定时任务是否存在service @@ -51,7 +54,7 @@ class JobService: return CommonConstant.UNIQUE @classmethod - async def add_job_services(cls, query_db: AsyncSession, page_object: JobModel): + async def add_job_services(cls, query_db: AsyncSession, page_object: JobModel) -> CrudResponseModel: """ 新增定时任务信息service @@ -61,38 +64,46 @@ class JobService: """ if not CronUtil.validate_cron_expression(page_object.cron_expression): raise ServiceException(message=f'新增定时任务{page_object.job_name}失败,Cron表达式不正确') - elif StringUtil.contains_ignore_case(page_object.invoke_target, CommonConstant.LOOKUP_RMI): + if 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( + if 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] - ): + if 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): + if 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): + if 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): + if 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) - 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() - result = dict(is_success=True, message='新增成功') - except Exception as e: - await query_db.rollback() - raise e + try: + 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() + result = {'is_success': True, 'message': '新增成功'} + except Exception as e: + await query_db.rollback() + raise e return CrudResponseModel(**result) @classmethod - async def edit_job_services(cls, query_db: AsyncSession, page_object: EditJobModel): + def _deal_edit_job(cls, page_object: EditJobModel, edit_job: dict[str, Any]) -> None: + """ + 处理编辑定时任务字典 + + :param page_object: 编辑定时任务对象 + :param edit_job: 编辑定时任务字典 + """ + if page_object.type == 'status': + del edit_job['type'] + + @classmethod + async def edit_job_services(cls, query_db: AsyncSession, page_object: EditJobModel) -> CrudResponseModel: """ 编辑定时任务信息service @@ -101,32 +112,31 @@ class JobService: :return: 编辑定时任务校验结果 """ edit_job = page_object.model_dump(exclude_unset=True) - if page_object.type == 'status': - del edit_job['type'] + cls._deal_edit_job(page_object, edit_job) job_info = await cls.job_detail_services(query_db, page_object.job_id) if job_info: if page_object.type != 'status': if not CronUtil.validate_cron_expression(page_object.cron_expression): raise ServiceException(message=f'修改定时任务{page_object.job_name}失败,Cron表达式不正确') - elif StringUtil.contains_ignore_case(page_object.invoke_target, CommonConstant.LOOKUP_RMI): + if 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( + if 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( + if 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): + if 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): + if 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): + if 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, job_info) @@ -143,7 +153,7 @@ class JobService: raise ServiceException(message='定时任务不存在') @classmethod - async def execute_job_once_services(cls, query_db: AsyncSession, page_object: JobModel): + async def execute_job_once_services(cls, query_db: AsyncSession, page_object: JobModel) -> CrudResponseModel: """ 执行一次定时任务service @@ -156,11 +166,10 @@ class JobService: if job_info: SchedulerUtil.execute_scheduler_job_once(job_info=job_info) return CrudResponseModel(is_success=True, message='执行成功') - else: - raise ServiceException(message='定时任务不存在') + raise ServiceException(message='定时任务不存在') @classmethod - async def delete_job_services(cls, query_db: AsyncSession, page_object: DeleteJobModel): + async def delete_job_services(cls, query_db: AsyncSession, page_object: DeleteJobModel) -> CrudResponseModel: """ 删除定时任务信息service @@ -183,7 +192,7 @@ class JobService: raise ServiceException(message='传入定时任务id为空') @classmethod - async def job_detail_services(cls, query_db: AsyncSession, job_id: int): + async def job_detail_services(cls, query_db: AsyncSession, job_id: int) -> JobModel: """ 获取定时任务详细信息service @@ -192,15 +201,12 @@ class JobService: :return: 定时任务id对应的信息 """ job = await JobDao.get_job_detail_by_id(query_db, job_id=job_id) - if job: - result = JobModel(**CamelCaseUtil.transform_result(job)) - else: - result = JobModel(**dict()) + result = JobModel(**CamelCaseUtil.transform_result(job)) if job else JobModel() return result @staticmethod - async def export_job_list_services(request: Request, job_list: List): + async def export_job_list_services(request: Request, job_list: list) -> bytes: """ 导出定时任务信息service @@ -231,13 +237,13 @@ class JobService: 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 = [{'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 + {'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} @@ -246,9 +252,9 @@ class JobService: item['status'] = '正常' else: item['status'] = '暂停' - if str(item.get('jobGroup')) in job_group_option_dict.keys(): + if str(item.get('jobGroup')) in job_group_option_dict: item['jobGroup'] = job_group_option_dict.get(str(item.get('jobGroup'))).get('label') - if str(item.get('jobExecutor')) in job_executor_option_dict.keys(): + if str(item.get('jobExecutor')) in job_executor_option_dict: item['jobExecutor'] = job_executor_option_dict.get(str(item.get('jobExecutor'))).get('label') if item.get('misfirePolicy') == '1': item['misfirePolicy'] = '立即执行' diff --git a/ruoyi-fastapi-backend/module_admin/service/log_service.py b/ruoyi-fastapi-backend/module_admin/service/log_service.py index 0983b1a..b577834 100644 --- a/ruoyi-fastapi-backend/module_admin/service/log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/log_service.py @@ -1,6 +1,8 @@ +from typing import Any, Union + from fastapi import Request from sqlalchemy.ext.asyncio import AsyncSession -from typing import List + from exceptions.exception import ServiceException from module_admin.dao.log_dao import LoginLogDao, OperationLogDao from module_admin.entity.vo.common_vo import CrudResponseModel @@ -15,6 +17,7 @@ from module_admin.entity.vo.log_vo import ( ) from module_admin.service.dict_service import DictDataService from utils.excel_util import ExcelUtil +from utils.page_util import PageResponseModel class OperationLogService: @@ -25,7 +28,7 @@ class OperationLogService: @classmethod async def get_operation_log_list_services( cls, query_db: AsyncSession, query_object: OperLogPageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取操作日志列表信息service @@ -39,7 +42,7 @@ class OperationLogService: return operation_log_list_result @classmethod - async def add_operation_log_services(cls, query_db: AsyncSession, page_object: OperLogModel): + async def add_operation_log_services(cls, query_db: AsyncSession, page_object: OperLogModel) -> CrudResponseModel: """ 新增操作日志service @@ -56,7 +59,9 @@ class OperationLogService: raise e @classmethod - async def delete_operation_log_services(cls, query_db: AsyncSession, page_object: DeleteOperLogModel): + async def delete_operation_log_services( + cls, query_db: AsyncSession, page_object: DeleteOperLogModel + ) -> CrudResponseModel: """ 删除操作日志信息service @@ -78,7 +83,7 @@ class OperationLogService: raise ServiceException(message='传入操作日志id为空') @classmethod - async def clear_operation_log_services(cls, query_db: AsyncSession): + async def clear_operation_log_services(cls, query_db: AsyncSession) -> CrudResponseModel: """ 清除操作日志信息service @@ -94,7 +99,7 @@ class OperationLogService: raise e @classmethod - async def export_operation_log_list_services(cls, request: Request, operation_log_list: List): + async def export_operation_log_list_services(cls, request: Request, operation_log_list: list) -> bytes: """ 导出操作日志信息service @@ -126,7 +131,7 @@ class OperationLogService: 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 + {'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} @@ -135,7 +140,7 @@ class OperationLogService: item['status'] = '成功' else: item['status'] = '失败' - if str(item.get('businessType')) in operation_type_option_dict.keys(): + if str(item.get('businessType')) in operation_type_option_dict: item['businessType'] = operation_type_option_dict.get(str(item.get('businessType'))).get('label') binary_data = ExcelUtil.export_list2excel(operation_log_list, mapping_dict) @@ -150,7 +155,7 @@ class LoginLogService: @classmethod async def get_login_log_list_services( cls, query_db: AsyncSession, query_object: LoginLogPageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取登录日志列表信息service @@ -164,7 +169,7 @@ class LoginLogService: return operation_log_list_result @classmethod - async def add_login_log_services(cls, query_db: AsyncSession, page_object: LogininforModel): + async def add_login_log_services(cls, query_db: AsyncSession, page_object: LogininforModel) -> CrudResponseModel: """ 新增登录日志service @@ -181,7 +186,9 @@ class LoginLogService: raise e @classmethod - async def delete_login_log_services(cls, query_db: AsyncSession, page_object: DeleteLoginLogModel): + async def delete_login_log_services( + cls, query_db: AsyncSession, page_object: DeleteLoginLogModel + ) -> CrudResponseModel: """ 删除操作日志信息service @@ -203,7 +210,7 @@ class LoginLogService: raise ServiceException(message='传入登录日志id为空') @classmethod - async def clear_login_log_services(cls, query_db: AsyncSession): + async def clear_login_log_services(cls, query_db: AsyncSession) -> CrudResponseModel: """ 清除操作日志信息service @@ -219,16 +226,15 @@ class LoginLogService: raise e @classmethod - async def unlock_user_services(cls, request: Request, unlock_user: UnlockUser): + async def unlock_user_services(cls, request: Request, unlock_user: UnlockUser) -> CrudResponseModel: 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}') return CrudResponseModel(is_success=True, message='解锁成功') - else: - raise ServiceException(message='该用户未锁定') + raise ServiceException(message='该用户未锁定') @staticmethod - async def export_login_log_list_services(login_log_list: List): + async def export_login_log_list_services(login_log_list: list) -> bytes: """ 导出登录日志信息service diff --git a/ruoyi-fastapi-backend/module_admin/service/login_service.py b/ruoyi-fastapi-backend/module_admin/service/login_service.py index 81c894a..f55eaa8 100644 --- a/ruoyi-fastapi-backend/module_admin/service/login_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/login_service.py @@ -1,20 +1,25 @@ -import jwt import random import uuid from datetime import datetime, timedelta, timezone +from typing import Any, Optional, Union + +import jwt from fastapi import Depends, Form, Request from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError +from sqlalchemy import Row from sqlalchemy.ext.asyncio import AsyncSession -from typing import Dict, List, Optional, Union + from config.constant import CommonConstant, MenuConstant from config.enums import RedisInitKeyConfig from config.env import AppConfig, JwtConfig from config.get_db import get_db -from exceptions.exception import LoginException, AuthException, ServiceException +from exceptions.exception import AuthException, LoginException, ServiceException from module_admin.dao.login_dao import login_by_account from module_admin.dao.user_dao import UserDao +from module_admin.entity.do.dept_do import SysDept from module_admin.entity.do.menu_do import SysMenu +from module_admin.entity.do.user_do import SysUser 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 @@ -42,8 +47,8 @@ class CustomOAuth2PasswordRequestForm(OAuth2PasswordRequestForm): 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), - ): + login_info: Optional[dict[str, str]] = Form(default=None), + ) -> None: super().__init__( grant_type=grant_type, username=username, @@ -63,7 +68,9 @@ class LoginService: """ @classmethod - async def authenticate_user(cls, request: Request, query_db: AsyncSession, login_user: UserLogin): + async def authenticate_user( + cls, request: Request, query_db: AsyncSession, login_user: UserLogin + ) -> Row[tuple[SysUser, SysDept]]: """ 根据用户名密码校验用户登录 @@ -110,7 +117,7 @@ class LoginService: password_error_count, ex=timedelta(minutes=10), ) - if password_error_count > 5: + if password_error_count > CommonConstant.PASSWORD_ERROR_COUNT: await request.app.state.redis.delete( f'{RedisInitKeyConfig.PASSWORD_ERROR_COUNT.key}:{login_user.user_name}' ) @@ -130,7 +137,7 @@ class LoginService: return user @classmethod - async def __check_login_ip(cls, request: Request): + async def __check_login_ip(cls, request: Request) -> bool: """ 校验用户登录ip是否在黑名单内 @@ -145,7 +152,7 @@ class LoginService: return True @classmethod - async def __check_login_captcha(cls, request: Request, login_user: UserLogin): + async def __check_login_captcha(cls, request: Request, login_user: UserLogin) -> bool: """ 校验用户登录验证码 @@ -163,7 +170,7 @@ class LoginService: return True @classmethod - async def create_access_token(cls, data: dict, expires_delta: Union[timedelta, None] = None): + async def create_access_token(cls, data: dict, expires_delta: Union[timedelta, None] = None) -> str: """ 根据登录信息创建当前用户token @@ -183,7 +190,7 @@ class LoginService: @classmethod async def get_current_user( cls, request: Request = Request, token: str = Depends(oauth2_scheme), query_db: AsyncSession = Depends(get_db) - ): + ) -> CurrentUserModel: """ 根据token获取当前用户信息 @@ -206,9 +213,9 @@ class LoginService: logger.warning('用户token不合法') raise AuthException(data='', message='用户token不合法') token_data = TokenData(user_id=int(user_id)) - except InvalidTokenError: + except InvalidTokenError as e: logger.warning('用户token已失效,请重新登录') - raise AuthException(data='', message='用户token已失效,请重新登录') + raise AuthException(data='', message='用户token已失效,请重新登录') from e 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不合法') @@ -235,7 +242,7 @@ class LoginService: ) role_id_list = [item.role_id for item in query_user.get('user_role_info')] - if 1 in role_id_list: + if 1 in role_id_list: # noqa: SIM108 permissions = ['*:*:*'] else: permissions = [row.perms for row in query_user.get('user_menu_info')] @@ -263,12 +270,11 @@ class LoginService: isPasswordExpired=is_password_expired, ) return current_user - else: - logger.warning('用户token已失效,请重新登录') - raise AuthException(data='', message='用户token已失效,请重新登录') + logger.warning('用户token已失效,请重新登录') + raise AuthException(data='', message='用户token已失效,请重新登录') @classmethod - async def __init_password_is_modify(cls, request: Request, pwd_update_date: datetime): + async def __init_password_is_modify(cls, request: Request, pwd_update_date: datetime) -> bool: """ 判断当前用户是否初始密码登录 @@ -282,7 +288,7 @@ class LoginService: return init_password_is_modify == '1' and pwd_update_date is None @classmethod - async def __password_is_expired(cls, request: Request, pwd_update_date: datetime): + async def __password_is_expired(cls, request: Request, pwd_update_date: datetime) -> bool: """ 判断当前用户密码是否过期 @@ -302,7 +308,7 @@ class LoginService: return False @classmethod - async def get_current_user_routers(cls, user_id: int, query_db: AsyncSession): + async def get_current_user_routers(cls, user_id: int, query_db: AsyncSession) -> list[dict[str, Any]]: """ 根据用户id获取当前用户路由信息 @@ -324,7 +330,7 @@ class LoginService: return [router.model_dump(exclude_unset=True, by_alias=True) for router in user_router] @classmethod - def __generate_menus(cls, pid: int, permission_list: List[SysMenu]): + def __generate_menus(cls, pid: int, permission_list: list[SysMenu]) -> list[MenuTreeModel]: """ 工具方法:根据菜单信息生成菜单信息树形嵌套数据 @@ -332,7 +338,7 @@ class LoginService: :param permission_list: 菜单列表信息 :return: 菜单信息树形嵌套数据 """ - menu_list: List[MenuTreeModel] = [] + menu_list: list[MenuTreeModel] = [] for permission in permission_list: if permission.parent_id == pid: children = cls.__generate_menus(permission.menu_id, permission_list) @@ -344,17 +350,17 @@ class LoginService: return menu_list @classmethod - def __generate_user_router_menu(cls, permission_list: List[MenuTreeModel]): + def __generate_user_router_menu(cls, permission_list: list[MenuTreeModel]) -> list[RouterModel]: """ 工具方法:根据菜单树信息生成路由信息树形嵌套数据 :param permission_list: 菜单树列表信息 :return: 路由信息树形嵌套数据 """ - router_list: List[RouterModel] = [] + router_list: list[RouterModel] = [] for permission in permission_list: router = RouterModel( - hidden=True if permission.visible == '1' else False, + hidden=permission.visible == '1', name=RouterUtil.get_router_name(permission), path=RouterUtil.get_router_path(permission), component=RouterUtil.get_component(permission), @@ -362,7 +368,7 @@ class LoginService: meta=MetaModel( title=permission.menu_name, icon=permission.icon, - noCache=True if permission.is_cache == 1 else False, + noCache=permission.is_cache == 1, link=permission.path if RouterUtil.is_http(permission.path) else None, ), ) @@ -373,7 +379,7 @@ class LoginService: router.children = cls.__generate_user_router_menu(c_menus) elif RouterUtil.is_menu_frame(permission): router.meta = None - children_list: List[RouterModel] = [] + children_list: list[RouterModel] = [] children = RouterModel( path=permission.path, component=permission.component, @@ -381,7 +387,7 @@ class LoginService: meta=MetaModel( title=permission.menu_name, icon=permission.icon, - noCache=True if permission.is_cache == 1 else False, + noCache=permission.is_cache == 1, link=permission.path if RouterUtil.is_http(permission.path) else None, ), query=permission.query, @@ -391,7 +397,7 @@ class LoginService: elif permission.parent_id == 0 and RouterUtil.is_inner_link(permission): router.meta = MetaModel(title=permission.menu_name, icon=permission.icon) router.path = '/' - children_list: List[RouterModel] = [] + children_list: list[RouterModel] = [] router_path = RouterUtil.inner_link_replace_each(permission.path) children = RouterModel( path=router_path, @@ -411,7 +417,9 @@ class LoginService: return router_list @classmethod - async def register_user_services(cls, request: Request, query_db: AsyncSession, user_register: UserRegister): + async def register_user_services( + cls, request: Request, query_db: AsyncSession, user_register: UserRegister + ) -> CrudResponseModel: """ 用户注册services @@ -421,16 +429,11 @@ class LoginService: :return: 注册结果 """ register_enabled = ( - True - if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.registerUser') - == 'true' - else False + await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.registerUser') == 'true' ) captcha_enabled = ( - True - if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') + await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') == 'true' - else False ) if user_register.password == user_register.confirm_password: if register_enabled: @@ -440,7 +443,7 @@ class LoginService: ) if not captcha_value: raise ServiceException(message='验证码已失效') - elif user_register.code != str(captcha_value): + if user_register.code != str(captcha_value): raise ServiceException(message='验证码错误') add_user = AddUserModel( userName=user_register.username, @@ -450,13 +453,11 @@ class LoginService: ) result = await UserService.add_user_services(query_db, add_user) return result - else: - raise ServiceException(message='注册程序已关闭,禁止注册') - else: - raise ServiceException(message='两次输入的密码不一致') + raise ServiceException(message='注册程序已关闭,禁止注册') + raise ServiceException(message='两次输入的密码不一致') @classmethod - async def get_sms_code_services(cls, request: Request, query_db: AsyncSession, user: ResetUserModel): + async def get_sms_code_services(cls, request: Request, query_db: AsyncSession, user: ResetUserModel) -> SmsCode: """ 获取短信验证码service @@ -467,7 +468,7 @@ class LoginService: """ redis_sms_result = await request.app.state.redis.get(f'{RedisInitKeyConfig.SMS_CODE.key}:{user.session_id}') if redis_sms_result: - return SmsCode(**dict(is_success=False, sms_code='', session_id='', message='短信验证码仍在有效期内')) + return SmsCode(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)) @@ -478,12 +479,14 @@ class LoginService: # 此处模拟调用短信服务 message_service(sms_code) - return SmsCode(**dict(is_success=True, sms_code=sms_code, session_id=session_id, message='获取成功')) + return SmsCode(is_success=True, sms_code=sms_code, session_id=session_id, message='获取成功') - return SmsCode(**dict(is_success=False, sms_code='', session_id='', message='用户不存在')) + return SmsCode(is_success=False, sms_code='', session_id='', message='用户不存在') @classmethod - async def forget_user_services(cls, request: Request, query_db: AsyncSession, forget_user: ResetUserModel): + async def forget_user_services( + cls, request: Request, query_db: AsyncSession, forget_user: ResetUserModel + ) -> CrudResponseModel: """ 用户忘记密码services @@ -501,15 +504,15 @@ class LoginService: edit_result = await UserService.reset_user_services(query_db, forget_user) result = edit_result.dict() elif not redis_sms_result: - result = dict(is_success=False, message='短信验证码已过期') + result = {'is_success': False, 'message': '短信验证码已过期'} else: await request.app.state.redis.delete(f'{RedisInitKeyConfig.SMS_CODE.key}:{forget_user.session_id}') - result = dict(is_success=False, message='短信验证码不正确') + result = {'is_success': False, 'message': '短信验证码不正确'} return CrudResponseModel(**result) @classmethod - async def logout_services(cls, request: Request, token_id: str): + async def logout_services(cls, request: Request, token_id: str) -> bool: """ 退出登录services @@ -530,7 +533,7 @@ class RouterUtil: """ @classmethod - def get_router_name(cls, menu: MenuTreeModel): + def get_router_name(cls, menu: MenuTreeModel) -> str: """ 获取路由名称 @@ -544,7 +547,7 @@ class RouterUtil: return cls.get_route_name(menu.route_name, menu.path) @classmethod - def get_route_name(cls, name: str, path: str): + def get_route_name(cls, name: str, path: str) -> str: """ 获取路由名称,如没有配置路由名称则取路由地址 @@ -556,7 +559,7 @@ class RouterUtil: return router_name.capitalize() @classmethod - def get_router_path(cls, menu: MenuTreeModel): + def get_router_path(cls, menu: MenuTreeModel) -> Union[str, None]: """ 获取路由地址 @@ -576,7 +579,7 @@ class RouterUtil: return router_path @classmethod - def get_component(cls, menu: MenuTreeModel): + def get_component(cls, menu: MenuTreeModel) -> str: """ 获取组件信息 @@ -593,7 +596,7 @@ class RouterUtil: return component @classmethod - def is_menu_frame(cls, menu: MenuTreeModel): + def is_menu_frame(cls, menu: MenuTreeModel) -> bool: """ 判断是否为菜单内部跳转 @@ -605,7 +608,7 @@ class RouterUtil: ) @classmethod - def is_inner_link(cls, menu: MenuTreeModel): + def is_inner_link(cls, menu: MenuTreeModel) -> bool: """ 判断是否为内链组件 @@ -615,7 +618,7 @@ class RouterUtil: return menu.is_frame == MenuConstant.NO_FRAME and cls.is_http(menu.path) @classmethod - def is_parent_view(cls, menu: MenuTreeModel): + def is_parent_view(cls, menu: MenuTreeModel) -> bool: """ 判断是否为parent_view组件 @@ -625,17 +628,17 @@ class RouterUtil: return menu.parent_id != 0 and menu.menu_type == MenuConstant.TYPE_DIR @classmethod - def is_http(cls, link: str): + def is_http(cls, link: str) -> bool: """ 判断是否为http(s)://开头 :param link: 链接 :return: 是否为http(s)://开头 """ - return link.startswith(CommonConstant.HTTP) or link.startswith(CommonConstant.HTTPS) + return link.startswith((CommonConstant.HTTP, CommonConstant.HTTPS)) @classmethod - def inner_link_replace_each(cls, path: str): + def inner_link_replace_each(cls, path: str) -> str: """ 内链域名特殊字符替换 diff --git a/ruoyi-fastapi-backend/module_admin/service/menu_service.py b/ruoyi-fastapi-backend/module_admin/service/menu_service.py index cb6368a..6c403d5 100644 --- a/ruoyi-fastapi-backend/module_admin/service/menu_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/menu_service.py @@ -1,11 +1,15 @@ +from collections.abc import Sequence +from typing import Any, Optional + 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.do.menu_do import SysMenu 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.menu_vo import DeleteMenuModel, MenuModel, MenuQueryModel from module_admin.entity.vo.role_vo import RoleMenuQueryModel from module_admin.entity.vo.user_vo import CurrentUserModel from utils.common_util import CamelCaseUtil @@ -18,7 +22,9 @@ class MenuService: """ @classmethod - async def get_menu_tree_services(cls, query_db: AsyncSession, current_user: Optional[CurrentUserModel] = None): + async def get_menu_tree_services( + cls, query_db: AsyncSession, current_user: Optional[CurrentUserModel] = None + ) -> list[dict[str, Any]]: """ 获取菜单树信息service @@ -36,7 +42,7 @@ class MenuService: @classmethod async def get_role_menu_tree_services( cls, query_db: AsyncSession, role_id: int, current_user: Optional[CurrentUserModel] = None - ): + ) -> RoleMenuQueryModel: """ 根据角色id获取菜单树信息service @@ -59,7 +65,7 @@ class MenuService: @classmethod async def get_menu_list_services( cls, query_db: AsyncSession, page_object: MenuQueryModel, current_user: Optional[CurrentUserModel] = None - ): + ) -> list[dict[str, Any]]: """ 获取菜单列表信息service @@ -75,7 +81,7 @@ class MenuService: return CamelCaseUtil.transform_result(menu_list_result) @classmethod - async def check_menu_name_unique_services(cls, query_db: AsyncSession, page_object: MenuModel): + async def check_menu_name_unique_services(cls, query_db: AsyncSession, page_object: MenuModel) -> bool: """ 校验菜单名称是否唯一service @@ -90,7 +96,7 @@ class MenuService: return CommonConstant.UNIQUE @classmethod - async def add_menu_services(cls, query_db: AsyncSession, page_object: MenuModel): + async def add_menu_services(cls, query_db: AsyncSession, page_object: MenuModel) -> CrudResponseModel: """ 新增菜单信息service @@ -100,19 +106,18 @@ class MenuService: """ if not await cls.check_menu_name_unique_services(query_db, page_object): raise ServiceException(message=f'新增菜单{page_object.menu_name}失败,菜单名称已存在') - elif page_object.is_frame == MenuConstant.YES_FRAME and not StringUtil.is_http(page_object.path): + if page_object.is_frame == MenuConstant.YES_FRAME and not StringUtil.is_http(page_object.path): raise ServiceException(message=f'新增菜单{page_object.menu_name}失败,地址必须以http(s)://开头') - else: - try: - await MenuDao.add_menu_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 + try: + await MenuDao.add_menu_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_menu_services(cls, query_db: AsyncSession, page_object: MenuModel): + async def edit_menu_services(cls, query_db: AsyncSession, page_object: MenuModel) -> CrudResponseModel: """ 编辑菜单信息service @@ -125,23 +130,22 @@ class MenuService: if menu_info.menu_id: if not await cls.check_menu_name_unique_services(query_db, page_object): raise ServiceException(message=f'修改菜单{page_object.menu_name}失败,菜单名称已存在') - elif page_object.is_frame == MenuConstant.YES_FRAME and not StringUtil.is_http(page_object.path): + if page_object.is_frame == MenuConstant.YES_FRAME and not StringUtil.is_http(page_object.path): raise ServiceException(message=f'修改菜单{page_object.menu_name}失败,地址必须以http(s)://开头') - elif page_object.menu_id == page_object.parent_id: + if page_object.menu_id == page_object.parent_id: raise ServiceException(message=f'修改菜单{page_object.menu_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 + 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: raise ServiceException(message='菜单不存在') @classmethod - async def delete_menu_services(cls, query_db: AsyncSession, page_object: DeleteMenuModel): + async def delete_menu_services(cls, query_db: AsyncSession, page_object: DeleteMenuModel) -> CrudResponseModel: """ 删除菜单信息service @@ -155,7 +159,7 @@ class MenuService: for menu_id in menu_id_list: if (await MenuDao.has_child_by_menu_id_dao(query_db, int(menu_id))) > 0: raise ServiceWarning(message='存在子菜单,不允许删除') - elif (await MenuDao.check_menu_exist_role_dao(query_db, int(menu_id))) > 0: + if (await MenuDao.check_menu_exist_role_dao(query_db, int(menu_id))) > 0: raise ServiceWarning(message='菜单已分配,不允许删除') await MenuDao.delete_menu_dao(query_db, MenuModel(menuId=menu_id)) await query_db.commit() @@ -167,7 +171,7 @@ class MenuService: raise ServiceException(message='传入菜单id为空') @classmethod - async def menu_detail_services(cls, query_db: AsyncSession, menu_id: int): + async def menu_detail_services(cls, query_db: AsyncSession, menu_id: int) -> MenuModel: """ 获取菜单详细信息service @@ -176,37 +180,34 @@ class MenuService: :return: 菜单id对应的信息 """ menu = await MenuDao.get_menu_detail_by_id(query_db, menu_id=menu_id) - if menu: - result = MenuModel(**CamelCaseUtil.transform_result(menu)) - else: - result = MenuModel(**dict()) + result = MenuModel(**CamelCaseUtil.transform_result(menu)) if menu else MenuModel() return result @classmethod - def list_to_tree(cls, permission_list: list) -> list: + def list_to_tree(cls, permission_list: Sequence[SysMenu]) -> list[dict[str, Any]]: """ 工具方法:根据菜单列表信息生成树形嵌套数据 :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 = [ + {'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)) + mapping: dict[int, dict[str, Any]] = dict(zip([i['id'] for i in _permission_list], _permission_list)) # 树容器 - container: list = [] + container: list[dict[str, Any]] = [] - for d in permission_list: + for d in _permission_list: # 如果找不到父级项,则是根节点 - parent: dict = mapping.get(d['parentId']) + parent = mapping.get(d['parentId']) if parent is None: container.append(d) else: - children: list = parent.get('children') + children: list[dict[str, Any]] = parent.get('children') if not children: children = [] children.append(d) diff --git a/ruoyi-fastapi-backend/module_admin/service/notice_service.py b/ruoyi-fastapi-backend/module_admin/service/notice_service.py index 4671703..51452e6 100644 --- a/ruoyi-fastapi-backend/module_admin/service/notice_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/notice_service.py @@ -1,10 +1,14 @@ +from typing import Any, Union + from sqlalchemy.ext.asyncio import AsyncSession + from config.constant import CommonConstant from exceptions.exception import ServiceException 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 +from utils.page_util import PageResponseModel class NoticeService: @@ -15,7 +19,7 @@ class NoticeService: @classmethod async def get_notice_list_services( cls, query_db: AsyncSession, query_object: NoticePageQueryModel, is_page: bool = True - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取通知公告列表信息service @@ -29,7 +33,7 @@ class NoticeService: return notice_list_result @classmethod - async def check_notice_unique_services(cls, query_db: AsyncSession, page_object: NoticeModel): + async def check_notice_unique_services(cls, query_db: AsyncSession, page_object: NoticeModel) -> bool: """ 校验通知公告是否存在service @@ -44,7 +48,7 @@ class NoticeService: return CommonConstant.UNIQUE @classmethod - async def add_notice_services(cls, query_db: AsyncSession, page_object: NoticeModel): + async def add_notice_services(cls, query_db: AsyncSession, page_object: NoticeModel) -> CrudResponseModel: """ 新增通知公告信息service @@ -54,17 +58,16 @@ class NoticeService: """ 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() - return CrudResponseModel(is_success=True, message='新增成功') - except Exception as e: - await query_db.rollback() - raise e + try: + await NoticeDao.add_notice_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_notice_services(cls, query_db: AsyncSession, page_object: NoticeModel): + async def edit_notice_services(cls, query_db: AsyncSession, page_object: NoticeModel) -> CrudResponseModel: """ 编辑通知公告信息service @@ -77,19 +80,18 @@ class NoticeService: 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 + 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: raise ServiceException(message='通知公告不存在') @classmethod - async def delete_notice_services(cls, query_db: AsyncSession, page_object: DeleteNoticeModel): + async def delete_notice_services(cls, query_db: AsyncSession, page_object: DeleteNoticeModel) -> CrudResponseModel: """ 删除通知公告信息service @@ -111,7 +113,7 @@ class NoticeService: raise ServiceException(message='传入通知公告id为空') @classmethod - async def notice_detail_services(cls, query_db: AsyncSession, notice_id: int): + async def notice_detail_services(cls, query_db: AsyncSession, notice_id: int) -> NoticeModel: """ 获取通知公告详细信息service @@ -120,9 +122,6 @@ class NoticeService: :return: 通知公告id对应的信息 """ notice = await NoticeDao.get_notice_detail_by_id(query_db, notice_id=notice_id) - if notice: - result = NoticeModel(**CamelCaseUtil.transform_result(notice)) - else: - result = NoticeModel(**dict()) + result = NoticeModel(**CamelCaseUtil.transform_result(notice)) if notice else NoticeModel() return result diff --git a/ruoyi-fastapi-backend/module_admin/service/online_service.py b/ruoyi-fastapi-backend/module_admin/service/online_service.py index 56742b0..2ba06c4 100644 --- a/ruoyi-fastapi-backend/module_admin/service/online_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/online_service.py @@ -1,5 +1,8 @@ +from typing import Any + import jwt from fastapi import Request + from config.enums import RedisInitKeyConfig from config.env import JwtConfig from exceptions.exception import ServiceException @@ -14,7 +17,7 @@ class OnlineService: """ @classmethod - async def get_online_list_services(cls, request: Request, query_object: OnlineQueryModel): + async def get_online_list_services(cls, request: Request, query_object: OnlineQueryModel) -> list[dict[str, Any]]: """ 获取在线用户表信息service @@ -29,16 +32,16 @@ class OnlineService: online_info_list = [] for item in access_token_values_list: payload = jwt.decode(item, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm]) - online_dict = dict( - token_id=payload.get('session_id'), - user_name=payload.get('user_name'), - dept_name=payload.get('dept_name'), - ipaddr=payload.get('login_info').get('ipaddr'), - 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'), - ) + online_dict = { + 'token_id': payload.get('session_id'), + 'user_name': payload.get('user_name'), + 'dept_name': payload.get('dept_name'), + 'ipaddr': payload.get('login_info').get('ipaddr'), + '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'), + } if query_object.user_name and not query_object.ipaddr: if query_object.user_name == payload.get('user_name'): online_info_list = [online_dict] @@ -59,7 +62,7 @@ class OnlineService: return CamelCaseUtil.transform_result(online_info_list) @classmethod - async def delete_online_services(cls, request: Request, page_object: DeleteOnlineModel): + async def delete_online_services(cls, request: Request, page_object: DeleteOnlineModel) -> CrudResponseModel: """ 强退在线用户信息service @@ -72,5 +75,4 @@ class OnlineService: for token_id in token_id_list: await request.app.state.redis.delete(f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{token_id}') return CrudResponseModel(is_success=True, message='强退成功') - else: - raise ServiceException(message='传入session_id为空') + raise ServiceException(message='传入session_id为空') diff --git a/ruoyi-fastapi-backend/module_admin/service/post_service.py b/ruoyi-fastapi-backend/module_admin/service/post_service.py index 9338a9f..f82016e 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 typing import Any, Union + from sqlalchemy.ext.asyncio import AsyncSession -from typing import List + from config.constant import CommonConstant from exceptions.exception import ServiceException from module_admin.dao.post_dao import PostDao @@ -7,6 +9,7 @@ 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 from utils.excel_util import ExcelUtil +from utils.page_util import PageResponseModel class PostService: @@ -17,7 +20,7 @@ class PostService: @classmethod async def get_post_list_services( cls, query_db: AsyncSession, query_object: PostPageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取岗位列表信息service @@ -31,7 +34,7 @@ class PostService: return post_list_result @classmethod - async def check_post_name_unique_services(cls, query_db: AsyncSession, page_object: PostModel): + async def check_post_name_unique_services(cls, query_db: AsyncSession, page_object: PostModel) -> bool: """ 检查岗位名称是否唯一service @@ -46,7 +49,7 @@ class PostService: return CommonConstant.UNIQUE @classmethod - async def check_post_code_unique_services(cls, query_db: AsyncSession, page_object: PostModel): + async def check_post_code_unique_services(cls, query_db: AsyncSession, page_object: PostModel) -> bool: """ 检查岗位编码是否唯一service @@ -61,7 +64,7 @@ class PostService: return CommonConstant.UNIQUE @classmethod - async def add_post_services(cls, query_db: AsyncSession, page_object: PostModel): + async def add_post_services(cls, query_db: AsyncSession, page_object: PostModel) -> CrudResponseModel: """ 新增岗位信息service @@ -71,19 +74,18 @@ class PostService: """ 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): + if 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() - return CrudResponseModel(is_success=True, message='新增成功') - except Exception as e: - await query_db.rollback() - raise e + try: + await PostDao.add_post_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_post_services(cls, query_db: AsyncSession, page_object: PostModel): + async def edit_post_services(cls, query_db: AsyncSession, page_object: PostModel) -> CrudResponseModel: """ 编辑岗位信息service @@ -96,21 +98,20 @@ class PostService: 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): + if 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 + 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: raise ServiceException(message='岗位不存在') @classmethod - async def delete_post_services(cls, query_db: AsyncSession, page_object: DeletePostModel): + async def delete_post_services(cls, query_db: AsyncSession, page_object: DeletePostModel) -> CrudResponseModel: """ 删除岗位信息service @@ -135,7 +136,7 @@ class PostService: raise ServiceException(message='传入岗位id为空') @classmethod - async def post_detail_services(cls, query_db: AsyncSession, post_id: int): + async def post_detail_services(cls, query_db: AsyncSession, post_id: int) -> PostModel: """ 获取岗位详细信息service @@ -144,15 +145,12 @@ class PostService: :return: 岗位id对应的信息 """ post = await PostDao.get_post_detail_by_id(query_db, post_id=post_id) - if post: - result = PostModel(**CamelCaseUtil.transform_result(post)) - else: - result = PostModel(**dict()) + result = PostModel(**CamelCaseUtil.transform_result(post)) if post else PostModel() return result @staticmethod - async def export_post_list_services(post_list: List): + async def export_post_list_services(post_list: list) -> bytes: """ 导出岗位信息service diff --git a/ruoyi-fastapi-backend/module_admin/service/role_service.py b/ruoyi-fastapi-backend/module_admin/service/role_service.py index 4b633de..a0eaf91 100644 --- a/ruoyi-fastapi-backend/module_admin/service/role_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/role_service.py @@ -1,7 +1,11 @@ +from typing import Any, Union + from sqlalchemy.ext.asyncio import AsyncSession -from typing import List + from config.constant import CommonConstant from exceptions.exception import ServiceException +from module_admin.dao.role_dao import RoleDao +from module_admin.dao.user_dao import UserDao from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.entity.vo.role_vo import ( AddRoleModel, @@ -13,8 +17,6 @@ from module_admin.entity.vo.role_vo import ( 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 from utils.excel_util import ExcelUtil from utils.page_util import PageResponseModel @@ -26,7 +28,7 @@ class RoleService: """ @classmethod - async def get_role_select_option_services(cls, query_db: AsyncSession): + async def get_role_select_option_services(cls, query_db: AsyncSession) -> list[dict[str, Any]]: """ 获取角色列表不分页信息service @@ -38,7 +40,7 @@ class RoleService: return CamelCaseUtil.transform_result(role_list_result) @classmethod - async def get_role_dept_tree_services(cls, query_db: AsyncSession, role_id: int): + async def get_role_dept_tree_services(cls, query_db: AsyncSession, role_id: int) -> RoleDeptQueryModel: """ 根据角色id获取部门树信息service @@ -56,7 +58,7 @@ class RoleService: @classmethod async def get_role_list_services( cls, query_db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取角色列表信息service @@ -71,7 +73,7 @@ class RoleService: return role_list_result @classmethod - async def check_role_allowed_services(cls, check_role: RoleModel): + async def check_role_allowed_services(cls, check_role: RoleModel) -> CrudResponseModel: """ 校验角色是否允许操作service @@ -80,11 +82,10 @@ class RoleService: """ if check_role.admin: raise ServiceException(message='不允许操作超级管理员角色') - else: - return CrudResponseModel(is_success=True, message='校验通过') + return CrudResponseModel(is_success=True, message='校验通过') @classmethod - async def check_role_data_scope_services(cls, query_db: AsyncSession, role_ids: str, data_scope_sql: str): + async def check_role_data_scope_services(cls, query_db: AsyncSession, role_ids: str, data_scope_sql: str) -> None: """ 校验角色是否有数据权限service @@ -101,11 +102,10 @@ class RoleService: ) if roles: continue - else: - raise ServiceException(message='没有权限访问角色数据') + raise ServiceException(message='没有权限访问角色数据') @classmethod - async def check_role_name_unique_services(cls, query_db: AsyncSession, page_object: RoleModel): + async def check_role_name_unique_services(cls, query_db: AsyncSession, page_object: RoleModel) -> bool: """ 校验角色名称是否唯一service @@ -120,7 +120,7 @@ class RoleService: return CommonConstant.UNIQUE @classmethod - async def check_role_key_unique_services(cls, query_db: AsyncSession, page_object: RoleModel): + async def check_role_key_unique_services(cls, query_db: AsyncSession, page_object: RoleModel) -> bool: """ 校验角色权限字符是否唯一service @@ -135,7 +135,7 @@ class RoleService: return CommonConstant.UNIQUE @classmethod - async def add_role_services(cls, query_db: AsyncSession, page_object: AddRoleModel): + async def add_role_services(cls, query_db: AsyncSession, page_object: AddRoleModel) -> CrudResponseModel: """ 新增角色信息service @@ -146,23 +146,22 @@ class RoleService: add_role = RoleModel(**page_object.model_dump(by_alias=True)) if not await cls.check_role_name_unique_services(query_db, page_object): raise ServiceException(message=f'新增角色{page_object.role_name}失败,角色名称已存在') - elif not await cls.check_role_key_unique_services(query_db, page_object): + if not await cls.check_role_key_unique_services(query_db, page_object): raise ServiceException(message=f'新增角色{page_object.role_name}失败,角色权限已存在') - else: - try: - add_result = await RoleDao.add_role_dao(query_db, add_role) - role_id = add_result.role_id - if page_object.menu_ids: - 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() - return CrudResponseModel(is_success=True, message='新增成功') - except Exception as e: - await query_db.rollback() - raise e + try: + add_result = await RoleDao.add_role_dao(query_db, add_role) + role_id = add_result.role_id + if page_object.menu_ids: + 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() + return CrudResponseModel(is_success=True, message='新增成功') + except Exception as e: + await query_db.rollback() + raise e @classmethod - async def edit_role_services(cls, query_db: AsyncSession, page_object: AddRoleModel): + async def edit_role_services(cls, query_db: AsyncSession, page_object: AddRoleModel) -> CrudResponseModel: """ 编辑角色信息service @@ -180,7 +179,7 @@ class RoleService: if page_object.type != 'status': if not await cls.check_role_name_unique_services(query_db, page_object): raise ServiceException(message=f'修改角色{page_object.role_name}失败,角色名称已存在') - elif not await cls.check_role_key_unique_services(query_db, page_object): + if not await cls.check_role_key_unique_services(query_db, page_object): raise ServiceException(message=f'修改角色{page_object.role_name}失败,角色权限已存在') try: await RoleDao.edit_role_dao(query_db, edit_role) @@ -200,7 +199,7 @@ class RoleService: raise ServiceException(message='角色不存在') @classmethod - async def role_datascope_services(cls, query_db: AsyncSession, page_object: AddRoleModel): + async def role_datascope_services(cls, query_db: AsyncSession, page_object: AddRoleModel) -> CrudResponseModel: """ 分配角色数据权限service @@ -228,7 +227,7 @@ class RoleService: raise ServiceException(message='角色不存在') @classmethod - async def delete_role_services(cls, query_db: AsyncSession, page_object: DeleteRoleModel): + async def delete_role_services(cls, query_db: AsyncSession, page_object: DeleteRoleModel) -> CrudResponseModel: """ 删除角色信息service @@ -243,9 +242,11 @@ 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 = { + '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)) @@ -258,7 +259,7 @@ class RoleService: raise ServiceException(message='传入角色id为空') @classmethod - async def role_detail_services(cls, query_db: AsyncSession, role_id: int): + async def role_detail_services(cls, query_db: AsyncSession, role_id: int) -> RoleModel: """ 获取角色详细信息service @@ -267,15 +268,12 @@ class RoleService: :return: 角色id对应的信息 """ role = await RoleDao.get_role_detail_by_id(query_db, role_id=role_id) - if role: - result = RoleModel(**CamelCaseUtil.transform_result(role)) - else: - result = RoleModel(**dict()) + result = RoleModel(**CamelCaseUtil.transform_result(role)) if role else RoleModel() return result @staticmethod - async def export_role_list_services(role_list: List): + async def export_role_list_services(role_list: list) -> bytes: """ 导出角色列表信息service @@ -308,7 +306,7 @@ class RoleService: @classmethod async def get_role_user_allocated_list_services( cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False - ): + ) -> PageResponseModel: """ 根据角色id获取已分配用户列表 @@ -333,7 +331,7 @@ class RoleService: @classmethod async def get_role_user_unallocated_list_services( cls, query_db: AsyncSession, page_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False - ): + ) -> PageResponseModel: """ 根据角色id获取未分配用户列表 diff --git a/ruoyi-fastapi-backend/module_admin/service/server_service.py b/ruoyi-fastapi-backend/module_admin/service/server_service.py index 2f9a53f..7bfca70 100644 --- a/ruoyi-fastapi-backend/module_admin/service/server_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/server_service.py @@ -1,8 +1,10 @@ import os import platform -import psutil import socket import time + +import psutil + from module_admin.entity.vo.server_vo import CpuInfo, MemoryInfo, PyInfo, ServerMonitorModel, SysFiles, SysInfo from utils.common_util import bytes2human @@ -13,7 +15,7 @@ class ServerService: """ @staticmethod - async def get_server_monitor_info(): + async def get_server_monitor_info() -> ServerMonitorModel: # CPU信息 # 获取CPU总核心数 cpu_num = psutil.cpu_count(logical=True) diff --git a/ruoyi-fastapi-backend/module_admin/service/user_service.py b/ruoyi-fastapi-backend/module_admin/service/user_service.py index 60f77c6..fe2bf8e 100644 --- a/ruoyi-fastapi-backend/module_admin/service/user_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/user_service.py @@ -1,12 +1,15 @@ import io -import pandas as pd from datetime import datetime +from typing import Any, Union + +import pandas as pd from fastapi import Request, UploadFile 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.do.user_do import SysUserRole 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 ( @@ -45,7 +48,7 @@ class UserService: @classmethod async def get_user_list_services( cls, query_db: AsyncSession, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取用户列表信息service @@ -71,7 +74,7 @@ class UserService: return user_list_result @classmethod - async def check_user_allowed_services(cls, check_user: UserModel): + async def check_user_allowed_services(cls, check_user: UserModel) -> CrudResponseModel: """ 校验用户是否允许操作service @@ -80,11 +83,12 @@ class UserService: """ if check_user.admin: raise ServiceException(message='不允许操作超级管理员用户') - else: - return CrudResponseModel(is_success=True, message='校验通过') + 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): + async def check_user_data_scope_services( + cls, query_db: AsyncSession, user_id: int, data_scope_sql: str + ) -> CrudResponseModel: """ 校验用户数据权限service @@ -96,11 +100,10 @@ class UserService: 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='没有权限访问用户数据') + raise ServiceException(message='没有权限访问用户数据') @classmethod - async def check_user_name_unique_services(cls, query_db: AsyncSession, page_object: UserModel): + async def check_user_name_unique_services(cls, query_db: AsyncSession, page_object: UserModel) -> bool: """ 校验用户名是否唯一service @@ -115,7 +118,7 @@ class UserService: return CommonConstant.UNIQUE @classmethod - async def check_phonenumber_unique_services(cls, query_db: AsyncSession, page_object: UserModel): + async def check_phonenumber_unique_services(cls, query_db: AsyncSession, page_object: UserModel) -> bool: """ 校验用户手机号是否唯一service @@ -130,7 +133,7 @@ class UserService: return CommonConstant.UNIQUE @classmethod - async def check_email_unique_services(cls, query_db: AsyncSession, page_object: UserModel): + async def check_email_unique_services(cls, query_db: AsyncSession, page_object: UserModel) -> bool: """ 校验用户邮箱是否唯一service @@ -145,7 +148,7 @@ class UserService: return CommonConstant.UNIQUE @classmethod - async def add_user_services(cls, query_db: AsyncSession, page_object: AddUserModel): + async def add_user_services(cls, query_db: AsyncSession, page_object: AddUserModel) -> CrudResponseModel: """ 新增用户信息service @@ -156,28 +159,43 @@ class UserService: add_user = UserModel(**page_object.model_dump(by_alias=True)) 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): + if 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): + if 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) - user_id = add_result.user_id - if page_object.role_ids: - for role in page_object.role_ids: - await UserDao.add_user_role_dao(query_db, UserRoleModel(userId=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=user_id, postId=post)) - await query_db.commit() - return CrudResponseModel(is_success=True, message='新增成功') - except Exception as e: - await query_db.rollback() - raise e + try: + add_result = await UserDao.add_user_dao(query_db, add_user) + user_id = add_result.user_id + if page_object.role_ids: + for role in page_object.role_ids: + await UserDao.add_user_role_dao(query_db, UserRoleModel(userId=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=user_id, postId=post)) + await query_db.commit() + return CrudResponseModel(is_success=True, message='新增成功') + except Exception as e: + await query_db.rollback() + raise e @classmethod - async def edit_user_services(cls, query_db: AsyncSession, page_object: EditUserModel): + def _deal_edit_user(cls, page_object: EditUserModel, edit_user: dict[str, Any]) -> None: + """ + 处理编辑用户字典 + + :param page_object: 编辑用户对象 + :param edit_user: 编辑用户字典 + :return: None + """ + if page_object.type not in ['status', 'avatar', 'pwd']: + del edit_user['role_ids'] + del edit_user['post_ids'] + del edit_user['role'] + else: + del edit_user['type'] + + @classmethod + async def edit_user_services(cls, query_db: AsyncSession, page_object: EditUserModel) -> CrudResponseModel: """ 编辑用户信息service @@ -186,24 +204,19 @@ class UserService: :return: 编辑用户校验结果 """ edit_user = page_object.model_dump(exclude_unset=True, exclude={'admin'}) - if page_object.type != 'status' and page_object.type != 'avatar' and page_object.type != 'pwd': - del edit_user['role_ids'] - del edit_user['post_ids'] - del edit_user['role'] - if page_object.type == 'status' or page_object.type == 'avatar' or page_object.type == 'pwd': - del edit_user['type'] + cls._deal_edit_user(page_object, edit_user) user_info = await cls.user_detail_services(query_db, edit_user.get('user_id')) 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 page_object.type not in ['status', 'avatar', '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): + if 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): + if 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': + if page_object.type not in {'status', 'avatar', 'pwd'}: await UserDao.delete_user_role_dao(query_db, UserRoleModel(userId=page_object.user_id)) await UserDao.delete_user_post_dao(query_db, UserPostModel(userId=page_object.user_id)) if page_object.role_ids: @@ -225,7 +238,7 @@ class UserService: raise ServiceException(message='用户不存在') @classmethod - async def delete_user_services(cls, query_db: AsyncSession, page_object: DeleteUserModel): + async def delete_user_services(cls, query_db: AsyncSession, page_object: DeleteUserModel) -> CrudResponseModel: """ 删除用户信息service @@ -237,9 +250,11 @@ 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 = { + '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)) @@ -252,7 +267,7 @@ class UserService: raise ServiceException(message='传入用户id为空') @classmethod - async def user_detail_services(cls, query_db: AsyncSession, user_id: Union[int, str]): + async def user_detail_services(cls, query_db: AsyncSession, user_id: Union[int, str]) -> UserDetailModel: """ 获取用户详细信息service @@ -260,7 +275,7 @@ class UserService: :param user_id: 用户id :return: 用户id对应的信息 """ - posts = await PostService.get_post_list_services(query_db, PostPageQueryModel(**{}), is_page=False) + posts = await PostService.get_post_list_services(query_db, PostPageQueryModel(), is_page=False) roles = await RoleService.get_role_select_option_services(query_db) if user_id != '': query_user = await UserDao.get_user_detail_by_id(query_db, user_id=user_id) @@ -286,7 +301,7 @@ class UserService: return UserDetailModel(posts=posts, roles=roles) @classmethod - async def user_profile_services(cls, query_db: AsyncSession, user_id: int): + async def user_profile_services(cls, query_db: AsyncSession, user_id: int) -> UserProfileModel: """ 获取用户个人详细信息service @@ -313,7 +328,7 @@ class UserService: ) @classmethod - async def reset_user_services(cls, query_db: AsyncSession, page_object: ResetUserModel): + async def reset_user_services(cls, query_db: AsyncSession, page_object: ResetUserModel) -> CrudResponseModel: """ 重置用户密码service @@ -326,10 +341,9 @@ class UserService: 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): raise ServiceException(message='修改密码失败,旧密码错误') - elif PwdUtil.verify_password(page_object.password, user.password): + if PwdUtil.verify_password(page_object.password, user.password): raise ServiceException(message='新密码不能与旧密码相同') - else: - del reset_user['old_password'] + del reset_user['old_password'] if page_object.sms_code and page_object.session_id: del reset_user['sms_code'] del reset_user['session_id'] @@ -342,6 +356,34 @@ class UserService: await query_db.rollback() raise e + @classmethod + def _set_row_sex_value(cls, row: pd.Series) -> None: + """ + 设置行性别值 + + :param row: 行数据 + :return: None + """ + if row['sex'] == '男': + row['sex'] = '0' + if row['sex'] == '女': + row['sex'] = '1' + if row['sex'] == '未知': + row['sex'] = '2' + + @classmethod + def _set_row_status_value(cls, row: pd.Series) -> None: + """ + 设置行状态值 + + :param row: 行数据 + :return: None + """ + if row['status'] == '正常': + row['status'] = '0' + if row['status'] == '停用': + row['status'] = '1' + @classmethod async def batch_import_user_services( cls, @@ -352,7 +394,7 @@ class UserService: current_user: CurrentUserModel, user_data_scope_sql: str, dept_data_scope_sql: str, - ): + ) -> CrudResponseModel: """ 批量导入用户service @@ -381,18 +423,10 @@ class UserService: add_error_result = [] count = 0 try: - for index, row in df.iterrows(): + for _index, row in df.iterrows(): count = count + 1 - if row['sex'] == '男': - row['sex'] = '0' - if row['sex'] == '女': - row['sex'] = '1' - if row['sex'] == '未知': - row['sex'] = '2' - if row['status'] == '正常': - row['status'] = '0' - if row['status'] == '停用': - row['status'] = '1' + cls._set_row_sex_value(row) + cls._set_row_status_value(row) add_user = UserModel( deptId=row['dept_id'], userName=row['user_name'], @@ -438,7 +472,7 @@ class UserService: 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']}已存在") + add_error_result.append(f'{count}.用户账号{row["user_name"]}已存在') else: add_user.validate_fields() if not current_user.user.admin: @@ -453,7 +487,7 @@ class UserService: raise e @staticmethod - async def get_user_import_template_services(): + async def get_user_import_template_services() -> bytes: """ 获取用户导入模板service @@ -469,7 +503,7 @@ class UserService: return binary_data @staticmethod - async def export_user_list_services(user_list: List): + async def export_user_list_services(user_list: list) -> bytes: """ 导出用户信息service @@ -510,7 +544,9 @@ class UserService: return binary_data @classmethod - async def get_user_role_allocated_list_services(cls, query_db: AsyncSession, page_object: UserRoleQueryModel): + async def get_user_role_allocated_list_services( + cls, query_db: AsyncSession, page_object: UserRoleQueryModel + ) -> UserRoleResponseModel: """ 根据用户id获取已分配角色列表 @@ -540,7 +576,7 @@ class UserService: return result @classmethod - async def add_user_role_services(cls, query_db: AsyncSession, page_object: CrudUserRoleModel): + async def add_user_role_services(cls, query_db: AsyncSession, page_object: CrudUserRoleModel) -> CrudResponseModel: """ 新增用户关联角色信息service @@ -576,10 +612,7 @@ class UserService: ) 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: @@ -589,7 +622,9 @@ class UserService: raise ServiceException(message='不满足新增条件') @classmethod - async def delete_user_role_services(cls, query_db: AsyncSession, page_object: CrudUserRoleModel): + async def delete_user_role_services( + cls, query_db: AsyncSession, page_object: CrudUserRoleModel + ) -> CrudResponseModel: """ 删除用户关联角色信息service @@ -626,7 +661,9 @@ class UserService: raise ServiceException(message='传入用户角色关联信息为空') @classmethod - async def detail_user_role_services(cls, query_db: AsyncSession, page_object: UserRoleModel): + async def detail_user_role_services( + cls, query_db: AsyncSession, page_object: UserRoleModel + ) -> Union[SysUserRole, None]: """ 获取用户关联角色详细信息service diff --git a/ruoyi-fastapi-backend/module_generator/controller/gen_controller.py b/ruoyi-fastapi-backend/module_generator/controller/gen_controller.py index 4e227c1..9a22bc8 100644 --- a/ruoyi-fastapi-backend/module_generator/controller/gen_controller.py +++ b/ruoyi-fastapi-backend/module_generator/controller/gen_controller.py @@ -1,14 +1,17 @@ from datetime import datetime -from fastapi import APIRouter, Depends, Query, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Path, Query, Request, Response from pydantic_validation_decorator import ValidateFields from sqlalchemy.ext.asyncio import AsyncSession + from config.enums import BusinessType from config.env import GenConfig from config.get_db import get_db from module_admin.annotation.log_annotation import Log from module_admin.aspect.interface_auth import CheckRoleInterfaceAuth, CheckUserInterfaceAuth -from module_admin.service.login_service import LoginService from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.login_service import LoginService from module_generator.entity.vo.gen_vo import DeleteGenTableModel, EditGenTableModel, GenTablePageQueryModel from module_generator.service.gen_service import GenTableColumnService, GenTableService from utils.common_util import bytes2file_response @@ -16,18 +19,17 @@ from utils.log_util import logger from utils.page_util import PageResponseModel from utils.response_util import ResponseUtil - -genController = APIRouter(prefix='/tool/gen', dependencies=[Depends(LoginService.get_current_user)]) +gen_controller = APIRouter(prefix='/tool/gen', dependencies=[Depends(LoginService.get_current_user)]) -@genController.get( +@gen_controller.get( '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:list'))] ) async def get_gen_table_list( request: Request, - gen_page_query: GenTablePageQueryModel = Depends(GenTablePageQueryModel.as_query), - query_db: AsyncSession = Depends(get_db), -): + gen_page_query: Annotated[GenTablePageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 gen_page_query_result = await GenTableService.get_gen_table_list_services(query_db, gen_page_query, is_page=True) logger.info('获取成功') @@ -35,14 +37,14 @@ async def get_gen_table_list( return ResponseUtil.success(model_content=gen_page_query_result) -@genController.get( +@gen_controller.get( '/db/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:list'))] ) async def get_gen_db_table_list( request: Request, - gen_page_query: GenTablePageQueryModel = Depends(GenTablePageQueryModel.as_query), - query_db: AsyncSession = Depends(get_db), -): + gen_page_query: Annotated[GenTablePageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取分页数据 gen_page_query_result = await GenTableService.get_gen_db_table_list_services(query_db, gen_page_query, is_page=True) logger.info('获取成功') @@ -50,14 +52,14 @@ async def get_gen_db_table_list( return ResponseUtil.success(model_content=gen_page_query_result) -@genController.post('/importTable', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:import'))]) +@gen_controller.post('/importTable', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:import'))]) @Log(title='代码生成', business_type=BusinessType.IMPORT) async def import_gen_table( request: Request, - tables: str = Query(), - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), -): + tables: Annotated[str, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: table_names = tables.split(',') if tables else [] add_gen_table_list = await GenTableService.get_gen_db_table_list_by_name_services(query_db, table_names) add_gen_table_result = await GenTableService.import_gen_table_services(query_db, add_gen_table_list, current_user) @@ -66,15 +68,15 @@ async def import_gen_table( return ResponseUtil.success(msg=add_gen_table_result.message) -@genController.put('', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:edit'))]) +@gen_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:edit'))]) @ValidateFields(validate_model='edit_gen_table') @Log(title='代码生成', business_type=BusinessType.UPDATE) async def edit_gen_table( request: Request, edit_gen_table: EditGenTableModel, - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: edit_gen_table.update_by = current_user.user.user_name edit_gen_table.update_time = datetime.now() await GenTableService.validate_edit(edit_gen_table) @@ -84,9 +86,13 @@ async def edit_gen_table( return ResponseUtil.success(msg=edit_gen_result.message) -@genController.delete('/{table_ids}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:remove'))]) +@gen_controller.delete('/{table_ids}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:remove'))]) @Log(title='代码生成', business_type=BusinessType.DELETE) -async def delete_gen_table(request: Request, table_ids: str, query_db: AsyncSession = Depends(get_db)): +async def delete_gen_table( + request: Request, + table_ids: Annotated[str, Path(description='需要删除的代码生成业务表ID')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: delete_gen_table = DeleteGenTableModel(tableIds=table_ids) delete_gen_table_result = await GenTableService.delete_gen_table_services(query_db, delete_gen_table) logger.info(delete_gen_table_result.message) @@ -94,23 +100,27 @@ async def delete_gen_table(request: Request, table_ids: str, query_db: AsyncSess return ResponseUtil.success(msg=delete_gen_table_result.message) -@genController.post('/createTable', dependencies=[Depends(CheckRoleInterfaceAuth('admin'))]) +@gen_controller.post('/createTable', dependencies=[Depends(CheckRoleInterfaceAuth('admin'))]) @Log(title='创建表', business_type=BusinessType.OTHER) async def create_table( request: Request, - sql: str = Query(), - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), -): + sql: Annotated[str, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: create_table_result = await GenTableService.create_table_services(query_db, sql, current_user) logger.info(create_table_result.message) return ResponseUtil.success(msg=create_table_result.message) -@genController.get('/batchGenCode', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:code'))]) +@gen_controller.get('/batchGenCode', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:code'))]) @Log(title='代码生成', business_type=BusinessType.GENCODE) -async def batch_gen_code(request: Request, tables: str = Query(), query_db: AsyncSession = Depends(get_db)): +async def batch_gen_code( + request: Request, + tables: Annotated[str, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: table_names = tables.split(',') if tables else [] batch_gen_code_result = await GenTableService.batch_gen_code_services(query_db, table_names) logger.info('生成代码成功') @@ -118,9 +128,13 @@ async def batch_gen_code(request: Request, tables: str = Query(), query_db: Asyn return ResponseUtil.streaming(data=bytes2file_response(batch_gen_code_result)) -@genController.get('/genCode/{table_name}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:code'))]) +@gen_controller.get('/genCode/{table_name}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:code'))]) @Log(title='代码生成', business_type=BusinessType.GENCODE) -async def gen_code_local(request: Request, table_name: str, query_db: AsyncSession = Depends(get_db)): +async def gen_code_local( + request: Request, + table_name: Annotated[str, Path(description='表名称')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: if not GenConfig.allow_overwrite: logger.error('【系统预设】不允许生成文件覆盖到本地') return ResponseUtil.error('【系统预设】不允许生成文件覆盖到本地') @@ -130,28 +144,40 @@ async def gen_code_local(request: Request, table_name: str, query_db: AsyncSessi return ResponseUtil.success(msg=gen_code_local_result.message) -@genController.get('/{table_id}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:query'))]) -async def query_detail_gen_table(request: Request, table_id: int, query_db: AsyncSession = Depends(get_db)): +@gen_controller.get('/{table_id}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:query'))]) +async def query_detail_gen_table( + request: Request, + table_id: Annotated[int, Path(description='表编号')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: gen_table = await GenTableService.get_gen_table_by_id_services(query_db, table_id) gen_tables = await GenTableService.get_gen_table_all_services(query_db) gen_columns = await GenTableColumnService.get_gen_table_column_list_by_table_id_services(query_db, table_id) - gen_table_detail_result = dict(info=gen_table, rows=gen_columns, tables=gen_tables) + gen_table_detail_result = {'info': gen_table, 'rows': gen_columns, 'tables': gen_tables} logger.info(f'获取table_id为{table_id}的信息成功') return ResponseUtil.success(data=gen_table_detail_result) -@genController.get('/preview/{table_id}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:preview'))]) -async def preview_code(request: Request, table_id: int, query_db: AsyncSession = Depends(get_db)): +@gen_controller.get('/preview/{table_id}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:preview'))]) +async def preview_code( + request: Request, + table_id: Annotated[int, Path(description='表编号')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: preview_code_result = await GenTableService.preview_code_services(query_db, table_id) logger.info('获取预览代码成功') return ResponseUtil.success(data=preview_code_result) -@genController.get('/synchDb/{table_name}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:edit'))]) +@gen_controller.get('/synchDb/{table_name}', dependencies=[Depends(CheckUserInterfaceAuth('tool:gen:edit'))]) @Log(title='代码生成', business_type=BusinessType.UPDATE) -async def sync_db(request: Request, table_name: str, query_db: AsyncSession = Depends(get_db)): +async def sync_db( + request: Request, + table_name: Annotated[str, Path(description='表名称')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: sync_db_result = await GenTableService.sync_db_services(query_db, table_name) logger.info(sync_db_result.message) diff --git a/ruoyi-fastapi-backend/module_generator/dao/gen_dao.py b/ruoyi-fastapi-backend/module_generator/dao/gen_dao.py index 937668a..ae4fc9b 100644 --- a/ruoyi-fastapi-backend/module_generator/dao/gen_dao.py +++ b/ruoyi-fastapi-backend/module_generator/dao/gen_dao.py @@ -1,9 +1,12 @@ +from collections.abc import Sequence from datetime import datetime, time -from sqlalchemy import delete, func, select, text, update +from typing import Any, Union + +from sqlalchemy import Row, delete, func, select, text, update from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from sqlglot.expressions import Expression -from typing import List + from config.env import DataBaseConfig from module_generator.entity.do.gen_do import GenTable, GenTableColumn from module_generator.entity.vo.gen_vo import ( @@ -13,7 +16,7 @@ from module_generator.entity.vo.gen_vo import ( GenTableModel, GenTablePageQueryModel, ) -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil class GenTableDao: @@ -22,7 +25,7 @@ class GenTableDao: """ @classmethod - async def get_gen_table_by_id(cls, db: AsyncSession, table_id: int): + async def get_gen_table_by_id(cls, db: AsyncSession, table_id: int) -> Union[GenTable, None]: """ 根据业务表id获取需要生成的业务表信息 @@ -43,7 +46,7 @@ class GenTableDao: return gen_table_info @classmethod - async def get_gen_table_by_name(cls, db: AsyncSession, table_name: str): + async def get_gen_table_by_name(cls, db: AsyncSession, table_name: str) -> Union[GenTable, None]: """ 根据业务表名称获取需要生成的业务表信息 @@ -64,7 +67,7 @@ class GenTableDao: return gen_table_info @classmethod - async def get_gen_table_all(cls, db: AsyncSession): + async def get_gen_table_all(cls, db: AsyncSession) -> Sequence[GenTable]: """ 获取所有业务表信息 @@ -76,7 +79,7 @@ class GenTableDao: return gen_table_all @classmethod - async def create_table_by_sql_dao(cls, db: AsyncSession, sql_statements: List[Expression]): + async def create_table_by_sql_dao(cls, db: AsyncSession, sql_statements: list[Expression]) -> None: """ 根据sql语句创建表结构 @@ -89,7 +92,9 @@ class GenTableDao: await db.execute(text(sql)) @classmethod - async def get_gen_table_list(cls, db: AsyncSession, query_object: GenTablePageQueryModel, is_page: bool = False): + async def get_gen_table_list( + cls, db: AsyncSession, query_object: GenTablePageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取代码生成业务表列表信息 @@ -117,12 +122,16 @@ class GenTableDao: ) .distinct() ) - gen_table_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + gen_table_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return gen_table_list @classmethod - async def get_gen_db_table_list(cls, db: AsyncSession, query_object: GenTablePageQueryModel, is_page: bool = False): + async def get_gen_db_table_list( + cls, db: AsyncSession, query_object: GenTablePageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取数据库列表信息 @@ -133,28 +142,28 @@ class GenTableDao: """ if DataBaseConfig.db_type == 'postgresql': query_sql = """ - table_name as table_name, - table_comment as table_comment, - create_time as create_time, + table_name as table_name, + table_comment as table_comment, + create_time as create_time, update_time as update_time - from + from list_table - where - table_name not like 'apscheduler_%' + where + table_name not like 'apscheduler_%' and table_name not like 'gen_%' and table_name not in (select table_name from gen_table) """ else: - query_sql = """ - table_name as table_name, - table_comment as table_comment, - create_time as create_time, + query_sql = r""" + table_name as table_name, + table_comment as table_comment, + create_time as create_time, update_time as update_time - from + from information_schema.tables - where + where table_schema = (select database()) - and table_name not like 'apscheduler\_%' + and table_name not like 'apscheduler\_%' and table_name not like 'gen\_%' and table_name not in (select table_name from gen_table) """ @@ -174,19 +183,16 @@ class GenTableDao: query_sql += """and date_format(create_time, '%Y%m%d') >= date_format(:end_time, '%Y%m%d')""" query_sql += """order by create_time desc""" query = select( - text(query_sql).bindparams( - **{ - k: v - for k, v in query_object.model_dump(exclude_none=True, exclude={'page_num', 'page_size'}).items() - } - ) + text(query_sql).bindparams(**query_object.model_dump(exclude_none=True, exclude={'page_num', 'page_size'})) + ) + gen_db_table_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page ) - gen_db_table_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) return gen_db_table_list @classmethod - async def get_gen_db_table_list_by_names(cls, db: AsyncSession, table_names: List[str]): + async def get_gen_db_table_list_by_names(cls, db: AsyncSession, table_names: list[str]) -> Sequence[Row]: """ 根据业务表名称组获取数据库列表信息 @@ -197,29 +203,29 @@ class GenTableDao: if DataBaseConfig.db_type == 'postgresql': query_sql = """ select - table_name as table_name, - table_comment as table_comment, - create_time as create_time, - update_time as update_time - from + table_name as table_name, + table_comment as table_comment, + create_time as create_time, + update_time as update_time + from list_table - where - table_name not like 'qrtz_%' - and table_name not like 'gen_%' + where + table_name not like 'qrtz_%' + and table_name not like 'gen_%' and table_name = any(:table_names) """ else: - query_sql = """ + query_sql = r""" select - table_name as table_name, - table_comment as table_comment, - create_time as create_time, - update_time as update_time - from + table_name as table_name, + table_comment as table_comment, + create_time as create_time, + update_time as update_time + from information_schema.tables - where - table_name not like 'qrtz\_%' - and table_name not like 'gen\_%' + where + table_name not like 'qrtz\_%' + and table_name not like 'gen\_%' and table_schema = (select database()) and table_name in :table_names """ @@ -229,7 +235,7 @@ class GenTableDao: return gen_db_table_list @classmethod - async def add_gen_table_dao(cls, db: AsyncSession, gen_table: GenTableModel): + async def add_gen_table_dao(cls, db: AsyncSession, gen_table: GenTableModel) -> GenTable: """ 新增业务表数据库操作 @@ -244,7 +250,7 @@ class GenTableDao: return db_gen_table @classmethod - async def edit_gen_table_dao(cls, db: AsyncSession, gen_table: dict): + async def edit_gen_table_dao(cls, db: AsyncSession, gen_table: dict) -> None: """ 编辑业务表数据库操作 @@ -255,7 +261,7 @@ class GenTableDao: await db.execute(update(GenTable), [GenTableBaseModel(**gen_table).model_dump()]) @classmethod - async def delete_gen_table_dao(cls, db: AsyncSession, gen_table: GenTableModel): + async def delete_gen_table_dao(cls, db: AsyncSession, gen_table: GenTableModel) -> None: """ 删除业务表数据库操作 @@ -272,7 +278,7 @@ class GenTableColumnDao: """ @classmethod - async def get_gen_table_column_list_by_table_id(cls, db: AsyncSession, table_id: int): + async def get_gen_table_column_list_by_table_id(cls, db: AsyncSession, table_id: int) -> GenTableColumn: """ 根据业务表id获取需要生成的业务表字段列表信息 @@ -293,7 +299,7 @@ class GenTableColumnDao: return gen_table_column_list @classmethod - async def get_gen_db_table_columns_by_name(cls, db: AsyncSession, table_name: str): + async def get_gen_db_table_columns_by_name(cls, db: AsyncSession, table_name: str) -> Sequence[Row]: """ 根据业务表名称获取业务表字段列表信息 @@ -312,29 +318,29 @@ class GenTableColumnDao: """ else: query_sql = """ - select + select column_name as column_name, - case - when is_nullable = 'no' and column_key != 'PRI' then '1' - else '0' + case + when is_nullable = 'no' and column_key != 'PRI' then '1' + else '0' end as is_required, - case - when column_key = 'PRI' then '1' - else '0' + case + when column_key = 'PRI' then '1' + else '0' end as is_pk, ordinal_position as sort, column_comment as column_comment, - case - when extra = 'auto_increment' then '1' - else '0' + case + when extra = 'auto_increment' then '1' + else '0' end as is_increment, column_type as column_type - from + from information_schema.columns - where - table_schema = (select database()) + where + table_schema = (select database()) and table_name = :table_name - order by + order by ordinal_position """ query = text(query_sql).bindparams(table_name=table_name) @@ -343,7 +349,7 @@ class GenTableColumnDao: return gen_db_table_columns @classmethod - async def add_gen_table_column_dao(cls, db: AsyncSession, gen_table_column: GenTableColumnModel): + async def add_gen_table_column_dao(cls, db: AsyncSession, gen_table_column: GenTableColumnModel) -> GenTableColumn: """ 新增业务表字段数据库操作 @@ -360,7 +366,7 @@ class GenTableColumnDao: return db_gen_table_column @classmethod - async def edit_gen_table_column_dao(cls, db: AsyncSession, gen_table_column: dict): + async def edit_gen_table_column_dao(cls, db: AsyncSession, gen_table_column: dict) -> None: """ 编辑业务表字段数据库操作 @@ -371,7 +377,9 @@ class GenTableColumnDao: await db.execute(update(GenTableColumn), [GenTableColumnBaseModel(**gen_table_column).model_dump()]) @classmethod - async def delete_gen_table_column_by_table_id_dao(cls, db: AsyncSession, gen_table_column: GenTableColumnModel): + async def delete_gen_table_column_by_table_id_dao( + cls, db: AsyncSession, gen_table_column: GenTableColumnModel + ) -> None: """ 通过业务表id删除业务表字段数据库操作 @@ -382,7 +390,9 @@ class GenTableColumnDao: await db.execute(delete(GenTableColumn).where(GenTableColumn.table_id.in_([gen_table_column.table_id]))) @classmethod - async def delete_gen_table_column_by_column_id_dao(cls, db: AsyncSession, gen_table_column: GenTableColumnModel): + async def delete_gen_table_column_by_column_id_dao( + cls, db: AsyncSession, gen_table_column: GenTableColumnModel + ) -> None: """ 通过业务字段id删除业务表字段数据库操作 diff --git a/ruoyi-fastapi-backend/module_generator/entity/do/gen_do.py b/ruoyi-fastapi-backend/module_generator/entity/do/gen_do.py index edd62f6..6f9e020 100644 --- a/ruoyi-fastapi-backend/module_generator/entity/do/gen_do.py +++ b/ruoyi-fastapi-backend/module_generator/entity/do/gen_do.py @@ -1,6 +1,8 @@ from datetime import datetime -from sqlalchemy import BigInteger, CHAR, Column, DateTime, ForeignKey, Integer, String + +from sqlalchemy import CHAR, BigInteger, Column, DateTime, ForeignKey, Integer, String from sqlalchemy.orm import relationship + from config.database import Base from config.env import DataBaseConfig from utils.common_util import SqlalchemyUtil diff --git a/ruoyi-fastapi-backend/module_generator/entity/vo/gen_vo.py b/ruoyi-fastapi-backend/module_generator/entity/vo/gen_vo.py index e5d7917..d821287 100644 --- a/ruoyi-fastapi-backend/module_generator/entity/vo/gen_vo.py +++ b/ruoyi-fastapi-backend/module_generator/entity/vo/gen_vo.py @@ -1,10 +1,11 @@ from datetime import datetime +from typing import Literal, Optional, Union + from pydantic import BaseModel, ConfigDict, Field, model_validator from pydantic.alias_generators import to_camel from pydantic_validation_decorator import NotBlank -from typing import List, Literal, Optional + from config.constant import GenConstant -from module_admin.annotation.pydantic_annotation import as_query from utils.string_util import StringUtil @@ -38,38 +39,38 @@ class GenTableBaseModel(BaseModel): remark: Optional[str] = Field(default=None, description='备注') @NotBlank(field_name='table_name', message='表名称不能为空') - def get_table_name(self): + def get_table_name(self) -> Union[str, None]: return self.table_name @NotBlank(field_name='table_comment', message='表描述不能为空') - def get_table_comment(self): + def get_table_comment(self) -> Union[str, None]: return self.table_comment @NotBlank(field_name='class_name', message='实体类名称不能为空') - def get_class_name(self): + def get_class_name(self) -> Union[str, None]: return self.class_name @NotBlank(field_name='package_name', message='生成包路径不能为空') - def get_package_name(self): + def get_package_name(self) -> Union[str, None]: return self.package_name @NotBlank(field_name='module_name', message='生成模块名不能为空') - def get_module_name(self): + def get_module_name(self) -> Union[str, None]: return self.module_name @NotBlank(field_name='business_name', message='生成业务名不能为空') - def get_business_name(self): + def get_business_name(self) -> Union[str, None]: return self.business_name @NotBlank(field_name='function_name', message='生成功能名不能为空') - def get_function_name(self): + def get_function_name(self) -> Union[str, None]: return self.function_name @NotBlank(field_name='function_author', message='生成功能作者不能为空') - def get_function_author(self): + def get_function_author(self) -> Union[str, None]: return self.function_author - def validate_fields(self): + def validate_fields(self) -> None: self.get_table_name() self.get_table_comment() self.get_class_name() @@ -87,7 +88,7 @@ class GenTableModel(GenTableBaseModel): pk_column: Optional['GenTableColumnModel'] = Field(default=None, description='主键信息') sub_table: Optional['GenTableModel'] = Field(default=None, description='子表信息') - columns: Optional[List['GenTableColumnModel']] = Field(default=None, description='表列信息') + columns: Optional[list['GenTableColumnModel']] = Field(default=None, description='表列信息') tree_code: Optional[str] = Field(default=None, description='树编码字段') tree_parent_code: Optional[str] = Field(default=None, description='树父编码字段') tree_name: Optional[str] = Field(default=None, description='树名称字段') @@ -99,9 +100,9 @@ class GenTableModel(GenTableBaseModel): @model_validator(mode='after') def check_some_is(self) -> 'GenTableModel': - self.sub = True if self.tpl_category and self.tpl_category == GenConstant.TPL_SUB else False - self.tree = True if self.tpl_category and self.tpl_category == GenConstant.TPL_TREE else False - self.crud = True if self.tpl_category and self.tpl_category == GenConstant.TPL_CRUD else False + self.sub = bool(self.tpl_category and self.tpl_category == GenConstant.TPL_SUB) + self.tree = bool(self.tpl_category and self.tpl_category == GenConstant.TPL_TREE) + self.crud = bool(self.tpl_category and self.tpl_category == GenConstant.TPL_CRUD) return self @@ -135,7 +136,6 @@ class GenTableQueryModel(GenTableBaseModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class GenTablePageQueryModel(GenTableQueryModel): """ 代码生成业务表分页查询模型 @@ -189,10 +189,10 @@ class GenTableColumnBaseModel(BaseModel): update_time: Optional[datetime] = Field(default=None, description='更新时间') @NotBlank(field_name='python_field', message='Python属性不能为空') - def get_python_field(self): + def get_python_field(self) -> Union[str, None]: return self.python_field - def validate_fields(self): + def validate_fields(self) -> None: self.get_python_field() @@ -216,21 +216,19 @@ class GenTableColumnModel(GenTableColumnBaseModel): @model_validator(mode='after') def check_some_is(self) -> 'GenTableModel': self.cap_python_field = self.python_field[0].upper() + self.python_field[1:] if self.python_field else None - self.pk = True if self.is_pk and self.is_pk == '1' else False - self.increment = True if self.is_increment and self.is_increment == '1' else False - self.required = True if self.is_required and self.is_required == '1' else False - self.unique = True if self.is_unique and self.is_unique == '1' else False - self.insert = True if self.is_insert and self.is_insert == '1' else False - self.edit = True if self.is_edit and self.is_edit == '1' else False - self.list = True if self.is_list and self.is_list == '1' else False - self.query = True if self.is_query and self.is_query == '1' else False - self.super_column = ( - True - if StringUtil.equals_any_ignore_case(self.python_field, GenConstant.TREE_ENTITY + GenConstant.BASE_ENTITY) - else False + self.pk = self.is_pk and self.is_pk == '1' + self.increment = bool(self.is_increment and self.is_increment == '1') + self.required = bool(self.is_required and self.is_required == '1') + self.unique = bool(self.is_unique and self.is_unique == '1') + self.insert = bool(self.is_insert and self.is_insert == '1') + self.edit = bool(self.is_edit and self.is_edit == '1') + self.list = bool(self.is_list and self.is_list == '1') + self.query = bool(self.is_query and self.is_query == '1') + self.super_column = bool( + StringUtil.equals_any_ignore_case(self.python_field, GenConstant.TREE_ENTITY + GenConstant.BASE_ENTITY) ) - self.usable_column = ( - True if StringUtil.equals_any_ignore_case(self.python_field, ['parentId', 'orderNum', 'remark']) else False + self.usable_column = bool( + StringUtil.equals_any_ignore_case(self.python_field, ['parentId', 'orderNum', 'remark']) ) return self @@ -244,7 +242,6 @@ class GenTableColumnQueryModel(GenTableColumnBaseModel): end_time: Optional[str] = Field(default=None, description='结束时间') -@as_query class GenTableColumnPageQueryModel(GenTableColumnQueryModel): """ 代码生成业务表字段分页查询模型 diff --git a/ruoyi-fastapi-backend/module_generator/service/gen_service.py b/ruoyi-fastapi-backend/module_generator/service/gen_service.py index aec0bbf..a77cd85 100644 --- a/ruoyi-fastapi-backend/module_generator/service/gen_service.py +++ b/ruoyi-fastapi-backend/module_generator/service/gen_service.py @@ -3,15 +3,19 @@ import json import os import zipfile from datetime import datetime +from typing import Any, Union + +import aiofiles from sqlalchemy.ext.asyncio import AsyncSession from sqlglot import parse as sqlglot_parse from sqlglot.expressions import Add, Alter, Create, Delete, Drop, Expression, Insert, Table, TruncateTable, Update -from typing import List + from config.constant import GenConstant from config.env import DataBaseConfig, GenConfig from exceptions.exception import ServiceException from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.entity.vo.user_vo import CurrentUserModel +from module_generator.dao.gen_dao import GenTableColumnDao, GenTableDao from module_generator.entity.vo.gen_vo import ( DeleteGenTableModel, EditGenTableModel, @@ -19,9 +23,9 @@ from module_generator.entity.vo.gen_vo import ( GenTableModel, GenTablePageQueryModel, ) -from module_generator.dao.gen_dao import GenTableColumnDao, GenTableDao from utils.common_util import CamelCaseUtil from utils.gen_util import GenUtils +from utils.page_util import PageResponseModel from utils.template_util import TemplateInitializer, TemplateUtils @@ -33,7 +37,7 @@ class GenTableService: @classmethod async def get_gen_table_list_services( cls, query_db: AsyncSession, query_object: GenTablePageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取代码生成业务表列表信息service @@ -49,7 +53,7 @@ class GenTableService: @classmethod async def get_gen_db_table_list_services( cls, query_db: AsyncSession, query_object: GenTablePageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取数据库列表信息service @@ -63,7 +67,9 @@ class GenTableService: return gen_db_table_list_result @classmethod - async def get_gen_db_table_list_by_name_services(cls, query_db: AsyncSession, table_names: List[str]): + async def get_gen_db_table_list_by_name_services( + cls, query_db: AsyncSession, table_names: list[str] + ) -> list[GenTableModel]: """ 根据表名称组获取数据库列表信息service @@ -77,8 +83,8 @@ class GenTableService: @classmethod async def import_gen_table_services( - cls, query_db: AsyncSession, gen_table_list: List[GenTableModel], current_user: CurrentUserModel - ): + cls, query_db: AsyncSession, gen_table_list: list[GenTableModel], current_user: CurrentUserModel + ) -> CrudResponseModel: """ 导入表结构service @@ -105,10 +111,10 @@ class GenTableService: return CrudResponseModel(is_success=True, message='导入成功') except Exception as e: await query_db.rollback() - raise ServiceException(message=f'导入失败, {str(e)}') + raise ServiceException(message=f'导入失败, {e}') from e @classmethod - async def edit_gen_table_services(cls, query_db: AsyncSession, page_object: EditGenTableModel): + async def edit_gen_table_services(cls, query_db: AsyncSession, page_object: EditGenTableModel) -> CrudResponseModel: """ 编辑业务表信息service @@ -137,7 +143,9 @@ class GenTableService: raise ServiceException(message='业务表不存在') @classmethod - async def delete_gen_table_services(cls, query_db: AsyncSession, page_object: DeleteGenTableModel): + async def delete_gen_table_services( + cls, query_db: AsyncSession, page_object: DeleteGenTableModel + ) -> CrudResponseModel: """ 删除业务表信息service @@ -162,7 +170,7 @@ class GenTableService: raise ServiceException(message='传入业务表id为空') @classmethod - async def get_gen_table_by_id_services(cls, query_db: AsyncSession, table_id: int): + async def get_gen_table_by_id_services(cls, query_db: AsyncSession, table_id: int) -> GenTableModel: """ 获取需要生成的业务表详细信息service @@ -176,7 +184,7 @@ class GenTableService: return result @classmethod - async def get_gen_table_all_services(cls, query_db: AsyncSession): + async def get_gen_table_all_services(cls, query_db: AsyncSession) -> list[GenTableModel]: """ 获取所有业务表信息service @@ -189,7 +197,9 @@ class GenTableService: return result @classmethod - async def create_table_services(cls, query_db: AsyncSession, sql: str, current_user: CurrentUserModel): + async def create_table_services( + cls, query_db: AsyncSession, sql: str, current_user: CurrentUserModel + ) -> CrudResponseModel: """ 创建表结构service @@ -208,12 +218,12 @@ class GenTableService: return CrudResponseModel(is_success=True, message='创建表结构成功') except Exception as e: - raise ServiceException(message=f'创建表结构异常,详细错误信息:{str(e)}') + raise ServiceException(message=f'创建表结构异常,详细错误信息:{e}') from e else: raise ServiceException(message='建表语句不合法') @classmethod - def __is_valid_create_table(cls, sql_statements: List[Expression]): + def __is_valid_create_table(cls, sql_statements: list[Expression]) -> bool: """ 校验sql语句是否为合法的建表语句 @@ -228,26 +238,24 @@ class GenTableService: ) for sql_statement in sql_statements ] - if not any(validate_create) or any(validate_forbidden_keywords): - return False - return True + return not (not any(validate_create) or any(validate_forbidden_keywords)) @classmethod - def __get_table_names(cls, sql_statements: List[Expression]): + def __get_table_names(cls, sql_statements: list[Expression]) -> list[str]: """ 获取sql语句中所有的建表表名 :param sql_statements: sql语句的ast列表 :return: 建表表名列表 """ - table_names = [] - for sql_statement in sql_statements: - if isinstance(sql_statement, Create): - table_names.append(sql_statement.find(Table).name) + table_names = [ + sql_statement.find(Table).name for sql_statement in sql_statements if isinstance(sql_statement, Create) + ] + return table_names @classmethod - async def preview_code_services(cls, query_db: AsyncSession, table_id: int): + async def preview_code_services(cls, query_db: AsyncSession, table_id: int) -> dict[str, str]: """ 预览代码service @@ -270,7 +278,7 @@ class GenTableService: return preview_code_result @classmethod - async def generate_code_services(cls, query_db: AsyncSession, table_name: str): + async def generate_code_services(cls, query_db: AsyncSession, table_name: str) -> CrudResponseModel: """ 生成代码至指定路径service @@ -280,22 +288,20 @@ class GenTableService: """ env = TemplateInitializer.init_jinja2() render_info = await cls.__get_gen_render_info(query_db, table_name) - for template in render_info[0]: - try: + try: + for template in render_info[0]: render_content = env.get_template(template).render(**render_info[2]) gen_path = cls.__get_gen_path(render_info[3], template) os.makedirs(os.path.dirname(gen_path), exist_ok=True) - with open(gen_path, 'w', encoding='utf-8') as f: - f.write(render_content) - except Exception as e: - raise ServiceException( - message=f'渲染模板失败,表名:{render_info[3].table_name},详细错误信息:{str(e)}' - ) + async with aiofiles.open(gen_path, 'w', encoding='utf-8') as f: + await f.write(render_content) + except Exception as e: + raise ServiceException(message=f'渲染模板失败,表名:{render_info[3].table_name},详细错误信息:{e}') from e return CrudResponseModel(is_success=True, message='生成代码成功') @classmethod - async def batch_gen_code_services(cls, query_db: AsyncSession, table_names: List[str]): + async def batch_gen_code_services(cls, query_db: AsyncSession, table_names: list[str]) -> bytes: """ 批量生成代码service @@ -317,7 +323,7 @@ class GenTableService: return zip_data @classmethod - async def __get_gen_render_info(cls, query_db: AsyncSession, table_name: str): + async def __get_gen_render_info(cls, query_db: AsyncSession, table_name: str) -> list: """ 获取生成代码渲染模板相关信息 @@ -337,7 +343,7 @@ class GenTableService: return [template_list, output_files, context, gen_table] @classmethod - def __get_gen_path(cls, gen_table: GenTableModel, template: str): + def __get_gen_path(cls, gen_table: GenTableModel, template: str) -> str: """ 根据GenTableModel对象和模板名称生成路径 @@ -348,11 +354,11 @@ class GenTableService: gen_path = gen_table.gen_path if gen_path == '/': return os.path.join(os.getcwd(), GenConfig.GEN_PATH, TemplateUtils.get_file_name(template, gen_table)) - else: - return os.path.join(gen_path, TemplateUtils.get_file_name(template, gen_table)) + + return os.path.join(gen_path, TemplateUtils.get_file_name(template, gen_table)) @classmethod - async def sync_db_services(cls, query_db: AsyncSession, table_name: str): + async def sync_db_services(cls, query_db: AsyncSession, table_name: str) -> CrudResponseModel: """ 同步数据库service @@ -402,7 +408,7 @@ class GenTableService: raise e @classmethod - async def set_sub_table(cls, query_db: AsyncSession, gen_table: GenTableModel): + async def set_sub_table(cls, query_db: AsyncSession, gen_table: GenTableModel) -> None: """ 设置主子表信息 @@ -415,7 +421,7 @@ class GenTableService: gen_table.sub_table = GenTableModel(**CamelCaseUtil.transform_result(sub_table)) @classmethod - async def set_pk_column(cls, gen_table: GenTableModel): + async def set_pk_column(cls, gen_table: GenTableModel) -> None: """ 设置主键列信息 @@ -437,7 +443,7 @@ class GenTableService: gen_table.sub_table.pk_column = gen_table.sub_table.columns[0] @classmethod - async def set_table_from_options(cls, gen_table: GenTableModel): + async def set_table_from_options(cls, gen_table: GenTableModel) -> GenTableModel: """ 设置代码生成其他选项值 @@ -455,7 +461,7 @@ class GenTableService: return gen_table @classmethod - async def validate_edit(cls, edit_gen_table: EditGenTableModel): + async def validate_edit(cls, edit_gen_table: EditGenTableModel) -> None: """ 编辑保存参数校验 @@ -466,14 +472,14 @@ class GenTableService: if GenConstant.TREE_CODE not in params_obj: raise ServiceException(message='树编码字段不能为空') - elif GenConstant.TREE_PARENT_CODE not in params_obj: + if GenConstant.TREE_PARENT_CODE not in params_obj: raise ServiceException(message='树父编码字段不能为空') - elif GenConstant.TREE_NAME not in params_obj: + if GenConstant.TREE_NAME not in params_obj: raise ServiceException(message='树名称字段不能为空') - elif edit_gen_table.tpl_category == GenConstant.TPL_SUB: + if edit_gen_table.tpl_category == GenConstant.TPL_SUB: if not edit_gen_table.sub_table_name: raise ServiceException(message='关联子表的表名不能为空') - elif not edit_gen_table.sub_table_fk_name: + if not edit_gen_table.sub_table_fk_name: raise ServiceException(message='子表关联的外键名不能为空') @@ -483,7 +489,9 @@ class GenTableColumnService: """ @classmethod - async def get_gen_table_column_list_by_table_id_services(cls, query_db: AsyncSession, table_id: int): + async def get_gen_table_column_list_by_table_id_services( + cls, query_db: AsyncSession, table_id: int + ) -> list[GenTableColumnModel]: """ 获取业务表字段列表信息service diff --git a/ruoyi-fastapi-backend/module_generator/templates/python/controller.py.jinja2 b/ruoyi-fastapi-backend/module_generator/templates/python/controller.py.jinja2 index 13cc466..fa9de0e 100644 --- a/ruoyi-fastapi-backend/module_generator/templates/python/controller.py.jinja2 +++ b/ruoyi-fastapi-backend/module_generator/templates/python/controller.py.jinja2 @@ -1,5 +1,7 @@ {% set pkField = pkColumn.python_field %} {% set pk_field = pkColumn.python_field | camel_to_snake %} +{% set pkParentheseIndex = pkColumn.column_comment.find("(") %} +{% set pk_field_comment = pkColumn.column_comment[:pkParentheseIndex] if pkParentheseIndex != -1 else pkColumn.column_comment %} {% set need_import_datetime = namespace(has_datetime=False) %} {% for column in columns %} {% if column.python_field in ["createTime", "updatetime"] %} @@ -9,9 +11,12 @@ {% if need_import_datetime.has_datetime %} from datetime import datetime {% endif %} -from fastapi import APIRouter, Depends, Form, Request +from typing import Annotated + +from fastapi import APIRouter, Depends, Form, Path, Query, Request, Response 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 @@ -26,17 +31,17 @@ from utils.page_util import PageResponseModel from utils.response_util import ResponseUtil -{{ businessName }}Controller = APIRouter(prefix='/{{ moduleName }}/{{ businessName }}', dependencies=[Depends(LoginService.get_current_user)]) +{{ businessName }}_controller = APIRouter(prefix='/{{ moduleName }}/{{ businessName }}', dependencies=[Depends(LoginService.get_current_user)]) -@{{ businessName }}Controller.get( +@{{ businessName }}_controller.get( '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:list'))] ) async def get_{{ moduleName }}_{{ businessName }}_list( request: Request, - {% if table.crud or table.sub %}{{ businessName }}_page_query{% elif table.tree %}{{ businessName }}_query{% endif %}: {{ BusinessName }}PageQueryModel = Depends({{ BusinessName }}PageQueryModel.as_query), - query_db: AsyncSession = Depends(get_db), -): + {% if table.crud or table.sub %}{{ businessName }}_page_query{% elif table.tree %}{{ businessName }}_query{% endif %}: Annotated[{{ BusinessName }}PageQueryModel, Query()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: {% if table.crud or table.sub %} # 获取分页数据 {{ businessName }}_page_query_result = await {{ BusinessName }}Service.get_{{ businessName }}_list_services(query_db, {{ businessName }}_page_query, is_page=True) @@ -51,15 +56,15 @@ async def get_{{ moduleName }}_{{ businessName }}_list( {% endif %} -@{{ businessName }}Controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:add'))]) +@{{ businessName }}_controller.post('', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:add'))]) @ValidateFields(validate_model='add_{{ businessName }}') @Log(title='{{ functionName }}', business_type=BusinessType.INSERT) async def add_{{ moduleName }}_{{ businessName }}( request: Request, add_{{ businessName }}: {{ BusinessName }}Model, - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: {% for column in columns %} {% if column.python_field == "createBy" %} add_{{ businessName }}.create_by = current_user.user.user_name @@ -77,15 +82,15 @@ async def add_{{ moduleName }}_{{ businessName }}( return ResponseUtil.success(msg=add_{{ businessName }}_result.message) -@{{ businessName }}Controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:edit'))]) +@{{ businessName }}_controller.put('', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:edit'))]) @ValidateFields(validate_model='edit_{{ businessName }}') @Log(title='{{ functionName }}', business_type=BusinessType.UPDATE) async def edit_{{ moduleName }}_{{ businessName }}( request: Request, edit_{{ businessName }}: {{ BusinessName }}Model, - query_db: AsyncSession = Depends(get_db), - current_user: CurrentUserModel = Depends(LoginService.get_current_user), -): + query_db: Annotated[AsyncSession, Depends(get_db)], + current_user: Annotated[CurrentUserModel, Depends(LoginService.get_current_user)], +) -> Response: {% for column in columns %} {% if column.python_field == "updateBy" %} edit_{{ businessName }}.update_by = current_user.user.user_name @@ -99,9 +104,13 @@ async def edit_{{ moduleName }}_{{ businessName }}( return ResponseUtil.success(msg=edit_{{ businessName }}_result.message) -@{{ businessName }}Controller.delete('/{% raw %}{{% endraw %}{{ pk_field }}s{% raw %}}{% endraw %}', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:remove'))]) +@{{ businessName }}_controller.delete('/{% raw %}{{% endraw %}{{ pk_field }}s{% raw %}}{% endraw %}', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:remove'))]) @Log(title='{{ functionName }}', business_type=BusinessType.DELETE) -async def delete_{{ moduleName }}_{{ businessName }}(request: Request, {{ pk_field }}s: str, query_db: AsyncSession = Depends(get_db)): +async def delete_{{ moduleName }}_{{ businessName }}( + request: Request, + {{ pk_field }}s: Annotated[str, Path(description='需要删除的{{ pk_field_comment }}')], + Annotated[AsyncSession, Depends(get_db)], +) -> Response: delete_{{ businessName }} = Delete{{ BusinessName }}Model({{ pkField }}s={{ pk_field }}s) delete_{{ businessName }}_result = await {{ BusinessName }}Service.delete_{{ businessName }}_services(query_db, delete_{{ businessName }}) logger.info(delete_{{ businessName }}_result.message) @@ -109,23 +118,27 @@ async def delete_{{ moduleName }}_{{ businessName }}(request: Request, {{ pk_fie return ResponseUtil.success(msg=delete_{{ businessName }}_result.message) -@{{ businessName }}Controller.get( +@{{ businessName }}_controller.get( '/{% raw %}{{% endraw %}{{ pk_field }}{% raw %}}{% endraw %}', response_model={{ BusinessName }}Model, dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:query'))] ) -async def query_detail_{{ moduleName }}_{{ businessName }}(request: Request, {{ pk_field }}: int, query_db: AsyncSession = Depends(get_db)): +async def query_detail_{{ moduleName }}_{{ businessName }}( + request: Request, + {{ pk_field }}: Annotated[{{ pkColumn.python_type }}, Path(description='{{ pk_field_comment }}')], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: {{ businessName }}_detail_result = await {{ BusinessName }}Service.{{ businessName }}_detail_services(query_db, {{ pk_field }}) logger.info(f'获取{{ pk_field }}为{% raw %}{{% endraw %}{{ pk_field }}{% raw %}}{% endraw %}的信息成功') return ResponseUtil.success(data={{ businessName }}_detail_result) -@{{ businessName }}Controller.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:export'))]) +@{{ businessName }}_controller.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:export'))]) @Log(title='{{ functionName }}', business_type=BusinessType.EXPORT) async def export_{{ moduleName }}_{{ businessName }}_list( request: Request, - {{ businessName }}_page_query: {{ BusinessName }}PageQueryModel = Form(), - query_db: AsyncSession = Depends(get_db), -): + {{ businessName }}_page_query: Annotated[{{ BusinessName }}PageQueryModel, Form()], + query_db: Annotated[AsyncSession, Depends(get_db)], +) -> Response: # 获取全量数据 {{ businessName }}_query_result = await {{ BusinessName }}Service.get_{{ businessName }}_list_services(query_db, {{ businessName }}_page_query, is_page=False) {{ businessName }}_export_result = await {{ BusinessName }}Service.export_{{ businessName }}_list_services({% if dicts %}request, {% endif %}{{ businessName }}_query_result) diff --git a/ruoyi-fastapi-backend/module_generator/templates/python/dao.py.jinja2 b/ruoyi-fastapi-backend/module_generator/templates/python/dao.py.jinja2 index 3b186c5..477ee84 100644 --- a/ruoyi-fastapi-backend/module_generator/templates/python/dao.py.jinja2 +++ b/ruoyi-fastapi-backend/module_generator/templates/python/dao.py.jinja2 @@ -7,11 +7,14 @@ from datetime import datetime, time {% endif %} {% endfor %} +from typing import Any, Union + from sqlalchemy import delete, select, update from sqlalchemy.ext.asyncio import AsyncSession {% if table.sub %} from sqlalchemy.orm import selectinload {% endif %} + {% if table.sub %} from {{ packageName }}.entity.do.{{ businessName }}_do import {{ ClassName }}, {{ subClassName }} from {{ packageName }}.entity.vo.{{ businessName }}_vo import {{ BusinessName }}Model, {{ BusinessName }}PageQueryModel, {{ subTable.business_name | capitalize }}Model @@ -19,7 +22,7 @@ from {{ packageName }}.entity.vo.{{ businessName }}_vo import {{ BusinessName }} from {{ packageName }}.entity.do.{{ businessName }}_do import {{ ClassName }} from {{ packageName }}.entity.vo.{{ businessName }}_vo import {{ BusinessName }}Model, {{ BusinessName }}PageQueryModel {% endif %} -from utils.page_util import PageUtil +from utils.page_util import PageResponseModel, PageUtil class {{ BusinessName }}Dao: @@ -28,7 +31,7 @@ class {{ BusinessName }}Dao: """ @classmethod - async def get_{{ businessName }}_detail_by_id(cls, db: AsyncSession, {{ pk_field }}: int): + async def get_{{ businessName }}_detail_by_id(cls, db: AsyncSession, {{ pk_field }}: int) -> Union[{{ ClassName }}, None]: """ 根据{{ pk_field_comment }}获取{{ functionName }}详细信息 @@ -57,7 +60,7 @@ class {{ BusinessName }}Dao: return {{ businessName }}_info @classmethod - async def get_{{ businessName }}_detail_by_info(cls, db: AsyncSession, {{ businessName }}: {{ BusinessName }}Model): + async def get_{{ businessName }}_detail_by_info(cls, db: AsyncSession, {{ businessName }}: {{ BusinessName }}Model) -> Union[{{ ClassName }}, None]: """ 根据{{ functionName }}参数获取{{ functionName }}信息 @@ -84,7 +87,9 @@ class {{ BusinessName }}Dao: return {{ businessName }}_info @classmethod - async def get_{{ businessName }}_list(cls, db: AsyncSession, query_object: {{ BusinessName }}PageQueryModel, is_page: bool = False): + async def get_{{ businessName }}_list( + cls, db: AsyncSession, query_object: {{ BusinessName }}PageQueryModel, is_page: bool = False + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 根据查询参数获取{{ functionName }}列表信息 @@ -132,12 +137,14 @@ class {{ BusinessName }}Dao: .order_by({{ ClassName }}.{{ pk_field }}) .distinct() ) - {{ businessName }}_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page) + {{ businessName }}_list: Union[PageResponseModel, list[dict[str, Any]]] = await PageUtil.paginate( + db, query, query_object.page_num, query_object.page_size, is_page + ) return {{ businessName }}_list @classmethod - async def add_{{ businessName }}_dao(cls, db: AsyncSession, {{ businessName }}: {{ BusinessName }}Model): + async def add_{{ businessName }}_dao(cls, db: AsyncSession, {{ businessName }}: {{ BusinessName }}Model) -> {{ ClassName }}: """ 新增{{ functionName }}数据库操作 @@ -152,7 +159,7 @@ class {{ BusinessName }}Dao: return db_{{ businessName }} @classmethod - async def edit_{{ businessName }}_dao(cls, db: AsyncSession, {{ businessName }}: dict): + async def edit_{{ businessName }}_dao(cls, db: AsyncSession, {{ businessName }}: dict) -> None: """ 编辑{{ functionName }}数据库操作 @@ -163,7 +170,7 @@ class {{ BusinessName }}Dao: await db.execute(update({{ ClassName }}), [{{ businessName }}]) @classmethod - async def delete_{{ businessName }}_dao(cls, db: AsyncSession, {{ businessName }}: {{ BusinessName }}Model): + async def delete_{{ businessName }}_dao(cls, db: AsyncSession, {{ businessName }}: {{ BusinessName }}Model) -> None: """ 删除{{ functionName }}数据库操作 @@ -175,7 +182,7 @@ class {{ BusinessName }}Dao: {% if table.sub %} @classmethod - async def add_{{ subTable.business_name }}_dao(cls, db: AsyncSession, {{ subTable.business_name }}: {{ subTable.business_name | capitalize }}Model): + async def add_{{ subTable.business_name }}_dao(cls, db: AsyncSession, {{ subTable.business_name }}: {{ subTable.business_name | capitalize }}Model) -> {{ subClassName }}: """ 新增{{ subTable.function_name }}数据库操作 @@ -190,7 +197,7 @@ class {{ BusinessName }}Dao: return db_{{ subTable.business_name }} @classmethod - async def edit_{{ subTable.business_name }}_dao(cls, db: AsyncSession, {{ subTable.business_name }}: dict): + async def edit_{{ subTable.business_name }}_dao(cls, db: AsyncSession, {{ subTable.business_name }}: dict) -> None: """ 编辑{{ subTable.function_name }}数据库操作 @@ -201,7 +208,7 @@ class {{ BusinessName }}Dao: await db.execute(update({{ subClassName }}), [{{ subTable.business_name }}]) @classmethod - async def delete_{{ subTable.business_name }}_dao(cls, db: AsyncSession, {{ subTable.business_name }}: {{ subTable.business_name | capitalize }}Model): + async def delete_{{ subTable.business_name }}_dao(cls, db: AsyncSession, {{ subTable.business_name }}: {{ subTable.business_name | capitalize }}Model) -> None: """ 删除{{ subTable.function_name }}数据库操作 diff --git a/ruoyi-fastapi-backend/module_generator/templates/python/do.py.jinja2 b/ruoyi-fastapi-backend/module_generator/templates/python/do.py.jinja2 index c7ea757..76137e3 100644 --- a/ruoyi-fastapi-backend/module_generator/templates/python/do.py.jinja2 +++ b/ruoyi-fastapi-backend/module_generator/templates/python/do.py.jinja2 @@ -4,6 +4,7 @@ {% if table.sub %} from sqlalchemy.orm import relationship {% endif %} + from config.database import Base diff --git a/ruoyi-fastapi-backend/module_generator/templates/python/service.py.jinja2 b/ruoyi-fastapi-backend/module_generator/templates/python/service.py.jinja2 index 5726c5d..a75563e 100644 --- a/ruoyi-fastapi-backend/module_generator/templates/python/service.py.jinja2 +++ b/ruoyi-fastapi-backend/module_generator/templates/python/service.py.jinja2 @@ -2,21 +2,24 @@ {% set pk_field = pkColumn.python_field | camel_to_snake %} {% set pkParentheseIndex = pkColumn.column_comment.find("(") %} {% set pk_field_comment = pkColumn.column_comment[:pkParentheseIndex] if pkParentheseIndex != -1 else pkColumn.column_comment %} +from typing import Any, Union + {% if dicts %} from fastapi import Request {% endif %} from sqlalchemy.ext.asyncio import AsyncSession -from typing import List + from config.constant import CommonConstant from exceptions.exception import ServiceException +from {{ packageName }}.dao.{{ businessName }}_dao import {{ BusinessName }}Dao from module_admin.entity.vo.common_vo import CrudResponseModel +from {{ packageName }}.entity.vo.{{ businessName }}_vo import Delete{{ BusinessName }}Model, {{ BusinessName }}Model, {{ BusinessName }}PageQueryModel {% if dicts %} from module_admin.service.dict_service import DictDataService {% endif %} -from {{ packageName }}.dao.{{ businessName }}_dao import {{ BusinessName }}Dao -from {{ packageName }}.entity.vo.{{ businessName }}_vo import Delete{{ BusinessName }}Model, {{ BusinessName }}Model, {{ BusinessName }}PageQueryModel from utils.common_util import CamelCaseUtil from utils.excel_util import ExcelUtil +from utils.page_util import PageResponseModel class {{ BusinessName }}Service: @@ -27,7 +30,7 @@ class {{ BusinessName }}Service: @classmethod async def get_{{ businessName }}_list_services( cls, query_db: AsyncSession, query_object: {{ BusinessName }}PageQueryModel, is_page: bool = False - ): + ) -> Union[PageResponseModel, list[dict[str, Any]]]: """ 获取{{ functionName }}列表信息service @@ -45,7 +48,7 @@ class {{ BusinessName }}Service: {% set comment = column.column_comment[:parentheseIndex] if parentheseIndex != -1 else column.column_comment %} {% if column.unique %} @classmethod - async def check_{{ column.python_field | camel_to_snake }}_unique_services(cls, query_db: AsyncSession, page_object: {{ BusinessName }}Model): + async def check_{{ column.python_field | camel_to_snake }}_unique_services(cls, query_db: AsyncSession, page_object: {{ BusinessName }}Model) -> bool: """ 检查{{ comment }}是否唯一service @@ -63,7 +66,7 @@ class {{ BusinessName }}Service: {% endfor %} @classmethod - async def add_{{ businessName }}_services(cls, query_db: AsyncSession, page_object: {{ BusinessName }}Model): + async def add_{{ businessName }}_services(cls, query_db: AsyncSession, page_object: {{ BusinessName }}Model) -> CrudResponseModel: """ 新增{{ functionName }}信息service @@ -95,7 +98,7 @@ class {{ BusinessName }}Service: raise e @classmethod - async def edit_{{ businessName }}_services(cls, query_db: AsyncSession, page_object: {{ BusinessName }}Model): + async def edit_{{ businessName }}_services(cls, query_db: AsyncSession, page_object: {{ BusinessName }}Model) -> CrudResponseModel: """ 编辑{{ functionName }}信息service @@ -131,7 +134,7 @@ class {{ BusinessName }}Service: raise ServiceException(message='{{ functionName }}不存在') @classmethod - async def delete_{{ businessName }}_services(cls, query_db: AsyncSession, page_object: Delete{{ BusinessName }}Model): + async def delete_{{ businessName }}_services(cls, query_db: AsyncSession, page_object: Delete{{ BusinessName }}Model) -> CrudResponseModel: """ 删除{{ functionName }}信息service @@ -158,7 +161,7 @@ class {{ BusinessName }}Service: raise ServiceException(message='传入{{ pk_field_comment }}为空') @classmethod - async def {{ businessName }}_detail_services(cls, query_db: AsyncSession, {{ pk_field }}: int): + async def {{ businessName }}_detail_services(cls, query_db: AsyncSession, {{ pk_field }}: int) -> {{ BusinessName }}Model: """ 获取{{ functionName }}详细信息service @@ -167,15 +170,12 @@ class {{ BusinessName }}Service: :return: {{ pk_field_comment }}对应的信息 """ {{ businessName }} = await {{ BusinessName }}Dao.get_{{ businessName }}_detail_by_id(query_db, {{ pk_field }}={{ pk_field }}) - if {{ businessName }}: - result = {{ BusinessName }}Model(**CamelCaseUtil.transform_result({{ businessName }})) - else: - result = {{ BusinessName }}Model(**dict()) + result = {{ BusinessName }}Model(**CamelCaseUtil.transform_result({{ businessName }})) if {{ businessName }} else {{ BusinessName }}Model() return result @staticmethod - async def export_{{ businessName }}_list_services({% if dicts %}request: Request, {% endif %}{{ businessName }}_list: List): + async def export_{{ businessName }}_list_services({% if dicts %}request: Request, {% endif %}{{ businessName }}_list: list) -> bytes: """ 导出{{ functionName }}信息service @@ -195,13 +195,13 @@ class {{ BusinessName }}Service: {{ dict_type[1:-1] }}_list = await DictDataService.query_dict_data_list_from_cache_services( request.app.state.redis, dict_type={{ dict_type }} ) - {{ dict_type[1:-1] }}_option = [dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in {{ dict_type[1:-1] }}_list] + {{ dict_type[1:-1] }}_option = [{'label': item.get('dictLabel'), 'value': item.get('dictValue')} for item in {{ dict_type[1:-1] }}_list] {{ dict_type[1:-1] }}_option_dict = {item.get('value'): item for item in {{ dict_type[1:-1] }}_option} {% endfor %} for item in {{ businessName }}_list: {% for column in columns %} {% if column.dict_type %} - if str(item.get('{{ column.python_field }}')) in {{ column.dict_type }}_option_dict.keys(): + if str(item.get('{{ column.python_field }}')) in {{ column.dict_type }}_option_dict: item['{{ column.python_field }}'] = {{ column.dict_type }}_option_dict.get(str(item.get('{{ column.python_field }}'))).get('label') {% endif %} {% endfor %} diff --git a/ruoyi-fastapi-backend/module_generator/templates/python/vo.py.jinja2 b/ruoyi-fastapi-backend/module_generator/templates/python/vo.py.jinja2 index 47abbf5..f525d54 100644 --- a/ruoyi-fastapi-backend/module_generator/templates/python/vo.py.jinja2 +++ b/ruoyi-fastapi-backend/module_generator/templates/python/vo.py.jinja2 @@ -23,17 +23,17 @@ {% for vo_import in voImportList %} {{ vo_import }} {% endfor %} +{% if table.sub %} +from typing import List, Optional +{% else %} +from typing import Optional, Union +{% endif %} + from pydantic import BaseModel, ConfigDict, Field from pydantic.alias_generators import to_camel {% if vo_field_required.has_required or sub_vo_field_required.has_required %} from pydantic_validation_decorator import NotBlank {% endif %} -{% if table.sub %} -from typing import List, Optional -{% else %} -from typing import Optional -{% endif %} -from module_admin.annotation.pydantic_annotation import as_query {% if table.sub %} @@ -53,14 +53,14 @@ class {{ BusinessName }}BaseModel(BaseModel): {% set parentheseIndex = column.column_comment.find("(") %} {% set comment = column.column_comment[:parentheseIndex] if parentheseIndex != -1 else column.column_comment %} @NotBlank(field_name='{{ column.column_name }}', message='{{ comment }}不能为空') - def get_{{ column.column_name }}(self): + def get_{{ column.column_name }}(self) -> Union[{{ column.python_type }}, None]: return self.{{ column.column_name }} {% if not loop.last %}{{ "\n" }}{% endif %} {% endif %} {% endfor %} {% if vo_field_required.has_required %} - def validate_fields(self): + def validate_fields(self) -> None: {% for column in columns %} {% if column.required %} self.get_{{ column.column_name }}() @@ -91,14 +91,14 @@ class {{ BusinessName }}Model({% if table.sub %}{{ BusinessName }}BaseModel{% el {% set parentheseIndex = column.column_comment.find("(") %} {% set comment = column.column_comment[:parentheseIndex] if parentheseIndex != -1 else column.column_comment %} @NotBlank(field_name='{{ column.column_name }}', message='{{ comment }}不能为空') - def get_{{ column.column_name }}(self): + def get_{{ column.column_name }}(self) -> Union[{{ column.python_type }}, None]: return self.{{ column.column_name }} {% if not loop.last %}{{ "\n" }}{% endif %} {% endif %} {% endfor %} {% if vo_field_required.has_required %} - def validate_fields(self): + def validate_fields(self) -> None: {% for column in columns %} {% if column.required %} self.get_{{ column.column_name }}() @@ -125,14 +125,14 @@ class {{ subTable.business_name | capitalize }}Model(BaseModel): {% set parentheseIndex = sub_column.column_comment.find("(") %} {% set comment = sub_column.column_comment[:parentheseIndex] if parentheseIndex != -1 else sub_column.column_comment %} @NotBlank(field_name='{{ sub_column.column_name }}', message='{{ comment }}不能为空') - def get_{{ sub_column.column_name }}(self): + def get_{{ sub_column.column_name }}(self) -> Union[{{ column.python_type }}, None]: return self.{{ sub_column.column_name }} {% if not loop.last %}{{ "\n" }}{% endif %} {% endif %} {% endfor %} {% if sub_vo_field_required.has_required %} - def validate_fields(self): + def validate_fields(self) -> None: {% for sub_column in subTable.columns %} {% if sub_column.required %} self.get_{{ sub_column.column_name }}() @@ -158,7 +158,6 @@ class {{ BusinessName }}QueryModel({% if table.sub %}{{ BusinessName }}BaseModel {% endif %} -@as_query class {{ BusinessName }}PageQueryModel({{ BusinessName }}QueryModel): """ {{ functionName }}分页查询模型 diff --git a/ruoyi-fastapi-backend/module_task/scheduler_test.py b/ruoyi-fastapi-backend/module_task/scheduler_test.py index b282732..7862c6d 100644 --- a/ruoyi-fastapi-backend/module_task/scheduler_test.py +++ b/ruoyi-fastapi-backend/module_task/scheduler_test.py @@ -1,7 +1,7 @@ from datetime import datetime -def job(*args, **kwargs): +def job(*args, **kwargs) -> None: """ 定时任务执行同步函数示例 """ @@ -10,7 +10,7 @@ def job(*args, **kwargs): print(f'{datetime.now()}同步函数执行了') -async def async_job(*args, **kwargs): +async def async_job(*args, **kwargs) -> None: """ 定时任务执行异步函数示例 """ diff --git a/ruoyi-fastapi-backend/requirements-pg.txt b/ruoyi-fastapi-backend/requirements-pg.txt index 9dbf1fd..a012eac 100644 --- a/ruoyi-fastapi-backend/requirements-pg.txt +++ b/ruoyi-fastapi-backend/requirements-pg.txt @@ -1,10 +1,11 @@ +aiofiles==25.1.0 alembic==1.16.4 APScheduler==3.11.0 async-lru==2.0.5 asyncpg==0.30.0 bcrypt==5.0.0 DateTime==5.5 -fastapi[all]==0.116.1 +fastapi[all]==0.123.9 loguru==0.7.3 openpyxl==3.1.5 pandas==2.3.2 @@ -14,6 +15,7 @@ pydantic-validation-decorator==0.1.4 PyJWT[crypto]==2.10.1 psycopg2==2.9.10 redis==6.4.0 +ruff==0.14.6 SQLAlchemy[asyncio]==2.0.43 sqlglot[rs]==27.8.0 user-agents==2.2.0 diff --git a/ruoyi-fastapi-backend/requirements.txt b/ruoyi-fastapi-backend/requirements.txt index af66bc7..5ae4b97 100644 --- a/ruoyi-fastapi-backend/requirements.txt +++ b/ruoyi-fastapi-backend/requirements.txt @@ -1,10 +1,11 @@ +aiofiles==25.1.0 alembic==1.16.4 APScheduler==3.11.0 async-lru==2.0.5 asyncmy==0.2.10 bcrypt==5.0.0 DateTime==5.5 -fastapi[all]==0.116.1 +fastapi[all]==0.123.9 loguru==0.7.3 openpyxl==3.1.5 pandas==2.3.2 @@ -14,6 +15,7 @@ pydantic-validation-decorator==0.1.4 PyJWT[crypto]==2.10.1 PyMySQL==1.1.1 redis==6.4.0 +ruff==0.14.6 SQLAlchemy[asyncio]==2.0.43 sqlglot[rs]==27.8.0 user-agents==2.2.0 diff --git a/ruoyi-fastapi-backend/ruff.toml b/ruoyi-fastapi-backend/ruff.toml index ea95368..61be1f7 100644 --- a/ruoyi-fastapi-backend/ruff.toml +++ b/ruoyi-fastapi-backend/ruff.toml @@ -1,4 +1,68 @@ line-length = 120 +show-fixes = true +target-version = "py39" +unsafe-fixes = true + +[lint] +select = [ + "FAST", # fastapi + "ANN", # flake8-annotations + "ASYNC", # flake8-async + "B", # flake8-bugbear + "A", # flake8-builtins + "COM", # flake8-commas + "C4", # flake8-comprehensions + "ISC", # flake8-implicit-str-concat + "ICN", # flake8-import-conventions + "PIE", # flake8-pie + "RSE", # flake8-raise + "RET", # flake8-return + "SIM", # flake8-simplify + "TC", # flake8-type-checking + "FLY", # flynt + "I", # isort + "N", # pep8-naming + "PERF", # perflint + "E", # pycodestyle errors + "W", # pycodestyle warnings + "F", # pyflakes + "PGH", # pygrep-hooks + "PL", # pylint + "UP", # pyupgrade + "RUF", # Ruff-specific rules +] +ignore = [ + "ANN002", # missing type annotation for *{name} + "ANN003", # missing type annotation for **{name} + "ANN401", # dynamically typed expressions (typing.Any) are disallowed in {name} + "B008", # do not perform function calls in argument defaults + "COM812", # trailing comma missing + "RET504", # unnecessary assignment to {name} before return statement + "SIM105", # use contextlib.suppress({exception}) instead of try-except-pass + "C901", # too complex + "N818", # exception name {name} should be named with an Error suffix + "E501", # line too long + "W191", # indentation contains tabs + "RUF001", # string contains ambiguous + "RUF002", # docstring contains ambiguous + "RUF003", # comment contains ambiguous + "RUF012", # mutable class attributes should be annotated with typing.ClassVar +] + +[lint.flake8-type-checking] +runtime-evaluated-base-classes = ["pydantic.BaseModel", "sqlalchemy.orm.DeclarativeBase"] + +[lint.isort] +known-third-party = ["alembic"] + +[lint.pylint] +max-args = 10 +max-returns = 10 + +[lint.pyupgrade] +# Preserve types, even if a file imports `from __future__ import annotations`. +keep-runtime-typing = true [format] +docstring-code-format = true quote-style = "single" \ No newline at end of file diff --git a/ruoyi-fastapi-backend/server.py b/ruoyi-fastapi-backend/server.py index 7a46e77..d401110 100644 --- a/ruoyi-fastapi-backend/server.py +++ b/ruoyi-fastapi-backend/server.py @@ -1,28 +1,31 @@ +from collections.abc import AsyncGenerator from contextlib import asynccontextmanager + 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 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.common_controller import commonController -from module_admin.controller.config_controller import configController -from module_admin.controller.dept_controller import deptController -from module_admin.controller.dict_controller import dictController -from module_admin.controller.log_controller import logController -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.user_controller import userController -from module_generator.controller.gen_controller import genController +from module_admin.controller.cache_controller import cache_controller +from module_admin.controller.captcha_controller import captcha_controller +from module_admin.controller.common_controller import common_controller +from module_admin.controller.config_controller import config_controller +from module_admin.controller.dept_controller import dept_controller +from module_admin.controller.dict_controller import dict_controller +from module_admin.controller.job_controller import job_controller +from module_admin.controller.log_controller import log_controller +from module_admin.controller.login_controller import login_controller +from module_admin.controller.menu_controller import menu_controller +from module_admin.controller.notice_controller import notice_controller +from module_admin.controller.online_controller import online_controller +from module_admin.controller.post_controller import post_controller +from module_admin.controller.role_controller import role_controller +from module_admin.controller.server_controller import server_controller +from module_admin.controller.user_controller import user_controller +from module_generator.controller.gen_controller import gen_controller from sub_applications.handle import handle_sub_applications from utils.common_util import worship from utils.log_util import logger @@ -30,7 +33,7 @@ from utils.log_util import logger # 生命周期事件 @asynccontextmanager -async def lifespan(app: FastAPI): +async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: logger.info(f'⏰️ {AppConfig.app_name}开始启动') worship() await init_create_table() @@ -62,23 +65,23 @@ handle_exception(app) # 加载路由列表 controller_list = [ - {'router': loginController, 'tags': ['登录模块']}, - {'router': captchaController, 'tags': ['验证码模块']}, - {'router': userController, 'tags': ['系统管理-用户管理']}, - {'router': roleController, 'tags': ['系统管理-角色管理']}, - {'router': menuController, 'tags': ['系统管理-菜单管理']}, - {'router': deptController, 'tags': ['系统管理-部门管理']}, - {'router': postController, 'tags': ['系统管理-岗位管理']}, - {'router': dictController, 'tags': ['系统管理-字典管理']}, - {'router': configController, 'tags': ['系统管理-参数管理']}, - {'router': noticeController, 'tags': ['系统管理-通知公告管理']}, - {'router': logController, 'tags': ['系统管理-日志管理']}, - {'router': onlineController, 'tags': ['系统监控-在线用户']}, - {'router': jobController, 'tags': ['系统监控-定时任务']}, - {'router': serverController, 'tags': ['系统监控-菜单管理']}, - {'router': cacheController, 'tags': ['系统监控-缓存监控']}, - {'router': commonController, 'tags': ['通用模块']}, - {'router': genController, 'tags': ['代码生成']}, + {'router': login_controller, 'tags': ['登录模块']}, + {'router': captcha_controller, 'tags': ['验证码模块']}, + {'router': user_controller, 'tags': ['系统管理-用户管理']}, + {'router': role_controller, 'tags': ['系统管理-角色管理']}, + {'router': menu_controller, 'tags': ['系统管理-菜单管理']}, + {'router': dept_controller, 'tags': ['系统管理-部门管理']}, + {'router': post_controller, 'tags': ['系统管理-岗位管理']}, + {'router': dict_controller, 'tags': ['系统管理-字典管理']}, + {'router': config_controller, 'tags': ['系统管理-参数管理']}, + {'router': notice_controller, 'tags': ['系统管理-通知公告管理']}, + {'router': log_controller, 'tags': ['系统管理-日志管理']}, + {'router': online_controller, 'tags': ['系统监控-在线用户']}, + {'router': job_controller, 'tags': ['系统监控-定时任务']}, + {'router': server_controller, 'tags': ['系统监控-服务监控']}, + {'router': cache_controller, 'tags': ['系统监控-缓存监控']}, + {'router': common_controller, 'tags': ['通用模块']}, + {'router': gen_controller, 'tags': ['代码生成']}, ] for controller in controller_list: diff --git a/ruoyi-fastapi-backend/sub_applications/handle.py b/ruoyi-fastapi-backend/sub_applications/handle.py index df2a5f4..325193e 100644 --- a/ruoyi-fastapi-backend/sub_applications/handle.py +++ b/ruoyi-fastapi-backend/sub_applications/handle.py @@ -1,8 +1,9 @@ from fastapi import FastAPI + from sub_applications.staticfiles import mount_staticfiles -def handle_sub_applications(app: FastAPI): +def handle_sub_applications(app: FastAPI) -> None: """ 全局处理子应用挂载 """ diff --git a/ruoyi-fastapi-backend/sub_applications/staticfiles.py b/ruoyi-fastapi-backend/sub_applications/staticfiles.py index c481d72..5e5d4e5 100644 --- a/ruoyi-fastapi-backend/sub_applications/staticfiles.py +++ b/ruoyi-fastapi-backend/sub_applications/staticfiles.py @@ -1,9 +1,10 @@ from fastapi import FastAPI from fastapi.staticfiles import StaticFiles + from config.env import UploadConfig -def mount_staticfiles(app: FastAPI): +def mount_staticfiles(app: FastAPI) -> None: """ 挂载静态文件 """ diff --git a/ruoyi-fastapi-backend/utils/common_util.py b/ruoyi-fastapi-backend/utils/common_util.py index 0ccb546..43ab2d2 100644 --- a/ruoyi-fastapi-backend/utils/common_util.py +++ b/ruoyi-fastapi-backend/utils/common_util.py @@ -1,7 +1,10 @@ import io import os -import pandas as pd import re +from collections.abc import Generator, Sequence +from typing import Any, Literal, Union, overload + +import pandas as pd from openpyxl import Workbook from openpyxl.styles import Alignment, PatternFill from openpyxl.utils import get_column_letter @@ -9,13 +12,13 @@ from openpyxl.worksheet.datavalidation import DataValidation from sqlalchemy.engine.row import Row from sqlalchemy.orm.collections import InstrumentedList from sqlalchemy.sql.expression import TextClause, null -from typing import Any, Dict, List, Literal, Union + from config.database import Base from config.env import CachePathConfig -def worship(): - print(""" +def worship() -> None: + print(r""" //////////////////////////////////////////////////////////////////// // _ooOoo_ // // o8888888o // @@ -36,7 +39,7 @@ def worship(): // ========`-.____`-.___\_____/___.-`____.-'======== // // `=---=' // // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // -// 佛祖保佑 永不宕机 永无BUG // +// 佛祖保佑 永不宕机 永无BUG // //////////////////////////////////////////////////////////////////// """) @@ -48,8 +51,8 @@ class SqlalchemyUtil: @classmethod def base_to_dict( - cls, obj: Union[Base, Dict], transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' - ): + cls, obj: Union[Base, dict], transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> dict: """ 将sqlalchemy模型对象转换为字典 @@ -67,15 +70,63 @@ class SqlalchemyUtil: base_dict = obj.copy() if transform_case == 'snake_to_camel': return {CamelCaseUtil.snake_to_camel(k): v for k, v in base_dict.items()} - elif transform_case == 'camel_to_snake': + if transform_case == 'camel_to_snake': return {SnakeCaseUtil.camel_to_snake(k): v for k, v in base_dict.items()} return base_dict @classmethod + @overload + def serialize_result( + cls, result: Base, transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> dict[str, Any]: ... + + @classmethod + @overload + def serialize_result( + cls, result: dict, transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> dict[Any, Any]: ... + + @classmethod + @overload + def serialize_result( + cls, result: Row, transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> Union[dict[str, Any], list[dict[Any, Any]]]: ... + + @classmethod + @overload + def serialize_result( + cls, result: Sequence[Base], transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> list[dict[str, Any]]: ... + + @classmethod + @overload + def serialize_result( + cls, result: Sequence[dict], transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> list[dict[Any, Any]]: ... + + @classmethod + @overload + def serialize_result( + cls, result: Sequence[Row], transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> list[Union[dict[str, Any], list[dict[Any, Any]]]]: ... + + @classmethod + @overload + def serialize_result( + cls, result: Sequence[Any], transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> list[Any]: ... + + @classmethod + @overload def serialize_result( cls, result: Any, transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' - ): + ) -> Any: ... + + @classmethod + def serialize_result( + cls, result: Any, transform_case: Literal['no_case', 'snake_to_camel', 'camel_to_snake'] = 'no_case' + ) -> Any: """ 将sqlalchemy查询结果序列化 @@ -85,20 +136,19 @@ class SqlalchemyUtil: """ if isinstance(result, (Base, dict)): return cls.base_to_dict(result, transform_case) - elif isinstance(result, list): + if isinstance(result, list): return [cls.serialize_result(row, transform_case) for row in result] - elif isinstance(result, Row): - if all([isinstance(row, Base) for row in result]): + if isinstance(result, Row): + if all(isinstance(row, Base) for row in result): return [cls.base_to_dict(row, transform_case) for row in result] - elif any([isinstance(row, Base) for row in result]): + if any(isinstance(row, Base) for row in result): return [cls.serialize_result(row, transform_case) for row in result] - else: - result_dict = result._asdict() - if transform_case == 'snake_to_camel': - return {CamelCaseUtil.snake_to_camel(k): v for k, v in result_dict.items()} - elif transform_case == 'camel_to_snake': - return {SnakeCaseUtil.camel_to_snake(k): v for k, v in result_dict.items()} - return result_dict + result_dict = result._asdict() + if transform_case == 'snake_to_camel': + return {CamelCaseUtil.snake_to_camel(k): v for k, v in result_dict.items()} + if transform_case == 'camel_to_snake': + return {SnakeCaseUtil.camel_to_snake(k): v for k, v in result_dict.items()} + return result_dict return result @classmethod @@ -121,7 +171,7 @@ class CamelCaseUtil: """ @classmethod - def snake_to_camel(cls, snake_str: str): + def snake_to_camel(cls, snake_str: str) -> str: """ 下划线形式字符串(snake_case)转换为小驼峰形式字符串(camelCase) @@ -134,7 +184,39 @@ class CamelCaseUtil: return words[0] + ''.join(word.capitalize() for word in words[1:]) @classmethod - def transform_result(cls, result: Any): + @overload + def transform_result(cls, result: Base) -> dict[str, Any]: ... + + @classmethod + @overload + def transform_result(cls, result: dict) -> dict[Any, Any]: ... + + @classmethod + @overload + def transform_result(cls, result: Row) -> Union[dict[str, Any], list[dict[Any, Any]]]: ... + + @classmethod + @overload + def transform_result(cls, result: Sequence[Base]) -> list[dict[str, Any]]: ... + + @classmethod + @overload + def transform_result(cls, result: Sequence[dict]) -> list[dict[Any, Any]]: ... + + @classmethod + @overload + def transform_result(cls, result: Sequence[Row]) -> list[Union[dict[str, Any], list[dict[Any, Any]]]]: ... + + @classmethod + @overload + def transform_result(cls, result: Sequence[Any]) -> list[Any]: ... + + @classmethod + @overload + def transform_result(cls, result: Any) -> Any: ... + + @classmethod + def transform_result(cls, result: Any) -> Any: """ 针对不同类型将下划线形式(snake_case)批量转换为小驼峰形式(camelCase)方法 @@ -150,7 +232,7 @@ class SnakeCaseUtil: """ @classmethod - def camel_to_snake(cls, camel_str: str): + def camel_to_snake(cls, camel_str: str) -> str: """ 小驼峰形式字符串(camelCase)转换为下划线形式字符串(snake_case) @@ -162,17 +244,49 @@ class SnakeCaseUtil: return re.sub('([a-z0-9])([A-Z])', r'\1_\2', words).lower() @classmethod - def transform_result(cls, result: Any): + @overload + def transform_result(cls, result: Base) -> dict[str, Any]: ... + + @classmethod + @overload + def transform_result(cls, result: dict) -> dict[Any, Any]: ... + + @classmethod + @overload + def transform_result(cls, result: Row) -> Union[dict[str, Any], list[dict[Any, Any]]]: ... + + @classmethod + @overload + def transform_result(cls, result: Sequence[Base]) -> list[dict[str, Any]]: ... + + @classmethod + @overload + def transform_result(cls, result: Sequence[dict]) -> list[dict[Any, Any]]: ... + + @classmethod + @overload + def transform_result(cls, result: Sequence[Row]) -> list[Union[dict[str, Any], list[dict[Any, Any]]]]: ... + + @classmethod + @overload + def transform_result(cls, result: Sequence[Any]) -> list[Any]: ... + + @classmethod + @overload + def transform_result(cls, result: Any) -> Any: ... + + @classmethod + def transform_result(cls, result: Any) -> Any: """ - 针对不同类型将下划线形式(snake_case)批量转换为小驼峰形式(camelCase)方法 + 针对不同类型将小驼峰形式(camelCase)批量转换为下划线形式(snake_case)方法 :param result: 输入数据 - :return: 小驼峰形式结果 + :return: 下划线形式结果 """ return SqlalchemyUtil.serialize_result(result=result, transform_case='camel_to_snake') -def bytes2human(n, format_str='%(value).1f%(symbol)s'): +def bytes2human(n: int, format_str: str = '%(value).1f%(symbol)s') -> str: """Used by various scripts. See: http://goo.gl/zeJZl @@ -189,14 +303,14 @@ def bytes2human(n, format_str='%(value).1f%(symbol)s'): if n >= prefix[symbol]: value = float(n) / prefix[symbol] return format_str % locals() - return format_str % dict(symbol=symbols[0], value=n) + return format_str % {'symbol': symbols[0], 'value': n} -def bytes2file_response(bytes_info): +def bytes2file_response(bytes_info: bytes) -> Generator[bytes]: yield bytes_info -def export_list2excel(list_data: List): +def export_list2excel(list_data: list) -> bytes: """ 工具方法:将需要导出的list数据转化为对应excel的二进制数据 @@ -211,7 +325,7 @@ def export_list2excel(list_data: List): return binary_data -def get_excel_template(header_list: List, selector_header_list: List, option_list: List[dict]): +def get_excel_template(header_list: list, selector_header_list: list, option_list: list[dict]) -> bytes: """ 工具方法:将需要导出的list数据转化为对应excel的二进制数据 @@ -272,7 +386,7 @@ def get_excel_template(header_list: List, selector_header_list: List, option_lis return excel_data -def get_filepath_from_url(url: str): +def get_filepath_from_url(url: str) -> str: """ 工具方法:根据请求参数获取文件路径 diff --git a/ruoyi-fastapi-backend/utils/cron_util.py b/ruoyi-fastapi-backend/utils/cron_util.py index 6232962..045f4ea 100644 --- a/ruoyi-fastapi-backend/utils/cron_util.py +++ b/ruoyi-fastapi-backend/utils/cron_util.py @@ -7,8 +7,13 @@ class CronUtil: Cron表达式工具类 """ + ONE_YEAR_LENGTH = 4 + MAX_YEAR = 2099 + CRON_EXPRESSION_LENGTH_MIN = 6 + CRON_EXPRESSION_LENGTH_MAX = 7 + @classmethod - def __valid_range(cls, search_str: str, start_range: int, end_range: int): + def __valid_range(cls, search_str: str, start_range: int, end_range: int) -> bool: match = re.match(r'^(\d+)-(\d+)$', search_str) if match: start, end = int(match.group(1)), int(match.group(2)) @@ -18,7 +23,7 @@ class CronUtil: @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 - ): + ) -> bool: match = re.match(r'^(\d+)/(\d+)$', search_str) if match: start, end = int(match.group(1)), int(match.group(2)) @@ -30,94 +35,84 @@ class CronUtil: return False @classmethod - def validate_second_or_minute(cls, second_or_minute: str): + def validate_second_or_minute(cls, second_or_minute: str) -> bool: """ 校验秒或分钟值是否正确 :param second_or_minute: 秒或分钟值 :return: 校验结果 """ - if ( + return bool( 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, 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): + def validate_hour(cls, hour: str) -> bool: """ 校验小时值是否正确 :param hour: 小时值 :return: 校验结果 """ - if ( + return bool( 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): + def validate_day(cls, day: str) -> bool: """ 校验日值是否正确 :param day: 日值 :return: 校验结果 """ - if ( + return bool( 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): + def validate_month(cls, month: str) -> bool: """ 校验月值是否正确 :param month: 月值 :return: 校验结果 """ - if ( + return bool( 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): + def validate_week(cls, week: str) -> bool: """ 校验周值是否正确 :param week: 周值 :return: 校验结果 """ - if ( + return bool( week in ['*', '?'] or ('-' in week and cls.__valid_range(week, 1, 7)) 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 - return False + ) @classmethod - def validate_year(cls, year: str): + def validate_year(cls, year: str) -> bool: """ 校验年值是否正确 @@ -126,22 +121,22 @@ class CronUtil: """ current_year = int(datetime.now().year) future_years = [current_year + i for i in range(9)] - if ( + return bool( 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 ('#' 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(',')) + (len(year) == cls.ONE_YEAR_LENGTH or ',' in year) + and all( + int(item) in future_years and current_year <= int(item) <= cls.MAX_YEAR for item in year.split(',') + ) ) - ): - return True - return False + ) @classmethod - def validate_cron_expression(cls, cron_expression: str): + def validate_cron_expression(cls, cron_expression: str) -> bool: """ 校验Cron表达式是否正确 @@ -149,7 +144,7 @@ class CronUtil: :return: 校验结果 """ values = cron_expression.split() - if len(values) != 6 and len(values) != 7: + if len(values) != cls.CRON_EXPRESSION_LENGTH_MIN and len(values) != cls.CRON_EXPRESSION_LENGTH_MAX: return False second_validation = cls.validate_second_or_minute(values[0]) minute_validation = cls.validate_second_or_minute(values[1]) @@ -165,8 +160,7 @@ class CronUtil: and month_validation and week_validation ) - if len(values) == 6: + if len(values) == cls.CRON_EXPRESSION_LENGTH_MIN: return validation - if len(values) == 7: - year_validation = cls.validate_year(values[6]) - return validation and year_validation + year_validation = cls.validate_year(values[6]) + return validation and year_validation diff --git a/ruoyi-fastapi-backend/utils/excel_util.py b/ruoyi-fastapi-backend/utils/excel_util.py index 875a41d..07168d1 100644 --- a/ruoyi-fastapi-backend/utils/excel_util.py +++ b/ruoyi-fastapi-backend/utils/excel_util.py @@ -1,10 +1,10 @@ import io + import pandas as pd from openpyxl import Workbook from openpyxl.styles import Alignment, PatternFill from openpyxl.utils import get_column_letter from openpyxl.worksheet.datavalidation import DataValidation -from typing import Dict, List class ExcelUtil: @@ -13,7 +13,7 @@ class ExcelUtil: """ @classmethod - def __mapping_list(cls, list_data: List, mapping_dict: Dict): + def __mapping_list(cls, list_data: list, mapping_dict: dict) -> list[dict]: """ 工具方法:将list数据中的字段名映射为对应的中文字段名 @@ -26,7 +26,7 @@ class ExcelUtil: return mapping_data @classmethod - def export_list2excel(cls, list_data: List, mapping_dict: Dict): + def export_list2excel(cls, list_data: list, mapping_dict: dict) -> bytes: """ 工具方法:将需要导出的list数据转化为对应excel的二进制数据 @@ -43,7 +43,7 @@ class ExcelUtil: return binary_data @classmethod - def get_excel_template(cls, header_list: List, selector_header_list: List, option_list: List[Dict]): + def get_excel_template(cls, header_list: list, selector_header_list: list, option_list: list[dict]) -> bytes: """ 工具方法:将需要导出的list数据转化为对应excel的二进制数据 diff --git a/ruoyi-fastapi-backend/utils/gen_util.py b/ruoyi-fastapi-backend/utils/gen_util.py index 355e5d0..68d3419 100644 --- a/ruoyi-fastapi-backend/utils/gen_util.py +++ b/ruoyi-fastapi-backend/utils/gen_util.py @@ -1,6 +1,6 @@ import re from datetime import datetime -from typing import List + from config.constant import GenConstant from config.env import GenConfig from module_generator.entity.vo.gen_vo import GenTableColumnModel, GenTableModel @@ -10,6 +10,8 @@ from utils.string_util import StringUtil class GenUtils: """代码生成器工具类""" + TEXTAREA_COLUMN_LENGTH = 500 + @classmethod def init_table(cls, gen_table: GenTableModel, oper_name: str) -> None: """ @@ -58,7 +60,8 @@ class GenUtils: column_length = cls.get_column_length(column.column_type) html_type = ( GenConstant.HTML_TEXTAREA - if column_length >= 500 or cls.arrays_contains(GenConstant.COLUMNTYPE_TEXT, data_type) + if column_length >= cls.TEXTAREA_COLUMN_LENGTH + or cls.arrays_contains(GenConstant.COLUMNTYPE_TEXT, data_type) else GenConstant.HTML_INPUT ) column.html_type = html_type @@ -98,14 +101,14 @@ class GenUtils: # 内容字段设置富文本控件 elif column_name.lower().endswith('content'): column.html_type = GenConstant.HTML_EDITOR - + column.create_by = table.create_by column.create_time = datetime.now() column.update_by = table.update_by column.update_time = datetime.now() @classmethod - def arrays_contains(cls, arr: List[str], target_value: str) -> bool: + def arrays_contains(cls, arr: list[str], target_value: str) -> bool: """ 校验数组是否包含指定值 @@ -151,7 +154,7 @@ class GenUtils: return StringUtil.convert_to_camel_case(table_name) @classmethod - def replace_first(cls, replacement: str, search_list: List[str]) -> str: + def replace_first(cls, replacement: str, search_list: list[str]) -> str: """ 批量替换前缀 @@ -200,7 +203,7 @@ class GenUtils: return 0 @classmethod - def split_column_type(cls, column_type: str) -> List[str]: + def split_column_type(cls, column_type: str) -> list[str]: """ 拆分列类型 diff --git a/ruoyi-fastapi-backend/utils/import_util.py b/ruoyi-fastapi-backend/utils/import_util.py index 4bb2a63..c349e9c 100644 --- a/ruoyi-fastapi-backend/utils/import_util.py +++ b/ruoyi-fastapi-backend/utils/import_util.py @@ -1,11 +1,13 @@ import importlib import inspect import os -from pathlib import Path import sys from functools import lru_cache +from pathlib import Path +from typing import Any + from sqlalchemy import inspect as sa_inspect -from typing import Any, List + from config.database import Base @@ -49,7 +51,7 @@ class ImportUtil: @classmethod @lru_cache(maxsize=256) - def find_models(cls, base_class: Base) -> List[Base]: + def find_models(cls, base_class: Base) -> list[Base]: """ 查找并过滤有效的模型类,避免重复和无效定义 @@ -64,7 +66,7 @@ class ImportUtil: project_root = cls.find_project_root() sys.path.append(str(project_root)) - print(f"⏰️ 开始在项目根目录 {project_root} 中查找模型...") + print(f'⏰️ 开始在项目根目录 {project_root} 中查找模型...') # 排除目录扩展 exclude_dirs = { @@ -87,13 +89,13 @@ class ImportUtil: for file in files: if file.endswith('.py') and not file.startswith('__'): relative_path = Path(root).relative_to(project_root) - module_parts = list(relative_path.parts) + [file[:-3]] + module_parts = [*list(relative_path.parts), file[:-3]] module_name = '.'.join(module_parts) try: module = importlib.import_module(module_name) - for name, obj in inspect.getmembers(module, inspect.isclass): + for _name, obj in inspect.getmembers(module, inspect.isclass): # 验证模型有效性 if not cls.is_valid_model(obj, base_class): continue diff --git a/ruoyi-fastapi-backend/utils/log_util.py b/ruoyi-fastapi-backend/utils/log_util.py index f953f55..8996306 100644 --- a/ruoyi-fastapi-backend/utils/log_util.py +++ b/ruoyi-fastapi-backend/utils/log_util.py @@ -1,18 +1,20 @@ import os import sys import time + from loguru import logger as _logger -from typing import Dict +from loguru._logger import Logger + from middlewares.trace_middleware import TraceCtx class LoggerInitializer: - def __init__(self): + def __init__(self) -> None: self.log_path = os.path.join(os.getcwd(), 'logs') self.__ensure_log_directory_exists() self.log_path_error = os.path.join(self.log_path, f'{time.strftime("%Y-%m-%d")}_error.log') - def __ensure_log_directory_exists(self): + def __ensure_log_directory_exists(self) -> None: """ 确保日志目录存在,如果不存在则创建 """ @@ -20,14 +22,14 @@ class LoggerInitializer: os.mkdir(self.log_path) @staticmethod - def __filter(log: Dict): + def __filter(log: dict) -> dict: """ 自定义日志过滤器,添加trace_id """ log['trace_id'] = TraceCtx.get_id() return log - def init_log(self): + def init_log(self) -> Logger: """ 初始化日志配置 """ diff --git a/ruoyi-fastapi-backend/utils/message_util.py b/ruoyi-fastapi-backend/utils/message_util.py index 3d3eb51..b425d3b 100644 --- a/ruoyi-fastapi-backend/utils/message_util.py +++ b/ruoyi-fastapi-backend/utils/message_util.py @@ -1,5 +1,5 @@ from utils.log_util import logger -def message_service(sms_code: str): +def message_service(sms_code: str) -> None: logger.info(f'短信验证码为{sms_code}') diff --git a/ruoyi-fastapi-backend/utils/page_util.py b/ruoyi-fastapi-backend/utils/page_util.py index dfe8a31..29b7f38 100644 --- a/ruoyi-fastapi-backend/utils/page_util.py +++ b/ruoyi-fastapi-backend/utils/page_util.py @@ -1,9 +1,11 @@ import math +from typing import Any, Optional, Union + from pydantic import BaseModel, ConfigDict from pydantic.alias_generators import to_camel -from sqlalchemy import func, select, Select +from sqlalchemy import Row, Select, func, select from sqlalchemy.ext.asyncio import AsyncSession -from typing import Optional, List + from utils.common_util import CamelCaseUtil @@ -14,7 +16,7 @@ class PageResponseModel(BaseModel): model_config = ConfigDict(alias_generator=to_camel) - rows: List = [] + rows: list = [] page_num: Optional[int] = None page_size: Optional[int] = None total: int @@ -27,7 +29,7 @@ class PageUtil: """ @classmethod - def get_page_obj(cls, data_list: List, page_num: int, page_size: int): + def get_page_obj(cls, data_list: list, page_num: int, page_size: int) -> PageResponseModel: """ 输入数据列表data_list和分页信息,返回分页数据列表结果 @@ -42,7 +44,7 @@ class PageUtil: # 根据计算得到的起始索引和结束索引对数据列表进行切片 paginated_data = data_list[start:end] - has_next = True if math.ceil(len(data_list) / page_size) > page_num else False + has_next = math.ceil(len(data_list) / page_size) > page_num result = PageResponseModel( rows=paginated_data, pageNum=page_num, pageSize=page_size, total=len(data_list), hasNext=has_next @@ -51,7 +53,9 @@ class PageUtil: return result @classmethod - async def paginate(cls, db: AsyncSession, query: Select, page_num: int, page_size: int, is_page: bool = False): + async def paginate( + cls, db: AsyncSession, query: Select, page_num: int, page_size: int, is_page: bool = False + ) -> Union[PageResponseModel, list[Union[dict[str, Any], list[dict[Any, Any]]]]]: """ 输入查询语句和分页信息,返回分页数据列表结果 @@ -65,7 +69,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)) - paginated_data = [] + paginated_data: list[Row] = [] for row in query_result: if row and len(row) == 1: paginated_data.append(row[0]) @@ -81,7 +85,7 @@ class PageUtil: ) else: query_result = await db.execute(query) - no_paginated_data = [] + no_paginated_data: list[Row] = [] for row in query_result: if row and len(row) == 1: no_paginated_data.append(row[0]) @@ -92,7 +96,7 @@ class PageUtil: return result -def get_page_obj(data_list: List, page_num: int, page_size: int): +def get_page_obj(data_list: list, page_num: int, page_size: int) -> PageResponseModel: """ 输入数据列表data_list和分页信息,返回分页数据列表结果 @@ -107,7 +111,7 @@ def get_page_obj(data_list: List, page_num: int, page_size: int): # 根据计算得到的起始索引和结束索引对数据列表进行切片 paginated_data = data_list[start:end] - has_next = True if math.ceil(len(data_list) / page_size) > page_num else False + has_next = math.ceil(len(data_list) / page_size) > page_num result = PageResponseModel( rows=paginated_data, pageNum=page_num, pageSize=page_size, total=len(data_list), hasNext=has_next diff --git a/ruoyi-fastapi-backend/utils/pwd_util.py b/ruoyi-fastapi-backend/utils/pwd_util.py index c3f91ce..9fa592f 100644 --- a/ruoyi-fastapi-backend/utils/pwd_util.py +++ b/ruoyi-fastapi-backend/utils/pwd_util.py @@ -20,7 +20,7 @@ class PwdUtil: ) @classmethod - def get_password_hash(cls, input_password): + def get_password_hash(cls, input_password: str) -> str: """ 工具方法:对当前输入的密码进行加密 diff --git a/ruoyi-fastapi-backend/utils/response_util.py b/ruoyi-fastapi-backend/utils/response_util.py index 01d4632..16ce145 100644 --- a/ruoyi-fastapi-backend/utils/response_util.py +++ b/ruoyi-fastapi-backend/utils/response_util.py @@ -1,10 +1,13 @@ +from collections.abc import Mapping from datetime import datetime +from typing import Any, Optional + from fastapi import status from fastapi.encoders import jsonable_encoder from fastapi.responses import JSONResponse, Response, StreamingResponse from pydantic import BaseModel from starlette.background import BackgroundTask -from typing import Any, Dict, Mapping, Optional + from config.constant import HttpStatusConstant @@ -19,7 +22,7 @@ class ResponseUtil: msg: str = '操作成功', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, + dict_content: Optional[dict] = None, model_content: Optional[BaseModel] = None, headers: Optional[Mapping[str, str]] = None, media_type: Optional[str] = None, @@ -65,7 +68,7 @@ class ResponseUtil: msg: str = '操作失败', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, + dict_content: Optional[dict] = None, model_content: Optional[BaseModel] = None, headers: Optional[Mapping[str, str]] = None, media_type: Optional[str] = None, @@ -111,7 +114,7 @@ class ResponseUtil: msg: str = '登录信息已过期,访问系统资源失败', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, + dict_content: Optional[dict] = None, model_content: Optional[BaseModel] = None, headers: Optional[Mapping[str, str]] = None, media_type: Optional[str] = None, @@ -157,7 +160,7 @@ class ResponseUtil: msg: str = '该用户无此接口权限', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, + dict_content: Optional[dict] = None, model_content: Optional[BaseModel] = None, headers: Optional[Mapping[str, str]] = None, media_type: Optional[str] = None, @@ -203,7 +206,7 @@ class ResponseUtil: msg: str = '接口异常', data: Optional[Any] = None, rows: Optional[Any] = None, - dict_content: Optional[Dict] = None, + dict_content: Optional[dict] = None, model_content: Optional[BaseModel] = None, headers: Optional[Mapping[str, str]] = None, media_type: Optional[str] = None, diff --git a/ruoyi-fastapi-backend/utils/string_util.py b/ruoyi-fastapi-backend/utils/string_util.py index 7196bcf..756456f 100644 --- a/ruoyi-fastapi-backend/utils/string_util.py +++ b/ruoyi-fastapi-backend/utils/string_util.py @@ -1,4 +1,5 @@ -from typing import Dict, List +from typing import Union + from config.constant import CommonConstant @@ -8,7 +9,7 @@ class StringUtil: """ @classmethod - def is_blank(cls, string: str) -> bool: + def is_blank(cls, string: Union[str, None]) -> bool: """ 校验字符串是否为''或全空格 @@ -20,14 +21,10 @@ class StringUtil: str_len = len(string) if str_len == 0: return True - else: - for i in range(str_len): - if string[i] != ' ': - return False - return True + return all(string[i] == ' ' for i in range(str_len)) @classmethod - def is_empty(cls, string) -> bool: + def is_empty(cls, string: str) -> bool: """ 校验字符串是否为''或None @@ -47,17 +44,17 @@ class StringUtil: return not cls.is_empty(string) @classmethod - def is_http(cls, link: str): + def is_http(cls, link: str) -> bool: """ 判断是否为http(s)://开头 :param link: 链接 :return: 是否为http(s)://开头 """ - return link.startswith(CommonConstant.HTTP) or link.startswith(CommonConstant.HTTPS) + return link.startswith((CommonConstant.HTTP, CommonConstant.HTTPS)) @classmethod - def contains_ignore_case(cls, search_str: str, compare_str: str): + def contains_ignore_case(cls, search_str: str, compare_str: str) -> bool: """ 查找指定字符串是否包含指定字符串同时忽略大小写 @@ -70,7 +67,7 @@ class StringUtil: return False @classmethod - def contains_any_ignore_case(cls, search_str: str, compare_str_list: List[str]): + def contains_any_ignore_case(cls, search_str: str, compare_str_list: list[str]) -> bool: """ 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时忽略大小写 @@ -79,11 +76,11 @@ class StringUtil: :return: 查找结果 """ if search_str and compare_str_list: - return any([cls.contains_ignore_case(search_str, compare_str) for compare_str in compare_str_list]) + return any(cls.contains_ignore_case(search_str, compare_str) for compare_str in compare_str_list) return False @classmethod - def equals_ignore_case(cls, search_str: str, compare_str: str): + def equals_ignore_case(cls, search_str: str, compare_str: str) -> bool: """ 比较两个字符串是否相等同时忽略大小写 @@ -96,7 +93,7 @@ class StringUtil: return False @classmethod - def equals_any_ignore_case(cls, search_str: str, compare_str_list: List[str]): + def equals_any_ignore_case(cls, search_str: str, compare_str_list: list[str]) -> bool: """ 比较指定字符串是否与指定字符串列表中的任意一个字符串相等同时忽略大小写 @@ -105,11 +102,11 @@ class StringUtil: :return: 比较结果 """ if search_str and compare_str_list: - return any([cls.equals_ignore_case(search_str, compare_str) for compare_str in compare_str_list]) + return any(cls.equals_ignore_case(search_str, compare_str) for compare_str in compare_str_list) return False @classmethod - def startswith_case(cls, search_str: str, compare_str: str): + def startswith_case(cls, search_str: str, compare_str: str) -> bool: """ 查找指定字符串是否以指定字符串开头 @@ -122,7 +119,7 @@ class StringUtil: return False @classmethod - def startswith_any_case(cls, search_str: str, compare_str_list: List[str]): + def startswith_any_case(cls, search_str: str, compare_str_list: list[str]) -> bool: """ 查找指定字符串是否以指定字符串列表中的任意一个字符串开头 @@ -131,7 +128,7 @@ class StringUtil: :return: 查找结果 """ if search_str and compare_str_list: - return any([cls.startswith_case(search_str, compare_str) for compare_str in compare_str_list]) + return any(cls.startswith_case(search_str, compare_str) for compare_str in compare_str_list) return False @classmethod @@ -155,7 +152,7 @@ class StringUtil: return ''.join(result) @classmethod - def get_mapping_value_by_key_ignore_case(cls, mapping: Dict[str, str], key: str) -> str: + def get_mapping_value_by_key_ignore_case(cls, mapping: dict[str, str], key: str) -> str: """ 根据忽略大小写的键获取字典中的对应的值 @@ -166,5 +163,5 @@ class StringUtil: for k, v in mapping.items(): if key.lower() == k.lower(): return v - + return '' diff --git a/ruoyi-fastapi-backend/utils/template_util.py b/ruoyi-fastapi-backend/utils/template_util.py index afe5c41..b5163a5 100644 --- a/ruoyi-fastapi-backend/utils/template_util.py +++ b/ruoyi-fastapi-backend/utils/template_util.py @@ -1,12 +1,14 @@ import json import os from datetime import datetime +from typing import Any + from jinja2 import Environment, FileSystemLoader -from typing import Dict, List, Set + from config.constant import GenConstant from config.env import DataBaseConfig from exceptions.exception import ServiceWarning -from module_generator.entity.vo.gen_vo import GenTableModel, GenTableColumnModel +from module_generator.entity.vo.gen_vo import GenTableColumnModel, GenTableModel from utils.common_util import CamelCaseUtil, SnakeCaseUtil from utils.string_util import StringUtil @@ -17,7 +19,7 @@ class TemplateInitializer: """ @classmethod - def init_jinja2(cls): + def init_jinja2(cls) -> Environment: """ 初始化 Jinja2 模板引擎 @@ -40,7 +42,7 @@ class TemplateInitializer: ) return env except Exception as e: - raise RuntimeError(f'初始化Jinja2模板引擎失败: {e}') + raise RuntimeError(f'初始化Jinja2模板引擎失败: {e}') from e class TemplateUtils: @@ -54,7 +56,7 @@ class TemplateUtils: DEFAULT_PARENT_MENU_ID = '3' @classmethod - def prepare_context(cls, gen_table: GenTableModel): + def prepare_context(cls, gen_table: GenTableModel) -> dict[str, Any]: """ 准备模板变量 @@ -106,7 +108,7 @@ class TemplateUtils: return context @classmethod - def set_menu_context(cls, context: Dict, gen_table: GenTableModel): + def set_menu_context(cls, context: dict, gen_table: GenTableModel) -> None: """ 设置菜单上下文 @@ -119,7 +121,7 @@ class TemplateUtils: context['parentMenuId'] = cls.get_parent_menu_id(params_obj) @classmethod - def set_tree_context(cls, context: Dict, gen_table: GenTableModel): + def set_tree_context(cls, context: dict, gen_table: GenTableModel) -> None: """ 设置树形结构上下文 @@ -135,7 +137,7 @@ class TemplateUtils: context['expandColumn'] = cls.get_expand_column(gen_table) @classmethod - def set_sub_context(cls, context: Dict, gen_table: GenTableModel): + def set_sub_context(cls, context: dict, gen_table: GenTableModel) -> None: """ 设置子表上下文 @@ -157,7 +159,7 @@ class TemplateUtils: context['subclassName'] = sub_class_name.lower() @classmethod - def get_template_list(cls, tpl_category: str, tpl_web_type: str): + def get_template_list(cls, tpl_category: str, tpl_web_type: str) -> list[str]: """ 获取模板列表 @@ -187,7 +189,7 @@ class TemplateUtils: return templates @classmethod - def get_file_name(cls, template: List[str], gen_table: GenTableModel): + def get_file_name(cls, template: list[str], gen_table: GenTableModel) -> str: """ 根据模板生成文件名 @@ -204,24 +206,24 @@ class TemplateUtils: if 'controller.py.jinja2' in template: return f'{python_path}/controller/{business_name}_controller.py' - elif 'dao.py.jinja2' in template: + if 'dao.py.jinja2' in template: return f'{python_path}/dao/{business_name}_dao.py' - elif 'do.py.jinja2' in template: + if 'do.py.jinja2' in template: return f'{python_path}/entity/do/{business_name}_do.py' - elif 'service.py.jinja2' in template: + if 'service.py.jinja2' in template: return f'{python_path}/service/{business_name}_service.py' - elif 'vo.py.jinja2' in template: + if 'vo.py.jinja2' in template: return f'{python_path}/entity/vo/{business_name}_vo.py' - elif 'sql.jinja2' in template: + if 'sql.jinja2' in template: return f'{cls.BACKEND_PROJECT_PATH}/sql/{business_name}_menu.sql' - elif 'api.js.jinja2' in template: + if 'api.js.jinja2' in template: return f'{vue_path}/api/{module_name}/{business_name}.js' - elif 'index.vue.jinja2' in template or 'index-tree.vue.jinja2' in template: + if 'index.vue.jinja2' in template or 'index-tree.vue.jinja2' in template: return f'{vue_path}/views/{module_name}/{business_name}/index.vue' return '' @classmethod - def get_package_prefix(cls, package_name: str): + def get_package_prefix(cls, package_name: str) -> str: """ 获取包前缀 @@ -231,7 +233,7 @@ class TemplateUtils: return package_name[: package_name.rfind('.')] @classmethod - def get_vo_import_list(cls, gen_table: GenTableModel): + def get_vo_import_list(cls, gen_table: GenTableModel) -> list[str]: """ 获取vo模板导入包列表 @@ -255,7 +257,7 @@ class TemplateUtils: return cls.merge_same_imports(list(import_list), 'from datetime import') @classmethod - def get_do_import_list(cls, gen_table: GenTableModel): + def get_do_import_list(cls, gen_table: GenTableModel) -> list[str]: """ 获取do模板导入包列表 @@ -295,7 +297,7 @@ class TemplateUtils: return column_type @classmethod - def merge_same_imports(cls, imports: List[str], import_start: str) -> List[str]: + def merge_same_imports(cls, imports: list[str], import_start: str) -> list[str]: """ 合并相同的导入语句 @@ -319,7 +321,7 @@ class TemplateUtils: return merged_imports @classmethod - def get_dicts(cls, gen_table: GenTableModel): + def get_dicts(cls, gen_table: GenTableModel) -> str: """ 获取字典列表 @@ -334,7 +336,7 @@ class TemplateUtils: return ', '.join(dicts) @classmethod - def add_dicts(cls, dicts: Set[str], columns: List[GenTableColumnModel]): + def add_dicts(cls, dicts: set[str], columns: list[GenTableColumnModel]) -> None: """ 添加字典列表 @@ -353,7 +355,7 @@ class TemplateUtils: dicts.add(f"'{column.dict_type}'") @classmethod - def get_permission_prefix(cls, module_name: str, business_name: str): + def get_permission_prefix(cls, module_name: str, business_name: str) -> str: """ 获取权限前缀 @@ -364,7 +366,7 @@ class TemplateUtils: return f'{module_name}:{business_name}' @classmethod - def get_parent_menu_id(cls, params_obj: Dict): + def get_parent_menu_id(cls, params_obj: dict) -> str: """ 获取上级菜单ID @@ -376,7 +378,7 @@ class TemplateUtils: return cls.DEFAULT_PARENT_MENU_ID @classmethod - def get_tree_code(cls, params_obj: Dict): + def get_tree_code(cls, params_obj: dict) -> str: """ 获取树编码 @@ -388,7 +390,7 @@ class TemplateUtils: return '' @classmethod - def get_tree_parent_code(cls, params_obj: Dict): + def get_tree_parent_code(cls, params_obj: dict) -> str: """ 获取树父编码 @@ -400,7 +402,7 @@ class TemplateUtils: return '' @classmethod - def get_tree_name(cls, params_obj: Dict): + def get_tree_name(cls, params_obj: dict) -> str: """ 获取树名称 @@ -412,7 +414,7 @@ class TemplateUtils: return '' @classmethod - def get_expand_column(cls, gen_table: GenTableModel): + def get_expand_column(cls, gen_table: GenTableModel) -> int: """ 获取展开列 @@ -442,7 +444,7 @@ class TemplateUtils: return parts[0] + ''.join(word.capitalize() for word in parts[1:]) @classmethod - def get_sqlalchemy_type(cls, column_type: str): + def get_sqlalchemy_type(cls, column_type: str) -> str: """ 获取SQLAlchemy类型 diff --git a/ruoyi-fastapi-backend/utils/time_format_util.py b/ruoyi-fastapi-backend/utils/time_format_util.py index bfb0481..71e9f6a 100644 --- a/ruoyi-fastapi-backend/utils/time_format_util.py +++ b/ruoyi-fastapi-backend/utils/time_format_util.py @@ -1,10 +1,11 @@ from copy import deepcopy -from datetime import datetime +from datetime import date, datetime +from typing import Any, Union + from dateutil.parser import parse -from typing import Dict, List, Union -def object_format_datetime(obj): +def object_format_datetime(obj: Any) -> Any: """ :param obj: 输入一个对象 :return:对目标对象所有datetime类型的属性格式化 @@ -16,7 +17,7 @@ def object_format_datetime(obj): return obj -def list_format_datetime(lst): +def list_format_datetime(lst: list[Any]) -> list[Any]: """ :param lst: 输入一个嵌套对象的列表 :return: 对目标列表中所有对象的datetime类型的属性格式化 @@ -29,7 +30,7 @@ def list_format_datetime(lst): return lst -def format_datetime_dict_list(dicts): +def format_datetime_dict_list(dicts: list[dict]) -> list[dict]: """ 递归遍历嵌套字典,并将 datetime 值转换为字符串格式 @@ -61,27 +62,27 @@ class TimeFormatUtil: """ @classmethod - def format_time(cls, time_info: Union[str, datetime], format: str = '%Y-%m-%d %H:%M:%S'): + def format_time(cls, time_info: Union[str, datetime], fmt: str = '%Y-%m-%d %H:%M:%S') -> str: """ 格式化时间字符串或datetime对象为指定格式 :param time_info: 时间字符串或datetime对象 - :param format: 格式化格式,默认为'%Y-%m-%d %H:%M:%S' + :param fmt: 格式化格式,默认为'%Y-%m-%d %H:%M:%S' :return: 格式化后的时间字符串 """ if isinstance(time_info, datetime): - format_date = time_info.strftime(format) + format_date = time_info.strftime(fmt) else: try: date = parse(time_info) - format_date = date.strftime(format) + format_date = date.strftime(fmt) except Exception: format_date = time_info return format_date @classmethod - def parse_date(cls, time_str: str): + def parse_date(cls, time_str: str) -> Union[date, str]: """ 解析时间字符串提取日期部分 @@ -95,44 +96,44 @@ class TimeFormatUtil: return time_str @classmethod - def format_time_dict(cls, time_dict: Dict, format: str = '%Y-%m-%d %H:%M:%S'): + def format_time_dict(cls, time_dict: dict, fmt: str = '%Y-%m-%d %H:%M:%S') -> dict: """ 格式化时间字典 :param time_dict: 时间字典 - :param format: 格式化格式,默认为'%Y-%m-%d %H:%M:%S' + :param fmt: 格式化格式,默认为'%Y-%m-%d %H:%M:%S' :return: 格式化后的时间字典 """ copy_time_dict = deepcopy(time_dict) for k, v in copy_time_dict.items(): if isinstance(v, (str, datetime)): - copy_time_dict[k] = cls.format_time(v, format) + copy_time_dict[k] = cls.format_time(v, fmt) elif isinstance(v, dict): - copy_time_dict[k] = cls.format_time_dict(v, format) + copy_time_dict[k] = cls.format_time_dict(v, fmt) elif isinstance(v, list): - copy_time_dict[k] = cls.format_time_list(v, format) + copy_time_dict[k] = cls.format_time_list(v, fmt) else: copy_time_dict[k] = v return copy_time_dict @classmethod - def format_time_list(cls, time_list: List, format: str = '%Y-%m-%d %H:%M:%S'): + def format_time_list(cls, time_list: list, fmt: str = '%Y-%m-%d %H:%M:%S') -> list: """ 格式化时间列表 :param time_list: 时间列表 - :param format: 格式化格式,默认为'%Y-%m-%d %H:%M:%S' + :param fmt: 格式化格式,默认为'%Y-%m-%d %H:%M:%S' :return: 格式化后的时间列表 """ format_time_list = [] for item in time_list: if isinstance(item, (str, datetime)): - format_item = cls.format_time(item, format) + format_item = cls.format_time(item, fmt) elif isinstance(item, dict): - format_item = cls.format_time_dict(item, format) + format_item = cls.format_time_dict(item, fmt) elif isinstance(item, list): - format_item = cls.format_time_list(item, format) + format_item = cls.format_time_list(item, fmt) else: format_item = item diff --git a/ruoyi-fastapi-backend/utils/upload_util.py b/ruoyi-fastapi-backend/utils/upload_util.py index 726789e..c979a14 100644 --- a/ruoyi-fastapi-backend/utils/upload_util.py +++ b/ruoyi-fastapi-backend/utils/upload_util.py @@ -1,7 +1,11 @@ import os import random +from collections.abc import AsyncGenerator from datetime import datetime + +import aiofiles from fastapi import UploadFile + from config.env import UploadConfig @@ -11,7 +15,7 @@ class UploadUtil: """ @classmethod - def generate_random_number(cls): + def generate_random_number(cls) -> str: """ 生成3位数字构成的字符串 @@ -22,7 +26,7 @@ class UploadUtil: return f'{random_number:03}' @classmethod - def check_file_exists(cls, filepath: str): + def check_file_exists(cls, filepath: str) -> bool: """ 检查文件是否存在 @@ -32,7 +36,7 @@ class UploadUtil: return os.path.exists(filepath) @classmethod - def check_file_extension(cls, file: UploadFile): + def check_file_extension(cls, file: UploadFile) -> bool: """ 检查文件后缀是否合法 @@ -40,12 +44,11 @@ class UploadUtil: :return: 校验结果 """ file_extension = file.filename.rsplit('.', 1)[-1] - if file_extension in UploadConfig.DEFAULT_ALLOWED_EXTENSION: - return True - return False + + return file_extension in UploadConfig.DEFAULT_ALLOWED_EXTENSION @classmethod - def check_file_timestamp(cls, filename: str): + def check_file_timestamp(cls, filename: str) -> bool: """ 校验文件时间戳是否合法 @@ -60,19 +63,17 @@ class UploadUtil: return False @classmethod - def check_file_machine(cls, filename: str): + def check_file_machine(cls, filename: str) -> bool: """ 校验文件机器码是否合法 :param filename: 文件名称 :return: 校验结果 """ - if filename.rsplit('.', 1)[0][-4] == UploadConfig.UPLOAD_MACHINE: - return True - return False + return filename.rsplit('.', 1)[0][-4] == UploadConfig.UPLOAD_MACHINE @classmethod - def check_file_random_code(cls, filename: str): + def check_file_random_code(cls, filename: str) -> bool: """ 校验文件随机码是否合法 @@ -80,23 +81,23 @@ class UploadUtil: :return: 校验结果 """ 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 + + return filename.rsplit('.', 1)[0][-3:] in valid_code_list @classmethod - def generate_file(cls, filepath: str): + async def generate_file(cls, filepath: str) -> AsyncGenerator[bytes, None]: """ 根据文件生成二进制数据 :param filepath: 文件路径 :yield: 二进制数据 """ - with open(filepath, 'rb') as response_file: - yield from response_file + async with aiofiles.open(filepath, 'rb') as response_file: + async for chunk in response_file: + yield chunk @classmethod - def delete_file(cls, filepath: str): + def delete_file(cls, filepath: str) -> None: """ 根据文件路径删除对应文件