diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 180f5d20a9e0b558dd11e29c25a8bda3b23331c6..0000000000000000000000000000000000000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# RuoYi-Vue3-FastAPI - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index 0bf9884dd1c744e162c5aa5adb3ff04c7f0db263..9671366cda32f9ce2593cf5cb7cbdbb2308e7e68 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,184 @@ -# RuoYi-Vue3-FastAPI +

+ logo +

+

RuoYi-Vue3-FastAPI v1.0.0

+

基于RuoYi-Vue3+FastAPI前后端分离的快速开发框架

+

+ + + + + + +

-#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +## 平台简介 -#### 软件架构 -软件架构说明 +RuoYi-Vue-FastAPI是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 +* 前端采用Vue、Element Plus,基于[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3)前端项目修改。 +* 后端采用FastAPI、sqlalchemy、MySQL、Redis、OAuth2 & Jwt。 +* 权限认证使用OAuth2 & Jwt,支持多终端认证系统。 +* 支持加载动态权限菜单,多方式轻松权限控制。 +* Vue2版本: + - Gitte仓库地址:https://gitee.com/insistence2022/RuoYi-Vue-FastAPI。 + - GitHub仓库地址:https://github.com/insistence/RuoYi-Vue-FastAPI。 +* 纯Python版本: + - Gitte仓库地址:https://gitee.com/insistence2022/dash-fastapi-admin。 + - GitHub仓库地址:https://github.com/insistence/Dash-FastAPI-Admin。 +* 特别鸣谢:[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3)。 -#### 安装教程 +## 内置功能 -1. xxxx -2. xxxx -3. xxxx +1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +2. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 +3. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 +4. 部门管理:配置系统组织机构(公司、部门、小组)。 +5. 岗位管理:配置系统用户所属担任职务。 +6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 +7. 参数管理:对系统动态配置常用参数。 +8. 通知公告:系统通知公告信息发布维护。 +9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +10. 登录日志:系统登录日志记录查询包含登录异常。 +11. 在线用户:当前系统中活跃用户状态监控。 +12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 +13. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 +14. 缓存监控:对系统的缓存信息查询,命令统计等。 +15. 系统接口:根据业务代码自动生成相关的api接口文档。 -#### 使用说明 +## 演示图 -1. xxxx -2. xxxx -3. xxxx + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-#### 参与贡献 +## 在线体验 +- *账号:admin* +- *密码:admin123* +- 演示地址:vfadmin管理系统 -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +## 项目开发及发布相关 +### 开发 -#### 特技 +```bash +# 克隆项目 +git clone https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI.git -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +# 进入项目根目录 +cd RuoYi-Vue3-FastAPI +``` + +#### 前端 +```bash +# 进入前端目录 +cd ruoyi-fastapi-frontend + +# 安装依赖 +npm install 或 yarn --registry=https://registry.npmmirror.com + +# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 +npm install --registry=https://registry.npmmirror.com + +# 启动服务 +npm run dev 或 yarn dev +``` + +#### 后端 +```bash +# 进入后端目录 +cd ruoyi-fastapi-backend + +# 安装项目依赖环境 +pip3 install -r requirements.txt + +# 配置环境 +在.env.dev文件中配置开发环境的数据库和redis + +# 运行sql文件 +1.新建数据库ruoyi-fastapi(默认,可修改) +2.使用命令或数据库连接工具运行sql文件夹下的ruoyi-fastapi.sql + +# 运行后端 +python3 app.py --env=dev +``` + +#### 访问 +```bash +# 默认账号密码 +账号:admin +密码:admin123 + +# 浏览器访问 +地址:http://localhost:80 +``` + +### 发布 + +#### 前端 +```bash +# 构建测试环境 +npm run build:stage 或 yarn build:stage + +# 构建生产环境 +npm run build:prod 或 yarn build:prod +``` + +#### 后端 +```bash +# 配置环境 +在.env.prod文件中配置生产环境的数据库和redis + +# 运行后端 +python3 app.py --env=prod +``` + +## 交流与赞助 +如果有对本项目及FastAPI感兴趣的朋友,欢迎加入知识星球一起交流学习,让我们一起变得更强。如果你觉得这个项目帮助到了你,你可以请作者喝杯咖啡表示鼓励☕。扫描下面微信二维码添加微信备注VF-Admin即可进群。 + + + + + + + + +
zsxqzanzhu
wxcode
\ No newline at end of file diff --git a/ruoyi-fastapi-backend/.env.dev b/ruoyi-fastapi-backend/.env.dev new file mode 100644 index 0000000000000000000000000000000000000000..33d19fc02ba3c70701448d05305841ec1e49198b --- /dev/null +++ b/ruoyi-fastapi-backend/.env.dev @@ -0,0 +1,50 @@ +# -------- 应用配置 -------- +# 应用运行环境 +APP_ENV = 'dev' +# 应用名称 +APP_NAME = 'RuoYi-FasAPI' +# 应用代理路径 +APP_ROOT_PATH = '/dev-api' +# 应用主机 +APP_HOST = '0.0.0.0' +# 应用端口 +APP_PORT = 9099 +# 应用版本 +APP_VERSION= '1.0.0' +# 应用是否开启热重载 +APP_RELOAD = true + +# -------- Jwt配置 -------- +# Jwt秘钥 +JWT_SECRET_KEY = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55' +# Jwt算法 +JWT_ALGORITHM = 'HS256' +# 令牌过期时间 +JWT_EXPIRE_MINUTES = 1440 +# redis中令牌过期时间 +JWT_REDIS_EXPIRE_MINUTES = 30 + + +# -------- 数据库配置 -------- +# 数据库主机 +DB_HOST = '127.0.0.1' +# 数据库端口 +DB_PORT = 3306 +# 数据库用户名 +DB_USERNAME = 'root' +# 数据库密码 +DB_PASSWORD = 'mysqlroot' +# 数据库名称 +DB_DATABASE = 'ruoyi-fastapi' + +# -------- Redis配置 -------- +# Redis主机 +REDIS_HOST = '127.0.0.1' +# Redis端口 +REDIS_PORT = 6379 +# Redis用户名 +REDIS_USERNAME = '' +# Redis密码 +REDIS_PASSWORD = '' +# Redis数据库 +REDIS_DATABASE = 2 \ No newline at end of file diff --git a/ruoyi-fastapi-backend/.env.prod b/ruoyi-fastapi-backend/.env.prod new file mode 100644 index 0000000000000000000000000000000000000000..eddcd5895248ea7add3ee18c22d7ce736451dacf --- /dev/null +++ b/ruoyi-fastapi-backend/.env.prod @@ -0,0 +1,50 @@ +# -------- 应用配置 -------- +# 应用运行环境 +APP_ENV = 'prod' +# 应用名称 +APP_NAME = 'RuoYi-FasAPI' +# 应用代理路径 +APP_ROOT_PATH = '/prod-api' +# 应用主机 +APP_HOST = '0.0.0.0' +# 应用端口 +APP_PORT = 9099 +# 应用版本 +APP_VERSION= '1.0.0' +# 应用是否开启热重载 +APP_RELOAD = false + +# -------- Jwt配置 -------- +# Jwt秘钥 +JWT_SECRET_KEY = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55' +# Jwt算法 +JWT_ALGORITHM = 'HS256' +# 令牌过期时间 +JWT_EXPIRE_MINUTES = 1440 +# redis中令牌过期时间 +JWT_REDIS_EXPIRE_MINUTES = 30 + + +# -------- 数据库配置 -------- +# 数据库主机 +DB_HOST = '127.0.0.1' +# 数据库端口 +DB_PORT = 3306 +# 数据库用户名 +DB_USERNAME = 'root' +# 数据库密码 +DB_PASSWORD = 'root' +# 数据库名称 +DB_DATABASE = 'ruoyi-fastapi' + +# -------- Redis配置 -------- +# Redis主机 +REDIS_HOST = '127.0.0.1' +# Redis端口 +REDIS_PORT = 6379 +# Redis用户名 +REDIS_USERNAME = '' +# Redis密码 +REDIS_PASSWORD = '' +# Redis数据库 +REDIS_DATABASE = 2 \ No newline at end of file diff --git a/ruoyi-fastapi-backend/app.py b/ruoyi-fastapi-backend/app.py index 97818b651fafb39c4a7101d49029973d86d8b441..7797fa934cb5641a857724ae64d0307221ac97f1 100644 --- a/ruoyi-fastapi-backend/app.py +++ b/ruoyi-fastapi-backend/app.py @@ -1,119 +1,12 @@ -from fastapi import FastAPI, Request -from fastapi.exceptions import HTTPException -from fastapi.middleware.cors import CORSMiddleware -from fastapi.staticfiles import StaticFiles import uvicorn -from contextlib import asynccontextmanager -from module_admin.controller.login_controller import loginController -from module_admin.controller.captcha_controller import captchaController -from module_admin.controller.user_controller import userController -from module_admin.controller.menu_controller import menuController -from module_admin.controller.dept_controller import deptController -from module_admin.controller.role_controller import roleController -from module_admin.controller.post_controler import postController -from module_admin.controller.dict_controller import dictController -from module_admin.controller.config_controller import configController -from module_admin.controller.notice_controller import noticeController -from module_admin.controller.log_controller import logController -from module_admin.controller.online_controller import onlineController -from module_admin.controller.job_controller import jobController -from module_admin.controller.server_controller import serverController -from module_admin.controller.cache_controller import cacheController -from module_admin.controller.common_controller import commonController -from config.env import UploadConfig -from config.get_redis import RedisUtil -from config.get_db import init_create_table -from config.get_scheduler import SchedulerUtil -from utils.response_util import * -from utils.log_util import logger -from utils.common_util import worship +from server import app, AppConfig -@asynccontextmanager -async def lifespan(app: FastAPI): - logger.info("RuoYi-FastAPI开始启动") - worship() - await init_create_table() - app.state.redis = await RedisUtil.create_redis_pool() - await RedisUtil.init_sys_dict(app.state.redis) - await RedisUtil.init_sys_config(app.state.redis) - await SchedulerUtil.init_system_scheduler() - logger.info("RuoYi-FastAPI启动成功") - yield - await RedisUtil.close_redis_pool(app) - await SchedulerUtil.close_system_scheduler() - - -app = FastAPI( - title='RuoYi-FastAPI', - description='RuoYi-FastAPI接口文档', - version='1.0.0', - lifespan=lifespan -) - -# 前端页面url -origins = [ - "http://localhost:81", - "http://127.0.0.1:81", -] - -# 后台api允许跨域 -app.add_middleware( - CORSMiddleware, - allow_origins=origins, - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -# 实例化UploadConfig,确保应用启动时上传目录存在 -upload_config = UploadConfig() - -# 挂载静态文件路径 -app.mount(f"{upload_config.UPLOAD_PREFIX}", StaticFiles(directory=f"{upload_config.UPLOAD_PATH}"), name="profile") - - -# 自定义token检验异常 -@app.exception_handler(AuthException) -async def auth_exception_handler(request: Request, exc: AuthException): - return ResponseUtil.unauthorized(data=exc.data, msg=exc.message) - - -# 自定义权限检验异常 -@app.exception_handler(PermissionException) -async def permission_exception_handler(request: Request, exc: PermissionException): - return ResponseUtil.forbidden(data=exc.data, msg=exc.message) - - -@app.exception_handler(HTTPException) -async def http_exception_handler(request: Request, exc: HTTPException): - return JSONResponse( - content=jsonable_encoder({"message": exc.detail, "code": exc.status_code}), - status_code=exc.status_code - ) - - -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': ['通用模块']} -] - -for controller in controller_list: - app.include_router(router=controller.get('router'), tags=controller.get('tags')) - if __name__ == '__main__': - uvicorn.run(app='app:app', host="0.0.0.0", port=9099, root_path='/dev-api', reload=True) + uvicorn.run( + app='app:app', + host=AppConfig.app_host, + port=AppConfig.app_port, + root_path=AppConfig.app_root_path, + reload=AppConfig.app_reload + ) diff --git a/ruoyi-fastapi-backend/caches/profile/avatar/blob_20240119210836.jpeg b/ruoyi-fastapi-backend/caches/profile/avatar/blob_20240119210836.jpeg deleted file mode 100644 index 98516d21b8043e34e36893a2219f29d13759b89d..0000000000000000000000000000000000000000 Binary files a/ruoyi-fastapi-backend/caches/profile/avatar/blob_20240119210836.jpeg and /dev/null differ diff --git a/ruoyi-fastapi-backend/config/database.py b/ruoyi-fastapi-backend/config/database.py index a9acc4c4f06f77155e6cbe2feaf82c7a0a7babc9..8d2012fbcd07067aacb69682876e474444058ace 100644 --- a/ruoyi-fastapi-backend/config/database.py +++ b/ruoyi-fastapi-backend/config/database.py @@ -4,8 +4,8 @@ from sqlalchemy.orm import sessionmaker from urllib.parse import quote_plus from config.env import DataBaseConfig -SQLALCHEMY_DATABASE_URL = f"mysql+pymysql://{DataBaseConfig.USERNAME}:{quote_plus(DataBaseConfig.PASSWORD)}@" \ - f"{DataBaseConfig.HOST}:{DataBaseConfig.PORT}/{DataBaseConfig.DB}" +SQLALCHEMY_DATABASE_URL = f"mysql+pymysql://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@" \ + f"{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}" engine = create_engine( SQLALCHEMY_DATABASE_URL, echo=True diff --git a/ruoyi-fastapi-backend/config/env.py b/ruoyi-fastapi-backend/config/env.py index 8b2121f91b171ba7a714db2dbe307320cb5aae9b..224a2708a0292022bc1fd874b6556a3952053a9c 100644 --- a/ruoyi-fastapi-backend/config/env.py +++ b/ruoyi-fastapi-backend/config/env.py @@ -1,39 +1,57 @@ import os +import sys +import argparse +from pydantic_settings import BaseSettings +from functools import lru_cache +from dotenv import load_dotenv -class JwtConfig: +class AppSettings(BaseSettings): + """ + 应用配置 + """ + app_env: str = 'dev' + app_name: str = 'RuoYi-FasAPI' + app_root_path: str = '/dev-api' + app_host: str = '0.0.0.0' + app_port: int = 9099 + app_version: str = '1.0.0' + app_reload: bool = True + + +class JwtSettings(BaseSettings): """ Jwt配置 """ - SECRET_KEY = "b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55" - ALGORITHM = "HS256" - ACCESS_TOKEN_EXPIRE_MINUTES = 1440 - REDIS_TOKEN_EXPIRE_MINUTES = 30 + jwt_secret_key: str = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55' + jwt_algorithm: str = 'HS256' + jwt_expire_minutes: int = 1440 + jwt_redis_expire_minutes: int = 30 -class DataBaseConfig: +class DataBaseSettings(BaseSettings): """ 数据库配置 """ - HOST = "127.0.0.1" - PORT = 3306 - USERNAME = 'root' - PASSWORD = 'mysqlroot' - DB = 'ruoyi-fastapi' + db_host: str = '127.0.0.1' + db_port: int = 3306 + db_username: str = 'root' + db_password: str = 'mysqlroot' + db_database: str = 'ruoyi-fastapi' -class RedisConfig: +class RedisSettings(BaseSettings): """ Redis配置 """ - HOST = "127.0.0.1" - PORT = 6379 - USERNAME = '' - PASSWORD = '' - DB = 2 + redis_host: str = '127.0.0.1' + redis_port: int = 6379 + redis_username: str = '' + redis_password: str = '' + redis_database: int = 2 -class UploadConfig: +class UploadSettings: """ 上传配置 """ @@ -80,3 +98,92 @@ class RedisInitKeyConfig: ACCOUNT_LOCK = {'key': 'account_lock', 'remark': '用户锁定'} PASSWORD_ERROR_COUNT = {'key': 'password_error_count', 'remark': '密码错误次数'} SMS_CODE = {'key': 'sms_code', 'remark': '短信验证码'} + + +class GetConfig: + """ + 获取配置 + """ + + def __init__(self): + self.parse_cli_args() + + @lru_cache() + def get_app_config(self): + """ + 获取应用配置 + """ + # 实例化应用配置模型 + return AppSettings() + + @lru_cache() + def get_jwt_config(self): + """ + 获取Jwt配置 + """ + # 实例化Jwt配置模型 + return JwtSettings() + + @lru_cache() + def get_database_config(self): + """ + 获取数据库配置 + """ + # 实例化数据库配置模型 + return DataBaseSettings() + + @lru_cache() + def get_redis_config(self): + """ + 获取Redis配置 + """ + # 实例化Redis配置模型 + return RedisSettings() + + @lru_cache() + def get_upload_config(self): + """ + 获取数据库配置 + """ + # 实例上传配置 + return UploadSettings() + + @staticmethod + def parse_cli_args(): + """ + 解析命令行参数 + """ + if 'uvicorn' in sys.argv[0]: + # 使用uvicorn启动时,命令行参数需要按照uvicorn的文档进行配置,无法自定义参数 + pass + else: + # 使用argparse定义命令行参数 + parser = argparse.ArgumentParser(description='命令行参数') + parser.add_argument('--env', type=str, default='', help='运行环境') + # 解析命令行参数 + args = parser.parse_args() + # 设置环境变量,如果未设置命令行参数,默认APP_ENV为dev + os.environ['APP_ENV'] = args.env if args.env else 'dev' + # 读取运行环境 + run_env = os.environ.get('APP_ENV', '') + # 运行环境未指定时默认加载.env.dev + env_file = '.env.dev' + # 运行环境不为空时按命令行参数加载对应.env文件 + if run_env != '': + env_file = f'.env.{run_env}' + # 加载配置 + load_dotenv(env_file) + + +# 实例化获取配置类 +get_config = GetConfig() +# 应用配置 +AppConfig = get_config.get_app_config() +# Jwt配置 +JwtConfig = get_config.get_jwt_config() +# 数据库配置 +DataBaseConfig = get_config.get_database_config() +# Redis配置 +RedisConfig = get_config.get_redis_config() +# 上传配置 +UploadConfig = get_config.get_upload_config() diff --git a/ruoyi-fastapi-backend/config/get_redis.py b/ruoyi-fastapi-backend/config/get_redis.py index c7bc8ec6dfdca02c4670df43e2c4e55699ad8cb0..4c3ef800f881cae013ac0d3a76590b98d5860ceb 100644 --- a/ruoyi-fastapi-backend/config/get_redis.py +++ b/ruoyi-fastapi-backend/config/get_redis.py @@ -1,4 +1,5 @@ -import aioredis +from redis import asyncio as aioredis +from redis.exceptions import AuthenticationError, TimeoutError, RedisError from module_admin.service.dict_service import DictDataService from module_admin.service.config_service import ConfigService from config.env import RedisConfig @@ -19,15 +20,26 @@ class RedisUtil: """ logger.info("开始连接redis...") redis = await aioredis.from_url( - url=f"redis://{RedisConfig.HOST}", - port=RedisConfig.PORT, - username=RedisConfig.USERNAME, - password=RedisConfig.PASSWORD, - db=RedisConfig.DB, + url=f"redis://{RedisConfig.redis_host}", + port=RedisConfig.redis_port, + username=RedisConfig.redis_username, + password=RedisConfig.redis_password, + db=RedisConfig.redis_database, encoding="utf-8", decode_responses=True ) - logger.info("redis连接成功") + try: + connection = await redis.ping() + if connection: + logger.info("redis连接成功") + else: + logger.error("redis连接失败") + except AuthenticationError as e: + logger.error(f"redis用户名或密码错误,详细错误信息:{e}") + except TimeoutError as e: + logger.error(f"redis连接超时,详细错误信息:{e}") + except RedisError as e: + logger.error(f"redis连接错误,详细错误信息:{e}") return redis @classmethod diff --git a/ruoyi-fastapi-backend/config/get_scheduler.py b/ruoyi-fastapi-backend/config/get_scheduler.py index 3910ebe3a518b5b4c459cd87779d3a698c27762c..17e5ae5bb8e6f8b4de759fee04c30de0cfb4acf5 100644 --- a/ruoyi-fastapi-backend/config/get_scheduler.py +++ b/ruoyi-fastapi-backend/config/get_scheduler.py @@ -70,11 +70,11 @@ job_stores = { 'sqlalchemy': SQLAlchemyJobStore(url=SQLALCHEMY_DATABASE_URL, engine=engine), 'redis': RedisJobStore( **dict( - host=RedisConfig.HOST, - port=RedisConfig.PORT, - username=RedisConfig.USERNAME, - password=RedisConfig.PASSWORD, - db=RedisConfig.DB + host=RedisConfig.redis_host, + port=RedisConfig.redis_port, + username=RedisConfig.redis_username, + password=RedisConfig.redis_password, + db=RedisConfig.redis_database ) ) } diff --git a/ruoyi-fastapi-backend/exceptions/exception.py b/ruoyi-fastapi-backend/exceptions/exception.py new file mode 100644 index 0000000000000000000000000000000000000000..ef2fda06fdc21e8ea79bf5969483e4a97e7018c5 --- /dev/null +++ b/ruoyi-fastapi-backend/exceptions/exception.py @@ -0,0 +1,28 @@ +class LoginException(Exception): + """ + 自定义登录异常LoginException + """ + + def __init__(self, data: str = None, message: str = None): + self.data = data + self.message = message + + +class AuthException(Exception): + """ + 自定义令牌异常AuthException + """ + + def __init__(self, data: str = None, message: str = None): + self.data = data + self.message = message + + +class PermissionException(Exception): + """ + 自定义权限异常PermissionException + """ + + def __init__(self, data: str = None, message: str = None): + self.data = data + self.message = message diff --git a/ruoyi-fastapi-backend/exceptions/handle.py b/ruoyi-fastapi-backend/exceptions/handle.py new file mode 100644 index 0000000000000000000000000000000000000000..61b7f9009f07b85e14f95399ee2671527792790a --- /dev/null +++ b/ruoyi-fastapi-backend/exceptions/handle.py @@ -0,0 +1,27 @@ +from fastapi import FastAPI, Request +from fastapi.exceptions import HTTPException +from exceptions.exception import AuthException, PermissionException +from utils.response_util import ResponseUtil, JSONResponse, jsonable_encoder + + +def handle_exception(app: FastAPI): + """ + 全局异常处理 + """ + # 自定义token检验异常 + @app.exception_handler(AuthException) + async def auth_exception_handler(request: Request, exc: AuthException): + return ResponseUtil.unauthorized(data=exc.data, msg=exc.message) + + # 自定义权限检验异常 + @app.exception_handler(PermissionException) + async def permission_exception_handler(request: Request, exc: PermissionException): + return ResponseUtil.forbidden(data=exc.data, msg=exc.message) + + # 处理其他http请求异常 + @app.exception_handler(HTTPException) + async def http_exception_handler(request: Request, exc: HTTPException): + return JSONResponse( + content=jsonable_encoder({"code": exc.status_code, "msg": exc.detail}), + status_code=exc.status_code + ) diff --git a/ruoyi-fastapi-backend/middlewares/cors_middleware.py b/ruoyi-fastapi-backend/middlewares/cors_middleware.py new file mode 100644 index 0000000000000000000000000000000000000000..4b78db9fc1f66cd449810a626cbbc3d4b88b49b7 --- /dev/null +++ b/ruoyi-fastapi-backend/middlewares/cors_middleware.py @@ -0,0 +1,19 @@ +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware + + +def add_cors_middleware(app: FastAPI): + # 前端页面url + origins = [ + "http://localhost:80", + "http://127.0.0.1:80", + ] + + # 后台api允许跨域 + app.add_middleware( + CORSMiddleware, + allow_origins=origins, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) diff --git a/ruoyi-fastapi-backend/middlewares/handle.py b/ruoyi-fastapi-backend/middlewares/handle.py new file mode 100644 index 0000000000000000000000000000000000000000..311ec6b62d27957b8aade8920b867ee8c818f8a0 --- /dev/null +++ b/ruoyi-fastapi-backend/middlewares/handle.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI +from middlewares.cors_middleware import add_cors_middleware + + +def handle_middleware(app: FastAPI): + """ + 全局中间件处理 + """ + # 加载跨域中间件 + add_cors_middleware(app) diff --git a/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py b/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py index 876670a8c14ecea29a57c358eac33f9b3cd64773..d91bdb4dfe022ffbc28cfab35b530408fd55fc48 100644 --- a/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py +++ b/ruoyi-fastapi-backend/module_admin/aspect/interface_auth.py @@ -1,7 +1,7 @@ from fastapi import Depends from module_admin.entity.vo.user_vo import CurrentUserModel from module_admin.service.login_service import LoginService -from utils.response_util import PermissionException +from exceptions.exception import PermissionException class CheckUserInterfaceAuth: diff --git a/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py b/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py index 8028ece7b25bc8f8d8d189f72b430591f7707c6b..4fc64b66b666dd2e8c21b5701ee218dbb35ed7f0 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/captcha_controller.py @@ -15,6 +15,8 @@ captchaController = APIRouter() async def get_captcha_image(request: Request): try: captcha_enabled = True if await request.app.state.redis.get(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") == 'true' else False + register_enabled = True if await request.app.state.redis.get( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.registerUser") == 'true' else False session_id = str(uuid.uuid4()) captcha_result = CaptchaService.create_captcha_image_service() image = captcha_result[0] @@ -22,7 +24,7 @@ async def get_captcha_image(request: Request): await request.app.state.redis.set(f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{session_id}", computed_result, ex=timedelta(minutes=2)) logger.info(f'编号为{session_id}的会话获取图片验证码成功') return ResponseUtil.success( - model_content=CaptchaCode(captchaEnabled=captcha_enabled, img=image, uuid=session_id) + model_content=CaptchaCode(captchaEnabled=captcha_enabled, registerEnabled=register_enabled, img=image, uuid=session_id) ) except Exception as e: logger.exception(e) diff --git a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py index 65f1b6ca4985683eef0e207b56e0f97ff1de8d53..db89e20e4a1a8225215f530e0a9da37d01a91fa4 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/config_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/config_controller.py @@ -17,11 +17,8 @@ configController = APIRouter(prefix='/system/config', dependencies=[Depends(Logi @configController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:list'))]) async def get_system_config_list(request: Request, config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - config_query = ConfigQueryModel(**config_page_query.model_dump(by_alias=True)) - # 获取全量数据 - config_query_result = ConfigService.get_config_list_services(query_db, config_query) - # 分页操作 - config_page_query_result = get_page_obj(config_query_result, config_page_query.page_num, config_page_query.page_size) + # 获取分页数据 + config_page_query_result = ConfigService.get_config_list_services(query_db, config_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=config_page_query_result) except Exception as e: @@ -125,9 +122,8 @@ async def query_system_config(request: Request, config_key: str): @log_decorator(title='参数管理', business_type=5) async def export_system_config_list(request: Request, config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - config_query = ConfigQueryModel(**config_page_query.model_dump(by_alias=True)) # 获取全量数据 - config_query_result = ConfigService.get_config_list_services(query_db, config_query) + config_query_result = ConfigService.get_config_list_services(query_db, config_page_query, is_page=False) config_export_result = ConfigService.export_config_list_services(config_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(config_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py index d69a839b5eae7101b326a2ece35ab55dd937bcb2..51e61f464fc8cd60cc21a58e4c6b66c034ab0bb6 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/dict_controller.py @@ -5,7 +5,7 @@ from module_admin.service.login_service import LoginService, CurrentUserModel from module_admin.service.dict_service import * from utils.response_util import * from utils.log_util import * -from utils.page_util import * +from utils.page_util import PageResponseModel from utils.common_util import bytes2file_response from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.annotation.log_annotation import log_decorator @@ -17,11 +17,8 @@ dictController = APIRouter(prefix='/system/dict', dependencies=[Depends(LoginSer @dictController.get("/type/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]) async def get_system_dict_type_list(request: Request, dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - dict_type_query = DictTypeQueryModel(**dict_type_page_query.model_dump(by_alias=True)) - # 获取全量数据 - dict_type_query_result = DictTypeService.get_dict_type_list_services(query_db, dict_type_query) - # 分页操作 - dict_type_page_query_result = get_page_obj(dict_type_query_result, dict_type_page_query.page_num, dict_type_page_query.page_size) + # 获取分页数据 + dict_type_page_query_result = DictTypeService.get_dict_type_list_services(query_db, dict_type_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=dict_type_page_query_result) except Exception as e: @@ -101,7 +98,7 @@ async def delete_system_dict_type(request: Request, dict_ids: str, query_db: Ses @dictController.get("/type/optionselect", response_model=List[DictTypeModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))]) async def query_system_dict_type_options(request: Request, query_db: Session = Depends(get_db)): try: - dict_type_query_result = DictTypeService.get_dict_type_list_services(query_db, DictTypeQueryModel(**dict())) + dict_type_query_result = DictTypeService.get_dict_type_list_services(query_db, DictTypePageQueryModel(**dict()), is_page=False) logger.info(f'获取成功') return ResponseUtil.success(data=dict_type_query_result) except Exception as e: @@ -124,9 +121,8 @@ async def query_detail_system_dict_type(request: Request, dict_id: int, query_db @log_decorator(title='字典管理', business_type=5) async def export_system_dict_type_list(request: Request, dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - dict_type_query = DictTypeQueryModel(**dict_type_page_query.model_dump(by_alias=True)) # 获取全量数据 - dict_type_query_result = DictTypeService.get_dict_type_list_services(query_db, dict_type_query) + dict_type_query_result = DictTypeService.get_dict_type_list_services(query_db, dict_type_page_query, is_page=False) dict_type_export_result = DictTypeService.export_dict_type_list_services(dict_type_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(dict_type_export_result)) @@ -150,11 +146,8 @@ async def query_system_dict_type_data(request: Request, dict_type: str, query_db @dictController.get("/data/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]) async def get_system_dict_data_list(request: Request, dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - dict_data_query = DictDataModel(**dict_data_page_query.model_dump(by_alias=True)) - # 获取全量数据 - dict_data_query_result = DictDataService.get_dict_data_list_services(query_db, dict_data_query) - # 分页操作 - dict_data_page_query_result = get_page_obj(dict_data_query_result, dict_data_page_query.page_num, dict_data_page_query.page_size) + # 获取分页数据 + dict_data_page_query_result = DictDataService.get_dict_data_list_services(query_db, dict_data_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=dict_data_page_query_result) except Exception as e: @@ -230,9 +223,8 @@ async def query_detail_system_dict_data(request: Request, dict_code: int, query_ @log_decorator(title='字典管理', business_type=5) async def export_system_dict_data_list(request: Request, dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - dict_data_query = DictDataModel(**dict_data_page_query.model_dump(by_alias=True)) # 获取全量数据 - dict_data_query_result = DictDataService.get_dict_data_list_services(query_db, dict_data_query) + dict_data_query_result = DictDataService.get_dict_data_list_services(query_db, dict_data_page_query, is_page=False) dict_data_export_result = DictDataService.export_dict_data_list_services(dict_data_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(dict_data_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py index dce55016bfffea99122294bb7f80db3bb1fe3ca1..508dd2c368f14838606d27ab96b5e11e79d83a43 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/job_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/job_controller.py @@ -18,11 +18,8 @@ jobController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService. @jobController.get("/job/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))]) async def get_system_job_list(request: Request, job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - job_query = JobModel(**job_page_query.model_dump(by_alias=True)) - # 获取全量数据 - job_query_result = JobService.get_job_list_services(query_db, job_query) - # 分页操作 - notice_page_query_result = get_page_obj(job_query_result, job_page_query.page_num, job_page_query.page_size) + # 获取分页数据 + notice_page_query_result = JobService.get_job_list_services(query_db, job_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=notice_page_query_result) except Exception as e: @@ -133,9 +130,8 @@ async def query_detail_system_job(request: Request, job_id: int, query_db: Sessi @log_decorator(title='定时任务管理', business_type=5) async def export_system_job_list(request: Request, job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - job_query = JobModel(**job_page_query.model_dump(by_alias=True)) # 获取全量数据 - job_query_result = JobService.get_job_list_services(query_db, job_query) + job_query_result = JobService.get_job_list_services(query_db, job_page_query, is_page=False) job_export_result = await JobService.export_job_list_services(request, job_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(job_export_result)) @@ -147,13 +143,10 @@ async def export_system_job_list(request: Request, job_page_query: JobPageQueryM @jobController.get("/jobLog/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))]) async def get_system_job_log_list(request: Request, job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - job_log_query = JobLogQueryModel(**job_log_page_query.model_dump(by_alias=True)) - # 获取全量数据 - job_log_query_result = JobLogService.get_job_log_list_services(query_db, job_log_query) - # 分页操作 - notice_page_query_result = get_page_obj(job_log_query_result, job_log_page_query.page_num, job_log_page_query.page_size) + # 获取分页数据 + job_log_page_query_result = JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=True) logger.info('获取成功') - return ResponseUtil.success(model_content=notice_page_query_result) + return ResponseUtil.success(model_content=job_log_page_query_result) except Exception as e: logger.exception(e) return ResponseUtil.error(msg=str(e)) @@ -196,10 +189,9 @@ async def clear_system_job_log(request: Request, query_db: Session = Depends(get @log_decorator(title='定时任务日志管理', business_type=5) async def export_system_job_log_list(request: Request, job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - job_log_query = JobLogQueryModel(**job_log_page_query.model_dump(by_alias=True)) # 获取全量数据 - job_log_query_result = JobLogService.get_job_log_list_services(query_db, job_log_query) - job_log_export_result = JobLogService.export_job_log_list_services(query_db, job_log_query_result) + job_log_query_result = JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=False) + job_log_export_result = await JobLogService.export_job_log_list_services(request, job_log_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(job_log_export_result)) except Exception as e: diff --git a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py index bf00fd87837d3df0972044f0df6457aa6615bdc4..095ca5ea9bf95f3a98a4df92b1f1d537906909c8 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/log_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/log_controller.py @@ -17,11 +17,8 @@ logController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService. @logController.get("/operlog/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:list'))]) async def get_system_operation_log_list(request: Request, operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - operation_log_query = OperLogQueryModel(**operation_log_page_query.model_dump(by_alias=True)) - # 获取全量数据 - operation_log_query_result = OperationLogService.get_operation_log_list_services(query_db, operation_log_query) - # 分页操作 - operation_log_page_query_result = get_page_obj(operation_log_query_result, operation_log_page_query.page_num, operation_log_page_query.page_size) + # 获取分页数据 + operation_log_page_query_result = OperationLogService.get_operation_log_list_services(query_db, operation_log_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=operation_log_page_query_result) except Exception as e: @@ -66,9 +63,8 @@ async def delete_system_operation_log(request: Request, oper_ids: str, query_db: @log_decorator(title='操作日志管理', business_type=5) async def export_system_operation_log_list(request: Request, operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - operation_log_query = OperLogQueryModel(**operation_log_page_query.model_dump(by_alias=True)) # 获取全量数据 - operation_log_query_result = OperationLogService.get_operation_log_list_services(query_db, operation_log_query) + operation_log_query_result = OperationLogService.get_operation_log_list_services(query_db, operation_log_page_query, is_page=False) operation_log_export_result = await OperationLogService.export_operation_log_list_services(request, operation_log_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result)) @@ -80,11 +76,8 @@ async def export_system_operation_log_list(request: Request, operation_log_page_ @logController.get("/logininfor/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:list'))]) async def get_system_login_log_list(request: Request, login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - login_log_query = LoginLogQueryModel(**login_log_page_query.model_dump(by_alias=True)) - # 获取全量数据 - login_log_query_result = LoginLogService.get_login_log_list_services(query_db, login_log_query) - # 分页操作 - login_log_page_query_result = get_page_obj(login_log_query_result, login_log_page_query.page_num, login_log_page_query.page_size) + # 获取分页数据 + login_log_page_query_result = LoginLogService.get_login_log_list_services(query_db, login_log_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=login_log_page_query_result) except Exception as e: @@ -146,9 +139,8 @@ async def clear_system_login_log(request: Request, user_name: str, query_db: Ses @log_decorator(title='登录日志管理', business_type=5) async def export_system_login_log_list(request: Request, login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - login_log_query = LoginLogQueryModel(**login_log_page_query.model_dump(by_alias=True)) # 获取全量数据 - login_log_query_result = LoginLogService.get_login_log_list_services(query_db, login_log_query) + login_log_query_result = LoginLogService.get_login_log_list_services(query_db, login_log_page_query, is_page=False) login_log_export_result = LoginLogService.export_login_log_list_services(login_log_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(login_log_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py index 4d52d156bcf31df237a4ea4935fb78277c39795f..a036862a4dbba5406fe8f4f1a970e99bdbad5114 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/login_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/login_controller.py @@ -2,10 +2,10 @@ from fastapi import APIRouter from module_admin.service.login_service import * from module_admin.entity.vo.login_vo import * from module_admin.dao.login_dao import * +from module_admin.annotation.log_annotation import log_decorator from config.env import JwtConfig, RedisInitKeyConfig -from utils.response_util import * +from utils.response_util import ResponseUtil from utils.log_util import * -from module_admin.annotation.log_annotation import log_decorator from datetime import timedelta @@ -29,7 +29,7 @@ async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = D except LoginException as e: return ResponseUtil.failure(msg=e.message) try: - access_token_expires = timedelta(minutes=JwtConfig.ACCESS_TOKEN_EXPIRE_MINUTES) + access_token_expires = timedelta(minutes=JwtConfig.jwt_expire_minutes) session_id = str(uuid.uuid4()) access_token = LoginService.create_access_token( data={ @@ -42,10 +42,11 @@ async def login(request: Request, form_data: CustomOAuth2PasswordRequestForm = D expires_delta=access_token_expires ) await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", access_token, - ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES)) + ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) # 此方法可实现同一账号同一时间只能登录一次 # await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{result[0].user_id}", access_token, - # ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES)) + # ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) + UserService.edit_user_services(query_db, EditUserModel(userId=result[0].user_id, loginDate=datetime.now(), type='status')) logger.info('登录成功') # 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False @@ -82,42 +83,57 @@ async def get_login_user_routers(request: Request, current_user: CurrentUserMode return ResponseUtil.error(msg=str(e)) -@loginController.post("/getSmsCode", response_model=SmsCode) -async def get_sms_code(request: Request, user: ResetUserModel, query_db: Session = Depends(get_db)): +@loginController.post("/register", response_model=CrudResponseModel) +async def register_user(request: Request, user_register: UserRegister, query_db: Session = Depends(get_db)): try: - sms_result = await get_sms_code_services(request, query_db, user) - if sms_result.is_success: - logger.info('获取成功') - return response_200(data=sms_result, message='获取成功') + user_register_result = await LoginService.register_user_services(request, query_db, user_register) + if user_register_result.is_success: + logger.info(user_register_result.message) + return ResponseUtil.success(data=user_register_result, msg=user_register_result.message) else: - logger.warning(sms_result.message) - return response_400(data='', message=sms_result.message) + logger.warning(user_register_result.message) + return ResponseUtil.failure(msg=user_register_result.message) except Exception as e: logger.exception(e) - return response_500(data="", message=str(e)) + return ResponseUtil.error(msg=str(e)) -@loginController.post("/forgetPwd", response_model=CrudResponseModel) -async def forget_user_pwd(request: Request, forget_user: ResetUserModel, query_db: Session = Depends(get_db)): - try: - forget_user_result = await forget_user_services(request, query_db, forget_user) - if forget_user_result.is_success: - logger.info(forget_user_result.message) - return response_200(data=forget_user_result, message=forget_user_result.message) - else: - logger.warning(forget_user_result.message) - return response_400(data="", message=forget_user_result.message) - except Exception as e: - logger.exception(e) - return response_500(data="", message=str(e)) +# @loginController.post("/getSmsCode", response_model=SmsCode) +# async def get_sms_code(request: Request, user: ResetUserModel, query_db: Session = Depends(get_db)): +# try: +# sms_result = await LoginService.get_sms_code_services(request, query_db, user) +# if sms_result.is_success: +# logger.info('获取成功') +# return ResponseUtil.success(data=sms_result) +# else: +# logger.warning(sms_result.message) +# return ResponseUtil.failure(msg=sms_result.message) +# except Exception as e: +# logger.exception(e) +# return ResponseUtil.error(msg=str(e)) +# +# +# @loginController.post("/forgetPwd", response_model=CrudResponseModel) +# async def forget_user_pwd(request: Request, forget_user: ResetUserModel, query_db: Session = Depends(get_db)): +# try: +# forget_user_result = await LoginService.forget_user_services(request, query_db, forget_user) +# if forget_user_result.is_success: +# logger.info(forget_user_result.message) +# return ResponseUtil.success(data=forget_user_result, msg=forget_user_result.message) +# else: +# logger.warning(forget_user_result.message) +# return ResponseUtil.failure(msg=forget_user_result.message) +# except Exception as e: +# logger.exception(e) +# return ResponseUtil.error(msg=str(e)) @loginController.post("/logout") async def logout(request: Request, token: Optional[str] = Depends(oauth2_scheme)): try: - payload = jwt.decode(token, JwtConfig.SECRET_KEY, algorithms=[JwtConfig.ALGORITHM]) + payload = jwt.decode(token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm]) session_id: str = payload.get("session_id") - await logout_services(request, session_id) + await LoginService.logout_services(request, session_id) logger.info('退出成功') return ResponseUtil.success(msg="退出成功") except Exception as e: diff --git a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py index 6c9836166f65dbd046bdd5801237bae47d688837..4caaa7a680a4cacc1e4246ee46a0c648c2c93ae2 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/notice_controller.py @@ -16,11 +16,8 @@ noticeController = APIRouter(prefix='/system/notice', dependencies=[Depends(Logi @noticeController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:list'))]) async def get_system_notice_list(request: Request, notice_page_query: NoticePageQueryModel = Depends(NoticePageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - notice_query = NoticeQueryModel(**notice_page_query.model_dump(by_alias=True)) - # 获取全量数据 - notice_query_result = NoticeService.get_notice_list_services(query_db, notice_query) - # 分页操作 - notice_page_query_result = get_page_obj(notice_query_result, notice_page_query.page_num, notice_page_query.page_size) + # 获取分页数据 + notice_page_query_result = NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=notice_page_query_result) except Exception as e: diff --git a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py index d07d2b125e84e40f95aa9668261363b5f8253998..ebf41ea78e393355c7b57bb7c3aa7b65fe60a4c5 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/post_controler.py +++ b/ruoyi-fastapi-backend/module_admin/controller/post_controler.py @@ -18,11 +18,8 @@ postController = APIRouter(prefix='/system/post', dependencies=[Depends(LoginSer @postController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:list'))]) async def get_system_post_list(request: Request, post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - post_query = PostModel(**post_page_query.model_dump(by_alias=True)) - # 获取全量数据 - post_query_result = PostService.get_post_list_services(query_db, post_query) - # 分页操作 - post_page_query_result = get_page_obj(post_query_result, post_page_query.page_num, post_page_query.page_size) + # 获取分页数据 + post_page_query_result = PostService.get_post_list_services(query_db, post_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=post_page_query_result) except Exception as e: @@ -98,9 +95,8 @@ async def query_detail_system_post(request: Request, post_id: int, query_db: Ses @log_decorator(title='岗位管理', business_type=5) async def export_system_post_list(request: Request, post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - post_query = PostModel(**post_page_query.model_dump(by_alias=True)) # 获取全量数据 - post_query_result = PostService.get_post_list_services(query_db, post_query) + post_query_result = PostService.get_post_list_services(query_db, post_page_query, is_page=False) post_export_result = PostService.export_post_list_services(post_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(post_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py index 4007ec58c32b686fd9b56b3c2af5ad8700682f30..d99096e9fd373c4d618b5024aa1cb180717ddbb3 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/role_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/role_controller.py @@ -7,7 +7,7 @@ from module_admin.service.dept_service import DeptService, DeptModel from module_admin.service.user_service import UserService, UserRoleQueryModel, UserRolePageQueryModel, CrudUserRoleModel from utils.response_util import * from utils.log_util import * -from utils.page_util import * +from utils.page_util import PageResponseModel from utils.common_util import bytes2file_response from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.data_scope import GetDataScope @@ -33,10 +33,7 @@ async def get_system_role_dept_tree(request: Request, role_id: int, query_db: Se @roleController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]) async def get_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - role_query = RoleQueryModel(**role_page_query.model_dump(by_alias=True)) - role_query_result = RoleService.get_role_list_services(query_db, role_query) - # 分页操作 - role_page_query_result = get_page_obj(role_query_result, role_page_query.page_num, role_page_query.page_size) + role_page_query_result = RoleService.get_role_list_services(query_db, role_page_query, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=role_page_query_result) except Exception as e: @@ -134,9 +131,8 @@ async def query_detail_system_role(request: Request, role_id: int, query_db: Ses @log_decorator(title='角色管理', business_type=5) async def export_system_role_list(request: Request, role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_form), query_db: Session = Depends(get_db)): try: - role_query = RoleQueryModel(**role_page_query.model_dump(by_alias=True)) # 获取全量数据 - role_query_result = RoleService.get_role_list_services(query_db, role_query) + role_query_result = RoleService.get_role_list_services(query_db, role_page_query, is_page=False) role_export_result = RoleService.export_role_list_services(role_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(role_export_result)) @@ -167,10 +163,7 @@ async def reset_system_role_status(request: Request, edit_role: AddRoleModel, qu @roleController.get("/authUser/allocatedList", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('common'))]) async def get_system_allocated_user_list(request: Request, user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - role_user_query = UserRoleQueryModel(**user_role.model_dump(by_alias=True)) - role_user_allocated_query_result = RoleService.get_role_user_allocated_list_services(query_db, role_user_query) - # 分页操作 - role_user_allocated_page_query_result = get_page_obj(role_user_allocated_query_result, user_role.page_num, user_role.page_size) + role_user_allocated_page_query_result = RoleService.get_role_user_allocated_list_services(query_db, user_role, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=role_user_allocated_page_query_result) except Exception as e: @@ -181,10 +174,7 @@ async def get_system_allocated_user_list(request: Request, user_role: UserRolePa @roleController.get("/authUser/unallocatedList", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('common'))]) async def get_system_unallocated_user_list(request: Request, user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query), query_db: Session = Depends(get_db)): try: - role_user_query = UserRoleQueryModel(**user_role.model_dump(by_alias=True)) - role_user_unallocated_query_result = RoleService.get_role_user_unallocated_list_services(query_db, role_user_query) - # 分页操作 - role_user_unallocated_page_query_result = get_page_obj(role_user_unallocated_query_result, user_role.page_num, user_role.page_size) + role_user_unallocated_page_query_result = RoleService.get_role_user_unallocated_list_services(query_db, user_role, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=role_user_unallocated_page_query_result) except Exception as e: diff --git a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py index d9b1eba9c57b48b856677a806af48ca354f28344..46ea0b82f9c708c8b535c67427978a4b5d25b42d 100644 --- a/ruoyi-fastapi-backend/module_admin/controller/user_controller.py +++ b/ruoyi-fastapi-backend/module_admin/controller/user_controller.py @@ -5,7 +5,7 @@ from config.env import UploadConfig from module_admin.service.login_service import LoginService from module_admin.service.user_service import * from module_admin.service.dept_service import DeptService -from utils.page_util import * +from utils.page_util import PageResponseModel from utils.response_util import * from utils.log_util import * from utils.common_util import bytes2file_response @@ -32,11 +32,8 @@ async def get_system_dept_tree(request: Request, query_db: Session = Depends(get @userController.get("/list", response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]) async def get_system_user_list(request: Request, user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_query), query_db: Session = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): try: - user_query = UserQueryModel(**user_page_query.model_dump(by_alias=True)) - # 获取全量数据 - user_query_result = UserService.get_user_list_services(query_db, user_query, data_scope_sql) - # 分页操作 - user_page_query_result = get_page_obj(user_query_result, user_page_query.page_num, user_page_query.page_size) + # 获取分页数据 + user_page_query_result = UserService.get_user_list_services(query_db, user_page_query, data_scope_sql, is_page=True) logger.info('获取成功') return ResponseUtil.success(model_content=user_page_query_result) except Exception as e: @@ -272,9 +269,8 @@ async def export_system_user_template(request: Request, query_db: Session = Depe @log_decorator(title='用户管理', business_type=5) async def export_system_user_list(request: Request, user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_form), query_db: Session = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysUser'))): try: - user_query = UserQueryModel(**user_page_query.model_dump(by_alias=True)) # 获取全量数据 - user_query_result = UserService.get_user_list_services(query_db, user_query, data_scope_sql) + user_query_result = UserService.get_user_list_services(query_db, user_page_query, data_scope_sql, is_page=False) user_export_result = UserService.export_user_list_services(user_query_result) logger.info('导出成功') return ResponseUtil.streaming(data=bytes2file_response(user_export_result)) diff --git a/ruoyi-fastapi-backend/module_admin/dao/config_dao.py b/ruoyi-fastapi-backend/module_admin/dao/config_dao.py index 3efea39818e0daf8bf5f6b5d8403700e76b81bbc..7a13a97a58b9d1ce281659eab9a0bb3799bb14d4 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/config_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/config_dao.py @@ -1,6 +1,7 @@ from sqlalchemy.orm import Session from module_admin.entity.do.config_do import SysConfig from module_admin.entity.vo.config_vo import * +from utils.page_util import PageUtil from datetime import datetime, time @@ -39,14 +40,15 @@ class ConfigDao: return config_info @classmethod - def get_config_list(cls, db: Session, query_object: ConfigQueryModel): + def get_config_list(cls, db: Session, query_object: ConfigPageQueryModel, is_page: bool = False): """ 根据查询参数获取参数配置列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 参数配置列表信息对象 """ - config_list = db.query(SysConfig) \ + query = db.query(SysConfig) \ .filter(SysConfig.config_name.like(f'%{query_object.config_name}%') if query_object.config_name else True, SysConfig.config_key.like(f'%{query_object.config_key}%') if query_object.config_key else True, SysConfig.config_type == query_object.config_type if query_object.config_type else True, @@ -55,7 +57,8 @@ class ConfigDao: datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) if query_object.begin_time and query_object.end_time else True ) \ - .distinct().all() + .distinct() + config_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return config_list diff --git a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py index d938c145271332302a6c779db4b00bb1131d991c..3b7d127d8ad534f932dec146920b643ea21e8ba5 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/dict_dao.py @@ -3,6 +3,7 @@ from sqlalchemy.orm import Session from module_admin.entity.do.dict_do import SysDictType, SysDictData from module_admin.entity.vo.dict_vo import * from utils.time_format_util import list_format_datetime +from utils.page_util import PageUtil from datetime import datetime, time @@ -52,14 +53,15 @@ class DictTypeDao: return list_format_datetime(dict_type_info) @classmethod - def get_dict_type_list(cls, db: Session, query_object: DictTypeQueryModel): + def get_dict_type_list(cls, db: Session, query_object: DictTypePageQueryModel, is_page: bool = False): """ 根据查询参数获取字典类型列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 字典类型列表信息对象 """ - dict_type_list = db.query(SysDictType) \ + query = db.query(SysDictType) \ .filter(SysDictType.dict_name.like(f'%{query_object.dict_name}%') if query_object.dict_name else True, SysDictType.dict_type.like(f'%{query_object.dict_type}%') if query_object.dict_type else True, SysDictType.status == query_object.status if query_object.status else True, @@ -68,7 +70,8 @@ class DictTypeDao: datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) if query_object.begin_time and query_object.end_time else True ) \ - .distinct().all() + .distinct() + dict_type_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return dict_type_list @@ -147,20 +150,22 @@ class DictDataDao: return dict_data_info @classmethod - def get_dict_data_list(cls, db: Session, query_object: DictDataModel): + def get_dict_data_list(cls, db: Session, query_object: DictDataPageQueryModel, is_page: bool = False): """ 根据查询参数获取字典数据列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 字典数据列表信息对象 """ - dict_data_list = db.query(SysDictData) \ + query = db.query(SysDictData) \ .filter(SysDictData.dict_type == query_object.dict_type if query_object.dict_type else True, SysDictData.dict_label.like(f'%{query_object.dict_label}%') if query_object.dict_label else True, SysDictData.status == query_object.status if query_object.status else True ) \ .order_by(SysDictData.dict_sort) \ - .distinct().all() + .distinct() + dict_data_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return dict_data_list diff --git a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py index 2456270eb8e1dcffe4878beebf44abf858500488..0007b5220225f57d5147fd7c365e05a88430670f 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_dao.py @@ -1,6 +1,7 @@ from sqlalchemy.orm import Session from module_admin.entity.do.job_do import SysJob from module_admin.entity.vo.job_vo import * +from utils.page_util import PageUtil class JobDao: @@ -40,19 +41,21 @@ class JobDao: return job_info @classmethod - def get_job_list(cls, db: Session, query_object: JobModel): + def get_job_list(cls, db: Session, query_object: JobPageQueryModel, is_page: bool = False): """ 根据查询参数获取定时任务列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 定时任务列表信息对象 """ - job_list = db.query(SysJob) \ + query = db.query(SysJob) \ .filter(SysJob.job_name.like(f'%{query_object.job_name}%') if query_object.job_name else True, SysJob.job_group == query_object.job_group if query_object.job_group else True, SysJob.status == query_object.status if query_object.status else True ) \ - .distinct().all() + .distinct() + job_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return job_list 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 6c090c76bb4df02929c58c7f839a5820b65eaeef..713946594c8067107cbc380a5f7a6973937757c3 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/job_log_dao.py @@ -1,6 +1,7 @@ from sqlalchemy.orm import Session from module_admin.entity.do.job_do import SysJobLog from module_admin.entity.vo.job_vo import * +from utils.page_util import PageUtil from datetime import datetime, time @@ -10,14 +11,15 @@ class JobLogDao: """ @classmethod - def get_job_log_list(cls, db: Session, query_object: JobLogQueryModel): + def get_job_log_list(cls, db: Session, query_object: JobLogPageQueryModel, is_page: bool = False): """ 根据查询参数获取定时任务日志列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 定时任务日志列表信息对象 """ - job_log_list = db.query(SysJobLog) \ + query = db.query(SysJobLog) \ .filter(SysJobLog.job_name.like(f'%{query_object.job_name}%') if query_object.job_name else True, SysJobLog.job_group == query_object.job_group if query_object.job_group else True, SysJobLog.status == query_object.status if query_object.status else True, @@ -26,7 +28,8 @@ class JobLogDao: datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) if query_object.begin_time and query_object.end_time else True ) \ - .distinct().all() + .distinct() + job_log_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return job_log_list diff --git a/ruoyi-fastapi-backend/module_admin/dao/log_dao.py b/ruoyi-fastapi-backend/module_admin/dao/log_dao.py index b6fdaac57b2134594f813108c5c9e4f171b00f5a..7fefc8f1edb0b287af9b58bd836ff7e7c7c1ce78 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/log_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/log_dao.py @@ -1,7 +1,7 @@ from sqlalchemy.orm import Session from module_admin.entity.do.log_do import SysOperLog, SysLogininfor from module_admin.entity.vo.log_vo import * -from utils.time_format_util import object_format_datetime, list_format_datetime +from utils.page_util import PageUtil from datetime import datetime, time @@ -10,14 +10,15 @@ class OperationLogDao: 操作日志管理模块数据库操作层 """ @classmethod - def get_operation_log_list(cls, db: Session, query_object: OperLogQueryModel): + def get_operation_log_list(cls, db: Session, query_object: OperLogPageQueryModel, is_page: bool = False): """ 根据查询参数获取操作日志列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 操作日志列表信息对象 """ - operation_log_list = db.query(SysOperLog) \ + query = db.query(SysOperLog) \ .filter(SysOperLog.title.like(f'%{query_object.title}%') if query_object.title else True, SysOperLog.oper_name.like(f'%{query_object.oper_name}%') if query_object.oper_name else True, SysOperLog.business_type == query_object.business_type if query_object.business_type else True, @@ -27,7 +28,8 @@ class OperationLogDao: datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) if query_object.begin_time and query_object.end_time else True )\ - .distinct().all() + .distinct() + operation_log_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return operation_log_list @@ -74,14 +76,15 @@ class LoginLogDao: """ @classmethod - def get_login_log_list(cls, db: Session, query_object: LoginLogQueryModel): + def get_login_log_list(cls, db: Session, query_object: LoginLogPageQueryModel, is_page: bool = False): """ 根据查询参数获取登录日志列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 登录日志列表信息对象 """ - login_log_list = db.query(SysLogininfor) \ + query = db.query(SysLogininfor) \ .filter(SysLogininfor.ipaddr.like(f'%{query_object.ipaddr}%') if query_object.ipaddr else True, SysLogininfor.user_name.like(f'%{query_object.user_name}%') if query_object.user_name else True, SysLogininfor.status == query_object.status if query_object.status else True, @@ -90,7 +93,8 @@ class LoginLogDao: datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) if query_object.begin_time and query_object.end_time else True )\ - .distinct().all() + .distinct() + login_log_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return login_log_list diff --git a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py index ff4b347b7510c78631bde8ccd51cf82b865ba504..2d3646f420496263489c7c29f1f16610e5c4073b 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/notice_dao.py @@ -1,6 +1,7 @@ from sqlalchemy.orm import Session from module_admin.entity.do.notice_do import SysNotice from module_admin.entity.vo.notice_vo import * +from utils.page_util import PageUtil from datetime import datetime, time @@ -40,14 +41,15 @@ class NoticeDao: return notice_info @classmethod - def get_notice_list(cls, db: Session, query_object: NoticeQueryModel): + def get_notice_list(cls, db: Session, query_object: NoticePageQueryModel, is_page: bool = False): """ 根据查询参数获取通知公告列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 通知公告列表信息对象 """ - notice_list = db.query(SysNotice) \ + query = db.query(SysNotice) \ .filter(SysNotice.notice_title.like(f'%{query_object.notice_title}%') if query_object.notice_title else True, SysNotice.update_by.like(f'%{query_object.update_by}%') if query_object.update_by else True, SysNotice.notice_type == query_object.notice_type if query_object.notice_type else True, @@ -56,7 +58,8 @@ class NoticeDao: datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59))) if query_object.begin_time and query_object.end_time else True ) \ - .distinct().all() + .distinct() + notice_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return notice_list diff --git a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py index 1c32dc3c9d5ecf002007e5dc289c48428c7683cb..2cb7f89744e972120897d2d291d8fc48c1c00a12 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/post_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/post_dao.py @@ -1,6 +1,7 @@ from sqlalchemy.orm import Session from module_admin.entity.do.post_do import SysPost from module_admin.entity.vo.post_vo import * +from utils.page_util import PageUtil class PostDao: @@ -54,20 +55,22 @@ class PostDao: return post_info @classmethod - def get_post_list(cls, db: Session, query_object: PostModel): + def get_post_list(cls, db: Session, query_object: PostPageQueryModel, is_page: bool = False): """ 根据查询参数获取岗位列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 岗位列表信息对象 """ - post_list = db.query(SysPost) \ + query = db.query(SysPost) \ .filter(SysPost.post_code.like(f'%{query_object.post_code}%') if query_object.post_code else True, SysPost.post_name.like(f'%{query_object.post_name}%') if query_object.post_name else True, SysPost.status == query_object.status if query_object.status else True ) \ .order_by(SysPost.post_sort) \ - .distinct().all() + .distinct() + post_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return post_list diff --git a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py index 17745b3497b92c5a0f5dc9c831220c7e98f06bc4..32267dabab28395fa627b16ed5b561611bce98c8 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/role_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/role_dao.py @@ -3,6 +3,7 @@ from sqlalchemy.orm import Session from module_admin.entity.do.role_do import SysRole, SysRoleMenu, SysRoleDept from module_admin.entity.do.dept_do import SysDept from module_admin.entity.vo.role_vo import * +from utils.page_util import PageUtil from datetime import datetime, time @@ -85,14 +86,15 @@ class RoleDao: return role_info @classmethod - def get_role_list(cls, db: Session, query_object: RoleQueryModel): + def get_role_list(cls, db: Session, query_object: RolePageQueryModel, is_page: bool = False): """ 根据查询参数获取角色列表信息 :param db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 角色列表信息对象 """ - role_list = db.query(SysRole) \ + query = db.query(SysRole) \ .filter(SysRole.del_flag == 0, SysRole.role_name.like(f'%{query_object.role_name}%') if query_object.role_name else True, SysRole.role_key.like(f'%{query_object.role_key}%') if query_object.role_key else True, @@ -103,7 +105,8 @@ class RoleDao: if query_object.begin_time and query_object.end_time else True ) \ .order_by(SysRole.role_sort) \ - .distinct().all() + .distinct() + role_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return role_list diff --git a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py index ee96936d5d475d768578f30452d1ebf699364d7f..f6c2c2fb3c6dd3c9f946929f8996b7ec715330ef 100644 --- a/ruoyi-fastapi-backend/module_admin/dao/user_dao.py +++ b/ruoyi-fastapi-backend/module_admin/dao/user_dao.py @@ -6,7 +6,7 @@ from module_admin.entity.do.dept_do import SysDept from module_admin.entity.do.post_do import SysPost from module_admin.entity.do.menu_do import SysMenu from module_admin.entity.vo.user_vo import * -from utils.time_format_util import list_format_datetime +from utils.page_util import PageUtil from datetime import datetime, time @@ -137,15 +137,16 @@ class UserDao: return results @classmethod - def get_user_list(cls, db: Session, query_object: UserQueryModel, data_scope_sql: str): + def get_user_list(cls, db: Session, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False): """ 根据查询参数获取用户列表信息 :param db: orm对象 :param query_object: 查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 + :param is_page: 是否开启分页 :return: 用户列表信息对象 """ - user_list = db.query(SysUser, SysDept) \ + query = db.query(SysUser, SysDept) \ .filter(SysUser.del_flag == 0, or_(SysUser.dept_id == query_object.dept_id, SysUser.dept_id.in_( db.query(SysDept.dept_id).filter(func.find_in_set(query_object.dept_id, SysDept.ancestors)) @@ -163,7 +164,8 @@ class UserDao: eval(data_scope_sql) ) \ .outerjoin(SysDept, and_(SysUser.dept_id == SysDept.dept_id, SysDept.status == 0, SysDept.del_flag == 0)) \ - .distinct().all() + .distinct() + user_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return user_list @@ -227,35 +229,15 @@ class UserDao: return allocated_role_list @classmethod - def get_user_role_unallocated_list_by_user_id(cls, db: Session, query_object: UserRoleQueryModel): - """ - 根据用户id获取用户未分配的角色列表信息数据库操作 - :param db: orm对象 - :param query_object: 用户角色查询对象 - :return: 用户未分配的角色列表信息 - """ - unallocated_role_list = db.query(SysRole) \ - .filter( - SysRole.del_flag == 0, - SysRole.role_id != 1, - SysRole.role_name == query_object.role_name if query_object.role_name else True, - SysRole.role_key == query_object.role_key if query_object.role_key else True, - ~SysRole.role_id.in_( - db.query(SysUserRole.role_id).filter(SysUserRole.user_id == query_object.user_id) - ) - ).distinct().all() - - return list_format_datetime(unallocated_role_list) - - @classmethod - def get_user_role_allocated_list_by_role_id(cls, db: Session, query_object: UserRoleQueryModel): + def get_user_role_allocated_list_by_role_id(cls, db: Session, query_object: UserRolePageQueryModel, is_page: bool = False): """ 根据角色id获取已分配的用户列表信息 :param db: orm对象 :param query_object: 用户角色查询对象 + :param is_page: 是否开启分页 :return: 角色已分配的用户列表信息 """ - allocated_user_list = db.query(SysUser) \ + query = db.query(SysUser) \ .filter( SysUser.del_flag == 0, SysUser.user_id != 1, @@ -264,19 +246,21 @@ class UserDao: SysUser.user_id.in_( db.query(SysUserRole.user_id).filter(SysUserRole.role_id == query_object.role_id) ) - ).distinct().all() + ).distinct() + allocated_user_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return allocated_user_list @classmethod - def get_user_role_unallocated_list_by_role_id(cls, db: Session, query_object: UserRoleQueryModel): + def get_user_role_unallocated_list_by_role_id(cls, db: Session, query_object: UserRolePageQueryModel, is_page: bool = False): """ 根据角色id获取未分配的用户列表信息 :param db: orm对象 :param query_object: 用户角色查询对象 + :param is_page: 是否开启分页 :return: 角色未分配的用户列表信息 """ - unallocated_user_list = db.query(SysUser) \ + query = db.query(SysUser) \ .filter( SysUser.del_flag == 0, SysUser.user_id != 1, @@ -285,7 +269,8 @@ class UserDao: ~SysUser.user_id.in_( db.query(SysUserRole.user_id).filter(SysUserRole.role_id == query_object.role_id) ) - ).distinct().all() + ).distinct() + unallocated_user_list = PageUtil.paginate(query, query_object.page_num, query_object.page_size, is_page) return unallocated_user_list 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 3d3cc3901f37e450968a0adc3325061f8abbd20d..6c7ada7c49b4e0c17484eee2e31c9f95be569f8d 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/config_vo.py @@ -37,8 +37,8 @@ class ConfigPageQueryModel(ConfigQueryModel): """ 参数配置管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class DeleteConfigModel(BaseModel): 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 f380802b7710a4bcbf2851a7a05e7433aec3c0cd..e4cda55c5c29ee5c0a110db16004ed0b8c69888a 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/dict_vo.py @@ -58,8 +58,8 @@ class DictTypePageQueryModel(DictTypeQueryModel): """ 字典类型管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class DeleteDictTypeModel(BaseModel): @@ -71,7 +71,7 @@ class DeleteDictTypeModel(BaseModel): dict_ids: str -class DictDataQueryModel(DictTypeModel): +class DictDataQueryModel(DictDataModel): """ 字典数据管理不分页查询模型 """ @@ -85,8 +85,8 @@ class DictDataPageQueryModel(DictDataQueryModel): """ 字典数据管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class DeleteDictDataModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py index fadcbea47c3e4db640e1abdfc7de36c9994a31d2..f6f91d3967337e1495fd1c4e4453096434f0fd4b 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/job_vo.py @@ -63,8 +63,8 @@ class JobPageQueryModel(JobQueryModel): """ 定时任务管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class EditJobModel(JobModel): @@ -97,8 +97,8 @@ class JobLogPageQueryModel(JobLogQueryModel): """ 定时任务日志管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class DeleteJobLogModel(BaseModel): 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 e7a53bf17f50620fa62ba838c751c3064be3aa7a..d410a238de89091f1957025859d640c6bf0bb093 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/log_vo.py @@ -61,8 +61,8 @@ class OperLogPageQueryModel(OperLogQueryModel): """ 操作日志管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class DeleteOperLogModel(BaseModel): @@ -89,8 +89,8 @@ class LoginLogPageQueryModel(LoginLogQueryModel): """ 登录日志管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class DeleteLoginLogModel(BaseModel): 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 6c1ba121df6510c805e5af1bcb15295cc46a542c..09a595f2a7cbbaf257045debc372790010e2d0a0 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/login_vo.py @@ -14,6 +14,16 @@ class UserLogin(BaseModel): captcha_enabled: Optional[bool] = None +class UserRegister(BaseModel): + model_config = ConfigDict(alias_generator=to_camel) + + username: str + password: str + confirm_password: str + code: Optional[str] = None + uuid: Optional[str] = None + + class Token(BaseModel): access_token: str token_type: str @@ -23,6 +33,7 @@ class CaptchaCode(BaseModel): model_config = ConfigDict(alias_generator=to_camel) captcha_enabled: bool + register_enabled: bool img: str uuid: str 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 cf2eab03b63486d74e2f93df6778029cbfcd85b5..8403fa24a4736d75a9e5a50448caa9218c9b8b17 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/notice_vo.py @@ -37,8 +37,8 @@ class NoticePageQueryModel(NoticeQueryModel): """ 通知公告管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class DeleteNoticeModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py index cd2136aad89f01613ae9f137dc1dcfbcf2fb97fe..8ba34958fcf78c2d4f2f82b36fcfd5d6da8b18e4 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/post_vo.py @@ -37,8 +37,8 @@ class PostPageQueryModel(PostQueryModel): """ 岗位管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class DeletePostModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py index 3dfe3057f1a5d88068d4049b90ebe5fc5b45d95b..5ec58f11e923a9b8d3a5b94da4728549f2aafe14 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/role_vo.py @@ -83,8 +83,8 @@ class RolePageQueryModel(RoleQueryModel): """ 角色管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class RoleMenuQueryModel(BaseModel): diff --git a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py index 9f7cc1b6f996f5a4e1dd2da67c11d9727832daca..fbc39831eb2976d5e6796f0191850f539b1b7352 100644 --- a/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py +++ b/ruoyi-fastapi-backend/module_admin/entity/vo/user_vo.py @@ -124,8 +124,8 @@ class UserPageQueryModel(UserQueryModel): """ 用户管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class AddUserModel(UserModel): @@ -176,8 +176,8 @@ class UserRolePageQueryModel(UserRoleQueryModel): """ 用户角色关联管理分页查询模型 """ - page_num: int - page_size: int + page_num: int = 1 + page_size: int = 10 class SelectedRoleModel(RoleModel): diff --git a/ruoyi-fastapi-backend/module_admin/service/config_service.py b/ruoyi-fastapi-backend/module_admin/service/config_service.py index 50e3d41cbbec77a1b4d14750684583c32fcd1dd0..1ab439bf9a6682fe251557a0c5da0b9e5ce74b2a 100644 --- a/ruoyi-fastapi-backend/module_admin/service/config_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/config_service.py @@ -11,16 +11,17 @@ class ConfigService: """ @classmethod - def get_config_list_services(cls, query_db: Session, query_object: ConfigQueryModel): + def get_config_list_services(cls, query_db: Session, query_object: ConfigPageQueryModel, is_page: bool = False): """ 获取参数配置列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 参数配置列表信息对象 """ - config_list_result = ConfigDao.get_config_list(query_db, query_object) + config_list_result = ConfigDao.get_config_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(config_list_result) + return config_list_result @classmethod async def init_cache_sys_config_services(cls, query_db: Session, redis): @@ -35,10 +36,10 @@ class ConfigService: # 删除匹配的键 if keys: await redis.delete(*keys) - config_all = ConfigDao.get_config_list(query_db, ConfigQueryModel(**dict())) + config_all = ConfigDao.get_config_list(query_db, ConfigPageQueryModel(**dict()), is_page=False) for config_obj in config_all: - if config_obj.config_type == 'Y': - await redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_obj.config_key}", config_obj.config_value) + if config_obj.get('configType') == 'Y': + await redis.set(f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:{config_obj.get('configKey')}", config_obj.get('configValue')) @classmethod async def query_config_list_from_cache_services(cls, redis, config_key: str): diff --git a/ruoyi-fastapi-backend/module_admin/service/dict_service.py b/ruoyi-fastapi-backend/module_admin/service/dict_service.py index d4bfe00cd2b65dd3cd1f65484adc2c58ef32ea6a..29dae05ddea257052891c19fe167f3230769ff63 100644 --- a/ruoyi-fastapi-backend/module_admin/service/dict_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/dict_service.py @@ -12,16 +12,17 @@ class DictTypeService: """ @classmethod - def get_dict_type_list_services(cls, query_db: Session, query_object: DictTypeQueryModel): + def get_dict_type_list_services(cls, query_db: Session, query_object: DictTypePageQueryModel, is_page: bool = False): """ 获取字典类型列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 字典类型列表信息对象 """ - dict_type_list_result = DictTypeDao.get_dict_type_list(query_db, query_object) + dict_type_list_result = DictTypeDao.get_dict_type_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(dict_type_list_result) + return dict_type_list_result @classmethod async def add_dict_type_services(cls, request: Request, query_db: Session, page_object: DictTypeModel): @@ -172,16 +173,17 @@ class DictDataService: """ @classmethod - def get_dict_data_list_services(cls, query_db: Session, query_object: DictDataModel): + def get_dict_data_list_services(cls, query_db: Session, query_object: DictDataPageQueryModel, is_page: bool = False): """ 获取字典数据列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 字典数据列表信息对象 """ - dict_data_list_result = DictDataDao.get_dict_data_list(query_db, query_object) + dict_data_list_result = DictDataDao.get_dict_data_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(dict_data_list_result) + return dict_data_list_result @classmethod def query_dict_data_list_services(cls, query_db: Session, dict_type: str): 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 28bac95dabc6ea7d01544af2f32bec589a475ef1..7de9d05b55dd4febc91e969f5e3a0395487cf9c9 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_log_service.py @@ -1,7 +1,7 @@ from module_admin.dao.job_log_dao import * -from module_admin.dao.dict_dao import DictDataDao +from module_admin.service.dict_service import Request, DictDataService from module_admin.entity.vo.common_vo import CrudResponseModel -from utils.common_util import export_list2excel, CamelCaseUtil +from utils.common_util import export_list2excel class JobLogService: @@ -10,16 +10,17 @@ class JobLogService: """ @classmethod - def get_job_log_list_services(cls, query_db: Session, query_object: JobLogQueryModel): + def get_job_log_list_services(cls, query_db: Session, query_object: JobLogPageQueryModel, is_page: bool = False): """ 获取定时任务日志列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 定时任务日志列表信息对象 """ - job_log_list_result = JobLogDao.get_job_log_list(query_db, query_object) + job_log_list_result = JobLogDao.get_job_log_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(job_log_list_result) + return job_log_list_result @classmethod def add_job_log_services(cls, query_db: Session, page_object: JobLogModel): @@ -79,10 +80,10 @@ class JobLogService: return CrudResponseModel(**result) @staticmethod - def export_job_log_list_services(query_db, job_log_list: List): + async def export_job_log_list_services(request: Request, job_log_list: List): """ 导出定时任务日志信息service - :param query_db: orm对象 + :param request: Request对象 :param job_log_list: 定时任务日志信息列表 :return: 定时任务日志信息对应excel的二进制数据 """ @@ -103,17 +104,22 @@ class JobLogService: } data = job_log_list - job_group_list = DictDataDao.query_dict_data_list(query_db, dict_type='sys_job_group') - job_group_option = [dict(label=item.dict_label, value=item.dict_value) for item in job_group_list] + job_group_list = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type='sys_job_group') + job_group_option = [dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in job_group_list] job_group_option_dict = {item.get('value'): item for item in job_group_option} + job_executor_list = await DictDataService.query_dict_data_list_from_cache_services(request.app.state.redis, dict_type='sys_job_executor') + job_executor_option = [dict(label=item.get('dictLabel'), value=item.get('dictValue')) for item in job_executor_list] + job_executor_option_dict = {item.get('value'): item for item in job_executor_option} for item in data: if item.get('status') == '0': item['status'] = '正常' else: item['status'] = '暂停' - if str(item.get('job_group')) in job_group_option_dict.keys(): - item['job_group'] = job_group_option_dict.get(str(item.get('job_group'))).get('label') + if str(item.get('jobGroup')) in job_group_option_dict.keys(): + item['jobGroup'] = job_group_option_dict.get(str(item.get('jobGroup'))).get('label') + if str(item.get('jobExecutor')) in job_executor_option_dict.keys(): + item['jobExecutor'] = job_executor_option_dict.get(str(item.get('jobExecutor'))).get('label') new_data = [{mapping_dict.get(key): value for key, value in item.items() if mapping_dict.get(key)} for item in data] binary_data = export_list2excel(new_data) diff --git a/ruoyi-fastapi-backend/module_admin/service/job_service.py b/ruoyi-fastapi-backend/module_admin/service/job_service.py index 727ccd14f1c2a2a31c99d0d4c1af5e7ad5a9ac59..62887e8424647845c8442a5e476bb5e9ee3f4217 100644 --- a/ruoyi-fastapi-backend/module_admin/service/job_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/job_service.py @@ -11,16 +11,17 @@ class JobService: """ @classmethod - def get_job_list_services(cls, query_db: Session, query_object: JobModel): + def get_job_list_services(cls, query_db: Session, query_object: JobPageQueryModel, is_page: bool = False): """ 获取定时任务列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 定时任务列表信息对象 """ - job_list_result = JobDao.get_job_list(query_db, query_object) + job_list_result = JobDao.get_job_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(job_list_result) + return job_list_result @classmethod def add_job_services(cls, query_db: Session, page_object: JobModel): diff --git a/ruoyi-fastapi-backend/module_admin/service/log_service.py b/ruoyi-fastapi-backend/module_admin/service/log_service.py index a4546e5b8f144f2fe3eafcae01fc69dd463f9aba..cbbb94e9314248ae39699561929efeb9d360977d 100644 --- a/ruoyi-fastapi-backend/module_admin/service/log_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/log_service.py @@ -10,16 +10,17 @@ class OperationLogService: """ @classmethod - def get_operation_log_list_services(cls, query_db: Session, query_object: OperLogQueryModel): + def get_operation_log_list_services(cls, query_db: Session, query_object: OperLogPageQueryModel, is_page: bool = False): """ 获取操作日志列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 操作日志列表信息对象 """ - operation_log_list_result = OperationLogDao.get_operation_log_list(query_db, query_object) + operation_log_list_result = OperationLogDao.get_operation_log_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(operation_log_list_result) + return operation_log_list_result @classmethod def add_operation_log_services(cls, query_db: Session, page_object: OperLogModel): @@ -131,16 +132,17 @@ class LoginLogService: """ @classmethod - def get_login_log_list_services(cls, query_db: Session, query_object: LoginLogQueryModel): + def get_login_log_list_services(cls, query_db: Session, query_object: LoginLogPageQueryModel, is_page: bool = False): """ 获取登录日志列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 登录日志列表信息对象 """ - operation_log_list_result = LoginLogDao.get_login_log_list(query_db, query_object) + operation_log_list_result = LoginLogDao.get_login_log_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(operation_log_list_result) + return operation_log_list_result @classmethod def add_login_log_services(cls, query_db: Session, page_object: LogininforModel): diff --git a/ruoyi-fastapi-backend/module_admin/service/login_service.py b/ruoyi-fastapi-backend/module_admin/service/login_service.py index 8ed597e952b2d24a0f77992d43d47469bcaf7700..f0ecaced1e230840f03eac0e73a863508a60a092 100644 --- a/ruoyi-fastapi-backend/module_admin/service/login_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/login_service.py @@ -9,12 +9,13 @@ from module_admin.service.user_service import * from module_admin.entity.vo.login_vo import * from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.login_dao import * -from config.env import JwtConfig, RedisInitKeyConfig +from exceptions.exception import LoginException, AuthException +from config.env import AppConfig, JwtConfig, RedisInitKeyConfig +from config.get_db import get_db from utils.common_util import CamelCaseUtil from utils.pwd_util import * from utils.response_util import * from utils.message_util import * -from config.get_db import get_db oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login") @@ -60,8 +61,13 @@ class LoginService: if login_user.user_name == account_lock: logger.warning("账号已锁定,请稍后再试") raise LoginException(data="", message="账号已锁定,请稍后再试") - # 判断是否开启验证码,开启则验证,否则不验证 - if login_user.captcha_enabled: + # 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug + request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False + request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False + # 判断是否开启验证码,开启则验证,否则不验证(dev模式下来自API文档的登录请求不检验) + if not login_user.captcha_enabled or ((request_from_swagger or request_from_redoc) and AppConfig.app_env == 'dev'): + pass + else: await cls.__check_login_captcha(request, login_user) user = login_by_account(query_db, login_user.user_name) if not user: @@ -124,9 +130,9 @@ class LoginService: if expires_delta: expire = datetime.utcnow() + expires_delta else: - expire = datetime.utcnow() + timedelta(minutes=15) + expire = datetime.utcnow() + timedelta(minutes=30) to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, JwtConfig.SECRET_KEY, algorithm=JwtConfig.ALGORITHM) + encoded_jwt = jwt.encode(to_encode, JwtConfig.jwt_secret_key, algorithm=JwtConfig.jwt_algorithm) return encoded_jwt @classmethod @@ -146,7 +152,7 @@ class LoginService: try: if token.startswith('Bearer'): token = token.split(' ')[1] - payload = jwt.decode(token, JwtConfig.SECRET_KEY, algorithms=[JwtConfig.ALGORITHM]) + payload = jwt.decode(token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm]) user_id: str = payload.get("user_id") session_id: str = payload.get("session_id") if user_id is None: @@ -165,9 +171,9 @@ class LoginService: # redis_token = await request.app.state.redis.get(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{user.user_basic_info.user_id}") if token == redis_token: await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}", redis_token, - ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES)) + ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) # await request.app.state.redis.set(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{user.user_basic_info.user_id}", redis_token, - # ex=timedelta(minutes=JwtConfig.REDIS_TOKEN_EXPIRE_MINUTES)) + # ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes)) role_id_list = [item.role_id for item in query_user.get('user_role_info')] if 1 in role_id_list: @@ -255,63 +261,104 @@ class LoginService: return router_list + @classmethod + async def register_user_services(cls, request: Request, query_db: Session, user_register: UserRegister): + """ + 用户注册services + :param request: Request对象 + :param query_db: orm对象 + :param user_register: 注册用户对象 + :return: 注册结果 + """ + register_enabled = True if await request.app.state.redis.get( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.registerUser") == 'true' else False + captcha_enabled = True if await request.app.state.redis.get( + f"{RedisInitKeyConfig.SYS_CONFIG.get('key')}:sys.account.captchaEnabled") == 'true' else False + if user_register.password == user_register.confirm_password: + if register_enabled: + if captcha_enabled: + captcha_value = await request.app.state.redis.get( + f"{RedisInitKeyConfig.CAPTCHA_CODES.get('key')}:{user_register.uuid}") + if not captcha_value: + logger.warning("验证码已失效") + return CrudResponseModel(is_success=False, message='验证码已失效') + elif user_register.code != str(captcha_value): + logger.warning("验证码错误") + return CrudResponseModel(is_success=False, message='验证码错误') + add_user = AddUserModel( + userName=user_register.username, + nickName=user_register.username, + password=PwdUtil.get_password_hash(user_register.password) + ) + result = UserService.add_user_services(query_db, add_user) + return result + else: + result = dict(is_success=False, message='注册程序已关闭,禁止注册') + else: + result = dict(is_success=False, message='两次输入的密码不一致') -async def get_sms_code_services(request: Request, query_db: Session, user: ResetUserModel): - """ - 获取短信验证码service - :param request: Request对象 - :param query_db: orm对象 - :param user: 用户对象 - :return: 短信验证码对象 - """ - redis_sms_result = await request.app.state.redis.get(f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{user.session_id}") - if redis_sms_result: - return SmsCode(**dict(is_success=False, sms_code='', session_id='', message='短信验证码仍在有效期内')) - is_user = UserDao.get_user_by_name(query_db, user.user_name) - if is_user: - sms_code = str(random.randint(100000, 999999)) - session_id = str(uuid.uuid4()) - await request.app.state.redis.set(f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{session_id}", sms_code, ex=timedelta(minutes=2)) - # 此处模拟调用短信服务 - message_service(sms_code) - - return SmsCode(**dict(is_success=True, sms_code=sms_code, session_id=session_id, message='获取成功')) + return CrudResponseModel(**result) - return SmsCode(**dict(is_success=False, sms_code='', session_id='', message='用户不存在')) + @classmethod + async def get_sms_code_services(cls, request: Request, query_db: Session, user: ResetUserModel): + """ + 获取短信验证码service + :param request: Request对象 + :param query_db: orm对象 + :param user: 用户对象 + :return: 短信验证码对象 + """ + redis_sms_result = await request.app.state.redis.get( + f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{user.session_id}") + if redis_sms_result: + return SmsCode(**dict(is_success=False, sms_code='', session_id='', message='短信验证码仍在有效期内')) + is_user = UserDao.get_user_by_name(query_db, user.user_name) + if is_user: + sms_code = str(random.randint(100000, 999999)) + session_id = str(uuid.uuid4()) + await request.app.state.redis.set(f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{session_id}", sms_code, + ex=timedelta(minutes=2)) + # 此处模拟调用短信服务 + message_service(sms_code) + return SmsCode(**dict(is_success=True, sms_code=sms_code, session_id=session_id, message='获取成功')) -async def forget_user_services(request: Request, query_db: Session, forget_user: ResetUserModel): - """ - 用户忘记密码services - :param request: Request对象 - :param query_db: orm对象 - :param forget_user: 重置用户对象 - :return: 重置结果 - """ - redis_sms_result = await request.app.state.redis.get(f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{forget_user.session_id}") - if forget_user.sms_code == redis_sms_result: - forget_user.password = PwdUtil.get_password_hash(forget_user.password) - forget_user.user_id = UserDao.get_user_by_name(query_db, forget_user.user_name).user_id - edit_result = UserService.reset_user_services(query_db, forget_user) - result = edit_result.dict() - elif not redis_sms_result: - result = dict(is_success=False, message='短信验证码已过期') - else: - await request.app.state.redis.delete(f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{forget_user.session_id}") - result = dict(is_success=False, message='短信验证码不正确') + return SmsCode(**dict(is_success=False, sms_code='', session_id='', message='用户不存在')) - return CrudResponseModel(**result) + @classmethod + async def forget_user_services(cls, request: Request, query_db: Session, forget_user: ResetUserModel): + """ + 用户忘记密码services + :param request: Request对象 + :param query_db: orm对象 + :param forget_user: 重置用户对象 + :return: 重置结果 + """ + redis_sms_result = await request.app.state.redis.get( + f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{forget_user.session_id}") + if forget_user.sms_code == redis_sms_result: + forget_user.password = PwdUtil.get_password_hash(forget_user.password) + forget_user.user_id = UserDao.get_user_by_name(query_db, forget_user.user_name).user_id + edit_result = UserService.reset_user_services(query_db, forget_user) + result = edit_result.dict() + elif not redis_sms_result: + result = dict(is_success=False, message='短信验证码已过期') + else: + await request.app.state.redis.delete(f"{RedisInitKeyConfig.SMS_CODE.get('key')}:{forget_user.session_id}") + result = dict(is_success=False, message='短信验证码不正确') + return CrudResponseModel(**result) -async def logout_services(request: Request, session_id: str): - """ - 退出登录services - :param request: Request对象 - :param session_id: 会话编号 - :return: 退出登录结果 - """ - await request.app.state.redis.delete(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}") - # await request.app.state.redis.delete(f'{current_user.user.user_id}_access_token') - # await request.app.state.redis.delete(f'{current_user.user.user_id}_session_id') + @classmethod + async def logout_services(cls, request: Request, session_id: str): + """ + 退出登录services + :param request: Request对象 + :param session_id: 会话编号 + :return: 退出登录结果 + """ + await request.app.state.redis.delete(f"{RedisInitKeyConfig.ACCESS_TOKEN.get('key')}:{session_id}") + # await request.app.state.redis.delete(f'{current_user.user.user_id}_access_token') + # await request.app.state.redis.delete(f'{current_user.user.user_id}_session_id') - return True + return True diff --git a/ruoyi-fastapi-backend/module_admin/service/notice_service.py b/ruoyi-fastapi-backend/module_admin/service/notice_service.py index 3b393be5e3867e04c21a26c39ab96059a8c9054e..1ca63a801d9e2570090338d0acd3b3dabca42df7 100644 --- a/ruoyi-fastapi-backend/module_admin/service/notice_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/notice_service.py @@ -9,16 +9,17 @@ class NoticeService: """ @classmethod - def get_notice_list_services(cls, query_db: Session, query_object: NoticeQueryModel): + def get_notice_list_services(cls, query_db: Session, query_object: NoticePageQueryModel, is_page: bool = True): """ 获取通知公告列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 通知公告列表信息对象 """ - notice_list_result = NoticeDao.get_notice_list(query_db, query_object) + notice_list_result = NoticeDao.get_notice_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(notice_list_result) + return notice_list_result @classmethod def add_notice_services(cls, query_db: Session, page_object: NoticeModel): diff --git a/ruoyi-fastapi-backend/module_admin/service/online_service.py b/ruoyi-fastapi-backend/module_admin/service/online_service.py index 3839c58e2382c2350109fe62a0a5120ad10c18ac..968aacb14dfa01a92d069ac3dc3a86513931e046 100644 --- a/ruoyi-fastapi-backend/module_admin/service/online_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/online_service.py @@ -25,7 +25,7 @@ class OnlineService: access_token_values_list = [await request.app.state.redis.get(key) for key in access_token_keys] online_info_list = [] for item in access_token_values_list: - payload = jwt.decode(item, JwtConfig.SECRET_KEY, algorithms=[JwtConfig.ALGORITHM]) + 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'), diff --git a/ruoyi-fastapi-backend/module_admin/service/post_service.py b/ruoyi-fastapi-backend/module_admin/service/post_service.py index bc6f21f0e6376fdb275efd0e25fd50805b8266b9..d6b097fef55872f53af574a57f616faac545de62 100644 --- a/ruoyi-fastapi-backend/module_admin/service/post_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/post_service.py @@ -8,16 +8,17 @@ class PostService: 岗位管理模块服务层 """ @classmethod - def get_post_list_services(cls, query_db: Session, query_object: PostModel): + def get_post_list_services(cls, query_db: Session, query_object: PostPageQueryModel, is_page: bool = False): """ 获取岗位列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 岗位列表信息对象 """ - post_list_result = PostDao.get_post_list(query_db, query_object) + post_list_result = PostDao.get_post_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(post_list_result) + return post_list_result @classmethod def add_post_services(cls, query_db: Session, page_object: PostModel): diff --git a/ruoyi-fastapi-backend/module_admin/service/role_service.py b/ruoyi-fastapi-backend/module_admin/service/role_service.py index bb82b78617dfd2183b3d5b3c1354f526172da497..71c3381e5d12061d2ae2e8f614ef96f9b6a1379d 100644 --- a/ruoyi-fastapi-backend/module_admin/service/role_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/role_service.py @@ -1,7 +1,8 @@ -from module_admin.entity.vo.user_vo import UserInfoModel, UserRoleQueryModel +from module_admin.entity.vo.user_vo import UserInfoModel, UserRolePageQueryModel from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.user_dao import UserDao from module_admin.dao.role_dao import * +from utils.page_util import PageResponseModel from utils.common_util import export_list2excel, CamelCaseUtil @@ -38,16 +39,17 @@ class RoleService: return result @classmethod - def get_role_list_services(cls, query_db: Session, query_object: RoleQueryModel): + def get_role_list_services(cls, query_db: Session, query_object: RolePageQueryModel, is_page: bool = False): """ 获取角色列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 + :param is_page: 是否开启分页 :return: 角色列表信息对象 """ - role_list_result = RoleDao.get_role_list(query_db, query_object) + role_list_result = RoleDao.get_role_list(query_db, query_object, is_page) - return CamelCaseUtil.transform_result(role_list_result) + return role_list_result @classmethod def add_role_services(cls, query_db: Session, page_object: AddRoleModel): @@ -230,27 +232,39 @@ class RoleService: return binary_data @classmethod - def get_role_user_allocated_list_services(cls, query_db: Session, page_object: UserRoleQueryModel): + def get_role_user_allocated_list_services(cls, query_db: Session, page_object: UserRolePageQueryModel, is_page: bool = False): """ 根据角色id获取已分配用户列表 :param query_db: orm对象 :param page_object: 用户关联角色对象 + :param is_page: 是否开启分页 :return: 已分配用户列表 """ - query_user_list = UserDao.get_user_role_allocated_list_by_role_id(query_db, page_object) - allocated_list = [UserInfoModel(**CamelCaseUtil.transform_result(row)) for row in query_user_list] + query_user_list = UserDao.get_user_role_allocated_list_by_role_id(query_db, page_object, is_page) + allocated_list = PageResponseModel( + **{ + **query_user_list.model_dump(by_alias=True), + 'rows': [UserInfoModel(**row) for row in query_user_list.rows] + } + ) return allocated_list @classmethod - def get_role_user_unallocated_list_services(cls, query_db: Session, page_object: UserRoleQueryModel): + def get_role_user_unallocated_list_services(cls, query_db: Session, page_object: UserRolePageQueryModel, is_page: bool = False): """ 根据角色id获取未分配用户列表 :param query_db: orm对象 :param page_object: 用户关联角色对象 + :param is_page: 是否开启分页 :return: 未分配用户列表 """ - query_user_list = UserDao.get_user_role_unallocated_list_by_role_id(query_db, page_object) - unallocated_list = [UserInfoModel(**CamelCaseUtil.transform_result(row)) for row in query_user_list] + query_user_list = UserDao.get_user_role_unallocated_list_by_role_id(query_db, page_object, is_page) + unallocated_list = PageResponseModel( + **{ + **query_user_list.model_dump(by_alias=True), + 'rows': [UserInfoModel(**row) for row in query_user_list.rows] + } + ) return unallocated_list diff --git a/ruoyi-fastapi-backend/module_admin/service/user_service.py b/ruoyi-fastapi-backend/module_admin/service/user_service.py index cf5612035e12461ec713ec7ff2a42a5eeaa9cff4..29a04b6810bcefd0c76f99a13c74f5bb7b84ea8d 100644 --- a/ruoyi-fastapi-backend/module_admin/service/user_service.py +++ b/ruoyi-fastapi-backend/module_admin/service/user_service.py @@ -1,8 +1,9 @@ from fastapi import UploadFile from module_admin.service.role_service import RoleService -from module_admin.service.post_service import PostService +from module_admin.service.post_service import PostService, PostPageQueryModel from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.dao.user_dao import * +from utils.page_util import PageResponseModel from utils.pwd_util import * from utils.common_util import * @@ -13,18 +14,27 @@ class UserService: """ @classmethod - def get_user_list_services(cls, query_db: Session, query_object: UserQueryModel, data_scope_sql: str): + def get_user_list_services(cls, query_db: Session, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False): """ 获取用户列表信息service :param query_db: orm对象 :param query_object: 查询参数对象 :param data_scope_sql: 数据权限对应的查询sql语句 + :param is_page: 是否开启分页 :return: 用户列表信息对象 """ - query_result = UserDao.get_user_list(query_db, query_object, data_scope_sql) - user_list_result = [] - if query_result: - user_list_result = [{**CamelCaseUtil.transform_result(row[0]), 'dept': CamelCaseUtil.transform_result(row[1])} for row in query_result] + query_result = UserDao.get_user_list(query_db, query_object, data_scope_sql, is_page) + if is_page: + user_list_result = PageResponseModel( + **{ + **query_result.model_dump(by_alias=True), + 'rows': [{**row[0], 'dept': row[1]} for row in query_result.rows] + } + ) + else: + user_list_result = [] + if query_result: + user_list_result = [{**row[0], 'dept': row[1]} for row in query_result] return user_list_result @@ -134,7 +144,7 @@ class UserService: :param user_id: 用户id :return: 用户id对应的信息 """ - posts = PostService.get_post_list_services(query_db, PostModel(**{})) + posts = PostService.get_post_list_services(query_db, PostPageQueryModel(**{}), is_page=False) roles = RoleService.get_role_select_option_services(query_db) if user_id != '': query_user = UserDao.get_user_detail_by_id(query_db, user_id=user_id) diff --git a/ruoyi-fastapi-backend/requirements.txt b/ruoyi-fastapi-backend/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..535284aad15dbbb1c7189c3535dbb3e3a1b56d7e --- /dev/null +++ b/ruoyi-fastapi-backend/requirements.txt @@ -0,0 +1,15 @@ +APScheduler==3.10.4 +DateTime==5.4 +fastapi[all]==0.109.0 +loguru==0.7.2 +openpyxl==3.1.2 +pandas==2.1.4 +passlib[bcrypt]==1.7.4 +Pillow==10.2.0 +psutil==5.9.7 +PyMySQL==1.1.0 +python-jose[cryptography]==3.3.0 +redis==5.0.1 +requests==2.31.0 +SQLAlchemy==2.0.25 +user-agents==2.2.0 diff --git a/ruoyi-fastapi-backend/server.py b/ruoyi-fastapi-backend/server.py new file mode 100644 index 0000000000000000000000000000000000000000..f7f85c20d6fc98ad3f5a1719f68ae1a20af9272c --- /dev/null +++ b/ruoyi-fastapi-backend/server.py @@ -0,0 +1,83 @@ +from fastapi import FastAPI +from contextlib import asynccontextmanager +from sub_applications.handle import handle_sub_applications +from middlewares.handle import handle_middleware +from exceptions.handle import handle_exception +from module_admin.controller.login_controller import loginController +from module_admin.controller.captcha_controller import captchaController +from module_admin.controller.user_controller import userController +from module_admin.controller.menu_controller import menuController +from module_admin.controller.dept_controller import deptController +from module_admin.controller.role_controller import roleController +from module_admin.controller.post_controler import postController +from module_admin.controller.dict_controller import dictController +from module_admin.controller.config_controller import configController +from module_admin.controller.notice_controller import noticeController +from module_admin.controller.log_controller import logController +from module_admin.controller.online_controller import onlineController +from module_admin.controller.job_controller import jobController +from module_admin.controller.server_controller import serverController +from module_admin.controller.cache_controller import cacheController +from module_admin.controller.common_controller import commonController +from config.env import AppConfig +from config.get_redis import RedisUtil +from config.get_db import init_create_table +from config.get_scheduler import SchedulerUtil +from utils.log_util import logger +from utils.common_util import worship + + +# 生命周期事件 +@asynccontextmanager +async def lifespan(app: FastAPI): + logger.info(f"{AppConfig.app_name}开始启动") + worship() + await init_create_table() + app.state.redis = await RedisUtil.create_redis_pool() + await RedisUtil.init_sys_dict(app.state.redis) + await RedisUtil.init_sys_config(app.state.redis) + await SchedulerUtil.init_system_scheduler() + logger.info(f"{AppConfig.app_name}启动成功") + yield + await RedisUtil.close_redis_pool(app) + await SchedulerUtil.close_system_scheduler() + + +# 初始化FastAPI对象 +app = FastAPI( + title=AppConfig.app_name, + description=f'{AppConfig.app_name}接口文档', + version=AppConfig.app_version, + lifespan=lifespan +) + +# 挂载子应用 +handle_sub_applications(app) +# 加载中间件处理方法 +handle_middleware(app) +# 加载全局异常处理方法 +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': ['通用模块']} +] + +for controller in controller_list: + app.include_router(router=controller.get('router'), tags=controller.get('tags')) diff --git a/ruoyi-fastapi-backend/sub_applications/handle.py b/ruoyi-fastapi-backend/sub_applications/handle.py new file mode 100644 index 0000000000000000000000000000000000000000..df2a5f481a56afa59be84e9aa9490b794600dd60 --- /dev/null +++ b/ruoyi-fastapi-backend/sub_applications/handle.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI +from sub_applications.staticfiles import mount_staticfiles + + +def handle_sub_applications(app: FastAPI): + """ + 全局处理子应用挂载 + """ + # 挂载静态文件 + mount_staticfiles(app) diff --git a/ruoyi-fastapi-backend/sub_applications/staticfiles.py b/ruoyi-fastapi-backend/sub_applications/staticfiles.py new file mode 100644 index 0000000000000000000000000000000000000000..6899035d82bdc211c9a3942847a918f969e8c17f --- /dev/null +++ b/ruoyi-fastapi-backend/sub_applications/staticfiles.py @@ -0,0 +1,10 @@ +from fastapi import FastAPI +from fastapi.staticfiles import StaticFiles +from config.env import UploadConfig + + +def mount_staticfiles(app: FastAPI): + """ + 挂载静态文件 + """ + app.mount(f"{UploadConfig.UPLOAD_PREFIX}", StaticFiles(directory=f"{UploadConfig.UPLOAD_PATH}"), name="profile") diff --git a/ruoyi-fastapi-backend/utils/common_util.py b/ruoyi-fastapi-backend/utils/common_util.py index a45d2661a7aa9fa478dea9ab658709a572b709bf..f8f8dcadbb9fac51f3b7bd996d033562d593c350 100644 --- a/ruoyi-fastapi-backend/utils/common_util.py +++ b/ruoyi-fastapi-backend/utils/common_util.py @@ -5,6 +5,7 @@ from openpyxl import Workbook from openpyxl.styles import Alignment, PatternFill from openpyxl.utils import get_column_letter from openpyxl.worksheet.datavalidation import DataValidation +from sqlalchemy.engine.row import Row from typing import List from config.env import CachePathConfig @@ -66,7 +67,10 @@ class CamelCaseUtil: return {cls.__to_camel_case(k): v for k, v in result.items()} # 如果是一组字典或其他类型的列表,遍历列表进行转换 elif isinstance(result, list): - return [cls.transform_result(row) if isinstance(row, dict) else cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) for row in result] + return [cls.transform_result(row) if isinstance(row, (dict, Row)) else (cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row) for row in result] + # 如果是sqlalchemy的Row实例,遍历Row进行转换 + elif isinstance(result, Row): + return [cls.transform_result(row) if isinstance(row, dict) else (cls.transform_result({c.name: getattr(row, c.name) for c in row.__table__.columns}) if row else row) for row in result] # 如果是其他类型,如模型实例,先转换为字典 else: return cls.transform_result({c.name: getattr(result, c.name) for c in result.__table__.columns}) diff --git a/ruoyi-fastapi-backend/utils/page_util.py b/ruoyi-fastapi-backend/utils/page_util.py index 341f80f3795e7b74e4d98330dfc0cb893c70cadd..cf2da9b0d224e163abaad82329cd3dccf172ddb8 100644 --- a/ruoyi-fastapi-backend/utils/page_util.py +++ b/ruoyi-fastapi-backend/utils/page_util.py @@ -1,30 +1,9 @@ import math from typing import Optional, List - +from sqlalchemy.orm.query import Query from pydantic import BaseModel, ConfigDict from pydantic.alias_generators import to_camel - - -class PageModel(BaseModel): - """ - 分页模型 - """ - offset: int - page_num: int - page_size: int - total: int - has_next: bool - - -class PageObjectResponse(BaseModel): - """ - 用户管理列表分页查询返回模型 - """ - rows: List = [] - page_num: int - page_size: int - total: int - has_next: bool +from utils.common_util import CamelCaseUtil class PageResponseModel(BaseModel): @@ -40,33 +19,64 @@ class PageResponseModel(BaseModel): has_next: Optional[bool] = None -def get_page_info(offset: int, page_num: int, page_size: int, count: int): +class PageUtil: """ - 根据分页参数获取分页信息 - :param offset: 起始数据位置 - :param page_num: 当前页码 - :param page_size: 当前页面数据量 - :param count: 数据总数 - :return: 分页信息对象 + 分页工具类 """ - has_next = False - if offset >= count: - res_offset_1 = (page_num - 2) * page_size - if res_offset_1 < 0: - res_offset = 0 - res_page_num = 1 - else: - res_offset = res_offset_1 - res_page_num = page_num - 1 - else: - res_offset = offset - if (res_offset + page_size) < count: - has_next = True - res_page_num = page_num - result = dict(offset=res_offset, page_num=res_page_num, page_size=page_size, total=count, has_next=has_next) + @classmethod + def get_page_obj(cls, data_list: List, page_num: int, page_size: int): + """ + 输入数据列表data_list和分页信息,返回分页数据列表结果 + :param data_list: 原始数据列表 + :param page_num: 当前页码 + :param page_size: 当前页面数据量 + :return: 分页数据对象 + """ + # 计算起始索引和结束索引 + start = (page_num - 1) * page_size + end = page_num * page_size + + # 根据计算得到的起始索引和结束索引对数据列表进行切片 + paginated_data = data_list[start:end] + has_next = True if math.ceil(len(data_list) / page_size) > page_num else False + + result = PageResponseModel( + rows=paginated_data, + pageNum=page_num, + pageSize=page_size, + total=len(data_list), + hasNext=has_next + ) + + return result + + @classmethod + def paginate(cls, query: Query, page_num: int, page_size: int, is_page: bool = False): + """ + 输入查询语句和分页信息,返回分页数据列表结果 + :param query: sqlalchemy查询语句 + :param page_num: 当前页码 + :param page_size: 当前页面数据量 + :param is_page: 是否开启分页 + :return: 分页数据对象 + """ + if is_page: + total = query.count() + paginated_data = query.offset((page_num - 1) * page_size).limit(page_size).all() + has_next = True if math.ceil(len(paginated_data) / page_size) > page_num else False + result = PageResponseModel( + rows=CamelCaseUtil.transform_result(paginated_data), + pageNum=page_num, + pageSize=page_size, + total=total, + hasNext=has_next + ) + else: + no_paginated_data = query.all() + result = CamelCaseUtil.transform_result(no_paginated_data) - return PageModel(**result) + return result def get_page_obj(data_list: List, page_num: int, page_size: int): @@ -94,5 +104,3 @@ def get_page_obj(data_list: List, page_num: int, page_size: int): ) return result - - diff --git a/ruoyi-fastapi-backend/utils/response_util.py b/ruoyi-fastapi-backend/utils/response_util.py index 4dab2538b94667e78407521f3c793bbc491646d2..a741074ad03ef7e93e659c877b7acf301ae2b8fb 100644 --- a/ruoyi-fastapi-backend/utils/response_util.py +++ b/ruoyi-fastapi-backend/utils/response_util.py @@ -187,115 +187,3 @@ class ResponseUtil: status_code=status.HTTP_200_OK, content=data ) - - -def response_200(*, data: Any = None, message="获取成功") -> Response: - return JSONResponse( - status_code=status.HTTP_200_OK, - content=jsonable_encoder( - { - 'code': 200, - 'message': message, - 'data': data, - 'success': 'true', - 'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S") - } - ) - ) - - -def response_400(*, data: Any = None, message: str = "获取失败") -> Response: - return JSONResponse( - status_code=status.HTTP_400_BAD_REQUEST, - content=jsonable_encoder( - { - 'code': 400, - 'message': message, - 'data': data, - 'success': 'false', - 'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S") - } - ) - ) - - -def response_401(*, data: Any = None, message: str = "获取失败") -> Response: - return JSONResponse( - status_code=status.HTTP_401_UNAUTHORIZED, - content=jsonable_encoder( - { - 'code': 401, - 'message': message, - 'data': data, - 'success': 'false', - 'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S") - } - ) - ) - - -def response_403(*, data: Any = None, message: str = "获取失败") -> Response: - return JSONResponse( - status_code=status.HTTP_403_FORBIDDEN, - content=jsonable_encoder( - { - 'code': 403, - 'message': message, - 'data': data, - 'success': 'false', - 'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S") - } - ) - ) - - -def response_500(*, data: Any = None, message: str = "接口异常") -> Response: - return JSONResponse( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - content=jsonable_encoder( - { - 'code': 500, - 'message': message, - 'data': data, - 'success': 'false', - 'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S") - } - ) - ) - - -def streaming_response_200(*, data: Any = None): - return StreamingResponse( - status_code=status.HTTP_200_OK, - content=data, - ) - - -class AuthException(Exception): - """ - 自定义令牌异常AuthException - """ - - def __init__(self, data: str = None, message: str = None): - self.data = data - self.message = message - - -class PermissionException(Exception): - """ - 自定义权限异常PermissionException - """ - - def __init__(self, data: str = None, message: str = None): - self.data = data - self.message = message - - -class LoginException(Exception): - """ - 自定义登录异常LoginException - """ - - def __init__(self, data: str = None, message: str = None): - self.data = data - self.message = message diff --git a/ruoyi-fastapi-frontend/package.json b/ruoyi-fastapi-frontend/package.json index 1cd246c48164d41ea8b47f63915450e91bc3b03e..bfaaf4ec8b02188d025725474f55cd823687b390 100644 --- a/ruoyi-fastapi-frontend/package.json +++ b/ruoyi-fastapi-frontend/package.json @@ -16,9 +16,12 @@ "url": "https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI.git" }, "dependencies": { + "@ant-design/icons-vue": "^7.0.1", + "@antv/g2plot": "^2.4.31", "@element-plus/icons-vue": "2.3.1", "@vueup/vue-quill": "1.2.0", "@vueuse/core": "10.6.1", + "ant-design-vue": "^4.1.1", "axios": "0.27.2", "echarts": "5.4.3", "element-plus": "2.4.3", @@ -35,11 +38,12 @@ "devDependencies": { "@vitejs/plugin-vue": "4.5.0", "@vue/compiler-sfc": "3.3.9", + "less": "^4.2.0", "sass": "1.69.5", "unplugin-auto-import": "0.17.1", + "unplugin-vue-setup-extend-plus": "1.0.0", "vite": "5.0.4", "vite-plugin-compression": "0.5.1", - "vite-plugin-svg-icons": "2.0.1", - "unplugin-vue-setup-extend-plus": "1.0.0" + "vite-plugin-svg-icons": "2.0.1" } } diff --git a/ruoyi-fastapi-frontend/src/components/RuoYi/Git/index.vue b/ruoyi-fastapi-frontend/src/components/RuoYi/Git/index.vue index b4459f3f731bdc15532ecb391c54100eaed0864f..611b440ad7ec14a12dccb68323b2846d67f468fb 100644 --- a/ruoyi-fastapi-frontend/src/components/RuoYi/Git/index.vue +++ b/ruoyi-fastapi-frontend/src/components/RuoYi/Git/index.vue @@ -5,7 +5,7 @@ + + + + \ No newline at end of file diff --git a/ruoyi-fastapi-frontend/src/views/dashboard/index.vue b/ruoyi-fastapi-frontend/src/views/dashboard/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..68023f70b0008c67c5ff165c0066050058d7dec4 --- /dev/null +++ b/ruoyi-fastapi-frontend/src/views/dashboard/index.vue @@ -0,0 +1,738 @@ + + + + + + + + \ No newline at end of file diff --git a/ruoyi-fastapi-frontend/src/views/index.vue b/ruoyi-fastapi-frontend/src/views/index.vue deleted file mode 100644 index 77f559c0b7f04aac264062139a684ca4c993cca4..0000000000000000000000000000000000000000 --- a/ruoyi-fastapi-frontend/src/views/index.vue +++ /dev/null @@ -1,1061 +0,0 @@ - - - - - - diff --git a/ruoyi-fastapi-frontend/src/views/login.vue b/ruoyi-fastapi-frontend/src/views/login.vue index 0591396d98503e61aae5028665c7ad9b2de12191..28904a7f7da1308c78b3021074b8d647bb5c8085 100644 --- a/ruoyi-fastapi-frontend/src/views/login.vue +++ b/ruoyi-fastapi-frontend/src/views/login.vue @@ -76,8 +76,8 @@ const router = useRouter(); const { proxy } = getCurrentInstance(); const loginForm = ref({ - username: "admin", - password: "admin123", + username: "", + password: "", rememberMe: false, code: "", uuid: "" @@ -140,6 +140,7 @@ function handleLogin() { function getCode() { getCodeImg().then(res => { captchaEnabled.value = res.captchaEnabled === undefined ? true : res.captchaEnabled; + register.value = res.registerEnabled === undefined ? false : res.registerEnabled; if (captchaEnabled.value) { codeUrl.value = "data:image/gif;base64," + res.img; loginForm.value.uuid = res.uuid; diff --git a/ruoyi-fastapi-frontend/src/views/register.vue b/ruoyi-fastapi-frontend/src/views/register.vue index 64aea639e656e76f8390ac48c8fe50e0f8420cfc..43e97e425dae29d1aba717c5aef0a0dbdddb12c7 100644 --- a/ruoyi-fastapi-frontend/src/views/register.vue +++ b/ruoyi-fastapi-frontend/src/views/register.vue @@ -1,7 +1,7 @@