mirror of
https://github.com/insistence/RuoYi-Vue3-FastAPI.git
synced 2026-09-23 21:18:10 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cb2afca39 | ||
|
|
d47613970b | ||
|
|
8833980008 | ||
|
|
0067e66fc8 | ||
|
|
39c4590c3f | ||
|
|
3196962197 | ||
|
|
1ffaaf5225 | ||
|
|
4ad671023d | ||
|
|
45bd2ddb21 | ||
|
|
267f76d6a2 | ||
|
|
67c09f3113 | ||
|
|
c8da8d5406 | ||
|
|
6ad0a63c68 | ||
|
|
ab4eb00bc1 | ||
|
|
954085666a | ||
|
|
35aa26f8a9 | ||
|
|
1e281508b2 | ||
|
|
a4e4c20c5e | ||
|
|
d4b85f38d8 | ||
|
|
ed88512bf8 | ||
|
|
b9b2f713b9 | ||
|
|
b1563b0d39 | ||
|
|
1857663c9f | ||
|
|
a28922acf0 | ||
|
|
cdacb1643c | ||
|
|
ad0327bf51 | ||
|
|
50af1bf573 | ||
|
|
d364394575 | ||
|
|
98651f4d8f | ||
|
|
40ccb84922 | ||
|
|
d9a19ce3ee | ||
|
|
e216b97163 | ||
|
|
1f51b628af | ||
|
|
1656670203 | ||
|
|
b8dcbdc448 | ||
|
|
dc2e255cd2 | ||
|
|
d9245ed2c9 | ||
|
|
8f4058977d | ||
|
|
044fa0f30b | ||
|
|
6565c50e08 | ||
|
|
184982eb08 | ||
|
|
9a1c53d9f4 | ||
|
|
44678985e9 | ||
|
|
077c8870b4 | ||
|
|
d1fcb6dc11 | ||
|
|
9114d65308 | ||
|
|
f5ec612850 | ||
|
|
a3355e2545 | ||
|
|
1516c1a941 | ||
|
|
a389ef66bc | ||
|
|
dcdeaa0394 | ||
|
|
f4d7d7a416 | ||
|
|
f5a91c0ece | ||
|
|
5ba6587b6c |
@@ -0,0 +1 @@
|
|||||||
|
github: [insistence]
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
name: Tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: "3.9"
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install ruff
|
||||||
|
|
||||||
|
- name: Run linting
|
||||||
|
run: |
|
||||||
|
ruff check ruoyi-fastapi-backend
|
||||||
|
|
||||||
|
- name: Run format check
|
||||||
|
run: |
|
||||||
|
ruff format ruoyi-fastapi-backend --check
|
||||||
+494
@@ -0,0 +1,494 @@
|
|||||||
|
# 更新日志
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.8.0
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
## 后端
|
||||||
|
|
||||||
|
1.后端依赖升级到最新版本,请升级依赖或重新创建环境。
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.新增请求上下文管理类。
|
||||||
|
2.新增`PreAuthDependency`、`CurrentUserDependency`、`DataScopeDependency`、`DBSessionDependency`、`UserInterfaceAuthDependency`和`RoleInterfaceAuthDependency`依赖函数。
|
||||||
|
3.新增上下文清理中间件。
|
||||||
|
4.新增公共vo模块。
|
||||||
|
5.新增配置文档静态资源方法。
|
||||||
|
6.新增自动注册路由功能。
|
||||||
|
7.新增docker compose部署方式。
|
||||||
|
8.菜单导航设置支持纯顶部。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复单账号登录模式下强退功能失效的问题 #52。
|
||||||
|
2.确保ApschedulerJobs字段类型与apscheduler默认创建的表字段类型一致 #53。
|
||||||
|
3.修复磁盘存在异常时服务监控无法正常运行的问题。
|
||||||
|
4.移除代码生成表业务表外键,修复无法删除的问题。
|
||||||
|
5.修复固定头部时出现的导航栏偏移问题。
|
||||||
|
6.修复表单构建移除所有控件后切换路由回来空白问题。
|
||||||
|
7.修复代码生成v3模板时间控件between选择后清空报错问题。
|
||||||
|
|
||||||
|
### 代码重构
|
||||||
|
|
||||||
|
1.增强ruff规则,完善类型提示。
|
||||||
|
2.优化项目结构,新增common模块,原annotation、aspect、constant、enums模块移动至common模块下。
|
||||||
|
3.重构app与server设计。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.controller层全部使用新依赖项。
|
||||||
|
2.当前用户信息使用上下文变量。
|
||||||
|
3.分页模型改为使用公共vo模块的PageModel。
|
||||||
|
4.优化API文档的响应模型显示。
|
||||||
|
5.操作响应模型改为使用公共vo模块的CrudResponseModel。
|
||||||
|
6.优化API文档的接口描述信息。
|
||||||
|
7.登录/注册页面底部版权信息修改为读取配置。
|
||||||
|
8.优化生成代码下载的zip文件名。
|
||||||
|
9.优化表单构建关闭页签销毁复制插件。
|
||||||
|
10.行内表单默认设置固定宽度。
|
||||||
|
11.优化操作日志详细请求参数显示。
|
||||||
|
12.优化index页面标题读取配置。
|
||||||
|
13.优化字典组件数字类型值处理逻辑。
|
||||||
|
14.优化字典组件值宽松匹配。
|
||||||
|
15.默认固定头部。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.7.1
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
1.后端依赖移除passlib,直接使用bcrypt。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复代码生成controller模板编辑接口异常生成字段的问题。
|
||||||
|
2.移除passlib直接使用bcrypt修复密码校验异常的问题 #48 #49。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.代码生成do模板补充表描述。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.7.0
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
1.前后端依赖升级,请升级依赖或重新创建环境。
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.新增alembic支持。
|
||||||
|
2.文件&图片上传组件支持自定义地址&参数。
|
||||||
|
3.新增默认打包配置项。
|
||||||
|
4.显隐列组件支持全选/全不选。
|
||||||
|
5.添加页签openPage支持传递参数。
|
||||||
|
6.外链加载时遮罩信息提示。
|
||||||
|
7.上传组件新增拖动排序属性。
|
||||||
|
8.图片上传组件新增disabled属性。
|
||||||
|
9.代码生成列支持拖动排序。
|
||||||
|
10.新增用户默认初始化密码。
|
||||||
|
11.新增页签图标显示开关功能。
|
||||||
|
12.新增底部版权信息及开关。
|
||||||
|
13.用户归属部门新增清除。
|
||||||
|
14.用户导入新增验证提示。
|
||||||
|
15.菜单搜索支持键盘选择&悬浮主题背景。
|
||||||
|
16.新增apscheduler_jobs表对应sqlalchemy模型类。
|
||||||
|
17.初始密码支持自定义修改策略。
|
||||||
|
18.账号密码支持自定义更新周期。
|
||||||
|
19.注册账号设置默认密码最后更新时间。
|
||||||
|
20.显示列信息支持对象格式。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复logout接口未按照app_same_time_login配置项动态判断的问题 #IBZZ1S。
|
||||||
|
2.修复上传组件被多次引用拖动仅对第一个有效的问题。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.优化接口耗时计算。
|
||||||
|
2.优化启动信息显示。
|
||||||
|
3.优化前端处理路由函数代码。
|
||||||
|
4.登录页和注册页表头使用VITE_APP_BASE_API配置值。
|
||||||
|
5.优化角色禁用不允许分配。
|
||||||
|
6.优化富文本控制台警告异常。
|
||||||
|
7.优化checkbox废弃API。
|
||||||
|
8.优化导航栏显示昵称&设置。
|
||||||
|
|
||||||
|
### 代码重构
|
||||||
|
|
||||||
|
1.重构IP归属区域查询为异步调用。
|
||||||
|
2.调整do与sql使其相互适配以支持alembic。
|
||||||
|
3.富文本复制粘贴图片上传至url。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.6.2
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.文件上传组件新增disabled属性。
|
||||||
|
2.文件上传组件新增类型。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复日志管理时间查询报错 #27。
|
||||||
|
2.修复定时任务状态暂停时执行单次任务会触发cron表达式的问题 #31。
|
||||||
|
3.修复修改字典类型时获取dict_code异常的问题。
|
||||||
|
4.修复修改字典类型时字典数据更新时间异常的问题。
|
||||||
|
5.修复代码生成模板时间查询问题 #28。
|
||||||
|
6.修复用户导出缺失部门名称的问题。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.优化代码生成新增和编辑字段显示和渲染。
|
||||||
|
2.pagination更换成flex布局。
|
||||||
|
3.优化代码生成vue模板 #23。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.6.1
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
#### 后端
|
||||||
|
|
||||||
|
1.新增sqlglot依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install sqlglot[rs]==26.6.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
|
```
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.引入sqlglot修复sql语句解析异常的问题。
|
||||||
|
2.修复代码生成字段唯一性校验dao层模板判断异常的问题。
|
||||||
|
3.引入泛型修复as_query和as_form装饰模型文档丢失的问题。
|
||||||
|
4.修复代码生成主子表vo模板可能缺失NotBlank的问题。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.6.0
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
1.后端依赖升级到最新版本,请升级依赖或重新创建环境。
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.新增代码生成功能,支持配置数据库表信息一键生成和下载前后端代码,需要重新执行sql文件,请先备份数据。
|
||||||
|
2.新增表单构建功能。
|
||||||
|
3.用户头像新增支持http(s)链接。
|
||||||
|
4.新增trace中间件强化日志链路追踪和响应头 [@y1ren](https://gitee.com/y1ren)。
|
||||||
|
5.用户管理支持分栏拖动。
|
||||||
|
6.菜单面包屑导航支持多层级显示。
|
||||||
|
7.白名单支持对通配符路径匹配。
|
||||||
|
8.支持开启暗黑模式。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复默认关闭Tags-Views时,内链页面打不开。
|
||||||
|
2.修复删除当前登录用户拦截失效的问题。
|
||||||
|
3.修复定时任务目标字符串规则校验不全的问题。
|
||||||
|
4.修复执行单次任务时会覆盖已启用任务的问题 #IBEKD2。
|
||||||
|
5.修复个人中心特殊字符密码修改失败问题。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.优化导出方法。
|
||||||
|
2.参数键值更换为多行文本。
|
||||||
|
3.优化日志中操作方法显示。
|
||||||
|
4.优化日志装饰器获取核心参数的方式。
|
||||||
|
5.用户管理过滤掉已禁用部门。
|
||||||
|
6.优化TopNav内链菜单点击没有高亮。
|
||||||
|
7.ResponseUtil补充完整参数。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.5.1
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.定时任务新增支持调用异步函数。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.优化字典数组条件判断。
|
||||||
|
2.校检文件名是否包含特殊字符。
|
||||||
|
3.移除已弃用的log_decorator装饰器。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.5.0
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.新增对PostgreSQL数据库的支持。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复DictTag组件控制台抛异常的问题 #IAYSVZ。
|
||||||
|
2.修复登录日志导出文件名称错误的问题。
|
||||||
|
|
||||||
|
### 代码回滚
|
||||||
|
|
||||||
|
1.因fastapi查询参数模型底层存在bug,回滚查询参数模型声明方式为as_query。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.优化CamelCaseUtil和SnakeCaseUtil以兼容更多转换场景。
|
||||||
|
2.优化列表查询排序。
|
||||||
|
3.优化参数设置页面。
|
||||||
|
4.优化上传图片带域名时不增加前缀。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.4.0
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
#### 后端
|
||||||
|
|
||||||
|
1.更新fastapi版本为0.115.0
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install fastapi[all]==0.115.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
|
```
|
||||||
|
|
||||||
|
### 代码重构
|
||||||
|
|
||||||
|
1.基于fastapi 0.115.0版本新特性,直接使用pydantic模型接收查询参数和表单数据,移除原有as_query和as_form使用方式。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复角色管理service书写错误。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.优化前端登录请求方法。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.3.3
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
#### 后端
|
||||||
|
|
||||||
|
1.更新pydantic-validation-decorator版本为0.1.4,修复了一些底层bug。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复在线用户模块条件查询无效的问题。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.优化在线用户模块前后端字段描述一致。
|
||||||
|
2.日志装饰器异常处理增加logger打印日志。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.3.2
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.新增gzip压缩中间件。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复分页函数计算has_next错误的问题 #10。
|
||||||
|
2.修复定时任务监听函数中事件没有job_id报错的问题。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.优化添加中间件函数注释。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.3.1
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复1.3.0版本采用新的异常处理机制后日志装饰器无法记录异常日志的问题。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.补充定时任务违规字符串。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.3.0
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
1.前后端依赖均升级到最新版本,请升级依赖或重新创建环境。
|
||||||
|
2.使用`PyJWT`替换`python-jose`以解决一些安全性问题。
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.新增字段校验装饰器,支持手动触发校验,已封装为`pydantic-validation-decorator`库。
|
||||||
|
2.各模块`service`层新增字段唯一性校验。
|
||||||
|
3.全局新增`ServiceException`自定义服务异常和`ServiceWarning`自定义服务警告,无需在接口中写大量的异常捕获。
|
||||||
|
4.菜单管理新增路由名称,请执行以下sql为数据库新增字段:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
ALTER TABLE sys_menu ADD COLUMN route_name varchar(50) DEFAULT '';
|
||||||
|
```
|
||||||
|
|
||||||
|
5.新增`constant`常量配置及`enums`枚举类型配置。
|
||||||
|
6.新增`StringUtil`、`CronUtil`工具类。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复用户管理、角色管理、部门管理越权漏洞。
|
||||||
|
2.修复各模块`dao`层`status`、`del_flag`类型与数据库不一致的问题。
|
||||||
|
3.修复移动端左侧菜单无法显示的问题。
|
||||||
|
4.修复其他已知BUG。
|
||||||
|
|
||||||
|
### 代码重构
|
||||||
|
|
||||||
|
1.重构日志装饰器为`Log`,未来版本将删除`log_decorator`装饰器,请尽快迁移。
|
||||||
|
2.重构`RedisInitKeyConfig`为枚举类型,现在可通过以下方式获取对应的`key`和`remark`
|
||||||
|
`RedisInitKeyConfig.ACCESS_TOKEN.key`、`RedisInitKeyConfig.ACCESS_TOKEN.remark`。
|
||||||
|
3.重构数据权限逻辑,底层进行优化,使用方法与之前相同。
|
||||||
|
|
||||||
|
### 代码优化
|
||||||
|
|
||||||
|
1.引入`ruff`对后端代码进行格式化及检测修复,优化导入。
|
||||||
|
2.各模块基于`ServiceException`自定义服务异常和`ServiceWarning`自定义服务警告优化了异常处理逻辑。
|
||||||
|
3.各模块`vo`层使用`Field`声明字段。
|
||||||
|
4.优化API文档字段描述显示。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.2.2
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复删除定时任务时未移除调度中任务的问题。
|
||||||
|
2.修复菜单生成路由时组件条件判断错误的问题。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.2.1
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复各模块新增数据时创建时间记录异常的问题。
|
||||||
|
2.修复菜单挂载到根目录时路由加载异常等一系列相关问题。
|
||||||
|
|
||||||
|
### 代码及性能优化
|
||||||
|
|
||||||
|
1.修改代理localhost为127.0.0.1以适配部分设备解析localhost异常的问题。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.2.0
|
||||||
|
|
||||||
|
### 重要说明
|
||||||
|
|
||||||
|
本次更新为 **_破坏性更新_** ,重构数据库orm为异步,代码改动很大,请谨慎升级。
|
||||||
|
1.原有的Session类型声明统一变更为AsyncSession。
|
||||||
|
2.service层和dao层的函数修改为异步函数,请使用await调用。
|
||||||
|
3.orm查询不再支持query,请使用select、update、delete等语句,具体使用方法请参考[https://docs.sqlalchemy.org/en/20/orm/queryguide/index.html](https://docs.sqlalchemy.org/en/20/orm/queryguide/index.html)。
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
#### 后端
|
||||||
|
|
||||||
|
1.增加asyncmy依赖用于支持orm异步操作mysql,请重新安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple。
|
||||||
|
```
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.新增SnakeCaseUtil工具类,将原CamelCaseUtil工具类的camel_to_snake函数迁移至SnakeCaseUtil工具类。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复用户管理模块重置用户密码时会异常重置用户岗位和角色的问题。
|
||||||
|
2.修复清空定时任务日志异常的问题。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.1.3
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.用户密码新增非法字符验证。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复通知公告列表查询前后端字段不一致的问题。
|
||||||
|
2.修复个人中心修改基本资料后端异常的问题。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.1.2
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.配置文件新增数据库连接池相关配置。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复个人中心修改密码后端异常的问题。
|
||||||
|
|
||||||
|
### 代码及性能优化
|
||||||
|
|
||||||
|
1.使用@lru_cache缓存ip归属区域查询结果,避免重复调用ip归属区域查询接口以优化性能。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.1.1
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复编辑定时任务时更新的信息未同步至scheduler的问题 #I9EK56。
|
||||||
|
2.修复编辑角色数据权限时后端异常的问题 #I9ENQN。
|
||||||
|
3.修复菜单配置路由参数不生效的问题。
|
||||||
|
4.修复获取路由信息时菜单排序不生效的问题。
|
||||||
|
5.修复添加菜单时是否外链和是否缓存回显异常的问题。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.1.0
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.后端配置文件新增sqlalchemy日志开关配置。
|
||||||
|
2.后端配置文件新增IP归属区域查询开关配置。
|
||||||
|
3.后端配置文件新增账号同时登录开关配置。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复token本身过期时退出登录接口异常的问题 #I9CBWT。
|
||||||
|
2.修复系统版本号或浏览器版本号无法获取时登录异常的问题 #I9CYNM。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.0.3
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.账号密码登录新增IP黑名单校验。
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复外链菜单无法打开的问题 #I95KBK。
|
||||||
|
2.修复添加和编辑菜单页面中是否缓存和是否外链字段回显异常的问题 #I95KBK。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.0.2
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.用户接口权限校验增加列表接收参数,实现同一接口支持多个权限标识校验。
|
||||||
|
2.新增按角色校验接口权限依赖
|
||||||
|
|
||||||
|
### BUG修复
|
||||||
|
|
||||||
|
1.修复用户管理和部门管理模块数据权限异常的问题。
|
||||||
|
|
||||||
|
### 代码及性能优化
|
||||||
|
|
||||||
|
1.调整参数设置、部门管理、字典管理、定时任务、日志管理、角色管理、菜单管理模块部分接口权限标识。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.0.1
|
||||||
|
|
||||||
|
### 项目依赖
|
||||||
|
|
||||||
|
#### 后端
|
||||||
|
|
||||||
|
1.更新fastapi版本为0.109.1,修复一些安全性问题,命令:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install fastapi[all]==0.109.1 -i https://mirrors.aliyun.com/pypi/simple/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 新增功能
|
||||||
|
|
||||||
|
1.日志管理模块新增字段排序查询。
|
||||||
|
|
||||||
|
## RuoYi-Vue3-FastAPI v1.0.0
|
||||||
|
|
||||||
|
RuoYi-Vue3-FastAPI第一个版本发布啦!
|
||||||
|
此版本功能如下:
|
||||||
|
1.用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
||||||
|
2.角色管理:角色菜单权限分配。
|
||||||
|
3.菜单管理:配置系统菜单,操作权限,按钮权限标识等。
|
||||||
|
4.部门管理:配置系统组织机构(公司、部门、小组)。
|
||||||
|
5.岗位管理:配置系统用户所属担任职务。
|
||||||
|
6.字典管理:对系统中经常使用的一些较为固定的数据进行维护。
|
||||||
|
7.参数管理:对系统动态配置常用参数。
|
||||||
|
8.通知公告:系统通知公告信息发布维护。
|
||||||
|
9.操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
||||||
|
10.登录日志:系统登录日志记录查询包含登录异常。
|
||||||
|
11.在线用户:当前系统中活跃用户状态监控。
|
||||||
|
12.定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
|
||||||
|
13.服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
|
||||||
|
14.缓存监控:对系统的缓存信息查询,命令统计等。
|
||||||
|
15.系统接口:根据业务代码自动生成相关的api接口文档。
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
|
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
|
||||||
</p>
|
</p>
|
||||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi-Vue3-FastAPI v1.7.0</h1>
|
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi-Vue3-FastAPI v1.8.0</h1>
|
||||||
<h4 align="center">基于RuoYi-Vue3+FastAPI前后端分离的快速开发框架</h4>
|
<h4 align="center">基于RuoYi-Vue3+FastAPI前后端分离的快速开发框架</h4>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/stargazers"><img src="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/badge/star.svg?theme=dark"></a>
|
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/stargazers"><img src="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/badge/star.svg?theme=dark"></a>
|
||||||
<a href="https://github.com/insistence/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/github/stars/insistence/RuoYi-Vue3-FastAPI?style=social"></a>
|
<a href="https://github.com/insistence/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/github/stars/insistence/RuoYi-Vue3-FastAPI?style=social"></a>
|
||||||
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/badge/RuoYiVue3FastAPI-v1.7.0-brightgreen.svg"></a>
|
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI"><img src="https://img.shields.io/badge/RuoYiVue3FastAPI-v1.8.0-brightgreen.svg"></a>
|
||||||
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
|
<a href="https://gitee.com/insistence2022/RuoYi-Vue3-FastAPI/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
|
||||||
<img src="https://img.shields.io/badge/node-≥18-blue">
|
<img src="https://img.shields.io/badge/node-≥18-blue">
|
||||||
<img src="https://img.shields.io/badge/python-≥3.9-blue">
|
<img src="https://img.shields.io/badge/python-≥3.9-blue">
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
services:
|
||||||
|
# 前端服务
|
||||||
|
ruoyi-frontend:
|
||||||
|
build:
|
||||||
|
context: ./ruoyi-fastapi-frontend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: ruoyi-frontend:latest
|
||||||
|
container_name: ruoyi-frontend
|
||||||
|
ports:
|
||||||
|
- "12580:80"
|
||||||
|
volumes:
|
||||||
|
- ./ruoyi-fastapi-frontend/bin/nginx.dockermy.conf:/etc/nginx/conf.d/default.conf
|
||||||
|
depends_on:
|
||||||
|
- ruoyi-backend-my
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
|
||||||
|
# 后端服务(MySQL版本)
|
||||||
|
ruoyi-backend-my:
|
||||||
|
build:
|
||||||
|
context: ./ruoyi-fastapi-backend
|
||||||
|
dockerfile: Dockerfile.my
|
||||||
|
image: ruoyi-backend-my:latest
|
||||||
|
container_name: ruoyi-backend-my
|
||||||
|
ports:
|
||||||
|
- "19099:9099"
|
||||||
|
depends_on:
|
||||||
|
ruoyi-mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
ruoyi-redis:
|
||||||
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
|
||||||
|
# MySQL服务
|
||||||
|
ruoyi-mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
container_name: ruoyi-mysql
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
MYSQL_DATABASE: ruoyi-fastapi
|
||||||
|
ports:
|
||||||
|
- "13306:3306"
|
||||||
|
volumes:
|
||||||
|
- ./ruoyi-fastapi-backend/sql/ruoyi-fastapi.sql:/docker-entrypoint-initdb.d/ruoyi-fastapi.sql
|
||||||
|
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci --skip-character-set-client-handshake=1
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 30
|
||||||
|
|
||||||
|
# Redis服务
|
||||||
|
ruoyi-redis:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: ruoyi-redis
|
||||||
|
ports:
|
||||||
|
- "16379:6379"
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 30
|
||||||
|
|
||||||
|
# 网络配置
|
||||||
|
networks:
|
||||||
|
ruoyi-network:
|
||||||
|
name: ruoyi-network
|
||||||
|
driver: bridge
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
services:
|
||||||
|
# 前端服务
|
||||||
|
ruoyi-frontend:
|
||||||
|
build:
|
||||||
|
context: ./ruoyi-fastapi-frontend
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
image: ruoyi-frontend:latest
|
||||||
|
container_name: ruoyi-frontend
|
||||||
|
ports:
|
||||||
|
- "12580:80"
|
||||||
|
volumes:
|
||||||
|
- ./ruoyi-fastapi-frontend/bin/nginx.dockerpg.conf:/etc/nginx/conf.d/default.conf
|
||||||
|
depends_on:
|
||||||
|
- ruoyi-backend-pg
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
|
||||||
|
# 后端服务(PostgreSQL版本)
|
||||||
|
ruoyi-backend-pg:
|
||||||
|
build:
|
||||||
|
context: ./ruoyi-fastapi-backend
|
||||||
|
dockerfile: Dockerfile.pg
|
||||||
|
image: ruoyi-backend-pg:latest
|
||||||
|
container_name: ruoyi-backend-pg
|
||||||
|
ports:
|
||||||
|
- "19099:9099"
|
||||||
|
depends_on:
|
||||||
|
- ruoyi-pg
|
||||||
|
- ruoyi-redis
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
|
||||||
|
# PostgreSQL服务
|
||||||
|
ruoyi-pg:
|
||||||
|
image: postgres:14
|
||||||
|
container_name: ruoyi-pg
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: root
|
||||||
|
POSTGRES_DB: ruoyi-fastapi
|
||||||
|
POSTGRES_INITDB_ARGS: --encoding=UTF8 --lc-collate=C --lc-ctype=C
|
||||||
|
ports:
|
||||||
|
- "15432:5432"
|
||||||
|
volumes:
|
||||||
|
- ./ruoyi-fastapi-backend/sql/ruoyi-fastapi-pg.sql:/docker-entrypoint-initdb.d/ruoyi-fastapi-pg.sql
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "pg_isready", "-U", "postgres"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 30
|
||||||
|
|
||||||
|
# Redis服务
|
||||||
|
ruoyi-redis:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: ruoyi-redis
|
||||||
|
ports:
|
||||||
|
- "16379:6379"
|
||||||
|
networks:
|
||||||
|
- ruoyi-network
|
||||||
|
|
||||||
|
# 网络配置
|
||||||
|
networks:
|
||||||
|
ruoyi-network:
|
||||||
|
name: ruoyi-network
|
||||||
|
driver: bridge
|
||||||
@@ -10,7 +10,7 @@ APP_HOST = '0.0.0.0'
|
|||||||
# 应用端口
|
# 应用端口
|
||||||
APP_PORT = 9099
|
APP_PORT = 9099
|
||||||
# 应用版本
|
# 应用版本
|
||||||
APP_VERSION= '1.7.0'
|
APP_VERSION= '1.8.0'
|
||||||
# 应用是否开启热重载
|
# 应用是否开启热重载
|
||||||
APP_RELOAD = true
|
APP_RELOAD = true
|
||||||
# 应用是否开启IP归属区域查询
|
# 应用是否开启IP归属区域查询
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# -------- 应用配置 --------
|
||||||
|
# 应用运行环境
|
||||||
|
APP_ENV = 'prod'
|
||||||
|
# 应用名称
|
||||||
|
APP_NAME = 'RuoYi-FastAPI'
|
||||||
|
# 应用代理路径
|
||||||
|
APP_ROOT_PATH = '/docker-api'
|
||||||
|
# 应用主机
|
||||||
|
APP_HOST = '0.0.0.0'
|
||||||
|
# 应用端口
|
||||||
|
APP_PORT = 9099
|
||||||
|
# 应用版本
|
||||||
|
APP_VERSION= '1.8.0'
|
||||||
|
# 应用是否开启热重载
|
||||||
|
APP_RELOAD = false
|
||||||
|
# 应用是否开启IP归属区域查询
|
||||||
|
APP_IP_LOCATION_QUERY = true
|
||||||
|
# 应用是否允许账号同时登录
|
||||||
|
APP_SAME_TIME_LOGIN = true
|
||||||
|
|
||||||
|
# -------- Jwt配置 --------
|
||||||
|
# Jwt秘钥
|
||||||
|
JWT_SECRET_KEY = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55'
|
||||||
|
# Jwt算法
|
||||||
|
JWT_ALGORITHM = 'HS256'
|
||||||
|
# 令牌过期时间
|
||||||
|
JWT_EXPIRE_MINUTES = 1440
|
||||||
|
# redis中令牌过期时间
|
||||||
|
JWT_REDIS_EXPIRE_MINUTES = 30
|
||||||
|
|
||||||
|
|
||||||
|
# -------- 数据库配置 --------
|
||||||
|
# 数据库类型,可选的有'mysql'、'postgresql',默认为'mysql'
|
||||||
|
DB_TYPE = 'mysql'
|
||||||
|
# 数据库主机
|
||||||
|
DB_HOST = 'ruoyi-mysql'
|
||||||
|
# 数据库端口
|
||||||
|
DB_PORT = 3306
|
||||||
|
# 数据库用户名
|
||||||
|
DB_USERNAME = 'root'
|
||||||
|
# 数据库密码
|
||||||
|
DB_PASSWORD = 'root'
|
||||||
|
# 数据库名称
|
||||||
|
DB_DATABASE = 'ruoyi-fastapi'
|
||||||
|
# 是否开启sqlalchemy日志
|
||||||
|
DB_ECHO = true
|
||||||
|
# 允许溢出连接池大小的最大连接数
|
||||||
|
DB_MAX_OVERFLOW = 10
|
||||||
|
# 连接池大小,0表示连接数无限制
|
||||||
|
DB_POOL_SIZE = 50
|
||||||
|
# 连接回收时间(单位:秒)
|
||||||
|
DB_POOL_RECYCLE = 3600
|
||||||
|
# 连接池中没有线程可用时,最多等待的时间(单位:秒)
|
||||||
|
DB_POOL_TIMEOUT = 30
|
||||||
|
|
||||||
|
# -------- Redis配置 --------
|
||||||
|
# Redis主机
|
||||||
|
REDIS_HOST = 'ruoyi-redis'
|
||||||
|
# Redis端口
|
||||||
|
REDIS_PORT = 6379
|
||||||
|
# Redis用户名
|
||||||
|
REDIS_USERNAME = ''
|
||||||
|
# Redis密码
|
||||||
|
REDIS_PASSWORD = ''
|
||||||
|
# Redis数据库
|
||||||
|
REDIS_DATABASE = 2
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# -------- 应用配置 --------
|
||||||
|
# 应用运行环境
|
||||||
|
APP_ENV = 'prod'
|
||||||
|
# 应用名称
|
||||||
|
APP_NAME = 'RuoYi-FastAPI'
|
||||||
|
# 应用代理路径
|
||||||
|
APP_ROOT_PATH = '/docker-api'
|
||||||
|
# 应用主机
|
||||||
|
APP_HOST = '0.0.0.0'
|
||||||
|
# 应用端口
|
||||||
|
APP_PORT = 9099
|
||||||
|
# 应用版本
|
||||||
|
APP_VERSION= '1.8.0'
|
||||||
|
# 应用是否开启热重载
|
||||||
|
APP_RELOAD = false
|
||||||
|
# 应用是否开启IP归属区域查询
|
||||||
|
APP_IP_LOCATION_QUERY = true
|
||||||
|
# 应用是否允许账号同时登录
|
||||||
|
APP_SAME_TIME_LOGIN = true
|
||||||
|
|
||||||
|
# -------- Jwt配置 --------
|
||||||
|
# Jwt秘钥
|
||||||
|
JWT_SECRET_KEY = 'b01c66dc2c58dc6a0aabfe2144256be36226de378bf87f72c0c795dda67f4d55'
|
||||||
|
# Jwt算法
|
||||||
|
JWT_ALGORITHM = 'HS256'
|
||||||
|
# 令牌过期时间
|
||||||
|
JWT_EXPIRE_MINUTES = 1440
|
||||||
|
# redis中令牌过期时间
|
||||||
|
JWT_REDIS_EXPIRE_MINUTES = 30
|
||||||
|
|
||||||
|
|
||||||
|
# -------- 数据库配置 --------
|
||||||
|
# 数据库类型,可选的有'mysql'、'postgresql',默认为'mysql'
|
||||||
|
DB_TYPE = 'postgresql'
|
||||||
|
# 数据库主机
|
||||||
|
DB_HOST = 'ruoyi-pg'
|
||||||
|
# 数据库端口
|
||||||
|
DB_PORT = 5432
|
||||||
|
# 数据库用户名
|
||||||
|
DB_USERNAME = 'postgres'
|
||||||
|
# 数据库密码
|
||||||
|
DB_PASSWORD = 'root'
|
||||||
|
# 数据库名称
|
||||||
|
DB_DATABASE = 'ruoyi-fastapi'
|
||||||
|
# 是否开启sqlalchemy日志
|
||||||
|
DB_ECHO = true
|
||||||
|
# 允许溢出连接池大小的最大连接数
|
||||||
|
DB_MAX_OVERFLOW = 10
|
||||||
|
# 连接池大小,0表示连接数无限制
|
||||||
|
DB_POOL_SIZE = 50
|
||||||
|
# 连接回收时间(单位:秒)
|
||||||
|
DB_POOL_RECYCLE = 3600
|
||||||
|
# 连接池中没有线程可用时,最多等待的时间(单位:秒)
|
||||||
|
DB_POOL_TIMEOUT = 30
|
||||||
|
|
||||||
|
# -------- Redis配置 --------
|
||||||
|
# Redis主机
|
||||||
|
REDIS_HOST = 'ruoyi-redis'
|
||||||
|
# Redis端口
|
||||||
|
REDIS_PORT = 6379
|
||||||
|
# Redis用户名
|
||||||
|
REDIS_USERNAME = ''
|
||||||
|
# Redis密码
|
||||||
|
REDIS_PASSWORD = ''
|
||||||
|
# Redis数据库
|
||||||
|
REDIS_DATABASE = 2
|
||||||
@@ -10,7 +10,7 @@ APP_HOST = '0.0.0.0'
|
|||||||
# 应用端口
|
# 应用端口
|
||||||
APP_PORT = 9099
|
APP_PORT = 9099
|
||||||
# 应用版本
|
# 应用版本
|
||||||
APP_VERSION= '1.7.0'
|
APP_VERSION= '1.8.0'
|
||||||
# 应用是否开启热重载
|
# 应用是否开启热重载
|
||||||
APP_RELOAD = false
|
APP_RELOAD = false
|
||||||
# 应用是否开启IP归属区域查询
|
# 应用是否开启IP归属区域查询
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
FROM python:3.10
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 复制源代码
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# 安装依赖
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
|
|
||||||
|
# 暴露端口
|
||||||
|
EXPOSE 9099
|
||||||
|
|
||||||
|
# 启动命令
|
||||||
|
CMD ["python", "app.py", "--env=dockermy"]
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
FROM python:3.10
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 复制源代码
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# 安装依赖
|
||||||
|
RUN pip install --no-cache-dir -r requirements-pg.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
|
|
||||||
|
# 暴露端口
|
||||||
|
EXPOSE 9099
|
||||||
|
|
||||||
|
# 启动命令
|
||||||
|
CMD ["python", "app.py", "--env=dockerpg"]
|
||||||
@@ -1,13 +1,18 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
from alembic import context
|
from collections.abc import Iterable
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
|
from alembic import context
|
||||||
|
from alembic.migration import MigrationContext
|
||||||
|
from alembic.operations.ops import MigrationScript
|
||||||
from sqlalchemy import pool
|
from sqlalchemy import pool
|
||||||
from sqlalchemy.engine import Connection
|
from sqlalchemy.engine import Connection
|
||||||
from sqlalchemy.ext.asyncio import async_engine_from_config
|
from sqlalchemy.ext.asyncio import async_engine_from_config
|
||||||
from config.database import Base, ASYNC_SQLALCHEMY_DATABASE_URL
|
|
||||||
from utils.import_util import ImportUtil
|
|
||||||
|
|
||||||
|
from config.database import ASYNC_SQLALCHEMY_DATABASE_URL, Base
|
||||||
|
from utils.import_util import ImportUtil
|
||||||
|
|
||||||
# 判断vesrions目录是否存在,如果不存在则创建
|
# 判断vesrions目录是否存在,如果不存在则创建
|
||||||
alembic_veresions_path = 'alembic/versions'
|
alembic_veresions_path = 'alembic/versions'
|
||||||
@@ -60,7 +65,11 @@ def run_migrations_offline() -> None:
|
|||||||
|
|
||||||
|
|
||||||
def do_run_migrations(connection: Connection) -> None:
|
def do_run_migrations(connection: Connection) -> None:
|
||||||
def process_revision_directives(context, revision, directives):
|
def process_revision_directives(
|
||||||
|
context: MigrationContext,
|
||||||
|
revision: Union[str, Iterable[Optional[str]], Iterable[str]],
|
||||||
|
directives: list[MigrationScript],
|
||||||
|
) -> None:
|
||||||
script = directives[0]
|
script = directives[0]
|
||||||
|
|
||||||
# 检查所有操作集是否为空
|
# 检查所有操作集是否为空
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import uvicorn
|
import uvicorn
|
||||||
from server import app, AppConfig # noqa: F401
|
|
||||||
|
|
||||||
|
from config.env import AppConfig
|
||||||
|
from server import create_app
|
||||||
|
|
||||||
|
app = create_app()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
|
|||||||
@@ -0,0 +1,415 @@
|
|||||||
|
import inspect
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from collections.abc import Awaitable
|
||||||
|
from datetime import datetime
|
||||||
|
from functools import wraps
|
||||||
|
from typing import Any, Callable, Literal, Optional, TypeVar
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
from async_lru import alru_cache
|
||||||
|
from fastapi import Request
|
||||||
|
from fastapi.responses import JSONResponse, ORJSONResponse, UJSONResponse
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from starlette.status import HTTP_200_OK
|
||||||
|
from typing_extensions import ParamSpec
|
||||||
|
from user_agents import parse
|
||||||
|
|
||||||
|
from common.context import RequestContext
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from config.env import AppConfig
|
||||||
|
from exceptions.exception import LoginException, ServiceException, ServiceWarning
|
||||||
|
from module_admin.entity.vo.log_vo import LogininforModel, OperLogModel
|
||||||
|
from module_admin.service.log_service import LoginLogService, OperationLogService
|
||||||
|
from utils.dependency_util import DependencyUtil
|
||||||
|
from utils.log_util import logger
|
||||||
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
P = ParamSpec('P')
|
||||||
|
R = TypeVar('R')
|
||||||
|
|
||||||
|
|
||||||
|
class Log:
|
||||||
|
"""
|
||||||
|
日志装饰器
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
title: str,
|
||||||
|
business_type: BusinessType,
|
||||||
|
log_type: Optional[Literal['login', 'operation']] = 'operation',
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
日志装饰器
|
||||||
|
|
||||||
|
:param title: 当前日志装饰器装饰的模块标题
|
||||||
|
:param business_type: 业务类型(OTHER其它 INSERT新增 UPDATE修改 DELETE删除 GRANT授权 EXPORT导出 IMPORT导入 FORCE强退 GENCODE生成代码 CLEAN清空数据)
|
||||||
|
:param log_type: 日志类型(login表示登录日志,operation表示为操作日志)
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.title = title
|
||||||
|
self.business_type = business_type.value
|
||||||
|
self.log_type = log_type
|
||||||
|
self._oper_param_len = 2000
|
||||||
|
|
||||||
|
def __call__(self, func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[R]]:
|
||||||
|
@wraps(func)
|
||||||
|
async def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
|
||||||
|
start_time = time.perf_counter()
|
||||||
|
# 获取当前被装饰函数所在路径
|
||||||
|
func_path = self._get_decorator_func_path(func)
|
||||||
|
# 获取上下文信息
|
||||||
|
request_name_list = get_function_parameters_name_by_type(func, Request)
|
||||||
|
request = get_function_parameters_value_by_name(func, request_name_list[0], *args, **kwargs)
|
||||||
|
DependencyUtil.check_exclude_routes(request, err_msg='当前路由不在认证规则内,不可使用Log装饰器')
|
||||||
|
session_name_list = get_function_parameters_name_by_type(func, AsyncSession)
|
||||||
|
query_db = get_function_parameters_value_by_name(func, session_name_list[0], *args, **kwargs)
|
||||||
|
request_method = request.method
|
||||||
|
user_agent = request.headers.get('User-Agent')
|
||||||
|
# 获取操作类型
|
||||||
|
operator_type = self._get_oper_type(user_agent)
|
||||||
|
# 获取请求的url
|
||||||
|
oper_url = request.url.path
|
||||||
|
# 获取请求ip
|
||||||
|
oper_ip = request.headers.get('X-Forwarded-For')
|
||||||
|
# 获取请求ip归属区域
|
||||||
|
oper_location = await self._get_oper_location(oper_ip)
|
||||||
|
# 获取请求参数
|
||||||
|
oper_param = await self._get_request_params(request)
|
||||||
|
# 日志表请求参数字段长度最大为2000,因此在此处判断长度
|
||||||
|
if len(oper_param) > self._oper_param_len:
|
||||||
|
oper_param = '请求参数过长'
|
||||||
|
|
||||||
|
# 获取操作时间
|
||||||
|
oper_time = datetime.now()
|
||||||
|
# 此处在登录之前向原始函数传递一些登录信息,用于监测在线用户的相关信息
|
||||||
|
login_log = self._get_login_log(user_agent, oper_ip, oper_location, oper_time, kwargs)
|
||||||
|
try:
|
||||||
|
# 调用原始函数
|
||||||
|
result = await func(*args, **kwargs)
|
||||||
|
except (LoginException, ServiceWarning) as e:
|
||||||
|
logger.warning(e.message)
|
||||||
|
result = ResponseUtil.failure(data=e.data, msg=e.message)
|
||||||
|
except ServiceException as e:
|
||||||
|
logger.error(e.message)
|
||||||
|
result = ResponseUtil.error(data=e.data, msg=e.message)
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception(e)
|
||||||
|
result = ResponseUtil.error(msg=str(e))
|
||||||
|
# 获取请求耗时
|
||||||
|
cost_time = float(time.perf_counter() - start_time) * 1000
|
||||||
|
# 判断请求是否来自api文档
|
||||||
|
request_from_swagger, request_from_redoc = self._is_request_from_swagger_or_redoc(request)
|
||||||
|
# 根据响应结果的类型使用不同的方法获取响应结果参数
|
||||||
|
result_dict = self._get_result_dict(result, request_from_swagger, request_from_redoc)
|
||||||
|
json_result = json.dumps(result_dict, ensure_ascii=False)
|
||||||
|
# 根据响应结果获取响应状态及异常信息
|
||||||
|
status, error_msg = self._get_status_and_error_msg(result_dict)
|
||||||
|
# 根据日志类型向对应的日志表插入数据
|
||||||
|
if self.log_type == 'login':
|
||||||
|
# 登录请求来自于api文档时不记录登录日志,其余情况则记录
|
||||||
|
if request_from_swagger or request_from_redoc:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
user = kwargs.get('form_data')
|
||||||
|
login_log.update(
|
||||||
|
{
|
||||||
|
'loginTime': oper_time,
|
||||||
|
'userName': user.username,
|
||||||
|
'status': str(status),
|
||||||
|
'msg': result_dict.get('msg'),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
await LoginLogService.add_login_log_services(query_db, LogininforModel(**login_log))
|
||||||
|
else:
|
||||||
|
current_user = RequestContext.get_current_user()
|
||||||
|
oper_name = current_user.user.user_name
|
||||||
|
dept_name = current_user.user.dept.dept_name if current_user.user.dept else None
|
||||||
|
operation_log = OperLogModel(
|
||||||
|
title=self.title,
|
||||||
|
businessType=self.business_type,
|
||||||
|
method=func_path,
|
||||||
|
requestMethod=request_method,
|
||||||
|
operatorType=operator_type,
|
||||||
|
operName=oper_name,
|
||||||
|
deptName=dept_name,
|
||||||
|
operUrl=oper_url,
|
||||||
|
operIp=oper_ip,
|
||||||
|
operLocation=oper_location,
|
||||||
|
operParam=oper_param,
|
||||||
|
jsonResult=json_result,
|
||||||
|
status=status,
|
||||||
|
errorMsg=error_msg,
|
||||||
|
operTime=oper_time,
|
||||||
|
costTime=int(cost_time),
|
||||||
|
)
|
||||||
|
await OperationLogService.add_operation_log_services(query_db, operation_log)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
def _get_decorator_func_path(self, func: Callable) -> str:
|
||||||
|
"""
|
||||||
|
获取被装饰函数所在路径
|
||||||
|
|
||||||
|
:param func: 被装饰函数
|
||||||
|
:return: 被装饰函数所在路径
|
||||||
|
"""
|
||||||
|
# 获取被装饰函数所在的模块
|
||||||
|
module = inspect.getmodule(func)
|
||||||
|
# 获取完整模块路径
|
||||||
|
module_path = module.__name__ if module else ''
|
||||||
|
# 获取当前被装饰函数所在路径
|
||||||
|
func_path = f'{module_path}.{func.__name__}()'
|
||||||
|
|
||||||
|
return func_path
|
||||||
|
|
||||||
|
def _get_oper_type(self, user_agent: Any) -> int:
|
||||||
|
"""
|
||||||
|
获取操作类型
|
||||||
|
|
||||||
|
:param user_agent: 用户代理字符串
|
||||||
|
:return: 操作类型
|
||||||
|
"""
|
||||||
|
operator_type = 0
|
||||||
|
if 'Windows' in user_agent or 'Macintosh' in user_agent or 'Linux' in user_agent:
|
||||||
|
operator_type = 1
|
||||||
|
if 'Mobile' in user_agent or 'Android' in user_agent or 'iPhone' in user_agent:
|
||||||
|
operator_type = 2
|
||||||
|
|
||||||
|
return operator_type
|
||||||
|
|
||||||
|
async def _get_oper_location(self, oper_ip: str) -> str:
|
||||||
|
"""
|
||||||
|
获取请求IP归属区域
|
||||||
|
|
||||||
|
:param oper_ip: 请求IP
|
||||||
|
:return: 请求IP归属区域
|
||||||
|
"""
|
||||||
|
oper_location = '内网IP'
|
||||||
|
if AppConfig.app_ip_location_query:
|
||||||
|
oper_location = await get_ip_location(oper_ip)
|
||||||
|
|
||||||
|
return oper_location
|
||||||
|
|
||||||
|
async def _get_request_params(self, request: Request) -> str:
|
||||||
|
"""
|
||||||
|
获取请求参数
|
||||||
|
|
||||||
|
:param request: Request对象
|
||||||
|
:return: 格式化后的请求参数字符串
|
||||||
|
"""
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
# 路径和查询参数
|
||||||
|
path_params = dict(request.path_params)
|
||||||
|
query_params = dict(request.query_params)
|
||||||
|
params.update({k: v for k, v in {'path_params': path_params, 'query_params': query_params}.items() if v})
|
||||||
|
|
||||||
|
# 请求体处理
|
||||||
|
content_type = request.headers.get('Content-Type', '')
|
||||||
|
|
||||||
|
# JSON请求
|
||||||
|
if 'application/json' in content_type:
|
||||||
|
json_body = await request.json()
|
||||||
|
if json_body:
|
||||||
|
params['json_body'] = json_body
|
||||||
|
|
||||||
|
# 表单数据
|
||||||
|
elif 'multipart/form-data' in content_type or 'application/x-www-form-urlencoded' in content_type:
|
||||||
|
form_data = await request.form()
|
||||||
|
if form_data:
|
||||||
|
# 过滤掉文件对象,只保留普通表单字段
|
||||||
|
form_dict = {key: value for key, value in form_data.items() if not hasattr(value, 'filename')}
|
||||||
|
if form_dict:
|
||||||
|
params['form_data'] = form_dict
|
||||||
|
|
||||||
|
# 仅在multipart时尝试处理文件
|
||||||
|
if 'multipart/form-data' in content_type:
|
||||||
|
file_info = {}
|
||||||
|
for key, value in form_data.items():
|
||||||
|
if hasattr(value, 'filename'):
|
||||||
|
file_info[key] = {
|
||||||
|
'filename': value.filename,
|
||||||
|
'content_type': value.content_type,
|
||||||
|
'size': value.size,
|
||||||
|
'headers': dict(value.headers),
|
||||||
|
}
|
||||||
|
if file_info:
|
||||||
|
params['files'] = file_info
|
||||||
|
|
||||||
|
# 其他文本请求
|
||||||
|
elif 'application/octet-stream' not in content_type:
|
||||||
|
body = await request.body()
|
||||||
|
if body:
|
||||||
|
params['raw_body'] = body.decode('utf-8')
|
||||||
|
|
||||||
|
return json.dumps(params, ensure_ascii=False, indent=2) if params else ''
|
||||||
|
|
||||||
|
def _get_login_log(
|
||||||
|
self, user_agent: Any, oper_ip: str, oper_location: str, oper_time: datetime, origin_kwargs: dict
|
||||||
|
) -> dict:
|
||||||
|
"""
|
||||||
|
获取登录日志信息
|
||||||
|
|
||||||
|
:param user_agent: 用户代理字符串
|
||||||
|
:param oper_ip: 操作ip
|
||||||
|
:param oper_location: 操作区域
|
||||||
|
:param oper_time: 操作时间
|
||||||
|
:param origin_kwargs: 原始函数参数
|
||||||
|
:return: 登录日志信息
|
||||||
|
"""
|
||||||
|
login_log = {}
|
||||||
|
if self.log_type == 'login':
|
||||||
|
user_agent_info = parse(user_agent)
|
||||||
|
browser = f'{user_agent_info.browser.family}'
|
||||||
|
system_os = f'{user_agent_info.os.family}'
|
||||||
|
if user_agent_info.browser.version != ():
|
||||||
|
browser += f' {user_agent_info.browser.version[0]}'
|
||||||
|
if user_agent_info.os.version != ():
|
||||||
|
system_os += f' {user_agent_info.os.version[0]}'
|
||||||
|
login_log = {
|
||||||
|
'ipaddr': oper_ip,
|
||||||
|
'loginLocation': oper_location,
|
||||||
|
'browser': browser,
|
||||||
|
'os': system_os,
|
||||||
|
'loginTime': oper_time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
|
}
|
||||||
|
self._set_login_data(login_log, origin_kwargs)
|
||||||
|
|
||||||
|
return login_log
|
||||||
|
|
||||||
|
def _set_login_data(self, login_log: dict, origin_kwargs: dict) -> None:
|
||||||
|
"""
|
||||||
|
设置登录日志数据
|
||||||
|
|
||||||
|
:param login_log: 登录日志信息
|
||||||
|
:param origin_kwargs: 原始函数参数
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
if 'form_data' in origin_kwargs:
|
||||||
|
origin_kwargs['form_data'].login_info = login_log
|
||||||
|
|
||||||
|
def _get_status_and_error_msg(self, result_dict: dict) -> tuple[int, str]:
|
||||||
|
"""
|
||||||
|
获取操作状态和错误信息
|
||||||
|
|
||||||
|
:param result_dict: 操作结果字典
|
||||||
|
:return: 操作状态和错误信息元组
|
||||||
|
"""
|
||||||
|
status = 1
|
||||||
|
error_msg = ''
|
||||||
|
if result_dict.get('code') == HTTP_200_OK:
|
||||||
|
status = 0
|
||||||
|
else:
|
||||||
|
error_msg = result_dict.get('msg')
|
||||||
|
|
||||||
|
return status, error_msg
|
||||||
|
|
||||||
|
def _is_request_from_swagger_or_redoc(self, request: Request) -> tuple[bool, bool]:
|
||||||
|
"""
|
||||||
|
判断请求是否来自swagger或redoc
|
||||||
|
|
||||||
|
:param request: Request对象
|
||||||
|
:return: 是否来自swagger请求和是否来自redoc请求元组
|
||||||
|
"""
|
||||||
|
request_from_swagger = (
|
||||||
|
request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False
|
||||||
|
)
|
||||||
|
request_from_redoc = (
|
||||||
|
request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False
|
||||||
|
)
|
||||||
|
|
||||||
|
return request_from_swagger, request_from_redoc
|
||||||
|
|
||||||
|
def _get_result_dict(self, result: Any, request_from_swagger: bool, request_from_redoc: bool) -> dict:
|
||||||
|
"""
|
||||||
|
获取操作结果字典
|
||||||
|
|
||||||
|
:param result: 操作结果
|
||||||
|
:param request_from_swagger: 是否来自swagger请求
|
||||||
|
:param request_from_redoc: 是否来自redoc请求
|
||||||
|
:return: 操作结果字典
|
||||||
|
"""
|
||||||
|
if isinstance(result, (JSONResponse, ORJSONResponse, UJSONResponse)):
|
||||||
|
result_dict = json.loads(str(result.body, 'utf-8'))
|
||||||
|
elif request_from_swagger or request_from_redoc:
|
||||||
|
result_dict = {}
|
||||||
|
elif result.status_code == HTTP_200_OK:
|
||||||
|
result_dict = {'code': result.status_code, 'message': '获取成功'}
|
||||||
|
else:
|
||||||
|
result_dict = {'code': result.status_code, 'message': '获取失败'}
|
||||||
|
|
||||||
|
return result_dict
|
||||||
|
|
||||||
|
|
||||||
|
@alru_cache()
|
||||||
|
async def get_ip_location(oper_ip: str) -> str:
|
||||||
|
"""
|
||||||
|
查询ip归属区域
|
||||||
|
|
||||||
|
:param oper_ip: 需要查询的ip
|
||||||
|
:return: ip归属区域
|
||||||
|
"""
|
||||||
|
oper_location = '内网IP'
|
||||||
|
try:
|
||||||
|
if oper_ip not in ['127.0.0.1', 'localhost']:
|
||||||
|
oper_location = '未知'
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
ip_result = await client.get(f'https://qifu-api.baidubce.com/ip/geo/v1/district?ip={oper_ip}')
|
||||||
|
if ip_result.status_code == HTTP_200_OK:
|
||||||
|
prov = ip_result.json().get('data', {}).get('prov')
|
||||||
|
city = ip_result.json().get('data', {}).get('city')
|
||||||
|
if prov or city:
|
||||||
|
oper_location = f'{prov}-{city}'
|
||||||
|
except Exception as e:
|
||||||
|
oper_location = '未知'
|
||||||
|
print(e)
|
||||||
|
return oper_location
|
||||||
|
|
||||||
|
|
||||||
|
def get_function_parameters_name_by_type(func: Callable, param_type: Any) -> list:
|
||||||
|
"""
|
||||||
|
获取函数指定类型的参数名称
|
||||||
|
|
||||||
|
:param func: 函数
|
||||||
|
:param arg_type: 参数类型
|
||||||
|
:return: 函数指定类型的参数名称
|
||||||
|
"""
|
||||||
|
# 获取函数的参数信息
|
||||||
|
parameters = inspect.signature(func).parameters
|
||||||
|
# 找到指定类型的参数名称
|
||||||
|
parameters_name_list = []
|
||||||
|
# 遍历所有参数
|
||||||
|
for name, param in parameters.items():
|
||||||
|
# 处理参数注解
|
||||||
|
annotation = param.annotation
|
||||||
|
# 检查参数类型是否匹配
|
||||||
|
# 1. 直接匹配
|
||||||
|
# 2. 检查是否为Annotated类型(通过类型名称判断)
|
||||||
|
if annotation == param_type or (
|
||||||
|
hasattr(annotation, '__class__')
|
||||||
|
and annotation.__class__.__name__ == '_AnnotatedAlias'
|
||||||
|
and annotation.__origin__ == param_type
|
||||||
|
):
|
||||||
|
parameters_name_list.append(name)
|
||||||
|
return parameters_name_list
|
||||||
|
|
||||||
|
|
||||||
|
def get_function_parameters_value_by_name(func: Callable, name: str, *args, **kwargs) -> Any:
|
||||||
|
"""
|
||||||
|
获取函数指定参数的值
|
||||||
|
|
||||||
|
:param func: 函数
|
||||||
|
:param name: 参数名
|
||||||
|
:return: 参数值
|
||||||
|
"""
|
||||||
|
# 获取参数值
|
||||||
|
bound_parameters = inspect.signature(func).bind(*args, **kwargs)
|
||||||
|
bound_parameters.apply_defaults()
|
||||||
|
parameters_value = bound_parameters.arguments.get(name)
|
||||||
|
|
||||||
|
return parameters_value
|
||||||
+16
-14
@@ -1,21 +1,23 @@
|
|||||||
import inspect
|
import inspect
|
||||||
|
from typing import TYPE_CHECKING, TypeVar
|
||||||
|
|
||||||
from fastapi import Form, Query
|
from fastapi import Form, Query
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from pydantic.fields import FieldInfo
|
|
||||||
from typing import Type, TypeVar
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from pydantic.fields import FieldInfo
|
||||||
|
|
||||||
BaseModelVar = TypeVar('BaseModelVar', bound=BaseModel)
|
BaseModelVar = TypeVar('BaseModelVar', bound=BaseModel)
|
||||||
|
|
||||||
|
|
||||||
def as_query(cls: Type[BaseModelVar]) -> Type[BaseModelVar]:
|
def as_query(cls: type[BaseModelVar]) -> type[BaseModelVar]:
|
||||||
"""
|
"""
|
||||||
pydantic模型查询参数装饰器,将pydantic模型用于接收查询参数
|
pydantic模型查询参数装饰器,将pydantic模型用于接收查询参数
|
||||||
"""
|
"""
|
||||||
new_parameters = []
|
new_parameters = []
|
||||||
|
|
||||||
for field_name, model_field in cls.model_fields.items():
|
for model_field in cls.model_fields.values():
|
||||||
model_field: FieldInfo # type: ignore
|
model_field: FieldInfo
|
||||||
|
|
||||||
if not model_field.is_required():
|
if not model_field.is_required():
|
||||||
new_parameters.append(
|
new_parameters.append(
|
||||||
@@ -36,24 +38,24 @@ def as_query(cls: Type[BaseModelVar]) -> Type[BaseModelVar]:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def as_query_func(**data):
|
async def as_query_func(**data) -> type[BaseModelVar]:
|
||||||
return cls(**data)
|
return cls(**data)
|
||||||
|
|
||||||
sig = inspect.signature(as_query_func)
|
sig = inspect.signature(as_query_func)
|
||||||
sig = sig.replace(parameters=new_parameters)
|
sig = sig.replace(parameters=new_parameters)
|
||||||
as_query_func.__signature__ = sig # type: ignore
|
as_query_func.__signature__ = sig
|
||||||
setattr(cls, 'as_query', as_query_func)
|
cls.as_query = as_query_func
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
|
|
||||||
def as_form(cls: Type[BaseModelVar]) -> Type[BaseModelVar]:
|
def as_form(cls: type[BaseModelVar]) -> type[BaseModelVar]:
|
||||||
"""
|
"""
|
||||||
pydantic模型表单参数装饰器,将pydantic模型用于接收表单参数
|
pydantic模型表单参数装饰器,将pydantic模型用于接收表单参数
|
||||||
"""
|
"""
|
||||||
new_parameters = []
|
new_parameters = []
|
||||||
|
|
||||||
for field_name, model_field in cls.model_fields.items():
|
for model_field in cls.model_fields.values():
|
||||||
model_field: FieldInfo # type: ignore
|
model_field: FieldInfo
|
||||||
|
|
||||||
if not model_field.is_required():
|
if not model_field.is_required():
|
||||||
new_parameters.append(
|
new_parameters.append(
|
||||||
@@ -74,11 +76,11 @@ def as_form(cls: Type[BaseModelVar]) -> Type[BaseModelVar]:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
async def as_form_func(**data):
|
async def as_form_func(**data) -> type[BaseModelVar]:
|
||||||
return cls(**data)
|
return cls(**data)
|
||||||
|
|
||||||
sig = inspect.signature(as_form_func)
|
sig = inspect.signature(as_form_func)
|
||||||
sig = sig.replace(parameters=new_parameters)
|
sig = sig.replace(parameters=new_parameters)
|
||||||
as_form_func.__signature__ = sig # type: ignore
|
as_form_func.__signature__ = sig
|
||||||
setattr(cls, 'as_form', as_form_func)
|
cls.as_form = as_form_func
|
||||||
return cls
|
return cls
|
||||||
+29
-7
@@ -1,7 +1,9 @@
|
|||||||
from fastapi import Depends
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
|
||||||
from module_admin.service.login_service import LoginService
|
from fastapi import Depends, Request, params
|
||||||
|
|
||||||
|
from common.context import RequestContext
|
||||||
|
from utils.dependency_util import DependencyUtil
|
||||||
|
|
||||||
|
|
||||||
class GetDataScope:
|
class GetDataScope:
|
||||||
@@ -21,7 +23,7 @@ class GetDataScope:
|
|||||||
db_alias: Optional[str] = 'db',
|
db_alias: Optional[str] = 'db',
|
||||||
user_alias: Optional[str] = 'user_id',
|
user_alias: Optional[str] = 'user_id',
|
||||||
dept_alias: Optional[str] = 'dept_id',
|
dept_alias: Optional[str] = 'dept_id',
|
||||||
):
|
) -> None:
|
||||||
"""
|
"""
|
||||||
获取当前用户数据权限对应的查询sql语句
|
获取当前用户数据权限对应的查询sql语句
|
||||||
|
|
||||||
@@ -35,7 +37,9 @@ class GetDataScope:
|
|||||||
self.user_alias = user_alias
|
self.user_alias = user_alias
|
||||||
self.dept_alias = dept_alias
|
self.dept_alias = dept_alias
|
||||||
|
|
||||||
def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
|
def __call__(self, request: Request) -> str:
|
||||||
|
DependencyUtil.check_exclude_routes(request, err_msg='当前路由不在认证规则内,不可使用GetDataScope依赖项')
|
||||||
|
current_user = RequestContext.get_current_user()
|
||||||
user_id = current_user.user.user_id
|
user_id = current_user.user.user_id
|
||||||
dept_id = current_user.user.dept_id
|
dept_id = current_user.user.dept_id
|
||||||
custom_data_scope_role_id_list = [
|
custom_data_scope_role_id_list = [
|
||||||
@@ -46,7 +50,7 @@ class GetDataScope:
|
|||||||
if current_user.user.admin or role.data_scope == self.DATA_SCOPE_ALL:
|
if current_user.user.admin or role.data_scope == self.DATA_SCOPE_ALL:
|
||||||
param_sql_list = ['1 == 1']
|
param_sql_list = ['1 == 1']
|
||||||
break
|
break
|
||||||
elif role.data_scope == self.DATA_SCOPE_CUSTOM:
|
if role.data_scope == self.DATA_SCOPE_CUSTOM:
|
||||||
if len(custom_data_scope_role_id_list) > 1:
|
if len(custom_data_scope_role_id_list) > 1:
|
||||||
param_sql_list.append(
|
param_sql_list.append(
|
||||||
f"{self.query_alias}.{self.dept_alias}.in_(select(SysRoleDept.dept_id).where(SysRoleDept.role_id.in_({custom_data_scope_role_id_list}))) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0"
|
f"{self.query_alias}.{self.dept_alias}.in_(select(SysRoleDept.dept_id).where(SysRoleDept.role_id.in_({custom_data_scope_role_id_list}))) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0"
|
||||||
@@ -70,6 +74,24 @@ class GetDataScope:
|
|||||||
else:
|
else:
|
||||||
param_sql_list.append('1 == 0')
|
param_sql_list.append('1 == 0')
|
||||||
param_sql_list = list(dict.fromkeys(param_sql_list))
|
param_sql_list = list(dict.fromkeys(param_sql_list))
|
||||||
param_sql = f"or_({', '.join(param_sql_list)})"
|
param_sql = f'or_({", ".join(param_sql_list)})'
|
||||||
|
|
||||||
return param_sql
|
return param_sql
|
||||||
|
|
||||||
|
|
||||||
|
def DataScopeDependency( # noqa: N802
|
||||||
|
query_alias: Optional[str] = '',
|
||||||
|
db_alias: Optional[str] = 'db',
|
||||||
|
user_alias: Optional[str] = 'user_id',
|
||||||
|
dept_alias: Optional[str] = 'dept_id',
|
||||||
|
) -> params.Depends:
|
||||||
|
"""
|
||||||
|
当前用户数据权限依赖
|
||||||
|
|
||||||
|
:param query_alias: 所要查询表对应的sqlalchemy模型名称,默认为''
|
||||||
|
:param db_alias: orm对象别名,默认为'db'
|
||||||
|
:param user_alias: 用户id字段别名,默认为'user_id'
|
||||||
|
:param dept_alias: 部门id字段别名,默认为'dept_id'
|
||||||
|
:return: 当前用户数据权限依赖
|
||||||
|
"""
|
||||||
|
return Depends(GetDataScope(query_alias, db_alias, user_alias, dept_alias))
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
from fastapi import Depends, params
|
||||||
|
|
||||||
|
from config.get_db import get_db
|
||||||
|
|
||||||
|
|
||||||
|
def DBSessionDependency() -> params.Depends: # noqa: N802
|
||||||
|
"""
|
||||||
|
数据库会话依赖
|
||||||
|
|
||||||
|
:return: 数据库会话依赖
|
||||||
|
"""
|
||||||
|
return Depends(get_db)
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
from typing import Union
|
||||||
|
|
||||||
|
from fastapi import Depends, Request, params
|
||||||
|
|
||||||
|
from common.context import RequestContext
|
||||||
|
from exceptions.exception import PermissionException
|
||||||
|
from utils.dependency_util import DependencyUtil
|
||||||
|
|
||||||
|
|
||||||
|
class CheckUserInterfaceAuth:
|
||||||
|
"""
|
||||||
|
校验当前用户是否具有相应的接口权限
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, perm: Union[str, list], is_strict: bool = False) -> None:
|
||||||
|
"""
|
||||||
|
校验当前用户是否具有相应的接口权限
|
||||||
|
|
||||||
|
:param perm: 权限标识
|
||||||
|
:param is_strict: 当传入的权限标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个权限标识,所有的校验结果都需要为True才会通过
|
||||||
|
"""
|
||||||
|
self.perm = perm
|
||||||
|
self.is_strict = is_strict
|
||||||
|
|
||||||
|
def __call__(self, request: Request) -> bool:
|
||||||
|
DependencyUtil.check_exclude_routes(
|
||||||
|
request, err_msg='当前路由不在认证规则内,不可使用CheckUserInterfaceAuth依赖项'
|
||||||
|
)
|
||||||
|
current_user = RequestContext.get_current_user()
|
||||||
|
user_auth_list = current_user.permissions
|
||||||
|
if '*:*:*' in user_auth_list:
|
||||||
|
return True
|
||||||
|
if isinstance(self.perm, str) and self.perm in user_auth_list:
|
||||||
|
return True
|
||||||
|
if isinstance(self.perm, list):
|
||||||
|
if self.is_strict:
|
||||||
|
if all(perm_str in user_auth_list for perm_str in self.perm):
|
||||||
|
return True
|
||||||
|
elif any(perm_str in user_auth_list for perm_str in self.perm):
|
||||||
|
return True
|
||||||
|
raise PermissionException(data='', message='该用户无此接口权限')
|
||||||
|
|
||||||
|
|
||||||
|
class CheckRoleInterfaceAuth:
|
||||||
|
"""
|
||||||
|
根据角色校验当前用户是否具有相应的接口权限
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, role_key: Union[str, list], is_strict: bool = False) -> None:
|
||||||
|
"""
|
||||||
|
根据角色校验当前用户是否具有相应的接口权限
|
||||||
|
|
||||||
|
:param role_key: 角色标识
|
||||||
|
:param is_strict: 当传入的角色标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个角色标识,所有的校验结果都需要为True才会通过
|
||||||
|
"""
|
||||||
|
self.role_key = role_key
|
||||||
|
self.is_strict = is_strict
|
||||||
|
|
||||||
|
def __call__(self, request: Request) -> bool:
|
||||||
|
DependencyUtil.check_exclude_routes(
|
||||||
|
request, err_msg='当前路由不在认证规则内,不可使用CheckRoleInterfaceAuth依赖项'
|
||||||
|
)
|
||||||
|
current_user = RequestContext.get_current_user()
|
||||||
|
user_role_list = current_user.user.role
|
||||||
|
user_role_key_list = [role.role_key for role in user_role_list]
|
||||||
|
if isinstance(self.role_key, str) and self.role_key in user_role_key_list:
|
||||||
|
return True
|
||||||
|
if isinstance(self.role_key, list):
|
||||||
|
if self.is_strict:
|
||||||
|
if all(role_key_str in user_role_key_list for role_key_str in self.role_key):
|
||||||
|
return True
|
||||||
|
elif any(role_key_str in user_role_key_list for role_key_str in self.role_key):
|
||||||
|
return True
|
||||||
|
raise PermissionException(data='', message='该用户无此接口权限')
|
||||||
|
|
||||||
|
|
||||||
|
def UserInterfaceAuthDependency(perm: Union[str, list], is_strict: bool = False) -> params.Depends: # noqa: N802
|
||||||
|
"""
|
||||||
|
根据权限标识校验当前用户接口权限依赖
|
||||||
|
|
||||||
|
:param perm: 权限标识
|
||||||
|
:param is_strict: 当传入的权限标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个权限标识,所有的校验结果都需要为True才会通过
|
||||||
|
:return: 根据权限标识校验当前用户接口权限依赖
|
||||||
|
"""
|
||||||
|
return Depends(CheckUserInterfaceAuth(perm, is_strict))
|
||||||
|
|
||||||
|
|
||||||
|
def RoleInterfaceAuthDependency(role_key: Union[str, list], is_strict: bool = False) -> params.Depends: # noqa: N802
|
||||||
|
"""
|
||||||
|
根据角色校验当前用户接口权限依赖
|
||||||
|
|
||||||
|
:param role_key: 角色标识
|
||||||
|
:param is_strict: 当传入的角色标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个角色标识,所有的校验结果都需要为True才会通过
|
||||||
|
:return: 根据角色校验当前用户接口权限依赖
|
||||||
|
"""
|
||||||
|
return Depends(CheckRoleInterfaceAuth(role_key, is_strict))
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import re
|
||||||
|
from typing import Literal, Optional, TypedDict, Union
|
||||||
|
|
||||||
|
from fastapi import Depends, Request, params
|
||||||
|
from fastapi.security import OAuth2PasswordBearer
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.context import RequestContext
|
||||||
|
from config.env import AppConfig
|
||||||
|
from config.get_db import get_db
|
||||||
|
from exceptions.exception import AuthException
|
||||||
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
|
from module_admin.service.login_service import LoginService
|
||||||
|
|
||||||
|
|
||||||
|
# 定义排除路由的字典结构
|
||||||
|
class ExcludeRoute(TypedDict, total=False):
|
||||||
|
"""
|
||||||
|
排除路由的字典结构
|
||||||
|
|
||||||
|
:param path: 路由路径(必填)
|
||||||
|
:param methods: HTTP方法列表,空列表表示所有方法(可选,默认为[])
|
||||||
|
:param ignore_paths: 需要忽略的特定路径列表,即使匹配通配符也不排除(可选,默认为[])
|
||||||
|
"""
|
||||||
|
|
||||||
|
path: str
|
||||||
|
methods: list[Literal['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']]
|
||||||
|
ignore_paths: list[str]
|
||||||
|
|
||||||
|
|
||||||
|
# 创建OAuth2PasswordBearer对象
|
||||||
|
oauth2_scheme = OAuth2PasswordBearer(tokenUrl='/login')
|
||||||
|
|
||||||
|
|
||||||
|
class PreAuth:
|
||||||
|
"""
|
||||||
|
登录认证前置校验依赖类
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, exclude_routes: Optional[list[ExcludeRoute]] = None) -> None:
|
||||||
|
"""
|
||||||
|
初始化登录认证前置校验依赖
|
||||||
|
|
||||||
|
:param exclude_routes: 需要排除的路由列表,格式为:
|
||||||
|
[{'path': '/path1', 'methods': ['GET', 'POST']}, {'path': '/path2/{param}', 'methods': ['GET']}]
|
||||||
|
methods 可以是字符串或列表,空列表表示所有方法
|
||||||
|
"""
|
||||||
|
self.exclude_routes = exclude_routes or []
|
||||||
|
# 编译排除路径为正则表达式模式,并存储方法信息
|
||||||
|
self.exclude_patterns = []
|
||||||
|
|
||||||
|
for route in self.exclude_routes:
|
||||||
|
# 使用TypedDict,确保路由字典包含path字段
|
||||||
|
path = route.get('path', '')
|
||||||
|
methods = route.get('methods', [])
|
||||||
|
ignore_paths = route.get('ignore_paths', [])
|
||||||
|
|
||||||
|
# 编译路径为正则表达式
|
||||||
|
pattern = self._compile_path_pattern(path)
|
||||||
|
# 存储编译后的模式和方法信息
|
||||||
|
self.exclude_patterns.append(
|
||||||
|
{
|
||||||
|
'pattern': pattern,
|
||||||
|
'methods': [method.upper() for method in methods],
|
||||||
|
'original_path': path,
|
||||||
|
'ignore_paths': ignore_paths,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def _compile_path_pattern(self, path: str) -> re.Pattern:
|
||||||
|
"""
|
||||||
|
将FastAPI路径转换为正则表达式模式
|
||||||
|
|
||||||
|
:param path: FastAPI路径(如 /configKey/{config_key})
|
||||||
|
:return: 编译后的正则表达式模式
|
||||||
|
"""
|
||||||
|
# 将FastAPI路径参数转换为正则表达式
|
||||||
|
# 例如:/configKey/{config_key} -> /configKey/[^/]+
|
||||||
|
pattern_str = re.sub(r'\{[^}]+\}', r'[^/]+', path)
|
||||||
|
# 添加开始和结束锚点,确保精确匹配
|
||||||
|
return re.compile(f'^{pattern_str}$')
|
||||||
|
|
||||||
|
async def __call__(self, request: Request, db: AsyncSession = Depends(get_db)) -> Union[CurrentUserModel, None]:
|
||||||
|
"""
|
||||||
|
执行登录认证校验
|
||||||
|
|
||||||
|
:param request: 当前请求对象
|
||||||
|
:param db: 数据库会话
|
||||||
|
:return: 当前用户信息
|
||||||
|
"""
|
||||||
|
# 获取当前请求路径和方法
|
||||||
|
path = request.url.path
|
||||||
|
method = request.method.upper()
|
||||||
|
|
||||||
|
# 从配置中获取APP_ROOT_PATH
|
||||||
|
app_root_path = AppConfig.app_root_path
|
||||||
|
|
||||||
|
# 去掉APP_ROOT_PATH前缀
|
||||||
|
if app_root_path and path.startswith(app_root_path):
|
||||||
|
path = path[len(app_root_path) :]
|
||||||
|
|
||||||
|
# 设置上下文变量
|
||||||
|
RequestContext.set_current_exclude_patterns(self.exclude_patterns)
|
||||||
|
|
||||||
|
# 检查路径和方法是否匹配排除模式
|
||||||
|
for item in self.exclude_patterns:
|
||||||
|
pattern = item['pattern']
|
||||||
|
exclude_methods = item['methods']
|
||||||
|
ignore_paths = item['ignore_paths']
|
||||||
|
|
||||||
|
# 检查当前路径是否在忽略列表中
|
||||||
|
if path in ignore_paths:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 检查路径是否匹配,并且methods为空列表(匹配所有方法)或者当前方法在允许列表中
|
||||||
|
if pattern.match(path) and (not exclude_methods or method in exclude_methods):
|
||||||
|
# 跳过认证
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 否则执行正常认证
|
||||||
|
token = request.headers.get('Authorization')
|
||||||
|
if not token:
|
||||||
|
raise AuthException(data='', message='用户未登录,请先完成登录')
|
||||||
|
current_user = await LoginService.get_current_user(request, token, db)
|
||||||
|
return current_user
|
||||||
|
|
||||||
|
|
||||||
|
def PreAuthDependency(exclude_routes: Optional[list[ExcludeRoute]] = None) -> params.Depends: # noqa: N802
|
||||||
|
"""
|
||||||
|
登录认证前置校验依赖
|
||||||
|
|
||||||
|
:param exclude_routes: 需要排除的路由列表,格式为:
|
||||||
|
[{'path': '/path1', 'methods': ['GET', 'POST']}, {'path': '/path2/{param}', 'methods': ['GET']}]
|
||||||
|
methods 可以是字符串或列表,空列表表示所有方法
|
||||||
|
:return: 登录认证前置校验依赖
|
||||||
|
"""
|
||||||
|
return Depends(PreAuth(exclude_routes))
|
||||||
|
|
||||||
|
|
||||||
|
def CurrentUserDependency() -> params.Depends: # noqa: N802
|
||||||
|
"""
|
||||||
|
当前登录用户信息依赖
|
||||||
|
|
||||||
|
:return: 当前登录用户信息依赖
|
||||||
|
"""
|
||||||
|
return Depends(LoginService.get_current_user)
|
||||||
@@ -5,6 +5,7 @@ class CommonConstant:
|
|||||||
"""
|
"""
|
||||||
常用常量
|
常用常量
|
||||||
|
|
||||||
|
PASSWORD_ERROR_COUNT: 密码错误次数
|
||||||
WWW: www主域
|
WWW: www主域
|
||||||
HTTP: http请求
|
HTTP: http请求
|
||||||
HTTPS: https请求
|
HTTPS: https请求
|
||||||
@@ -19,6 +20,7 @@ class CommonConstant:
|
|||||||
NOT_UNIQUE: 校验是否唯一的返回标识(否)
|
NOT_UNIQUE: 校验是否唯一的返回标识(否)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
PASSWORD_ERROR_COUNT = 5
|
||||||
WWW = 'www.'
|
WWW = 'www.'
|
||||||
HTTP = 'http://'
|
HTTP = 'http://'
|
||||||
HTTPS = 'https://'
|
HTTPS = 'https://'
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
import re
|
||||||
|
from contextvars import ContextVar, Token
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
|
from exceptions.exception import LoginException
|
||||||
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
|
|
||||||
|
# 定义上下文变量
|
||||||
|
# 存储当前请求的编译后的排除路由模式列表
|
||||||
|
current_exclude_patterns: ContextVar[
|
||||||
|
Optional[
|
||||||
|
list[
|
||||||
|
dict[str, Union[str, list[Literal['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']], re.Pattern]]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
] = ContextVar('current_exclude_patterns', default=None)
|
||||||
|
# 存储当前用户信息
|
||||||
|
current_user: ContextVar[Optional[CurrentUserModel]] = ContextVar('current_user', default=None)
|
||||||
|
|
||||||
|
|
||||||
|
class RequestContext:
|
||||||
|
"""
|
||||||
|
请求上下文管理类,用于设置和清理上下文变量
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_current_exclude_patterns(
|
||||||
|
exclude_patterns: list[
|
||||||
|
dict[str, Union[str, list[Literal['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']], re.Pattern]]
|
||||||
|
],
|
||||||
|
) -> Token:
|
||||||
|
"""
|
||||||
|
设置当前请求的编译后的排除路由模式列表
|
||||||
|
|
||||||
|
:param exclude_patterns: 编译后的排除路由模式列表
|
||||||
|
:return: 上下文变量令牌,用于重置
|
||||||
|
"""
|
||||||
|
return current_exclude_patterns.set(exclude_patterns)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_current_exclude_patterns() -> list[
|
||||||
|
dict[str, Union[str, list[Literal['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']], re.Pattern]]
|
||||||
|
]:
|
||||||
|
"""
|
||||||
|
获取当前请求的编译后的排除路由模式列表
|
||||||
|
|
||||||
|
:return: 编译后的排除路由模式列表
|
||||||
|
"""
|
||||||
|
_exclude_patterns = current_exclude_patterns.get()
|
||||||
|
if _exclude_patterns is None:
|
||||||
|
_exclude_patterns = []
|
||||||
|
return _exclude_patterns
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_current_user(user: CurrentUserModel) -> Token:
|
||||||
|
"""
|
||||||
|
设置当前用户信息
|
||||||
|
|
||||||
|
:param user: 用户信息
|
||||||
|
:return: 上下文变量令牌,用于重置
|
||||||
|
"""
|
||||||
|
return current_user.set(user)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_current_user() -> CurrentUserModel:
|
||||||
|
"""
|
||||||
|
获取当前用户信息
|
||||||
|
|
||||||
|
:return: 用户信息
|
||||||
|
"""
|
||||||
|
_current_user = current_user.get()
|
||||||
|
if _current_user is None:
|
||||||
|
raise LoginException(data='', message='当前用户信息为空,请检查是否已登录')
|
||||||
|
return _current_user
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def reset_current_exclude_patterns(token: Token) -> None:
|
||||||
|
"""
|
||||||
|
重置当前请求的编译后的排除路由模式列表
|
||||||
|
|
||||||
|
:param token: 设置编译后的排除路由模式列表时返回的令牌
|
||||||
|
"""
|
||||||
|
current_exclude_patterns.reset(token)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def reset_current_user(token: Token) -> None:
|
||||||
|
"""
|
||||||
|
重置当前用户信息
|
||||||
|
|
||||||
|
:param token: 设置用户信息时返回的令牌
|
||||||
|
"""
|
||||||
|
current_user.reset(token)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def clear_all() -> None:
|
||||||
|
"""
|
||||||
|
清除所有上下文变量
|
||||||
|
"""
|
||||||
|
current_exclude_patterns.set(None)
|
||||||
|
current_user.set(None)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class BusinessType(Enum):
|
class BusinessType(Enum):
|
||||||
@@ -35,11 +36,11 @@ class RedisInitKeyConfig(Enum):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def key(self):
|
def key(self) -> Union[str, None]:
|
||||||
return self.value.get('key')
|
return self.value.get('key')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def remark(self):
|
def remark(self) -> Union[str, None]:
|
||||||
return self.value.get('remark')
|
return self.value.get('remark')
|
||||||
|
|
||||||
ACCESS_TOKEN = {'key': 'access_token', 'remark': '登录令牌信息'}
|
ACCESS_TOKEN = {'key': 'access_token', 'remark': '登录令牌信息'}
|
||||||
@@ -0,0 +1,405 @@
|
|||||||
|
import importlib
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from collections.abc import Sequence
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Annotated, Any, Callable, Literal, Optional, Union
|
||||||
|
|
||||||
|
from annotated_doc import Doc
|
||||||
|
from fastapi import FastAPI, params
|
||||||
|
from fastapi.datastructures import Default
|
||||||
|
from fastapi.routing import APIRoute, APIRouter
|
||||||
|
from fastapi.utils import generate_unique_id
|
||||||
|
from starlette.responses import JSONResponse, Response
|
||||||
|
from starlette.routing import BaseRoute
|
||||||
|
from starlette.types import ASGIApp, Lifespan
|
||||||
|
from typing_extensions import deprecated
|
||||||
|
|
||||||
|
|
||||||
|
class APIRouterPro(APIRouter):
|
||||||
|
"""
|
||||||
|
`APIRouterPro` class, inherited from the `APIRouter` class, it has all the functions of `APIRouter` and provides some additional parameter settings.
|
||||||
|
`APIRouter` class, used to group *path operations*, for example to structure
|
||||||
|
an app in multiple files. It would then be included in the `FastAPI` app, or
|
||||||
|
in another `APIRouter` (ultimately included in the app).
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/).
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```python
|
||||||
|
from common.router import APIRouterPro, FastAPI
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
router = APIRouterPro()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/users/', tags=['users'])
|
||||||
|
async def read_users():
|
||||||
|
return [{'username': 'Rick'}, {'username': 'Morty'}]
|
||||||
|
|
||||||
|
|
||||||
|
app.include_router(router)
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__( # noqa: PLR0913
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
prefix: Annotated[str, Doc('An optional path prefix for the router.')] = '',
|
||||||
|
order_num: Annotated[int, Doc('An optional order number for the router.')] = 100,
|
||||||
|
auto_register: Annotated[bool, Doc('An optional auto register flag for the router.')] = True,
|
||||||
|
tags: Annotated[
|
||||||
|
Optional[list[Union[str, Enum]]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
A list of tags to be applied to all the *path operations* in this
|
||||||
|
router.
|
||||||
|
|
||||||
|
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
dependencies: Annotated[
|
||||||
|
Optional[Sequence[params.Depends]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
A list of dependencies (using `Depends()`) to be applied to all the
|
||||||
|
*path operations* in this router.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
default_response_class: Annotated[
|
||||||
|
type[Response],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
The default response class to be used.
|
||||||
|
|
||||||
|
Read more in the
|
||||||
|
[FastAPI docs for Custom Response - HTML, Stream, File, others](https://fastapi.tiangolo.com/advanced/custom-response/#default-response-class).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = Default(JSONResponse),
|
||||||
|
responses: Annotated[
|
||||||
|
Optional[dict[Union[int, str], dict[str, Any]]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
Additional responses to be shown in OpenAPI.
|
||||||
|
|
||||||
|
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Additional Responses in OpenAPI](https://fastapi.tiangolo.com/advanced/additional-responses/).
|
||||||
|
|
||||||
|
And in the
|
||||||
|
[FastAPI docs for Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
callbacks: Annotated[
|
||||||
|
Optional[list[BaseRoute]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
OpenAPI callbacks that should apply to all *path operations* in this
|
||||||
|
router.
|
||||||
|
|
||||||
|
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for OpenAPI Callbacks](https://fastapi.tiangolo.com/advanced/openapi-callbacks/).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
routes: Annotated[
|
||||||
|
Optional[list[BaseRoute]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
**Note**: you probably shouldn't use this parameter, it is inherited
|
||||||
|
from Starlette and supported for compatibility.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
A list of routes to serve incoming HTTP and WebSocket requests.
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
deprecated(
|
||||||
|
"""
|
||||||
|
You normally wouldn't use this parameter with FastAPI, it is inherited
|
||||||
|
from Starlette and supported for compatibility.
|
||||||
|
|
||||||
|
In FastAPI, you normally would use the *path operation methods*,
|
||||||
|
like `router.get()`, `router.post()`, etc.
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
redirect_slashes: Annotated[
|
||||||
|
bool,
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
Whether to detect and redirect slashes in URLs when the client doesn't
|
||||||
|
use the same format.
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = True,
|
||||||
|
default: Annotated[
|
||||||
|
Optional[ASGIApp],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
Default function handler for this router. Used to handle
|
||||||
|
404 Not Found errors.
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
dependency_overrides_provider: Annotated[
|
||||||
|
Optional[Any],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
Only used internally by FastAPI to handle dependency overrides.
|
||||||
|
|
||||||
|
You shouldn't need to use it. It normally points to the `FastAPI` app
|
||||||
|
object.
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
route_class: Annotated[
|
||||||
|
type[APIRoute],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
Custom route (*path operation*) class to be used by this router.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Custom Request and APIRoute class](https://fastapi.tiangolo.com/how-to/custom-request-and-route/#custom-apiroute-class-in-a-router).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = APIRoute,
|
||||||
|
on_startup: Annotated[
|
||||||
|
Optional[Sequence[Callable[[], Any]]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
A list of startup event handler functions.
|
||||||
|
|
||||||
|
You should instead use the `lifespan` handlers.
|
||||||
|
|
||||||
|
Read more in the [FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
on_shutdown: Annotated[
|
||||||
|
Optional[Sequence[Callable[[], Any]]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
A list of shutdown event handler functions.
|
||||||
|
|
||||||
|
You should instead use the `lifespan` handlers.
|
||||||
|
|
||||||
|
Read more in the
|
||||||
|
[FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
# the generic to Lifespan[AppType] is the type of the top level application
|
||||||
|
# which the router cannot know statically, so we use typing.Any
|
||||||
|
lifespan: Annotated[
|
||||||
|
Optional[Lifespan[Any]],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
A `Lifespan` context manager handler. This replaces `startup` and
|
||||||
|
`shutdown` functions with a single context manager.
|
||||||
|
|
||||||
|
Read more in the
|
||||||
|
[FastAPI docs for `lifespan`](https://fastapi.tiangolo.com/advanced/events/).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
deprecated: Annotated[
|
||||||
|
Optional[bool],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
Mark all *path operations* in this router as deprecated.
|
||||||
|
|
||||||
|
It will be added to the generated OpenAPI (e.g. visible at `/docs`).
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Path Operation Configuration](https://fastapi.tiangolo.com/tutorial/path-operation-configuration/).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = None,
|
||||||
|
include_in_schema: Annotated[
|
||||||
|
bool,
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
To include (or not) all the *path operations* in this router in the
|
||||||
|
generated OpenAPI.
|
||||||
|
|
||||||
|
This affects the generated OpenAPI (e.g. visible at `/docs`).
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs for Query Parameters and String Validations](https://fastapi.tiangolo.com/tutorial/query-params-str-validations/#exclude-parameters-from-openapi).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = True,
|
||||||
|
generate_unique_id_function: Annotated[
|
||||||
|
Callable[[APIRoute], str],
|
||||||
|
Doc(
|
||||||
|
"""
|
||||||
|
Customize the function used to generate unique IDs for the *path
|
||||||
|
operations* shown in the generated OpenAPI.
|
||||||
|
|
||||||
|
This is particularly useful when automatically generating clients or
|
||||||
|
SDKs for your API.
|
||||||
|
|
||||||
|
Read more about it in the
|
||||||
|
[FastAPI docs about how to Generate Clients](https://fastapi.tiangolo.com/advanced/generate-clients/#custom-generate-unique-id-function).
|
||||||
|
"""
|
||||||
|
),
|
||||||
|
] = Default(generate_unique_id),
|
||||||
|
) -> None:
|
||||||
|
self.order_num = order_num
|
||||||
|
self.auto_register = auto_register
|
||||||
|
super().__init__(
|
||||||
|
prefix=prefix,
|
||||||
|
tags=tags,
|
||||||
|
dependencies=dependencies,
|
||||||
|
default_response_class=default_response_class,
|
||||||
|
responses=responses,
|
||||||
|
callbacks=callbacks,
|
||||||
|
routes=routes,
|
||||||
|
redirect_slashes=redirect_slashes,
|
||||||
|
default=default,
|
||||||
|
dependency_overrides_provider=dependency_overrides_provider,
|
||||||
|
route_class=route_class,
|
||||||
|
on_startup=on_startup,
|
||||||
|
on_shutdown=on_shutdown,
|
||||||
|
lifespan=lifespan,
|
||||||
|
deprecated=deprecated,
|
||||||
|
include_in_schema=include_in_schema,
|
||||||
|
generate_unique_id_function=generate_unique_id_function,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RouterRegister:
|
||||||
|
"""
|
||||||
|
路由注册器,用于自动注册所有controller目录下的路由
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, app: FastAPI) -> None:
|
||||||
|
"""
|
||||||
|
初始化路由注册器
|
||||||
|
|
||||||
|
:param app: FastAPI对象
|
||||||
|
"""
|
||||||
|
self.app = app
|
||||||
|
# 获取项目根目录
|
||||||
|
self.project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||||
|
sys.path.insert(0, self.project_root)
|
||||||
|
|
||||||
|
def _find_controller_files(self) -> list[str]:
|
||||||
|
"""
|
||||||
|
查找所有controller目录下的py文件
|
||||||
|
|
||||||
|
:return: py文件路径列表
|
||||||
|
"""
|
||||||
|
controller_files = []
|
||||||
|
# 遍历所有目录,查找controller目录
|
||||||
|
for root, _dirs, files in os.walk(self.project_root):
|
||||||
|
# 检查当前目录是否为controller目录
|
||||||
|
if os.path.basename(root) == 'controller':
|
||||||
|
# 遍历controller目录下的所有py文件
|
||||||
|
for file in files:
|
||||||
|
if file.endswith('.py') and not file.startswith('__'):
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
controller_files.append(file_path)
|
||||||
|
return controller_files
|
||||||
|
|
||||||
|
def _import_module_and_get_routers(self, controller_files: list[str]) -> list[tuple[str, APIRouter]]:
|
||||||
|
"""
|
||||||
|
导入模块并获取路由实例
|
||||||
|
|
||||||
|
:param controller_files: controller目录下的py文件路径列表
|
||||||
|
:return: 路由实例列表
|
||||||
|
"""
|
||||||
|
routers = []
|
||||||
|
for file_path in controller_files:
|
||||||
|
# 计算模块路径
|
||||||
|
relative_path = os.path.relpath(file_path, self.project_root)
|
||||||
|
module_name = relative_path.replace(os.sep, '.')[:-3]
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 动态导入模块
|
||||||
|
module = importlib.import_module(module_name)
|
||||||
|
# 遍历模块属性,寻找APIRouter和APIRouterPro实例
|
||||||
|
for attr_name in dir(module):
|
||||||
|
attr = getattr(module, attr_name)
|
||||||
|
# 对于APIRouterPro实例,只有当auto_register=True时才添加
|
||||||
|
if isinstance(attr, APIRouterPro):
|
||||||
|
if attr.auto_register:
|
||||||
|
routers.append((attr_name, attr))
|
||||||
|
# 对于APIRouter实例,直接添加
|
||||||
|
elif isinstance(attr, APIRouter):
|
||||||
|
routers.append((attr_name, attr))
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Error importing module {module_name}: {e}')
|
||||||
|
return routers
|
||||||
|
|
||||||
|
def _sort_routers(self, routers: list[tuple[str, APIRouter]]) -> list[tuple[str, APIRouter]]:
|
||||||
|
"""
|
||||||
|
按规则排序路由
|
||||||
|
|
||||||
|
:param routers: 路由实例列表
|
||||||
|
:return: 排序后的路由实例列表
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 按规则排序路由
|
||||||
|
def sort_key(item: tuple[str, APIRouter]) -> Union[tuple[Literal[0], int, str], tuple[Literal[1], str]]:
|
||||||
|
attr_name, router = item
|
||||||
|
# APIRouterPro实例按order_num排序,序号越小越靠前
|
||||||
|
if isinstance(router, APIRouterPro):
|
||||||
|
return (0, router.order_num, attr_name)
|
||||||
|
# APIRouter实例按变量名首字母排序
|
||||||
|
return (1, attr_name)
|
||||||
|
|
||||||
|
return sorted(routers, key=sort_key)
|
||||||
|
|
||||||
|
def _register_routers_to_app(self, routers: list[tuple[str, APIRouter]]) -> None:
|
||||||
|
"""
|
||||||
|
将路由注册到FastAPI应用
|
||||||
|
|
||||||
|
:param routers: 排序后的路由实例列表
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
for _attr_name, router in routers:
|
||||||
|
self.app.include_router(router=router)
|
||||||
|
|
||||||
|
def register_routers(self) -> None:
|
||||||
|
"""
|
||||||
|
自动注册所有controller目录下的路由
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
# 查找所有controller目录下的py文件
|
||||||
|
controller_files = self._find_controller_files()
|
||||||
|
# 导入模块并获取路由实例
|
||||||
|
routers = self._import_module_and_get_routers(controller_files)
|
||||||
|
# 按规则排序路由
|
||||||
|
sorted_routers = self._sort_routers(routers)
|
||||||
|
# 注册路由到FastAPI应用
|
||||||
|
self._register_routers_to_app(sorted_routers)
|
||||||
|
|
||||||
|
|
||||||
|
def auto_register_routers(app: FastAPI) -> None:
|
||||||
|
"""
|
||||||
|
自动注册所有controller目录下的路由
|
||||||
|
|
||||||
|
:param app: FastAPI对象
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
# 使用路由注册器进行注册
|
||||||
|
router_register = RouterRegister(app)
|
||||||
|
router_register.register_routers()
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Any, Generic, Optional, TypeVar, Union
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field, create_model
|
||||||
|
from pydantic.alias_generators import to_camel
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from common.constant import HttpStatusConstant
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
|
||||||
|
class CrudResponseModel(BaseModel):
|
||||||
|
"""
|
||||||
|
操作响应模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
is_success: bool = Field(description='操作是否成功')
|
||||||
|
message: str = Field(description='响应信息')
|
||||||
|
result: Optional[Any] = Field(default=None, description='响应结果')
|
||||||
|
|
||||||
|
|
||||||
|
class ResponseBaseModel(BaseModel):
|
||||||
|
"""
|
||||||
|
响应模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
code: int = Field(default=HttpStatusConstant.SUCCESS, description='响应码')
|
||||||
|
msg: str = Field(default='操作成功', description='响应信息')
|
||||||
|
success: bool = Field(default=True, description='响应是否成功')
|
||||||
|
time: datetime = Field(default_factory=datetime.now, description='响应时间')
|
||||||
|
|
||||||
|
|
||||||
|
class DynamicResponseModel(ResponseBaseModel, Generic[T]):
|
||||||
|
"""
|
||||||
|
动态响应模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
|
def __class_getitem__(cls, item: Any) -> Union[Any, Self]:
|
||||||
|
"""
|
||||||
|
当使用 DynamicResponseModel[Item] 语法时,动态创建一个包含所有字段的新模型
|
||||||
|
"""
|
||||||
|
# 检查是否已经为该类型创建了模型
|
||||||
|
if not hasattr(cls, '_cached_models'):
|
||||||
|
cls._cached_models = {}
|
||||||
|
|
||||||
|
if item in cls._cached_models:
|
||||||
|
return cls._cached_models[item]
|
||||||
|
|
||||||
|
# 检查item是否为Pydantic模型
|
||||||
|
if not hasattr(item, 'model_fields'):
|
||||||
|
raise TypeError(f'{item} 不是一个Pydantic模型,请使用Pydantic模型作为泛型参数')
|
||||||
|
|
||||||
|
# 获取ResponseBaseModel的字段
|
||||||
|
base_fields = {}
|
||||||
|
for field_name, field in cls.model_fields.items():
|
||||||
|
base_fields[field_name] = (field.annotation, field)
|
||||||
|
|
||||||
|
# 获取泛型类型的字段
|
||||||
|
item_fields = {}
|
||||||
|
for field_name, field in item.model_fields.items():
|
||||||
|
item_fields[field_name] = (field.annotation, field)
|
||||||
|
|
||||||
|
# 合并所有字段
|
||||||
|
all_fields = {**base_fields, **item_fields}
|
||||||
|
|
||||||
|
# 动态创建新模型
|
||||||
|
new_model = create_model(
|
||||||
|
f'DynamicResponseModel[{item.__name__}]', __base__=cls, __config__=cls.model_config, **all_fields
|
||||||
|
)
|
||||||
|
|
||||||
|
# 缓存模型
|
||||||
|
cls._cached_models[item] = new_model
|
||||||
|
|
||||||
|
return new_model
|
||||||
|
|
||||||
|
|
||||||
|
class PageModel(BaseModel, Generic[T]):
|
||||||
|
"""
|
||||||
|
分页模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
|
rows: list[T] = Field(description='记录列表')
|
||||||
|
page_num: int = Field(description='当前页码')
|
||||||
|
page_size: int = Field(description='每页记录数')
|
||||||
|
total: int = Field(description='总记录数')
|
||||||
|
has_next: bool = Field(description='是否有下一页')
|
||||||
|
|
||||||
|
|
||||||
|
class PageResponseModel(PageModel, ResponseBaseModel, Generic[T]):
|
||||||
|
"""
|
||||||
|
分页响应模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class DataResponseModel(ResponseBaseModel, Generic[T]):
|
||||||
|
"""
|
||||||
|
数据响应模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
data: T = Field(description='响应数据')
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
from sqlalchemy.ext.asyncio import create_async_engine
|
|
||||||
from sqlalchemy.ext.asyncio import async_sessionmaker
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncAttrs
|
|
||||||
from sqlalchemy.orm import DeclarativeBase
|
|
||||||
from urllib.parse import quote_plus
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncAttrs, async_sessionmaker, create_async_engine
|
||||||
|
from sqlalchemy.orm import DeclarativeBase
|
||||||
|
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
|
|
||||||
ASYNC_SQLALCHEMY_DATABASE_URL = (
|
ASYNC_SQLALCHEMY_DATABASE_URL = (
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import argparse
|
|||||||
import configparser
|
import configparser
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
from typing import Literal
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from functools import lru_cache
|
|
||||||
from pydantic import computed_field
|
from pydantic import computed_field
|
||||||
from pydantic_settings import BaseSettings
|
from pydantic_settings import BaseSettings
|
||||||
from typing import Literal
|
|
||||||
|
|
||||||
|
|
||||||
class AppSettings(BaseSettings):
|
class AppSettings(BaseSettings):
|
||||||
@@ -86,7 +86,7 @@ class GenSettings:
|
|||||||
|
|
||||||
GEN_PATH = 'vf_admin/gen_path'
|
GEN_PATH = 'vf_admin/gen_path'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
if not os.path.exists(self.GEN_PATH):
|
if not os.path.exists(self.GEN_PATH):
|
||||||
os.makedirs(self.GEN_PATH)
|
os.makedirs(self.GEN_PATH)
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ class UploadSettings:
|
|||||||
]
|
]
|
||||||
DOWNLOAD_PATH = 'vf_admin/download_path'
|
DOWNLOAD_PATH = 'vf_admin/download_path'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
if not os.path.exists(self.UPLOAD_PATH):
|
if not os.path.exists(self.UPLOAD_PATH):
|
||||||
os.makedirs(self.UPLOAD_PATH)
|
os.makedirs(self.UPLOAD_PATH)
|
||||||
if not os.path.exists(self.DOWNLOAD_PATH):
|
if not os.path.exists(self.DOWNLOAD_PATH):
|
||||||
@@ -151,59 +151,53 @@ class GetConfig:
|
|||||||
获取配置
|
获取配置
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
self.parse_cli_args()
|
self.parse_cli_args()
|
||||||
|
|
||||||
@lru_cache()
|
def get_app_config(self) -> AppSettings:
|
||||||
def get_app_config(self):
|
|
||||||
"""
|
"""
|
||||||
获取应用配置
|
获取应用配置
|
||||||
"""
|
"""
|
||||||
# 实例化应用配置模型
|
# 实例化应用配置模型
|
||||||
return AppSettings()
|
return AppSettings()
|
||||||
|
|
||||||
@lru_cache()
|
def get_jwt_config(self) -> JwtSettings:
|
||||||
def get_jwt_config(self):
|
|
||||||
"""
|
"""
|
||||||
获取Jwt配置
|
获取Jwt配置
|
||||||
"""
|
"""
|
||||||
# 实例化Jwt配置模型
|
# 实例化Jwt配置模型
|
||||||
return JwtSettings()
|
return JwtSettings()
|
||||||
|
|
||||||
@lru_cache()
|
def get_database_config(self) -> DataBaseSettings:
|
||||||
def get_database_config(self):
|
|
||||||
"""
|
"""
|
||||||
获取数据库配置
|
获取数据库配置
|
||||||
"""
|
"""
|
||||||
# 实例化数据库配置模型
|
# 实例化数据库配置模型
|
||||||
return DataBaseSettings()
|
return DataBaseSettings()
|
||||||
|
|
||||||
@lru_cache()
|
def get_redis_config(self) -> RedisSettings:
|
||||||
def get_redis_config(self):
|
|
||||||
"""
|
"""
|
||||||
获取Redis配置
|
获取Redis配置
|
||||||
"""
|
"""
|
||||||
# 实例化Redis配置模型
|
# 实例化Redis配置模型
|
||||||
return RedisSettings()
|
return RedisSettings()
|
||||||
|
|
||||||
@lru_cache()
|
def get_gen_config(self) -> GenSettings:
|
||||||
def get_gen_config(self):
|
|
||||||
"""
|
"""
|
||||||
获取代码生成配置
|
获取代码生成配置
|
||||||
"""
|
"""
|
||||||
# 实例化代码生成配置
|
# 实例化代码生成配置
|
||||||
return GenSettings()
|
return GenSettings()
|
||||||
|
|
||||||
@lru_cache()
|
def get_upload_config(self) -> UploadSettings:
|
||||||
def get_upload_config(self):
|
|
||||||
"""
|
"""
|
||||||
获取数据库配置
|
获取上传配置
|
||||||
"""
|
"""
|
||||||
# 实例上传配置
|
# 实例上传配置
|
||||||
return UploadSettings()
|
return UploadSettings()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_cli_args():
|
def parse_cli_args() -> None:
|
||||||
"""
|
"""
|
||||||
解析命令行参数
|
解析命令行参数
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
from config.database import async_engine, AsyncSessionLocal, Base
|
from collections.abc import AsyncGenerator
|
||||||
|
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from config.database import AsyncSessionLocal, Base, async_engine
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
|
|
||||||
|
|
||||||
async def get_db():
|
async def get_db() -> AsyncGenerator[AsyncSession, None]:
|
||||||
"""
|
"""
|
||||||
每一个请求处理完毕后会关闭当前连接,不同的请求使用不同的连接
|
每一个请求处理完毕后会关闭当前连接,不同的请求使用不同的连接
|
||||||
|
|
||||||
@@ -12,7 +16,7 @@ async def get_db():
|
|||||||
yield current_db
|
yield current_db
|
||||||
|
|
||||||
|
|
||||||
async def init_create_table():
|
async def init_create_table() -> None:
|
||||||
"""
|
"""
|
||||||
应用启动时初始化数据库连接
|
应用启动时初始化数据库连接
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
from redis import asyncio as aioredis
|
from redis import asyncio as aioredis
|
||||||
from redis.exceptions import AuthenticationError, TimeoutError, RedisError
|
from redis.exceptions import AuthenticationError, RedisError
|
||||||
|
from redis.exceptions import TimeoutError as RedisTimeoutError
|
||||||
|
|
||||||
from config.database import AsyncSessionLocal
|
from config.database import AsyncSessionLocal
|
||||||
from config.env import RedisConfig
|
from config.env import RedisConfig
|
||||||
from module_admin.service.config_service import ConfigService
|
from module_admin.service.config_service import ConfigService
|
||||||
@@ -37,14 +40,14 @@ class RedisUtil:
|
|||||||
logger.error('❌️ redis连接失败')
|
logger.error('❌️ redis连接失败')
|
||||||
except AuthenticationError as e:
|
except AuthenticationError as e:
|
||||||
logger.error(f'❌️ redis用户名或密码错误,详细错误信息:{e}')
|
logger.error(f'❌️ redis用户名或密码错误,详细错误信息:{e}')
|
||||||
except TimeoutError as e:
|
except RedisTimeoutError as e:
|
||||||
logger.error(f'❌️ redis连接超时,详细错误信息:{e}')
|
logger.error(f'❌️ redis连接超时,详细错误信息:{e}')
|
||||||
except RedisError as e:
|
except RedisError as e:
|
||||||
logger.error(f'❌️ redis连接错误,详细错误信息:{e}')
|
logger.error(f'❌️ redis连接错误,详细错误信息:{e}')
|
||||||
return redis
|
return redis
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def close_redis_pool(cls, app):
|
async def close_redis_pool(cls, app: FastAPI) -> None:
|
||||||
"""
|
"""
|
||||||
应用关闭时关闭redis连接
|
应用关闭时关闭redis连接
|
||||||
|
|
||||||
@@ -55,7 +58,7 @@ class RedisUtil:
|
|||||||
logger.info('✅️ 关闭redis连接成功')
|
logger.info('✅️ 关闭redis连接成功')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def init_sys_dict(cls, redis):
|
async def init_sys_dict(cls, redis: FastAPI) -> None:
|
||||||
"""
|
"""
|
||||||
应用启动时缓存字典表
|
应用启动时缓存字典表
|
||||||
|
|
||||||
@@ -66,7 +69,7 @@ class RedisUtil:
|
|||||||
await DictDataService.init_cache_sys_dict_services(session, redis)
|
await DictDataService.init_cache_sys_dict_services(session, redis)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def init_sys_config(cls, redis):
|
async def init_sys_config(cls, redis: aioredis.Redis) -> None:
|
||||||
"""
|
"""
|
||||||
应用启动时缓存参数配置表
|
应用启动时缓存参数配置表
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
import json
|
import json
|
||||||
from apscheduler.events import EVENT_ALL
|
from asyncio import iscoroutinefunction
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
|
from apscheduler.events import EVENT_ALL, SchedulerEvent
|
||||||
from apscheduler.executors.asyncio import AsyncIOExecutor
|
from apscheduler.executors.asyncio import AsyncIOExecutor
|
||||||
from apscheduler.executors.pool import ProcessPoolExecutor
|
from apscheduler.executors.pool import ProcessPoolExecutor
|
||||||
|
from apscheduler.job import Job
|
||||||
from apscheduler.jobstores.memory import MemoryJobStore
|
from apscheduler.jobstores.memory import MemoryJobStore
|
||||||
from apscheduler.jobstores.redis import RedisJobStore
|
from apscheduler.jobstores.redis import RedisJobStore
|
||||||
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
|
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
|
||||||
@@ -9,27 +14,29 @@ from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|||||||
from apscheduler.triggers.combining import OrTrigger
|
from apscheduler.triggers.combining import OrTrigger
|
||||||
from apscheduler.triggers.cron import CronTrigger
|
from apscheduler.triggers.cron import CronTrigger
|
||||||
from apscheduler.triggers.date import DateTrigger
|
from apscheduler.triggers.date import DateTrigger
|
||||||
from asyncio import iscoroutinefunction
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
from sqlalchemy.engine import create_engine
|
from sqlalchemy.engine import create_engine
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
from typing import Union
|
|
||||||
|
import module_task # noqa: F401
|
||||||
from config.database import AsyncSessionLocal, quote_plus
|
from config.database import AsyncSessionLocal, quote_plus
|
||||||
from config.env import DataBaseConfig, RedisConfig
|
from config.env import DataBaseConfig, RedisConfig
|
||||||
from module_admin.dao.job_dao import JobDao
|
from module_admin.dao.job_dao import JobDao
|
||||||
from module_admin.entity.vo.job_vo import JobLogModel, JobModel
|
from module_admin.entity.vo.job_vo import JobLogModel, JobModel
|
||||||
from module_admin.service.job_log_service import JobLogService
|
from module_admin.service.job_log_service import JobLogService
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
import module_task # noqa: F401
|
|
||||||
|
|
||||||
|
|
||||||
# 重写Cron定时
|
# 重写Cron定时
|
||||||
class MyCronTrigger(CronTrigger):
|
class MyCronTrigger(CronTrigger):
|
||||||
|
CRON_EXPRESSION_LENGTH_MIN = 6
|
||||||
|
CRON_EXPRESSION_LENGTH_MAX = 7
|
||||||
|
WEEKDAY_COUNT = 5
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_crontab(cls, expr: str, timezone=None):
|
def from_crontab(cls, expr: str, timezone: Optional[str] = None) -> 'MyCronTrigger':
|
||||||
values = expr.split()
|
values = expr.split()
|
||||||
if len(values) != 6 and len(values) != 7:
|
if len(values) != cls.CRON_EXPRESSION_LENGTH_MIN and len(values) != cls.CRON_EXPRESSION_LENGTH_MAX:
|
||||||
raise ValueError('Wrong number of fields; got {}, expected 6 or 7'.format(len(values)))
|
raise ValueError(f'Wrong number of fields; got {len(values)}, expected 6 or 7')
|
||||||
|
|
||||||
second = values[0]
|
second = values[0]
|
||||||
minute = values[1]
|
minute = values[1]
|
||||||
@@ -37,7 +44,7 @@ class MyCronTrigger(CronTrigger):
|
|||||||
if '?' in values[3]:
|
if '?' in values[3]:
|
||||||
day = None
|
day = None
|
||||||
elif 'L' in values[5]:
|
elif 'L' in values[5]:
|
||||||
day = f"last {values[5].replace('L', '')}"
|
day = f'last {values[5].replace("L", "")}'
|
||||||
elif 'W' in values[3]:
|
elif 'W' in values[3]:
|
||||||
day = cls.__find_recent_workday(int(values[3].split('W')[0]))
|
day = cls.__find_recent_workday(int(values[3].split('W')[0]))
|
||||||
else:
|
else:
|
||||||
@@ -49,11 +56,8 @@ class MyCronTrigger(CronTrigger):
|
|||||||
week = int(values[5].split('#')[1])
|
week = int(values[5].split('#')[1])
|
||||||
else:
|
else:
|
||||||
week = values[5]
|
week = values[5]
|
||||||
if '#' in values[5]:
|
day_of_week = int(values[5].split('#')[0]) - 1 if '#' in values[5] else None
|
||||||
day_of_week = int(values[5].split('#')[0]) - 1
|
year = values[6] if len(values) == cls.CRON_EXPRESSION_LENGTH_MAX else None
|
||||||
else:
|
|
||||||
day_of_week = None
|
|
||||||
year = values[6] if len(values) == 7 else None
|
|
||||||
return cls(
|
return cls(
|
||||||
second=second,
|
second=second,
|
||||||
minute=minute,
|
minute=minute,
|
||||||
@@ -67,19 +71,17 @@ class MyCronTrigger(CronTrigger):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __find_recent_workday(cls, day: int):
|
def __find_recent_workday(cls, day: int) -> int:
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
date = datetime(now.year, now.month, day)
|
date = datetime(now.year, now.month, day)
|
||||||
if date.weekday() < 5:
|
if date.weekday() < cls.WEEKDAY_COUNT:
|
||||||
return date.day
|
return date.day
|
||||||
else:
|
diff = 1
|
||||||
diff = 1
|
while True:
|
||||||
while True:
|
previous_day = date - timedelta(days=diff)
|
||||||
previous_day = date - timedelta(days=diff)
|
if previous_day.weekday() < cls.WEEKDAY_COUNT:
|
||||||
if previous_day.weekday() < 5:
|
return previous_day.day
|
||||||
return previous_day.day
|
diff += 1
|
||||||
else:
|
|
||||||
diff += 1
|
|
||||||
|
|
||||||
|
|
||||||
SQLALCHEMY_DATABASE_URL = (
|
SQLALCHEMY_DATABASE_URL = (
|
||||||
@@ -100,18 +102,17 @@ engine = create_engine(
|
|||||||
pool_timeout=DataBaseConfig.db_pool_timeout,
|
pool_timeout=DataBaseConfig.db_pool_timeout,
|
||||||
)
|
)
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
redis_config = {
|
||||||
|
'host': RedisConfig.redis_host,
|
||||||
|
'port': RedisConfig.redis_port,
|
||||||
|
'username': RedisConfig.redis_username,
|
||||||
|
'password': RedisConfig.redis_password,
|
||||||
|
'db': RedisConfig.redis_database,
|
||||||
|
}
|
||||||
job_stores = {
|
job_stores = {
|
||||||
'default': MemoryJobStore(),
|
'default': MemoryJobStore(),
|
||||||
'sqlalchemy': SQLAlchemyJobStore(url=SQLALCHEMY_DATABASE_URL, engine=engine),
|
'sqlalchemy': SQLAlchemyJobStore(url=SQLALCHEMY_DATABASE_URL, engine=engine),
|
||||||
'redis': RedisJobStore(
|
'redis': RedisJobStore(**redis_config),
|
||||||
**dict(
|
|
||||||
host=RedisConfig.redis_host,
|
|
||||||
port=RedisConfig.redis_port,
|
|
||||||
username=RedisConfig.redis_username,
|
|
||||||
password=RedisConfig.redis_password,
|
|
||||||
db=RedisConfig.redis_database,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
executors = {'default': AsyncIOExecutor(), 'processpool': ProcessPoolExecutor(5)}
|
executors = {'default': AsyncIOExecutor(), 'processpool': ProcessPoolExecutor(5)}
|
||||||
job_defaults = {'coalesce': False, 'max_instance': 1}
|
job_defaults = {'coalesce': False, 'max_instance': 1}
|
||||||
@@ -125,7 +126,7 @@ class SchedulerUtil:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def init_system_scheduler(cls):
|
async def init_system_scheduler(cls) -> None:
|
||||||
"""
|
"""
|
||||||
应用启动时初始化定时任务
|
应用启动时初始化定时任务
|
||||||
|
|
||||||
@@ -142,7 +143,7 @@ class SchedulerUtil:
|
|||||||
logger.info('✅️ 系统初始定时任务加载成功')
|
logger.info('✅️ 系统初始定时任务加载成功')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def close_system_scheduler(cls):
|
async def close_system_scheduler(cls) -> None:
|
||||||
"""
|
"""
|
||||||
应用关闭时关闭定时任务
|
应用关闭时关闭定时任务
|
||||||
|
|
||||||
@@ -152,7 +153,7 @@ class SchedulerUtil:
|
|||||||
logger.info('✅️ 关闭定时任务成功')
|
logger.info('✅️ 关闭定时任务成功')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_scheduler_job(cls, job_id: Union[str, int]):
|
def get_scheduler_job(cls, job_id: Union[str, int]) -> Job:
|
||||||
"""
|
"""
|
||||||
根据任务id获取任务对象
|
根据任务id获取任务对象
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ class SchedulerUtil:
|
|||||||
return query_job
|
return query_job
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_scheduler_job(cls, job_info: JobModel):
|
def add_scheduler_job(cls, job_info: JobModel) -> None:
|
||||||
"""
|
"""
|
||||||
根据输入的任务对象信息添加任务
|
根据输入的任务对象信息添加任务
|
||||||
|
|
||||||
@@ -183,14 +184,14 @@ class SchedulerUtil:
|
|||||||
id=str(job_info.job_id),
|
id=str(job_info.job_id),
|
||||||
name=job_info.job_name,
|
name=job_info.job_name,
|
||||||
misfire_grace_time=1000000000000 if job_info.misfire_policy == '3' else None,
|
misfire_grace_time=1000000000000 if job_info.misfire_policy == '3' else None,
|
||||||
coalesce=True if job_info.misfire_policy == '2' else False,
|
coalesce=job_info.misfire_policy == '2',
|
||||||
max_instances=3 if job_info.concurrent == '0' else 1,
|
max_instances=3 if job_info.concurrent == '0' else 1,
|
||||||
jobstore=job_info.job_group,
|
jobstore=job_info.job_group,
|
||||||
executor=job_executor,
|
executor=job_executor,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execute_scheduler_job_once(cls, job_info: JobModel):
|
def execute_scheduler_job_once(cls, job_info: JobModel) -> None:
|
||||||
"""
|
"""
|
||||||
根据输入的任务对象执行一次任务
|
根据输入的任务对象执行一次任务
|
||||||
|
|
||||||
@@ -212,14 +213,14 @@ class SchedulerUtil:
|
|||||||
id=str(job_info.job_id),
|
id=str(job_info.job_id),
|
||||||
name=job_info.job_name,
|
name=job_info.job_name,
|
||||||
misfire_grace_time=1000000000000 if job_info.misfire_policy == '3' else None,
|
misfire_grace_time=1000000000000 if job_info.misfire_policy == '3' else None,
|
||||||
coalesce=True if job_info.misfire_policy == '2' else False,
|
coalesce=job_info.misfire_policy == '2',
|
||||||
max_instances=3 if job_info.concurrent == '0' else 1,
|
max_instances=3 if job_info.concurrent == '0' else 1,
|
||||||
jobstore=job_info.job_group,
|
jobstore=job_info.job_group,
|
||||||
executor=job_executor,
|
executor=job_executor,
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def remove_scheduler_job(cls, job_id: Union[str, int]):
|
def remove_scheduler_job(cls, job_id: Union[str, int]) -> None:
|
||||||
"""
|
"""
|
||||||
根据任务id移除任务
|
根据任务id移除任务
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ class SchedulerUtil:
|
|||||||
scheduler.remove_job(job_id=str(job_id))
|
scheduler.remove_job(job_id=str(job_id))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def scheduler_event_listener(cls, event):
|
def scheduler_event_listener(cls, event: SchedulerEvent) -> None:
|
||||||
# 获取事件类型和任务ID
|
# 获取事件类型和任务ID
|
||||||
event_type = event.__class__.__name__
|
event_type = event.__class__.__name__
|
||||||
# 获取任务执行异常信息
|
# 获取任务执行异常信息
|
||||||
@@ -260,7 +261,7 @@ class SchedulerUtil:
|
|||||||
# 获取任务触发器
|
# 获取任务触发器
|
||||||
job_trigger = str(query_job_info.get('trigger'))
|
job_trigger = str(query_job_info.get('trigger'))
|
||||||
# 构造日志消息
|
# 构造日志消息
|
||||||
job_message = f"事件类型: {event_type}, 任务ID: {job_id}, 任务名称: {job_name}, 执行于{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
job_message = f'事件类型: {event_type}, 任务ID: {job_id}, 任务名称: {job_name}, 执行于{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}'
|
||||||
job_log = JobLogModel(
|
job_log = JobLogModel(
|
||||||
jobName=job_name,
|
jobName=job_name,
|
||||||
jobGroup=job_group,
|
jobGroup=job_group,
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
class LoginException(Exception):
|
class LoginException(Exception):
|
||||||
"""
|
"""
|
||||||
自定义登录异常LoginException
|
自定义登录异常LoginException
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data: str = None, message: str = None):
|
def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None:
|
||||||
self.data = data
|
self.data = data
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
@@ -13,7 +16,7 @@ class AuthException(Exception):
|
|||||||
自定义令牌异常AuthException
|
自定义令牌异常AuthException
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data: str = None, message: str = None):
|
def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None:
|
||||||
self.data = data
|
self.data = data
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
@@ -23,7 +26,7 @@ class PermissionException(Exception):
|
|||||||
自定义权限异常PermissionException
|
自定义权限异常PermissionException
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data: str = None, message: str = None):
|
def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None:
|
||||||
self.data = data
|
self.data = data
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
@@ -33,7 +36,7 @@ class ServiceException(Exception):
|
|||||||
自定义服务异常ServiceException
|
自定义服务异常ServiceException
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data: str = None, message: str = None):
|
def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None:
|
||||||
self.data = data
|
self.data = data
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
@@ -43,7 +46,7 @@ class ServiceWarning(Exception):
|
|||||||
自定义服务警告ServiceWarning
|
自定义服务警告ServiceWarning
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data: str = None, message: str = None):
|
def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None:
|
||||||
self.data = data
|
self.data = data
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
@@ -53,6 +56,6 @@ class ModelValidatorException(Exception):
|
|||||||
自定义模型校验异常ModelValidatorException
|
自定义模型校验异常ModelValidatorException
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, data: str = None, message: str = None):
|
def __init__(self, data: Optional[str] = None, message: Optional[str] = None) -> None:
|
||||||
self.data = data
|
self.data = data
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI, Request, Response
|
||||||
from fastapi.exceptions import HTTPException
|
from fastapi.exceptions import HTTPException
|
||||||
from pydantic_validation_decorator import FieldValidationError
|
from pydantic_validation_decorator import FieldValidationError
|
||||||
|
|
||||||
from exceptions.exception import (
|
from exceptions.exception import (
|
||||||
AuthException,
|
AuthException,
|
||||||
LoginException,
|
LoginException,
|
||||||
@@ -10,62 +11,62 @@ from exceptions.exception import (
|
|||||||
ServiceWarning,
|
ServiceWarning,
|
||||||
)
|
)
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.response_util import jsonable_encoder, JSONResponse, ResponseUtil
|
from utils.response_util import JSONResponse, ResponseUtil, jsonable_encoder
|
||||||
|
|
||||||
|
|
||||||
def handle_exception(app: FastAPI):
|
def handle_exception(app: FastAPI) -> None:
|
||||||
"""
|
"""
|
||||||
全局异常处理
|
全局异常处理
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 自定义token检验异常
|
# 自定义token检验异常
|
||||||
@app.exception_handler(AuthException)
|
@app.exception_handler(AuthException)
|
||||||
async def auth_exception_handler(request: Request, exc: AuthException):
|
async def auth_exception_handler(request: Request, exc: AuthException) -> Response:
|
||||||
return ResponseUtil.unauthorized(data=exc.data, msg=exc.message)
|
return ResponseUtil.unauthorized(data=exc.data, msg=exc.message)
|
||||||
|
|
||||||
# 自定义登录检验异常
|
# 自定义登录检验异常
|
||||||
@app.exception_handler(LoginException)
|
@app.exception_handler(LoginException)
|
||||||
async def login_exception_handler(request: Request, exc: LoginException):
|
async def login_exception_handler(request: Request, exc: LoginException) -> Response:
|
||||||
return ResponseUtil.failure(data=exc.data, msg=exc.message)
|
return ResponseUtil.failure(data=exc.data, msg=exc.message)
|
||||||
|
|
||||||
# 自定义模型检验异常
|
# 自定义模型检验异常
|
||||||
@app.exception_handler(ModelValidatorException)
|
@app.exception_handler(ModelValidatorException)
|
||||||
async def model_validator_exception_handler(request: Request, exc: ModelValidatorException):
|
async def model_validator_exception_handler(request: Request, exc: ModelValidatorException) -> Response:
|
||||||
logger.warning(exc.message)
|
logger.warning(exc.message)
|
||||||
return ResponseUtil.failure(data=exc.data, msg=exc.message)
|
return ResponseUtil.failure(data=exc.data, msg=exc.message)
|
||||||
|
|
||||||
# 自定义字段检验异常
|
# 自定义字段检验异常
|
||||||
@app.exception_handler(FieldValidationError)
|
@app.exception_handler(FieldValidationError)
|
||||||
async def field_validation_error_handler(request: Request, exc: FieldValidationError):
|
async def field_validation_error_handler(request: Request, exc: FieldValidationError) -> Response:
|
||||||
logger.warning(exc.message)
|
logger.warning(exc.message)
|
||||||
return ResponseUtil.failure(msg=exc.message)
|
return ResponseUtil.failure(msg=exc.message)
|
||||||
|
|
||||||
# 自定义权限检验异常
|
# 自定义权限检验异常
|
||||||
@app.exception_handler(PermissionException)
|
@app.exception_handler(PermissionException)
|
||||||
async def permission_exception_handler(request: Request, exc: PermissionException):
|
async def permission_exception_handler(request: Request, exc: PermissionException) -> Response:
|
||||||
return ResponseUtil.forbidden(data=exc.data, msg=exc.message)
|
return ResponseUtil.forbidden(data=exc.data, msg=exc.message)
|
||||||
|
|
||||||
# 自定义服务异常
|
# 自定义服务异常
|
||||||
@app.exception_handler(ServiceException)
|
@app.exception_handler(ServiceException)
|
||||||
async def service_exception_handler(request: Request, exc: ServiceException):
|
async def service_exception_handler(request: Request, exc: ServiceException) -> Response:
|
||||||
logger.error(exc.message)
|
logger.error(exc.message)
|
||||||
return ResponseUtil.error(data=exc.data, msg=exc.message)
|
return ResponseUtil.error(data=exc.data, msg=exc.message)
|
||||||
|
|
||||||
# 自定义服务警告
|
# 自定义服务警告
|
||||||
@app.exception_handler(ServiceWarning)
|
@app.exception_handler(ServiceWarning)
|
||||||
async def service_warning_handler(request: Request, exc: ServiceWarning):
|
async def service_warning_handler(request: Request, exc: ServiceWarning) -> Response:
|
||||||
logger.warning(exc.message)
|
logger.warning(exc.message)
|
||||||
return ResponseUtil.failure(data=exc.data, msg=exc.message)
|
return ResponseUtil.failure(data=exc.data, msg=exc.message)
|
||||||
|
|
||||||
# 处理其他http请求异常
|
# 处理其他http请求异常
|
||||||
@app.exception_handler(HTTPException)
|
@app.exception_handler(HTTPException)
|
||||||
async def http_exception_handler(request: Request, exc: HTTPException):
|
async def http_exception_handler(request: Request, exc: HTTPException) -> Response:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
content=jsonable_encoder({'code': exc.status_code, 'msg': exc.detail}), status_code=exc.status_code
|
content=jsonable_encoder({'code': exc.status_code, 'msg': exc.detail}), status_code=exc.status_code
|
||||||
)
|
)
|
||||||
|
|
||||||
# 处理其他异常
|
# 处理其他异常
|
||||||
@app.exception_handler(Exception)
|
@app.exception_handler(Exception)
|
||||||
async def exception_handler(request: Request, exc: Exception):
|
async def exception_handler(request: Request, exc: Exception) -> Response:
|
||||||
logger.exception(exc)
|
logger.exception(exc)
|
||||||
return ResponseUtil.error(msg=str(exc))
|
return ResponseUtil.error(msg=str(exc))
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
from fastapi import FastAPI, Request
|
||||||
|
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
|
||||||
|
from starlette.responses import Response
|
||||||
|
|
||||||
|
from common.context import RequestContext
|
||||||
|
|
||||||
|
|
||||||
|
class ContextCleanupMiddleware(BaseHTTPMiddleware):
|
||||||
|
"""
|
||||||
|
上下文清理中间件
|
||||||
|
"""
|
||||||
|
|
||||||
|
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
|
||||||
|
"""
|
||||||
|
在每个请求处理完成后清理上下文信息
|
||||||
|
"""
|
||||||
|
response = await call_next(request)
|
||||||
|
# 请求处理完成后清理所有上下文变量
|
||||||
|
RequestContext.clear_all()
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
def add_context_cleanup_middleware(app: FastAPI) -> None:
|
||||||
|
"""
|
||||||
|
添加上下文清理中间件
|
||||||
|
|
||||||
|
:param app: FastAPI对象
|
||||||
|
"""
|
||||||
|
app.add_middleware(ContextCleanupMiddleware)
|
||||||
@@ -2,7 +2,7 @@ from fastapi import FastAPI
|
|||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
|
|
||||||
def add_cors_middleware(app: FastAPI):
|
def add_cors_middleware(app: FastAPI) -> None:
|
||||||
"""
|
"""
|
||||||
添加跨域中间件
|
添加跨域中间件
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from fastapi import FastAPI
|
|||||||
from starlette.middleware.gzip import GZipMiddleware
|
from starlette.middleware.gzip import GZipMiddleware
|
||||||
|
|
||||||
|
|
||||||
def add_gzip_middleware(app: FastAPI):
|
def add_gzip_middleware(app: FastAPI) -> None:
|
||||||
"""
|
"""
|
||||||
添加gzip压缩中间件
|
添加gzip压缩中间件
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
from middlewares.context_middleware import add_context_cleanup_middleware
|
||||||
from middlewares.cors_middleware import add_cors_middleware
|
from middlewares.cors_middleware import add_cors_middleware
|
||||||
from middlewares.gzip_middleware import add_gzip_middleware
|
from middlewares.gzip_middleware import add_gzip_middleware
|
||||||
from middlewares.trace_middleware import add_trace_middleware
|
from middlewares.trace_middleware import add_trace_middleware
|
||||||
|
|
||||||
|
|
||||||
def handle_middleware(app: FastAPI):
|
def handle_middleware(app: FastAPI) -> None:
|
||||||
"""
|
"""
|
||||||
全局中间件处理
|
全局中间件处理
|
||||||
"""
|
"""
|
||||||
|
# 加载上下文清理中间件
|
||||||
|
add_context_cleanup_middleware(app)
|
||||||
# 加载跨域中间件
|
# 加载跨域中间件
|
||||||
add_cors_middleware(app)
|
add_cors_middleware(app)
|
||||||
# 加载gzip压缩中间件
|
# 加载gzip压缩中间件
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
from .ctx import TraceCtx
|
from .ctx import TraceCtx
|
||||||
from .middle import TraceASGIMiddleware
|
from .middle import TraceASGIMiddleware
|
||||||
|
|
||||||
@@ -7,7 +8,7 @@ __all__ = ('TraceASGIMiddleware', 'TraceCtx')
|
|||||||
__version__ = '0.1.0'
|
__version__ = '0.1.0'
|
||||||
|
|
||||||
|
|
||||||
def add_trace_middleware(app: FastAPI):
|
def add_trace_middleware(app: FastAPI) -> None:
|
||||||
"""
|
"""
|
||||||
添加trace中间件
|
添加trace中间件
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@author: peng
|
|
||||||
@file: ctx.py
|
|
||||||
@time: 2025/1/17 16:57
|
|
||||||
"""
|
|
||||||
|
|
||||||
import contextvars
|
import contextvars
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
@@ -13,11 +6,11 @@ CTX_REQUEST_ID: contextvars.ContextVar[str] = contextvars.ContextVar('request-id
|
|||||||
|
|
||||||
class TraceCtx:
|
class TraceCtx:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_id():
|
def set_id() -> str:
|
||||||
_id = uuid4().hex
|
_id = uuid4().hex
|
||||||
CTX_REQUEST_ID.set(_id)
|
CTX_REQUEST_ID.set(_id)
|
||||||
return _id
|
return _id
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_id():
|
def get_id() -> str:
|
||||||
return CTX_REQUEST_ID.get()
|
return CTX_REQUEST_ID.get()
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
@author: peng
|
|
||||||
@file: middle.py
|
|
||||||
@time: 2025/1/17 16:57
|
|
||||||
"""
|
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from starlette.types import ASGIApp, Message, Receive, Scope, Send
|
from starlette.types import ASGIApp, Message, Receive, Scope, Send
|
||||||
from .span import get_current_span, Span
|
|
||||||
|
from .span import Span, get_current_span
|
||||||
|
|
||||||
|
|
||||||
class TraceASGIMiddleware:
|
class TraceASGIMiddleware:
|
||||||
@@ -21,11 +16,11 @@ class TraceASGIMiddleware:
|
|||||||
self.app = app
|
self.app = app
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def my_receive(receive: Receive, span: Span):
|
async def my_receive(receive: Receive, span: Span) -> Receive:
|
||||||
await span.request_before()
|
await span.request_before()
|
||||||
|
|
||||||
@wraps(receive)
|
@wraps(receive)
|
||||||
async def my_receive():
|
async def my_receive() -> Message:
|
||||||
message = await receive()
|
message = await receive()
|
||||||
await span.request_after(message)
|
await span.request_after(message)
|
||||||
return message
|
return message
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
from collections.abc import AsyncGenerator
|
||||||
"""
|
|
||||||
@author: peng
|
|
||||||
@file: span.py
|
|
||||||
@time: 2025/1/17 16:57
|
|
||||||
"""
|
|
||||||
|
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from starlette.types import Scope, Message
|
|
||||||
|
from starlette.types import Message, Scope
|
||||||
|
|
||||||
from .ctx import TraceCtx
|
from .ctx import TraceCtx
|
||||||
|
|
||||||
|
|
||||||
@@ -16,16 +12,16 @@ class Span:
|
|||||||
request(before) --> request(after) --> response(before) --> response(after)
|
request(before) --> request(after) --> response(before) --> response(after)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, scope: Scope):
|
def __init__(self, scope: Scope) -> None:
|
||||||
self.scope = scope
|
self.scope = scope
|
||||||
|
|
||||||
async def request_before(self):
|
async def request_before(self) -> None:
|
||||||
"""
|
"""
|
||||||
request_before: 处理header信息等, 如记录请求体信息
|
request_before: 处理header信息等, 如记录请求体信息
|
||||||
"""
|
"""
|
||||||
TraceCtx.set_id()
|
TraceCtx.set_id()
|
||||||
|
|
||||||
async def request_after(self, message: Message):
|
async def request_after(self, message: Message) -> Message:
|
||||||
"""
|
"""
|
||||||
request_after: 处理请求bytes, 如记录请求参数
|
request_after: 处理请求bytes, 如记录请求参数
|
||||||
|
|
||||||
@@ -34,7 +30,7 @@ class Span:
|
|||||||
"""
|
"""
|
||||||
return message
|
return message
|
||||||
|
|
||||||
async def response(self, message: Message):
|
async def response(self, message: Message) -> Message:
|
||||||
"""
|
"""
|
||||||
if message['type'] == "http.response.start": -----> request-before
|
if message['type'] == "http.response.start": -----> request-before
|
||||||
pass
|
pass
|
||||||
@@ -48,5 +44,5 @@ class Span:
|
|||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def get_current_span(scope: Scope):
|
async def get_current_span(scope: Scope) -> AsyncGenerator[Span, None]:
|
||||||
yield Span(scope)
|
yield Span(scope)
|
||||||
|
|||||||
@@ -1,263 +0,0 @@
|
|||||||
import httpx
|
|
||||||
import inspect
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
from async_lru import alru_cache
|
|
||||||
from datetime import datetime
|
|
||||||
from fastapi import Request
|
|
||||||
from fastapi.responses import JSONResponse, ORJSONResponse, UJSONResponse
|
|
||||||
from functools import wraps
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
from typing import Any, Callable, Literal, Optional
|
|
||||||
from user_agents import parse
|
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.env import AppConfig
|
|
||||||
from exceptions.exception import LoginException, ServiceException, ServiceWarning
|
|
||||||
from module_admin.entity.vo.log_vo import LogininforModel, OperLogModel
|
|
||||||
from module_admin.service.log_service import LoginLogService, OperationLogService
|
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from utils.log_util import logger
|
|
||||||
from utils.response_util import ResponseUtil
|
|
||||||
|
|
||||||
|
|
||||||
class Log:
|
|
||||||
"""
|
|
||||||
日志装饰器
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
title: str,
|
|
||||||
business_type: BusinessType,
|
|
||||||
log_type: Optional[Literal['login', 'operation']] = 'operation',
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
日志装饰器
|
|
||||||
|
|
||||||
:param title: 当前日志装饰器装饰的模块标题
|
|
||||||
:param business_type: 业务类型(OTHER其它 INSERT新增 UPDATE修改 DELETE删除 GRANT授权 EXPORT导出 IMPORT导入 FORCE强退 GENCODE生成代码 CLEAN清空数据)
|
|
||||||
:param log_type: 日志类型(login表示登录日志,operation表示为操作日志)
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.title = title
|
|
||||||
self.business_type = business_type.value
|
|
||||||
self.log_type = log_type
|
|
||||||
|
|
||||||
def __call__(self, func):
|
|
||||||
@wraps(func)
|
|
||||||
async def wrapper(*args, **kwargs):
|
|
||||||
start_time = time.perf_counter()
|
|
||||||
# 获取被装饰函数的文件路径
|
|
||||||
file_path = inspect.getfile(func)
|
|
||||||
# 获取项目根路径
|
|
||||||
project_root = os.getcwd()
|
|
||||||
# 处理文件路径,去除项目根路径部分
|
|
||||||
relative_path = os.path.relpath(file_path, start=project_root)[0:-2].replace('\\', '.').replace('/', '.')
|
|
||||||
# 获取当前被装饰函数所在路径
|
|
||||||
func_path = f'{relative_path}{func.__name__}()'
|
|
||||||
# 获取上下文信息
|
|
||||||
request_name_list = get_function_parameters_name_by_type(func, Request)
|
|
||||||
request = get_function_parameters_value_by_name(func, request_name_list[0], *args, **kwargs)
|
|
||||||
token = request.headers.get('Authorization')
|
|
||||||
session_name_list = get_function_parameters_name_by_type(func, AsyncSession)
|
|
||||||
query_db = get_function_parameters_value_by_name(func, session_name_list[0], *args, **kwargs)
|
|
||||||
request_method = request.method
|
|
||||||
operator_type = 0
|
|
||||||
user_agent = request.headers.get('User-Agent')
|
|
||||||
if 'Windows' in user_agent or 'Macintosh' in user_agent or 'Linux' in user_agent:
|
|
||||||
operator_type = 1
|
|
||||||
if 'Mobile' in user_agent or 'Android' in user_agent or 'iPhone' in user_agent:
|
|
||||||
operator_type = 2
|
|
||||||
# 获取请求的url
|
|
||||||
oper_url = request.url.path
|
|
||||||
# 获取请求的ip及ip归属区域
|
|
||||||
oper_ip = request.headers.get('X-Forwarded-For')
|
|
||||||
oper_location = '内网IP'
|
|
||||||
if AppConfig.app_ip_location_query:
|
|
||||||
oper_location = await get_ip_location(oper_ip)
|
|
||||||
# 根据不同的请求类型使用不同的方法获取请求参数
|
|
||||||
content_type = request.headers.get('Content-Type')
|
|
||||||
if content_type and (
|
|
||||||
'multipart/form-data' in content_type or 'application/x-www-form-urlencoded' in content_type
|
|
||||||
):
|
|
||||||
payload = await request.form()
|
|
||||||
oper_param = '\n'.join([f'{key}: {value}' for key, value in payload.items()])
|
|
||||||
else:
|
|
||||||
payload = await request.body()
|
|
||||||
# 通过 request.path_params 直接访问路径参数
|
|
||||||
path_params = request.path_params
|
|
||||||
oper_param = {}
|
|
||||||
if payload:
|
|
||||||
oper_param.update(json.loads(str(payload, 'utf-8')))
|
|
||||||
if path_params:
|
|
||||||
oper_param.update(path_params)
|
|
||||||
oper_param = json.dumps(oper_param, ensure_ascii=False)
|
|
||||||
# 日志表请求参数字段长度最大为2000,因此在此处判断长度
|
|
||||||
if len(oper_param) > 2000:
|
|
||||||
oper_param = '请求参数过长'
|
|
||||||
|
|
||||||
# 获取操作时间
|
|
||||||
oper_time = datetime.now()
|
|
||||||
# 此处在登录之前向原始函数传递一些登录信息,用于监测在线用户的相关信息
|
|
||||||
login_log = {}
|
|
||||||
if self.log_type == 'login':
|
|
||||||
user_agent_info = parse(user_agent)
|
|
||||||
browser = f'{user_agent_info.browser.family}'
|
|
||||||
system_os = f'{user_agent_info.os.family}'
|
|
||||||
if user_agent_info.browser.version != ():
|
|
||||||
browser += f' {user_agent_info.browser.version[0]}'
|
|
||||||
if user_agent_info.os.version != ():
|
|
||||||
system_os += f' {user_agent_info.os.version[0]}'
|
|
||||||
login_log = dict(
|
|
||||||
ipaddr=oper_ip,
|
|
||||||
loginLocation=oper_location,
|
|
||||||
browser=browser,
|
|
||||||
os=system_os,
|
|
||||||
loginTime=oper_time.strftime('%Y-%m-%d %H:%M:%S'),
|
|
||||||
)
|
|
||||||
kwargs['form_data'].login_info = login_log
|
|
||||||
try:
|
|
||||||
# 调用原始函数
|
|
||||||
result = await func(*args, **kwargs)
|
|
||||||
except (LoginException, ServiceWarning) as e:
|
|
||||||
logger.warning(e.message)
|
|
||||||
result = ResponseUtil.failure(data=e.data, msg=e.message)
|
|
||||||
except ServiceException as e:
|
|
||||||
logger.error(e.message)
|
|
||||||
result = ResponseUtil.error(data=e.data, msg=e.message)
|
|
||||||
except Exception as e:
|
|
||||||
logger.exception(e)
|
|
||||||
result = ResponseUtil.error(msg=str(e))
|
|
||||||
# 获取请求耗时
|
|
||||||
cost_time = float(time.perf_counter() - start_time) * 1000
|
|
||||||
# 判断请求是否来自api文档
|
|
||||||
request_from_swagger = (
|
|
||||||
request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False
|
|
||||||
)
|
|
||||||
request_from_redoc = (
|
|
||||||
request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False
|
|
||||||
)
|
|
||||||
# 根据响应结果的类型使用不同的方法获取响应结果参数
|
|
||||||
if (
|
|
||||||
isinstance(result, JSONResponse)
|
|
||||||
or isinstance(result, ORJSONResponse)
|
|
||||||
or isinstance(result, UJSONResponse)
|
|
||||||
):
|
|
||||||
result_dict = json.loads(str(result.body, 'utf-8'))
|
|
||||||
else:
|
|
||||||
if request_from_swagger or request_from_redoc:
|
|
||||||
result_dict = {}
|
|
||||||
else:
|
|
||||||
if result.status_code == 200:
|
|
||||||
result_dict = {'code': result.status_code, 'message': '获取成功'}
|
|
||||||
else:
|
|
||||||
result_dict = {'code': result.status_code, 'message': '获取失败'}
|
|
||||||
json_result = json.dumps(result_dict, ensure_ascii=False)
|
|
||||||
# 根据响应结果获取响应状态及异常信息
|
|
||||||
status = 1
|
|
||||||
error_msg = ''
|
|
||||||
if result_dict.get('code') == 200:
|
|
||||||
status = 0
|
|
||||||
else:
|
|
||||||
error_msg = result_dict.get('msg')
|
|
||||||
# 根据日志类型向对应的日志表插入数据
|
|
||||||
if self.log_type == 'login':
|
|
||||||
# 登录请求来自于api文档时不记录登录日志,其余情况则记录
|
|
||||||
if request_from_swagger or request_from_redoc:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
user = kwargs.get('form_data')
|
|
||||||
user_name = user.username
|
|
||||||
login_log['loginTime'] = oper_time
|
|
||||||
login_log['userName'] = user_name
|
|
||||||
login_log['status'] = str(status)
|
|
||||||
login_log['msg'] = result_dict.get('msg')
|
|
||||||
|
|
||||||
await LoginLogService.add_login_log_services(query_db, LogininforModel(**login_log))
|
|
||||||
else:
|
|
||||||
current_user = await LoginService.get_current_user(request, token, query_db)
|
|
||||||
oper_name = current_user.user.user_name
|
|
||||||
dept_name = current_user.user.dept.dept_name if current_user.user.dept else None
|
|
||||||
operation_log = OperLogModel(
|
|
||||||
title=self.title,
|
|
||||||
businessType=self.business_type,
|
|
||||||
method=func_path,
|
|
||||||
requestMethod=request_method,
|
|
||||||
operatorType=operator_type,
|
|
||||||
operName=oper_name,
|
|
||||||
deptName=dept_name,
|
|
||||||
operUrl=oper_url,
|
|
||||||
operIp=oper_ip,
|
|
||||||
operLocation=oper_location,
|
|
||||||
operParam=oper_param,
|
|
||||||
jsonResult=json_result,
|
|
||||||
status=status,
|
|
||||||
errorMsg=error_msg,
|
|
||||||
operTime=oper_time,
|
|
||||||
costTime=int(cost_time),
|
|
||||||
)
|
|
||||||
await OperationLogService.add_operation_log_services(query_db, operation_log)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
@alru_cache()
|
|
||||||
async def get_ip_location(oper_ip: str):
|
|
||||||
"""
|
|
||||||
查询ip归属区域
|
|
||||||
|
|
||||||
:param oper_ip: 需要查询的ip
|
|
||||||
:return: ip归属区域
|
|
||||||
"""
|
|
||||||
oper_location = '内网IP'
|
|
||||||
try:
|
|
||||||
if oper_ip != '127.0.0.1' and oper_ip != 'localhost':
|
|
||||||
oper_location = '未知'
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
ip_result = await client.get(f'https://qifu-api.baidubce.com/ip/geo/v1/district?ip={oper_ip}')
|
|
||||||
if ip_result.status_code == 200:
|
|
||||||
prov = ip_result.json().get('data', {}).get('prov')
|
|
||||||
city = ip_result.json().get('data', {}).get('city')
|
|
||||||
if prov or city:
|
|
||||||
oper_location = f'{prov}-{city}'
|
|
||||||
except Exception as e:
|
|
||||||
oper_location = '未知'
|
|
||||||
print(e)
|
|
||||||
return oper_location
|
|
||||||
|
|
||||||
|
|
||||||
def get_function_parameters_name_by_type(func: Callable, param_type: Any):
|
|
||||||
"""
|
|
||||||
获取函数指定类型的参数名称
|
|
||||||
|
|
||||||
:param func: 函数
|
|
||||||
:param arg_type: 参数类型
|
|
||||||
:return: 函数指定类型的参数名称
|
|
||||||
"""
|
|
||||||
# 获取函数的参数信息
|
|
||||||
parameters = inspect.signature(func).parameters
|
|
||||||
# 找到指定类型的参数名称
|
|
||||||
parameters_name_list = []
|
|
||||||
for name, param in parameters.items():
|
|
||||||
if param.annotation == param_type:
|
|
||||||
parameters_name_list.append(name)
|
|
||||||
return parameters_name_list
|
|
||||||
|
|
||||||
|
|
||||||
def get_function_parameters_value_by_name(func: Callable, name: str, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
获取函数指定参数的值
|
|
||||||
|
|
||||||
:param func: 函数
|
|
||||||
:param name: 参数名
|
|
||||||
:return: 参数值
|
|
||||||
"""
|
|
||||||
# 获取参数值
|
|
||||||
bound_parameters = inspect.signature(func).bind(*args, **kwargs)
|
|
||||||
bound_parameters.apply_defaults()
|
|
||||||
parameters_value = bound_parameters.arguments.get(name)
|
|
||||||
|
|
||||||
return parameters_value
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
from fastapi import Depends
|
|
||||||
from typing import List, Union
|
|
||||||
from exceptions.exception import PermissionException
|
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
|
|
||||||
|
|
||||||
class CheckUserInterfaceAuth:
|
|
||||||
"""
|
|
||||||
校验当前用户是否具有相应的接口权限
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, perm: Union[str, List], is_strict: bool = False):
|
|
||||||
"""
|
|
||||||
校验当前用户是否具有相应的接口权限
|
|
||||||
|
|
||||||
:param perm: 权限标识
|
|
||||||
:param is_strict: 当传入的权限标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个权限标识,所有的校验结果都需要为True才会通过
|
|
||||||
"""
|
|
||||||
self.perm = perm
|
|
||||||
self.is_strict = is_strict
|
|
||||||
|
|
||||||
def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
|
|
||||||
user_auth_list = current_user.permissions
|
|
||||||
if '*:*:*' in user_auth_list:
|
|
||||||
return True
|
|
||||||
if isinstance(self.perm, str):
|
|
||||||
if self.perm in user_auth_list:
|
|
||||||
return True
|
|
||||||
if isinstance(self.perm, list):
|
|
||||||
if self.is_strict:
|
|
||||||
if all([perm_str in user_auth_list for perm_str in self.perm]):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
if any([perm_str in user_auth_list for perm_str in self.perm]):
|
|
||||||
return True
|
|
||||||
raise PermissionException(data='', message='该用户无此接口权限')
|
|
||||||
|
|
||||||
|
|
||||||
class CheckRoleInterfaceAuth:
|
|
||||||
"""
|
|
||||||
根据角色校验当前用户是否具有相应的接口权限
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, role_key: Union[str, List], is_strict: bool = False):
|
|
||||||
"""
|
|
||||||
根据角色校验当前用户是否具有相应的接口权限
|
|
||||||
|
|
||||||
:param role_key: 角色标识
|
|
||||||
:param is_strict: 当传入的角色标识是list类型时,是否开启严格模式,开启表示会校验列表中的每一个角色标识,所有的校验结果都需要为True才会通过
|
|
||||||
"""
|
|
||||||
self.role_key = role_key
|
|
||||||
self.is_strict = is_strict
|
|
||||||
|
|
||||||
def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
|
|
||||||
user_role_list = current_user.user.role
|
|
||||||
user_role_key_list = [role.role_key for role in user_role_list]
|
|
||||||
if isinstance(self.role_key, str):
|
|
||||||
if self.role_key in user_role_key_list:
|
|
||||||
return True
|
|
||||||
if isinstance(self.role_key, list):
|
|
||||||
if self.is_strict:
|
|
||||||
if all([role_key_str in user_role_key_list for role_key_str in self.role_key]):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
if any([role_key_str in user_role_key_list for role_key_str in self.role_key]):
|
|
||||||
return True
|
|
||||||
raise PermissionException(data='', message='该用户无此接口权限')
|
|
||||||
@@ -1,20 +1,29 @@
|
|||||||
from fastapi import APIRouter, Depends, Request
|
from typing import Annotated
|
||||||
from typing import List
|
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from fastapi import Path, Request, Response
|
||||||
|
|
||||||
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import PreAuthDependency
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, ResponseBaseModel
|
||||||
from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel
|
from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel
|
||||||
from module_admin.service.cache_service import CacheService
|
from module_admin.service.cache_service import CacheService
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
cache_controller = APIRouterPro(
|
||||||
cacheController = APIRouter(prefix='/monitor/cache', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/monitor/cache', order_num=15, tags=['系统监控-缓存监控'], dependencies=[PreAuthDependency()]
|
||||||
|
|
||||||
|
|
||||||
@cacheController.get(
|
|
||||||
'', response_model=CacheMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]
|
|
||||||
)
|
)
|
||||||
async def get_monitor_cache_info(request: Request):
|
|
||||||
|
|
||||||
|
@cache_controller.get(
|
||||||
|
'',
|
||||||
|
summary='获取缓存监控信息接口',
|
||||||
|
description='用于获取缓存监控信息',
|
||||||
|
response_model=DataResponseModel[CacheMonitorModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
|
||||||
|
)
|
||||||
|
async def get_monitor_cache_info(request: Request) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
cache_info_query_result = await CacheService.get_cache_monitor_statistical_info_services(request)
|
cache_info_query_result = await CacheService.get_cache_monitor_statistical_info_services(request)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -22,12 +31,14 @@ async def get_monitor_cache_info(request: Request):
|
|||||||
return ResponseUtil.success(data=cache_info_query_result)
|
return ResponseUtil.success(data=cache_info_query_result)
|
||||||
|
|
||||||
|
|
||||||
@cacheController.get(
|
@cache_controller.get(
|
||||||
'/getNames',
|
'/getNames',
|
||||||
response_model=List[CacheInfoModel],
|
summary='获取缓存名称列表接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))],
|
description='用于获取缓存名称列表',
|
||||||
|
response_model=DataResponseModel[list[CacheInfoModel]],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
|
||||||
)
|
)
|
||||||
async def get_monitor_cache_name(request: Request):
|
async def get_monitor_cache_name(request: Request) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
cache_name_list_result = await CacheService.get_cache_monitor_cache_name_services()
|
cache_name_list_result = await CacheService.get_cache_monitor_cache_name_services()
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -35,12 +46,14 @@ async def get_monitor_cache_name(request: Request):
|
|||||||
return ResponseUtil.success(data=cache_name_list_result)
|
return ResponseUtil.success(data=cache_name_list_result)
|
||||||
|
|
||||||
|
|
||||||
@cacheController.get(
|
@cache_controller.get(
|
||||||
'/getKeys/{cache_name}',
|
'/getKeys/{cache_name}',
|
||||||
response_model=List[str],
|
summary='获取缓存键列表接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))],
|
description='用于获取指定缓存名称下的所有缓存键列表',
|
||||||
|
response_model=DataResponseModel[list[str]],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
|
||||||
)
|
)
|
||||||
async def get_monitor_cache_key(request: Request, cache_name: str):
|
async def get_monitor_cache_key(request: Request, cache_name: Annotated[str, Path(description='缓存名称')]) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
cache_key_list_result = await CacheService.get_cache_monitor_cache_key_services(request, cache_name)
|
cache_key_list_result = await CacheService.get_cache_monitor_cache_key_services(request, cache_name)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -48,12 +61,18 @@ async def get_monitor_cache_key(request: Request, cache_name: str):
|
|||||||
return ResponseUtil.success(data=cache_key_list_result)
|
return ResponseUtil.success(data=cache_key_list_result)
|
||||||
|
|
||||||
|
|
||||||
@cacheController.get(
|
@cache_controller.get(
|
||||||
'/getValue/{cache_name}/{cache_key}',
|
'/getValue/{cache_name}/{cache_key}',
|
||||||
response_model=CacheInfoModel,
|
summary='获取缓存值接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))],
|
description='用于获取指定缓存名称下的指定缓存键对应的值',
|
||||||
|
response_model=DataResponseModel[CacheInfoModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
|
||||||
)
|
)
|
||||||
async def get_monitor_cache_value(request: Request, cache_name: str, cache_key: str):
|
async def get_monitor_cache_value(
|
||||||
|
request: Request,
|
||||||
|
cache_name: Annotated[str, Path(description='缓存名称')],
|
||||||
|
cache_key: Annotated[str, Path(description='缓存键')],
|
||||||
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
cache_value_list_result = await CacheService.get_cache_monitor_cache_value_services(request, cache_name, cache_key)
|
cache_value_list_result = await CacheService.get_cache_monitor_cache_value_services(request, cache_name, cache_key)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -61,28 +80,44 @@ async def get_monitor_cache_value(request: Request, cache_name: str, cache_key:
|
|||||||
return ResponseUtil.success(data=cache_value_list_result)
|
return ResponseUtil.success(data=cache_value_list_result)
|
||||||
|
|
||||||
|
|
||||||
@cacheController.delete(
|
@cache_controller.delete(
|
||||||
'/clearCacheName/{cache_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]
|
'/clearCacheName/{cache_name}',
|
||||||
|
summary='清除缓存名称接口',
|
||||||
|
description='用于清除指定缓存名称下的所有缓存键值对',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
|
||||||
)
|
)
|
||||||
async def clear_monitor_cache_name(request: Request, cache_name: str):
|
async def clear_monitor_cache_name(
|
||||||
|
request: Request, cache_name: Annotated[str, Path(description='缓存名称')]
|
||||||
|
) -> Response:
|
||||||
clear_cache_name_result = await CacheService.clear_cache_monitor_cache_name_services(request, cache_name)
|
clear_cache_name_result = await CacheService.clear_cache_monitor_cache_name_services(request, cache_name)
|
||||||
logger.info(clear_cache_name_result.message)
|
logger.info(clear_cache_name_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=clear_cache_name_result.message)
|
return ResponseUtil.success(msg=clear_cache_name_result.message)
|
||||||
|
|
||||||
|
|
||||||
@cacheController.delete(
|
@cache_controller.delete(
|
||||||
'/clearCacheKey/{cache_key}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]
|
'/clearCacheKey/{cache_key}',
|
||||||
|
summary='清除缓存键接口',
|
||||||
|
description='用于清除指定缓存键对应的值',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
|
||||||
)
|
)
|
||||||
async def clear_monitor_cache_key(request: Request, cache_key: str):
|
async def clear_monitor_cache_key(request: Request, cache_key: Annotated[str, Path(description='缓存键')]) -> Response:
|
||||||
clear_cache_key_result = await CacheService.clear_cache_monitor_cache_key_services(request, cache_key)
|
clear_cache_key_result = await CacheService.clear_cache_monitor_cache_key_services(request, cache_key)
|
||||||
logger.info(clear_cache_key_result.message)
|
logger.info(clear_cache_key_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=clear_cache_key_result.message)
|
return ResponseUtil.success(msg=clear_cache_key_result.message)
|
||||||
|
|
||||||
|
|
||||||
@cacheController.delete('/clearCacheAll', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))])
|
@cache_controller.delete(
|
||||||
async def clear_monitor_cache_all(request: Request):
|
'/clearCacheAll',
|
||||||
|
summary='清除所有缓存接口',
|
||||||
|
description='用于清除所有缓存键值对',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
|
||||||
|
)
|
||||||
|
async def clear_monitor_cache_all(request: Request) -> Response:
|
||||||
clear_cache_all_result = await CacheService.clear_cache_monitor_all_services(request)
|
clear_cache_all_result = await CacheService.clear_cache_monitor_all_services(request)
|
||||||
logger.info(clear_cache_all_result.message)
|
logger.info(clear_cache_all_result.message)
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,31 @@
|
|||||||
import uuid
|
import uuid
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from fastapi import APIRouter, Request
|
|
||||||
from config.enums import RedisInitKeyConfig
|
from fastapi import Request, Response
|
||||||
|
|
||||||
|
from common.enums import RedisInitKeyConfig
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DynamicResponseModel
|
||||||
from module_admin.entity.vo.login_vo import CaptchaCode
|
from module_admin.entity.vo.login_vo import CaptchaCode
|
||||||
from module_admin.service.captcha_service import CaptchaService
|
from module_admin.service.captcha_service import CaptchaService
|
||||||
from utils.response_util import ResponseUtil
|
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
captcha_controller = APIRouterPro(order_num=2, tags=['验证码模块'])
|
||||||
|
|
||||||
|
|
||||||
captchaController = APIRouter()
|
@captcha_controller.get(
|
||||||
|
'/captchaImage',
|
||||||
|
summary='获取图片验证码接口',
|
||||||
@captchaController.get('/captchaImage')
|
description='用于获取图片验证码',
|
||||||
async def get_captcha_image(request: Request):
|
response_model=DynamicResponseModel[CaptchaCode],
|
||||||
|
)
|
||||||
|
async def get_captcha_image(request: Request) -> Response:
|
||||||
captcha_enabled = (
|
captcha_enabled = (
|
||||||
True
|
await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') == 'true'
|
||||||
if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled')
|
|
||||||
== 'true'
|
|
||||||
else False
|
|
||||||
)
|
)
|
||||||
register_enabled = (
|
register_enabled = (
|
||||||
True
|
await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.registerUser') == 'true'
|
||||||
if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.registerUser') == 'true'
|
|
||||||
else False
|
|
||||||
)
|
)
|
||||||
session_id = str(uuid.uuid4())
|
session_id = str(uuid.uuid4())
|
||||||
captcha_result = await CaptchaService.create_captcha_image_service()
|
captcha_result = await CaptchaService.create_captcha_image_service()
|
||||||
|
|||||||
@@ -1,35 +1,73 @@
|
|||||||
from fastapi import APIRouter, BackgroundTasks, Depends, File, Query, Request, UploadFile
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import BackgroundTasks, File, Query, Request, Response, UploadFile
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
|
|
||||||
|
from common.aspect.pre_auth import PreAuthDependency
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DynamicResponseModel
|
||||||
|
from module_admin.entity.vo.common_vo import UploadResponseModel
|
||||||
from module_admin.service.common_service import CommonService
|
from module_admin.service.common_service import CommonService
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
commonController = APIRouter(prefix='/common', dependencies=[Depends(LoginService.get_current_user)])
|
common_controller = APIRouterPro(prefix='/common', order_num=16, tags=['通用模块'], dependencies=[PreAuthDependency()])
|
||||||
|
|
||||||
|
|
||||||
@commonController.post('/upload')
|
@common_controller.post(
|
||||||
async def common_upload(request: Request, file: UploadFile = File(...)):
|
'/upload',
|
||||||
|
summary='通用文件上传接口',
|
||||||
|
description='用于上传文件',
|
||||||
|
response_model=DynamicResponseModel[UploadResponseModel],
|
||||||
|
)
|
||||||
|
async def common_upload(request: Request, file: Annotated[UploadFile, File(...)]) -> Response:
|
||||||
upload_result = await CommonService.upload_service(request, file)
|
upload_result = await CommonService.upload_service(request, file)
|
||||||
logger.info('上传成功')
|
logger.info('上传成功')
|
||||||
|
|
||||||
return ResponseUtil.success(model_content=upload_result.result)
|
return ResponseUtil.success(model_content=upload_result.result)
|
||||||
|
|
||||||
|
|
||||||
@commonController.get('/download')
|
@common_controller.get(
|
||||||
|
'/download',
|
||||||
|
summary='通用文件下载接口',
|
||||||
|
description='用于下载下载目录中的文件',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
async def common_download(
|
async def common_download(
|
||||||
request: Request,
|
request: Request,
|
||||||
background_tasks: BackgroundTasks,
|
background_tasks: BackgroundTasks,
|
||||||
file_name: str = Query(alias='fileName'),
|
file_name: Annotated[str, Query(alias='fileName')],
|
||||||
delete: bool = Query(),
|
delete: Annotated[bool, Query()],
|
||||||
):
|
) -> Response:
|
||||||
download_result = await CommonService.download_services(background_tasks, file_name, delete)
|
download_result = await CommonService.download_services(background_tasks, file_name, delete)
|
||||||
logger.info(download_result.message)
|
logger.info(download_result.message)
|
||||||
|
|
||||||
return ResponseUtil.streaming(data=download_result.result)
|
return ResponseUtil.streaming(data=download_result.result)
|
||||||
|
|
||||||
|
|
||||||
@commonController.get('/download/resource')
|
@common_controller.get(
|
||||||
async def common_download_resource(request: Request, resource: str = Query()):
|
'/download/resource',
|
||||||
|
summary='通用资源文件下载接口',
|
||||||
|
description='用于下载上传目录中的资源文件',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
async def common_download_resource(request: Request, resource: Annotated[str, Query()]) -> Response:
|
||||||
download_resource_result = await CommonService.download_resource_services(resource)
|
download_resource_result = await CommonService.download_resource_services(resource)
|
||||||
logger.info(download_resource_result.message)
|
logger.info(download_resource_result.message)
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,42 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, Form, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Form, Path, Query, Request, Response
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
from pydantic_validation_decorator import ValidateFields
|
from pydantic_validation_decorator import ValidateFields
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.get_db import get_db
|
from common.annotation.log_annotation import Log
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
|
||||||
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel
|
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
from module_admin.service.config_service import ConfigService
|
from module_admin.service.config_service import ConfigService
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from utils.common_util import bytes2file_response
|
from utils.common_util import bytes2file_response
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
config_controller = APIRouterPro(
|
||||||
configController = APIRouter(prefix='/system/config', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/system/config', order_num=9, tags=['系统管理-参数管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@configController.get(
|
@config_controller.get(
|
||||||
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:list'))]
|
'/list',
|
||||||
|
summary='获取参数分页列表接口',
|
||||||
|
description='用于获取参数分页列表',
|
||||||
|
response_model=PageResponseModel[ConfigModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:config:list')],
|
||||||
)
|
)
|
||||||
async def get_system_config_list(
|
async def get_system_config_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_query),
|
config_page_query: Annotated[ConfigPageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
config_page_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=True)
|
config_page_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=True)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -34,15 +44,21 @@ async def get_system_config_list(
|
|||||||
return ResponseUtil.success(model_content=config_page_query_result)
|
return ResponseUtil.success(model_content=config_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@configController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))])
|
@config_controller.post(
|
||||||
|
'',
|
||||||
|
summary='新增参数接口',
|
||||||
|
description='用于新增参数',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:config:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_config')
|
@ValidateFields(validate_model='add_config')
|
||||||
@Log(title='参数管理', business_type=BusinessType.INSERT)
|
@Log(title='参数管理', business_type=BusinessType.INSERT)
|
||||||
async def add_system_config(
|
async def add_system_config(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_config: ConfigModel,
|
add_config: ConfigModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
add_config.create_by = current_user.user.user_name
|
add_config.create_by = current_user.user.user_name
|
||||||
add_config.create_time = datetime.now()
|
add_config.create_time = datetime.now()
|
||||||
add_config.update_by = current_user.user.user_name
|
add_config.update_by = current_user.user.user_name
|
||||||
@@ -53,15 +69,21 @@ async def add_system_config(
|
|||||||
return ResponseUtil.success(msg=add_config_result.message)
|
return ResponseUtil.success(msg=add_config_result.message)
|
||||||
|
|
||||||
|
|
||||||
@configController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))])
|
@config_controller.put(
|
||||||
|
'',
|
||||||
|
summary='编辑参数接口',
|
||||||
|
description='用于编辑参数',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:config:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_config')
|
@ValidateFields(validate_model='edit_config')
|
||||||
@Log(title='参数管理', business_type=BusinessType.UPDATE)
|
@Log(title='参数管理', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_config(
|
async def edit_system_config(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_config: ConfigModel,
|
edit_config: ConfigModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
edit_config.update_by = current_user.user.user_name
|
edit_config.update_by = current_user.user.user_name
|
||||||
edit_config.update_time = datetime.now()
|
edit_config.update_time = datetime.now()
|
||||||
edit_config_result = await ConfigService.edit_config_services(request, query_db, edit_config)
|
edit_config_result = await ConfigService.edit_config_services(request, query_db, edit_config)
|
||||||
@@ -70,18 +92,37 @@ async def edit_system_config(
|
|||||||
return ResponseUtil.success(msg=edit_config_result.message)
|
return ResponseUtil.success(msg=edit_config_result.message)
|
||||||
|
|
||||||
|
|
||||||
@configController.delete('/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))])
|
@config_controller.delete(
|
||||||
|
'/refreshCache',
|
||||||
|
summary='刷新参数缓存接口',
|
||||||
|
description='用于刷新参数缓存',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:config:remove')],
|
||||||
|
)
|
||||||
@Log(title='参数管理', business_type=BusinessType.UPDATE)
|
@Log(title='参数管理', business_type=BusinessType.UPDATE)
|
||||||
async def refresh_system_config(request: Request, query_db: AsyncSession = Depends(get_db)):
|
async def refresh_system_config(
|
||||||
|
request: Request,
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db)
|
refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db)
|
||||||
logger.info(refresh_config_result.message)
|
logger.info(refresh_config_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=refresh_config_result.message)
|
return ResponseUtil.success(msg=refresh_config_result.message)
|
||||||
|
|
||||||
|
|
||||||
@configController.delete('/{config_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))])
|
@config_controller.delete(
|
||||||
|
'/{config_ids}',
|
||||||
|
summary='删除参数接口',
|
||||||
|
description='用于删除参数',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:config:remove')],
|
||||||
|
)
|
||||||
@Log(title='参数管理', business_type=BusinessType.DELETE)
|
@Log(title='参数管理', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_config(request: Request, config_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_config(
|
||||||
|
request: Request,
|
||||||
|
config_ids: Annotated[str, Path(description='需要删除的参数主键')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_config = DeleteConfigModel(configIds=config_ids)
|
delete_config = DeleteConfigModel(configIds=config_ids)
|
||||||
delete_config_result = await ConfigService.delete_config_services(request, query_db, delete_config)
|
delete_config_result = await ConfigService.delete_config_services(request, query_db, delete_config)
|
||||||
logger.info(delete_config_result.message)
|
logger.info(delete_config_result.message)
|
||||||
@@ -89,18 +130,31 @@ async def delete_system_config(request: Request, config_ids: str, query_db: Asyn
|
|||||||
return ResponseUtil.success(msg=delete_config_result.message)
|
return ResponseUtil.success(msg=delete_config_result.message)
|
||||||
|
|
||||||
|
|
||||||
@configController.get(
|
@config_controller.get(
|
||||||
'/{config_id}', response_model=ConfigModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:query'))]
|
'/{config_id}',
|
||||||
|
summary='获取参数详情接口',
|
||||||
|
description='用于获取指定参数的详细信息',
|
||||||
|
response_model=DataResponseModel[ConfigModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:config:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_config(request: Request, config_id: int, query_db: AsyncSession = Depends(get_db)):
|
async def query_detail_system_config(
|
||||||
|
request: Request,
|
||||||
|
config_id: Annotated[int, Path(description='参数主键')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
config_detail_result = await ConfigService.config_detail_services(query_db, config_id)
|
config_detail_result = await ConfigService.config_detail_services(query_db, config_id)
|
||||||
logger.info(f'获取config_id为{config_id}的信息成功')
|
logger.info(f'获取config_id为{config_id}的信息成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=config_detail_result)
|
return ResponseUtil.success(data=config_detail_result)
|
||||||
|
|
||||||
|
|
||||||
@configController.get('/configKey/{config_key}')
|
@config_controller.get(
|
||||||
async def query_system_config(request: Request, config_key: str):
|
'/configKey/{config_key}',
|
||||||
|
summary='根据参数键查询参数值接口',
|
||||||
|
description='用于根据参数键从缓存中查询参数值',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
)
|
||||||
|
async def query_system_config(request: Request, config_key: str) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key)
|
config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -108,13 +162,27 @@ async def query_system_config(request: Request, config_key: str):
|
|||||||
return ResponseUtil.success(msg=config_query_result)
|
return ResponseUtil.success(msg=config_query_result)
|
||||||
|
|
||||||
|
|
||||||
@configController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))])
|
@config_controller.post(
|
||||||
|
'/export',
|
||||||
|
summary='导出参数列表接口',
|
||||||
|
description='用于导出当前符合查询条件的参数列表数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回参数列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:config:export')],
|
||||||
|
)
|
||||||
@Log(title='参数管理', business_type=BusinessType.EXPORT)
|
@Log(title='参数管理', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_config_list(
|
async def export_system_config_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
config_page_query: ConfigPageQueryModel = Form(),
|
config_page_query: Annotated[ConfigPageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
config_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=False)
|
config_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=False)
|
||||||
config_export_result = await ConfigService.export_config_list_services(config_query_result)
|
config_export_result = await ConfigService.export_config_list_services(config_query_result)
|
||||||
|
|||||||
@@ -1,35 +1,42 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Path, Query, Request, Response
|
||||||
from pydantic_validation_decorator import ValidateFields
|
from pydantic_validation_decorator import ValidateFields
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from typing import List
|
|
||||||
from config.enums import BusinessType
|
from common.annotation.log_annotation import Log
|
||||||
from config.get_db import get_db
|
from common.aspect.data_scope import DataScopeDependency
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.aspect.data_scope import GetDataScope
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, ResponseBaseModel
|
||||||
from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel, DeptQueryModel
|
from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel, DeptQueryModel
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
from module_admin.service.dept_service import DeptService
|
from module_admin.service.dept_service import DeptService
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
dept_controller = APIRouterPro(
|
||||||
deptController = APIRouter(prefix='/system/dept', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/system/dept', order_num=6, tags=['系统管理-部门管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@deptController.get(
|
@dept_controller.get(
|
||||||
'/list/exclude/{dept_id}',
|
'/list/exclude/{dept_id}',
|
||||||
response_model=List[DeptModel],
|
summary='获取编辑部门的下拉树接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))],
|
description='用于获取部门下拉树,不包含指定部门及其子部门',
|
||||||
|
response_model=DataResponseModel[list[DeptModel]],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dept:list')],
|
||||||
)
|
)
|
||||||
async def get_system_dept_tree_for_edit_option(
|
async def get_system_dept_tree_for_edit_option(
|
||||||
request: Request,
|
request: Request,
|
||||||
dept_id: int,
|
dept_id: Annotated[int, Path(description='部门id')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
dept_query = DeptModel(deptId=dept_id)
|
dept_query = DeptModel(deptId=dept_id)
|
||||||
dept_query_result = await DeptService.get_dept_for_edit_option_services(query_db, dept_query, data_scope_sql)
|
dept_query_result = await DeptService.get_dept_for_edit_option_services(query_db, dept_query, data_scope_sql)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -37,30 +44,40 @@ async def get_system_dept_tree_for_edit_option(
|
|||||||
return ResponseUtil.success(data=dept_query_result)
|
return ResponseUtil.success(data=dept_query_result)
|
||||||
|
|
||||||
|
|
||||||
@deptController.get(
|
@dept_controller.get(
|
||||||
'/list', response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))]
|
'/list',
|
||||||
|
summary='获取部门列表接口',
|
||||||
|
description='用于获取部门列表',
|
||||||
|
response_model=DataResponseModel[list[DeptModel]],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dept:list')],
|
||||||
)
|
)
|
||||||
async def get_system_dept_list(
|
async def get_system_dept_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
dept_query: DeptQueryModel = Depends(DeptQueryModel.as_query),
|
dept_query: Annotated[DeptQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
dept_query_result = await DeptService.get_dept_list_services(query_db, dept_query, data_scope_sql)
|
dept_query_result = await DeptService.get_dept_list_services(query_db, dept_query, data_scope_sql)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=dept_query_result)
|
return ResponseUtil.success(data=dept_query_result)
|
||||||
|
|
||||||
|
|
||||||
@deptController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))])
|
@dept_controller.post(
|
||||||
|
'',
|
||||||
|
summary='新增部门接口',
|
||||||
|
description='用于新增部门',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dept:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_dept')
|
@ValidateFields(validate_model='add_dept')
|
||||||
@Log(title='部门管理', business_type=BusinessType.INSERT)
|
@Log(title='部门管理', business_type=BusinessType.INSERT)
|
||||||
async def add_system_dept(
|
async def add_system_dept(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_dept: DeptModel,
|
add_dept: DeptModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
add_dept.create_by = current_user.user.user_name
|
add_dept.create_by = current_user.user.user_name
|
||||||
add_dept.create_time = datetime.now()
|
add_dept.create_time = datetime.now()
|
||||||
add_dept.update_by = current_user.user.user_name
|
add_dept.update_by = current_user.user.user_name
|
||||||
@@ -68,19 +85,25 @@ async def add_system_dept(
|
|||||||
add_dept_result = await DeptService.add_dept_services(query_db, add_dept)
|
add_dept_result = await DeptService.add_dept_services(query_db, add_dept)
|
||||||
logger.info(add_dept_result.message)
|
logger.info(add_dept_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(data=add_dept_result)
|
return ResponseUtil.success(msg=add_dept_result.message)
|
||||||
|
|
||||||
|
|
||||||
@deptController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))])
|
@dept_controller.put(
|
||||||
|
'',
|
||||||
|
summary='编辑部门接口',
|
||||||
|
description='用于编辑部门',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dept:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_dept')
|
@ValidateFields(validate_model='edit_dept')
|
||||||
@Log(title='部门管理', business_type=BusinessType.UPDATE)
|
@Log(title='部门管理', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_dept(
|
async def edit_system_dept(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_dept: DeptModel,
|
edit_dept: DeptModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await DeptService.check_dept_data_scope_services(query_db, edit_dept.dept_id, data_scope_sql)
|
await DeptService.check_dept_data_scope_services(query_db, edit_dept.dept_id, data_scope_sql)
|
||||||
edit_dept.update_by = current_user.user.user_name
|
edit_dept.update_by = current_user.user.user_name
|
||||||
@@ -91,15 +114,21 @@ async def edit_system_dept(
|
|||||||
return ResponseUtil.success(msg=edit_dept_result.message)
|
return ResponseUtil.success(msg=edit_dept_result.message)
|
||||||
|
|
||||||
|
|
||||||
@deptController.delete('/{dept_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))])
|
@dept_controller.delete(
|
||||||
|
'/{dept_ids}',
|
||||||
|
summary='删除部门接口',
|
||||||
|
description='用于删除部门',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dept:remove')],
|
||||||
|
)
|
||||||
@Log(title='部门管理', business_type=BusinessType.DELETE)
|
@Log(title='部门管理', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_dept(
|
async def delete_system_dept(
|
||||||
request: Request,
|
request: Request,
|
||||||
dept_ids: str,
|
dept_ids: Annotated[str, Path(description='需要删除的部门id')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
dept_id_list = dept_ids.split(',') if dept_ids else []
|
dept_id_list = dept_ids.split(',') if dept_ids else []
|
||||||
if dept_id_list:
|
if dept_id_list:
|
||||||
for dept_id in dept_id_list:
|
for dept_id in dept_id_list:
|
||||||
@@ -114,16 +143,20 @@ async def delete_system_dept(
|
|||||||
return ResponseUtil.success(msg=delete_dept_result.message)
|
return ResponseUtil.success(msg=delete_dept_result.message)
|
||||||
|
|
||||||
|
|
||||||
@deptController.get(
|
@dept_controller.get(
|
||||||
'/{dept_id}', response_model=DeptModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dept:query'))]
|
'/{dept_id}',
|
||||||
|
summary='获取部门详情接口',
|
||||||
|
description='用于获取指定部门的详情信息',
|
||||||
|
response_model=DataResponseModel[DeptModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dept:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_dept(
|
async def query_detail_system_dept(
|
||||||
request: Request,
|
request: Request,
|
||||||
dept_id: int,
|
dept_id: Annotated[int, Path(description='部门id')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await DeptService.check_dept_data_scope_services(query_db, dept_id, data_scope_sql)
|
await DeptService.check_dept_data_scope_services(query_db, dept_id, data_scope_sql)
|
||||||
detail_dept_result = await DeptService.dept_detail_services(query_db, dept_id)
|
detail_dept_result = await DeptService.dept_detail_services(query_db, dept_id)
|
||||||
|
|||||||
@@ -1,12 +1,18 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, Form, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Form, Path, Query, Request, Response
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
from pydantic_validation_decorator import ValidateFields
|
from pydantic_validation_decorator import ValidateFields
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from typing import List
|
|
||||||
from config.enums import BusinessType
|
from common.annotation.log_annotation import Log
|
||||||
from config.get_db import get_db
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
|
||||||
from module_admin.entity.vo.dict_vo import (
|
from module_admin.entity.vo.dict_vo import (
|
||||||
DeleteDictDataModel,
|
DeleteDictDataModel,
|
||||||
DeleteDictTypeModel,
|
DeleteDictTypeModel,
|
||||||
@@ -17,24 +23,27 @@ from module_admin.entity.vo.dict_vo import (
|
|||||||
)
|
)
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
from module_admin.service.dict_service import DictDataService, DictTypeService
|
from module_admin.service.dict_service import DictDataService, DictTypeService
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from utils.common_util import bytes2file_response
|
from utils.common_util import bytes2file_response
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
dict_controller = APIRouterPro(
|
||||||
dictController = APIRouter(prefix='/system/dict', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/system/dict', order_num=8, tags=['系统管理-字典管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dictController.get(
|
@dict_controller.get(
|
||||||
'/type/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]
|
'/type/list',
|
||||||
|
summary='获取字典类型分页列表接口',
|
||||||
|
description='用于获取字典类型分页列表',
|
||||||
|
response_model=PageResponseModel[DictTypeModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:list')],
|
||||||
)
|
)
|
||||||
async def get_system_dict_type_list(
|
async def get_system_dict_type_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_query),
|
dict_type_page_query: Annotated[DictTypePageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
dict_type_page_query_result = await DictTypeService.get_dict_type_list_services(
|
dict_type_page_query_result = await DictTypeService.get_dict_type_list_services(
|
||||||
query_db, dict_type_page_query, is_page=True
|
query_db, dict_type_page_query, is_page=True
|
||||||
@@ -44,15 +53,21 @@ async def get_system_dict_type_list(
|
|||||||
return ResponseUtil.success(model_content=dict_type_page_query_result)
|
return ResponseUtil.success(model_content=dict_type_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@dictController.post('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))])
|
@dict_controller.post(
|
||||||
|
'/type',
|
||||||
|
summary='新增字典类型接口',
|
||||||
|
description='用于新增字典类型',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_dict_type')
|
@ValidateFields(validate_model='add_dict_type')
|
||||||
@Log(title='字典类型', business_type=BusinessType.INSERT)
|
@Log(title='字典类型', business_type=BusinessType.INSERT)
|
||||||
async def add_system_dict_type(
|
async def add_system_dict_type(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_dict_type: DictTypeModel,
|
add_dict_type: DictTypeModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
add_dict_type.create_by = current_user.user.user_name
|
add_dict_type.create_by = current_user.user.user_name
|
||||||
add_dict_type.create_time = datetime.now()
|
add_dict_type.create_time = datetime.now()
|
||||||
add_dict_type.update_by = current_user.user.user_name
|
add_dict_type.update_by = current_user.user.user_name
|
||||||
@@ -63,15 +78,21 @@ async def add_system_dict_type(
|
|||||||
return ResponseUtil.success(msg=add_dict_type_result.message)
|
return ResponseUtil.success(msg=add_dict_type_result.message)
|
||||||
|
|
||||||
|
|
||||||
@dictController.put('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))])
|
@dict_controller.put(
|
||||||
|
'/type',
|
||||||
|
summary='编辑字典类型接口',
|
||||||
|
description='用于编辑字典类型',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_dict_type')
|
@ValidateFields(validate_model='edit_dict_type')
|
||||||
@Log(title='字典类型', business_type=BusinessType.UPDATE)
|
@Log(title='字典类型', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_dict_type(
|
async def edit_system_dict_type(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_dict_type: DictTypeModel,
|
edit_dict_type: DictTypeModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
edit_dict_type.update_by = current_user.user.user_name
|
edit_dict_type.update_by = current_user.user.user_name
|
||||||
edit_dict_type.update_time = datetime.now()
|
edit_dict_type.update_time = datetime.now()
|
||||||
edit_dict_type_result = await DictTypeService.edit_dict_type_services(request, query_db, edit_dict_type)
|
edit_dict_type_result = await DictTypeService.edit_dict_type_services(request, query_db, edit_dict_type)
|
||||||
@@ -80,18 +101,34 @@ async def edit_system_dict_type(
|
|||||||
return ResponseUtil.success(msg=edit_dict_type_result.message)
|
return ResponseUtil.success(msg=edit_dict_type_result.message)
|
||||||
|
|
||||||
|
|
||||||
@dictController.delete('/type/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))])
|
@dict_controller.delete(
|
||||||
|
'/type/refreshCache',
|
||||||
|
summary='刷新字典缓存接口',
|
||||||
|
description='用于刷新字典缓存',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:remove')],
|
||||||
|
)
|
||||||
@Log(title='字典类型', business_type=BusinessType.UPDATE)
|
@Log(title='字典类型', business_type=BusinessType.UPDATE)
|
||||||
async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends(get_db)):
|
async def refresh_system_dict(request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]) -> Response:
|
||||||
refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db)
|
refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db)
|
||||||
logger.info(refresh_dict_result.message)
|
logger.info(refresh_dict_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=refresh_dict_result.message)
|
return ResponseUtil.success(msg=refresh_dict_result.message)
|
||||||
|
|
||||||
|
|
||||||
@dictController.delete('/type/{dict_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))])
|
@dict_controller.delete(
|
||||||
|
'/type/{dict_ids}',
|
||||||
|
summary='删除字典类型接口',
|
||||||
|
description='用于删除字典类型',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:remove')],
|
||||||
|
)
|
||||||
@Log(title='字典类型', business_type=BusinessType.DELETE)
|
@Log(title='字典类型', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_dict_type(request: Request, dict_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_dict_type(
|
||||||
|
request: Request,
|
||||||
|
dict_ids: Annotated[str, Path(description='需要删除的字典主键')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids)
|
delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids)
|
||||||
delete_dict_type_result = await DictTypeService.delete_dict_type_services(request, query_db, delete_dict_type)
|
delete_dict_type_result = await DictTypeService.delete_dict_type_services(request, query_db, delete_dict_type)
|
||||||
logger.info(delete_dict_type_result.message)
|
logger.info(delete_dict_type_result.message)
|
||||||
@@ -99,33 +136,62 @@ async def delete_system_dict_type(request: Request, dict_ids: str, query_db: Asy
|
|||||||
return ResponseUtil.success(msg=delete_dict_type_result.message)
|
return ResponseUtil.success(msg=delete_dict_type_result.message)
|
||||||
|
|
||||||
|
|
||||||
@dictController.get('/type/optionselect', response_model=List[DictTypeModel])
|
@dict_controller.get(
|
||||||
async def query_system_dict_type_options(request: Request, query_db: AsyncSession = Depends(get_db)):
|
'/type/optionselect',
|
||||||
|
summary='获取字典类型下拉列表接口',
|
||||||
|
description='用于获取字典类型下拉列表',
|
||||||
|
response_model=DataResponseModel[list[DictTypeModel]],
|
||||||
|
)
|
||||||
|
async def query_system_dict_type_options(
|
||||||
|
request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
|
||||||
|
) -> Response:
|
||||||
dict_type_query_result = await DictTypeService.get_dict_type_list_services(
|
dict_type_query_result = await DictTypeService.get_dict_type_list_services(
|
||||||
query_db, DictTypePageQueryModel(**dict()), is_page=False
|
query_db, DictTypePageQueryModel(), is_page=False
|
||||||
)
|
)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=dict_type_query_result)
|
return ResponseUtil.success(data=dict_type_query_result)
|
||||||
|
|
||||||
|
|
||||||
@dictController.get(
|
@dict_controller.get(
|
||||||
'/type/{dict_id}', response_model=DictTypeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))]
|
'/type/{dict_id}',
|
||||||
|
summary='获取字典类型详情接口',
|
||||||
|
description='用于获取指定字典类型的详细信息',
|
||||||
|
response_model=DataResponseModel[DictTypeModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_dict_type(request: Request, dict_id: int, query_db: AsyncSession = Depends(get_db)):
|
async def query_detail_system_dict_type(
|
||||||
|
request: Request,
|
||||||
|
dict_id: Annotated[int, Path(description='字典主键')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
dict_type_detail_result = await DictTypeService.dict_type_detail_services(query_db, dict_id)
|
dict_type_detail_result = await DictTypeService.dict_type_detail_services(query_db, dict_id)
|
||||||
logger.info(f'获取dict_id为{dict_id}的信息成功')
|
logger.info(f'获取dict_id为{dict_id}的信息成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=dict_type_detail_result)
|
return ResponseUtil.success(data=dict_type_detail_result)
|
||||||
|
|
||||||
|
|
||||||
@dictController.post('/type/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))])
|
@dict_controller.post(
|
||||||
|
'/type/export',
|
||||||
|
summary='导出字典类型列表接口',
|
||||||
|
description='用于导出当前符合查询条件的字典类型列表数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回字典类型列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:export')],
|
||||||
|
)
|
||||||
@Log(title='字典类型', business_type=BusinessType.EXPORT)
|
@Log(title='字典类型', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_dict_type_list(
|
async def export_system_dict_type_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
dict_type_page_query: DictTypePageQueryModel = Form(),
|
dict_type_page_query: Annotated[DictTypePageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
dict_type_query_result = await DictTypeService.get_dict_type_list_services(
|
dict_type_query_result = await DictTypeService.get_dict_type_list_services(
|
||||||
query_db, dict_type_page_query, is_page=False
|
query_db, dict_type_page_query, is_page=False
|
||||||
@@ -136,8 +202,17 @@ async def export_system_dict_type_list(
|
|||||||
return ResponseUtil.streaming(data=bytes2file_response(dict_type_export_result))
|
return ResponseUtil.streaming(data=bytes2file_response(dict_type_export_result))
|
||||||
|
|
||||||
|
|
||||||
@dictController.get('/data/type/{dict_type}')
|
@dict_controller.get(
|
||||||
async def query_system_dict_type_data(request: Request, dict_type: str, query_db: AsyncSession = Depends(get_db)):
|
'/data/type/{dict_type}',
|
||||||
|
summary='获取指定字典类型的数据列表接口',
|
||||||
|
description='用于从缓存中获取指定字典类型的所有数据项',
|
||||||
|
response_model=DataResponseModel[list[DictDataModel]],
|
||||||
|
)
|
||||||
|
async def query_system_dict_type_data(
|
||||||
|
request: Request,
|
||||||
|
dict_type: Annotated[str, Path(description='字典类型')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services(
|
dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services(
|
||||||
request.app.state.redis, dict_type
|
request.app.state.redis, dict_type
|
||||||
@@ -147,14 +222,18 @@ async def query_system_dict_type_data(request: Request, dict_type: str, query_db
|
|||||||
return ResponseUtil.success(data=dict_data_query_result)
|
return ResponseUtil.success(data=dict_data_query_result)
|
||||||
|
|
||||||
|
|
||||||
@dictController.get(
|
@dict_controller.get(
|
||||||
'/data/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]
|
'/data/list',
|
||||||
|
summary='获取字典数据分页列表接口',
|
||||||
|
description='用于获取字典数据分页列表',
|
||||||
|
response_model=PageResponseModel[DictDataModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:list')],
|
||||||
)
|
)
|
||||||
async def get_system_dict_data_list(
|
async def get_system_dict_data_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_query),
|
dict_data_page_query: Annotated[DictDataPageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
dict_data_page_query_result = await DictDataService.get_dict_data_list_services(
|
dict_data_page_query_result = await DictDataService.get_dict_data_list_services(
|
||||||
query_db, dict_data_page_query, is_page=True
|
query_db, dict_data_page_query, is_page=True
|
||||||
@@ -164,15 +243,21 @@ async def get_system_dict_data_list(
|
|||||||
return ResponseUtil.success(model_content=dict_data_page_query_result)
|
return ResponseUtil.success(model_content=dict_data_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@dictController.post('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))])
|
@dict_controller.post(
|
||||||
|
'/data',
|
||||||
|
summary='新增字典数据接口',
|
||||||
|
description='用于新增字典数据',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_dict_data')
|
@ValidateFields(validate_model='add_dict_data')
|
||||||
@Log(title='字典数据', business_type=BusinessType.INSERT)
|
@Log(title='字典数据', business_type=BusinessType.INSERT)
|
||||||
async def add_system_dict_data(
|
async def add_system_dict_data(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_dict_data: DictDataModel,
|
add_dict_data: DictDataModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
add_dict_data.create_by = current_user.user.user_name
|
add_dict_data.create_by = current_user.user.user_name
|
||||||
add_dict_data.create_time = datetime.now()
|
add_dict_data.create_time = datetime.now()
|
||||||
add_dict_data.update_by = current_user.user.user_name
|
add_dict_data.update_by = current_user.user.user_name
|
||||||
@@ -183,15 +268,21 @@ async def add_system_dict_data(
|
|||||||
return ResponseUtil.success(msg=add_dict_data_result.message)
|
return ResponseUtil.success(msg=add_dict_data_result.message)
|
||||||
|
|
||||||
|
|
||||||
@dictController.put('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))])
|
@dict_controller.put(
|
||||||
|
'/data',
|
||||||
|
summary='编辑字典数据接口',
|
||||||
|
description='用于编辑字典数据',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_dict_data')
|
@ValidateFields(validate_model='edit_dict_data')
|
||||||
@Log(title='字典数据', business_type=BusinessType.UPDATE)
|
@Log(title='字典数据', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_dict_data(
|
async def edit_system_dict_data(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_dict_data: DictDataModel,
|
edit_dict_data: DictDataModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
edit_dict_data.update_by = current_user.user.user_name
|
edit_dict_data.update_by = current_user.user.user_name
|
||||||
edit_dict_data.update_time = datetime.now()
|
edit_dict_data.update_time = datetime.now()
|
||||||
edit_dict_data_result = await DictDataService.edit_dict_data_services(request, query_db, edit_dict_data)
|
edit_dict_data_result = await DictDataService.edit_dict_data_services(request, query_db, edit_dict_data)
|
||||||
@@ -200,9 +291,19 @@ async def edit_system_dict_data(
|
|||||||
return ResponseUtil.success(msg=edit_dict_data_result.message)
|
return ResponseUtil.success(msg=edit_dict_data_result.message)
|
||||||
|
|
||||||
|
|
||||||
@dictController.delete('/data/{dict_codes}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))])
|
@dict_controller.delete(
|
||||||
|
'/data/{dict_codes}',
|
||||||
|
summary='删除字典数据接口',
|
||||||
|
description='用于删除字典数据',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:remove')],
|
||||||
|
)
|
||||||
@Log(title='字典数据', business_type=BusinessType.DELETE)
|
@Log(title='字典数据', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_dict_data(request: Request, dict_codes: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_dict_data(
|
||||||
|
request: Request,
|
||||||
|
dict_codes: Annotated[str, Path(description='需要删除的字典编码')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes)
|
delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes)
|
||||||
delete_dict_data_result = await DictDataService.delete_dict_data_services(request, query_db, delete_dict_data)
|
delete_dict_data_result = await DictDataService.delete_dict_data_services(request, query_db, delete_dict_data)
|
||||||
logger.info(delete_dict_data_result.message)
|
logger.info(delete_dict_data_result.message)
|
||||||
@@ -210,25 +311,45 @@ async def delete_system_dict_data(request: Request, dict_codes: str, query_db: A
|
|||||||
return ResponseUtil.success(msg=delete_dict_data_result.message)
|
return ResponseUtil.success(msg=delete_dict_data_result.message)
|
||||||
|
|
||||||
|
|
||||||
@dictController.get(
|
@dict_controller.get(
|
||||||
'/data/{dict_code}',
|
'/data/{dict_code}',
|
||||||
response_model=DictDataModel,
|
summary='获取字典数据详情接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))],
|
description='用于获取指定字典数据的详细信息',
|
||||||
|
response_model=DataResponseModel[DictDataModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_dict_data(request: Request, dict_code: int, query_db: AsyncSession = Depends(get_db)):
|
async def query_detail_system_dict_data(
|
||||||
|
request: Request,
|
||||||
|
dict_code: Annotated[int, Path(description='字典编码')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
detail_dict_data_result = await DictDataService.dict_data_detail_services(query_db, dict_code)
|
detail_dict_data_result = await DictDataService.dict_data_detail_services(query_db, dict_code)
|
||||||
logger.info(f'获取dict_code为{dict_code}的信息成功')
|
logger.info(f'获取dict_code为{dict_code}的信息成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=detail_dict_data_result)
|
return ResponseUtil.success(data=detail_dict_data_result)
|
||||||
|
|
||||||
|
|
||||||
@dictController.post('/data/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))])
|
@dict_controller.post(
|
||||||
|
'/data/export',
|
||||||
|
summary='导出字典数据列表接口',
|
||||||
|
description='用于导出当前符合查询条件的字典数据列表数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回字典数据列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:dict:export')],
|
||||||
|
)
|
||||||
@Log(title='字典数据', business_type=BusinessType.EXPORT)
|
@Log(title='字典数据', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_dict_data_list(
|
async def export_system_dict_data_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
dict_data_page_query: DictDataPageQueryModel = Form(),
|
dict_data_page_query: Annotated[DictDataPageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
dict_data_query_result = await DictDataService.get_dict_data_list_services(
|
dict_data_query_result = await DictDataService.get_dict_data_list_services(
|
||||||
query_db, dict_data_page_query, is_page=False
|
query_db, dict_data_page_query, is_page=False
|
||||||
|
|||||||
@@ -1,15 +1,23 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, Form, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Form, Path, Query, Request, Response
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
from pydantic_validation_decorator import ValidateFields
|
from pydantic_validation_decorator import ValidateFields
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.get_db import get_db
|
from common.annotation.log_annotation import Log
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
|
||||||
from module_admin.entity.vo.job_vo import (
|
from module_admin.entity.vo.job_vo import (
|
||||||
DeleteJobLogModel,
|
DeleteJobLogModel,
|
||||||
DeleteJobModel,
|
DeleteJobModel,
|
||||||
EditJobModel,
|
EditJobModel,
|
||||||
|
JobLogModel,
|
||||||
JobLogPageQueryModel,
|
JobLogPageQueryModel,
|
||||||
JobModel,
|
JobModel,
|
||||||
JobPageQueryModel,
|
JobPageQueryModel,
|
||||||
@@ -17,40 +25,49 @@ from module_admin.entity.vo.job_vo import (
|
|||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
from module_admin.service.job_log_service import JobLogService
|
from module_admin.service.job_log_service import JobLogService
|
||||||
from module_admin.service.job_service import JobService
|
from module_admin.service.job_service import JobService
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from utils.common_util import bytes2file_response
|
from utils.common_util import bytes2file_response
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
job_controller = APIRouterPro(
|
||||||
jobController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/monitor', order_num=13, tags=['系统监控-定时任务'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@jobController.get(
|
@job_controller.get(
|
||||||
'/job/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))]
|
'/job/list',
|
||||||
|
summary='获取定时任务分页列表接口',
|
||||||
|
description='用于获取定时任务分页列表',
|
||||||
|
response_model=PageResponseModel[JobModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:list')],
|
||||||
)
|
)
|
||||||
async def get_system_job_list(
|
async def get_system_job_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_query),
|
job_page_query: Annotated[JobPageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
notice_page_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=True)
|
job_page_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=True)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(model_content=notice_page_query_result)
|
return ResponseUtil.success(model_content=job_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@jobController.post('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))])
|
@job_controller.post(
|
||||||
|
'/job',
|
||||||
|
summary='新增定时任务接口',
|
||||||
|
description='用于新增定时任务',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_job')
|
@ValidateFields(validate_model='add_job')
|
||||||
@Log(title='定时任务', business_type=BusinessType.INSERT)
|
@Log(title='定时任务', business_type=BusinessType.INSERT)
|
||||||
async def add_system_job(
|
async def add_system_job(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_job: JobModel,
|
add_job: JobModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
add_job.create_by = current_user.user.user_name
|
add_job.create_by = current_user.user.user_name
|
||||||
add_job.create_time = datetime.now()
|
add_job.create_time = datetime.now()
|
||||||
add_job.update_by = current_user.user.user_name
|
add_job.update_by = current_user.user.user_name
|
||||||
@@ -61,15 +78,21 @@ async def add_system_job(
|
|||||||
return ResponseUtil.success(msg=add_job_result.message)
|
return ResponseUtil.success(msg=add_job_result.message)
|
||||||
|
|
||||||
|
|
||||||
@jobController.put('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))])
|
@job_controller.put(
|
||||||
|
'/job',
|
||||||
|
summary='编辑定时任务接口',
|
||||||
|
description='用于编辑定时任务',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_job')
|
@ValidateFields(validate_model='edit_job')
|
||||||
@Log(title='定时任务', business_type=BusinessType.UPDATE)
|
@Log(title='定时任务', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_job(
|
async def edit_system_job(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_job: EditJobModel,
|
edit_job: EditJobModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
edit_job.update_by = current_user.user.user_name
|
edit_job.update_by = current_user.user.user_name
|
||||||
edit_job.update_time = datetime.now()
|
edit_job.update_time = datetime.now()
|
||||||
edit_job_result = await JobService.edit_job_services(query_db, edit_job)
|
edit_job_result = await JobService.edit_job_services(query_db, edit_job)
|
||||||
@@ -78,14 +101,20 @@ async def edit_system_job(
|
|||||||
return ResponseUtil.success(msg=edit_job_result.message)
|
return ResponseUtil.success(msg=edit_job_result.message)
|
||||||
|
|
||||||
|
|
||||||
@jobController.put('/job/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))])
|
@job_controller.put(
|
||||||
|
'/job/changeStatus',
|
||||||
|
summary='修改定时任务状态接口',
|
||||||
|
description='用于修改定时任务状态',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:changeStatus')],
|
||||||
|
)
|
||||||
@Log(title='定时任务', business_type=BusinessType.UPDATE)
|
@Log(title='定时任务', business_type=BusinessType.UPDATE)
|
||||||
async def change_system_job_status(
|
async def change_system_job_status(
|
||||||
request: Request,
|
request: Request,
|
||||||
change_job: EditJobModel,
|
change_job: EditJobModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
edit_job = EditJobModel(
|
edit_job = EditJobModel(
|
||||||
jobId=change_job.job_id,
|
jobId=change_job.job_id,
|
||||||
status=change_job.status,
|
status=change_job.status,
|
||||||
@@ -99,18 +128,38 @@ async def change_system_job_status(
|
|||||||
return ResponseUtil.success(msg=edit_job_result.message)
|
return ResponseUtil.success(msg=edit_job_result.message)
|
||||||
|
|
||||||
|
|
||||||
@jobController.put('/job/run', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))])
|
@job_controller.put(
|
||||||
|
'/job/run',
|
||||||
|
summary='执行定时任务接口',
|
||||||
|
description='用于执行指定的定时任务',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:changeStatus')],
|
||||||
|
)
|
||||||
@Log(title='定时任务', business_type=BusinessType.UPDATE)
|
@Log(title='定时任务', business_type=BusinessType.UPDATE)
|
||||||
async def execute_system_job(request: Request, execute_job: JobModel, query_db: AsyncSession = Depends(get_db)):
|
async def execute_system_job(
|
||||||
|
request: Request,
|
||||||
|
execute_job: JobModel,
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
execute_job_result = await JobService.execute_job_once_services(query_db, execute_job)
|
execute_job_result = await JobService.execute_job_once_services(query_db, execute_job)
|
||||||
logger.info(execute_job_result.message)
|
logger.info(execute_job_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=execute_job_result.message)
|
return ResponseUtil.success(msg=execute_job_result.message)
|
||||||
|
|
||||||
|
|
||||||
@jobController.delete('/job/{job_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))])
|
@job_controller.delete(
|
||||||
|
'/job/{job_ids}',
|
||||||
|
summary='删除定时任务接口',
|
||||||
|
description='用于删除定时任务',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:remove')],
|
||||||
|
)
|
||||||
@Log(title='定时任务', business_type=BusinessType.DELETE)
|
@Log(title='定时任务', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_job(
|
||||||
|
request: Request,
|
||||||
|
job_ids: Annotated[str, Path(description='需要删除的定时任务ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_job = DeleteJobModel(jobIds=job_ids)
|
delete_job = DeleteJobModel(jobIds=job_ids)
|
||||||
delete_job_result = await JobService.delete_job_services(query_db, delete_job)
|
delete_job_result = await JobService.delete_job_services(query_db, delete_job)
|
||||||
logger.info(delete_job_result.message)
|
logger.info(delete_job_result.message)
|
||||||
@@ -118,23 +167,45 @@ async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSessi
|
|||||||
return ResponseUtil.success(msg=delete_job_result.message)
|
return ResponseUtil.success(msg=delete_job_result.message)
|
||||||
|
|
||||||
|
|
||||||
@jobController.get(
|
@job_controller.get(
|
||||||
'/job/{job_id}', response_model=JobModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:query'))]
|
'/job/{job_id}',
|
||||||
|
summary='获取定时任务详情接口',
|
||||||
|
description='用于获取指定定时任务的详情信息',
|
||||||
|
response_model=DataResponseModel[JobModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_job(request: Request, job_id: int, query_db: AsyncSession = Depends(get_db)):
|
async def query_detail_system_job(
|
||||||
|
request: Request,
|
||||||
|
job_id: Annotated[int, Path(description='任务ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
job_detail_result = await JobService.job_detail_services(query_db, job_id)
|
job_detail_result = await JobService.job_detail_services(query_db, job_id)
|
||||||
logger.info(f'获取job_id为{job_id}的信息成功')
|
logger.info(f'获取job_id为{job_id}的信息成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=job_detail_result)
|
return ResponseUtil.success(data=job_detail_result)
|
||||||
|
|
||||||
|
|
||||||
@jobController.post('/job/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))])
|
@job_controller.post(
|
||||||
|
'/job/export',
|
||||||
|
summary='导出定时任务列表接口',
|
||||||
|
description='用于导出当前符合查询条件的定时任务列表数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回定时任务列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:export')],
|
||||||
|
)
|
||||||
@Log(title='定时任务', business_type=BusinessType.EXPORT)
|
@Log(title='定时任务', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_job_list(
|
async def export_system_job_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
job_page_query: JobPageQueryModel = Form(),
|
job_page_query: Annotated[JobPageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
job_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=False)
|
job_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=False)
|
||||||
job_export_result = await JobService.export_job_list_services(request, job_query_result)
|
job_export_result = await JobService.export_job_list_services(request, job_query_result)
|
||||||
@@ -143,14 +214,18 @@ async def export_system_job_list(
|
|||||||
return ResponseUtil.streaming(data=bytes2file_response(job_export_result))
|
return ResponseUtil.streaming(data=bytes2file_response(job_export_result))
|
||||||
|
|
||||||
|
|
||||||
@jobController.get(
|
@job_controller.get(
|
||||||
'/jobLog/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))]
|
'/jobLog/list',
|
||||||
|
summary='获取定时任务调度日志分页列表接口',
|
||||||
|
description='用于获取定时任务调度日志分页列表',
|
||||||
|
response_model=PageResponseModel[JobLogModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:list')],
|
||||||
)
|
)
|
||||||
async def get_system_job_log_list(
|
async def get_system_job_log_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_query),
|
job_log_page_query: Annotated[JobLogPageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
job_log_page_query_result = await JobLogService.get_job_log_list_services(
|
job_log_page_query_result = await JobLogService.get_job_log_list_services(
|
||||||
query_db, job_log_page_query, is_page=True
|
query_db, job_log_page_query, is_page=True
|
||||||
@@ -160,18 +235,37 @@ async def get_system_job_log_list(
|
|||||||
return ResponseUtil.success(model_content=job_log_page_query_result)
|
return ResponseUtil.success(model_content=job_log_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@jobController.delete('/jobLog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))])
|
@job_controller.delete(
|
||||||
|
'/jobLog/clean',
|
||||||
|
summary='清空定时任务调度日志接口',
|
||||||
|
description='用于清空所有定时任务调度日志',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:remove')],
|
||||||
|
)
|
||||||
@Log(title='定时任务调度日志', business_type=BusinessType.CLEAN)
|
@Log(title='定时任务调度日志', business_type=BusinessType.CLEAN)
|
||||||
async def clear_system_job_log(request: Request, query_db: AsyncSession = Depends(get_db)):
|
async def clear_system_job_log(
|
||||||
|
request: Request,
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
clear_job_log_result = await JobLogService.clear_job_log_services(query_db)
|
clear_job_log_result = await JobLogService.clear_job_log_services(query_db)
|
||||||
logger.info(clear_job_log_result.message)
|
logger.info(clear_job_log_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=clear_job_log_result.message)
|
return ResponseUtil.success(msg=clear_job_log_result.message)
|
||||||
|
|
||||||
|
|
||||||
@jobController.delete('/jobLog/{job_log_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))])
|
@job_controller.delete(
|
||||||
|
'/jobLog/{job_log_ids}',
|
||||||
|
summary='删除定时任务调度日志接口',
|
||||||
|
description='用于删除定时任务调度日志',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:remove')],
|
||||||
|
)
|
||||||
@Log(title='定时任务调度日志', business_type=BusinessType.DELETE)
|
@Log(title='定时任务调度日志', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_job_log(request: Request, job_log_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_job_log(
|
||||||
|
request: Request,
|
||||||
|
job_log_ids: Annotated[str, Path(description='需要删除的定时任务日志ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_job_log = DeleteJobLogModel(jobLogIds=job_log_ids)
|
delete_job_log = DeleteJobLogModel(jobLogIds=job_log_ids)
|
||||||
delete_job_log_result = await JobLogService.delete_job_log_services(query_db, delete_job_log)
|
delete_job_log_result = await JobLogService.delete_job_log_services(query_db, delete_job_log)
|
||||||
logger.info(delete_job_log_result.message)
|
logger.info(delete_job_log_result.message)
|
||||||
@@ -179,13 +273,27 @@ async def delete_system_job_log(request: Request, job_log_ids: str, query_db: As
|
|||||||
return ResponseUtil.success(msg=delete_job_log_result.message)
|
return ResponseUtil.success(msg=delete_job_log_result.message)
|
||||||
|
|
||||||
|
|
||||||
@jobController.post('/jobLog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))])
|
@job_controller.post(
|
||||||
|
'/jobLog/export',
|
||||||
|
summary='导出定时任务调度日志列表接口',
|
||||||
|
description='用于导出当前符合查询条件的定时任务调度日志列表数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回定时任务日志列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:job:export')],
|
||||||
|
)
|
||||||
@Log(title='定时任务调度日志', business_type=BusinessType.EXPORT)
|
@Log(title='定时任务调度日志', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_job_log_list(
|
async def export_system_job_log_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
job_log_page_query: JobLogPageQueryModel = Form(),
|
job_log_page_query: Annotated[JobLogPageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
job_log_query_result = await JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=False)
|
job_log_query_result = await JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=False)
|
||||||
job_log_export_result = await JobLogService.export_job_log_list_services(request, job_log_query_result)
|
job_log_export_result = await JobLogService.export_job_log_list_services(request, job_log_query_result)
|
||||||
|
|||||||
@@ -1,37 +1,47 @@
|
|||||||
from fastapi import APIRouter, Depends, Form, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Form, Path, Query, Request, Response
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.get_db import get_db
|
from common.annotation.log_annotation import Log
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import PageResponseModel, ResponseBaseModel
|
||||||
from module_admin.entity.vo.log_vo import (
|
from module_admin.entity.vo.log_vo import (
|
||||||
DeleteLoginLogModel,
|
DeleteLoginLogModel,
|
||||||
DeleteOperLogModel,
|
DeleteOperLogModel,
|
||||||
|
LogininforModel,
|
||||||
LoginLogPageQueryModel,
|
LoginLogPageQueryModel,
|
||||||
|
OperLogModel,
|
||||||
OperLogPageQueryModel,
|
OperLogPageQueryModel,
|
||||||
UnlockUser,
|
UnlockUser,
|
||||||
)
|
)
|
||||||
from module_admin.service.log_service import LoginLogService, OperationLogService
|
from module_admin.service.log_service import LoginLogService, OperationLogService
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from utils.common_util import bytes2file_response
|
from utils.common_util import bytes2file_response
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
log_controller = APIRouterPro(
|
||||||
logController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/monitor', order_num=11, tags=['系统管理-日志管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@logController.get(
|
@log_controller.get(
|
||||||
'/operlog/list',
|
'/operlog/list',
|
||||||
response_model=PageResponseModel,
|
summary='获取操作日志分页列表接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:list'))],
|
description='用于获取操作日志分页列表',
|
||||||
|
response_model=PageResponseModel[OperLogModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:operlog:list')],
|
||||||
)
|
)
|
||||||
async def get_system_operation_log_list(
|
async def get_system_operation_log_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_query),
|
operation_log_page_query: Annotated[OperLogPageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
operation_log_page_query_result = await OperationLogService.get_operation_log_list_services(
|
operation_log_page_query_result = await OperationLogService.get_operation_log_list_services(
|
||||||
query_db, operation_log_page_query, is_page=True
|
query_db, operation_log_page_query, is_page=True
|
||||||
@@ -41,18 +51,36 @@ async def get_system_operation_log_list(
|
|||||||
return ResponseUtil.success(model_content=operation_log_page_query_result)
|
return ResponseUtil.success(model_content=operation_log_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@logController.delete('/operlog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))])
|
@log_controller.delete(
|
||||||
|
'/operlog/clean',
|
||||||
|
summary='清空操作日志接口',
|
||||||
|
description='用于清空所有操作日志',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:operlog:remove')],
|
||||||
|
)
|
||||||
@Log(title='操作日志', business_type=BusinessType.CLEAN)
|
@Log(title='操作日志', business_type=BusinessType.CLEAN)
|
||||||
async def clear_system_operation_log(request: Request, query_db: AsyncSession = Depends(get_db)):
|
async def clear_system_operation_log(
|
||||||
|
request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
|
||||||
|
) -> Response:
|
||||||
clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db)
|
clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db)
|
||||||
logger.info(clear_operation_log_result.message)
|
logger.info(clear_operation_log_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=clear_operation_log_result.message)
|
return ResponseUtil.success(msg=clear_operation_log_result.message)
|
||||||
|
|
||||||
|
|
||||||
@logController.delete('/operlog/{oper_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))])
|
@log_controller.delete(
|
||||||
|
'/operlog/{oper_ids}',
|
||||||
|
summary='删除操作日志接口',
|
||||||
|
description='用于删除操作日志',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:operlog:remove')],
|
||||||
|
)
|
||||||
@Log(title='操作日志', business_type=BusinessType.DELETE)
|
@Log(title='操作日志', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_operation_log(request: Request, oper_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_operation_log(
|
||||||
|
request: Request,
|
||||||
|
oper_ids: Annotated[str, Path(description='需要删除的日志主键')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_operation_log = DeleteOperLogModel(operIds=oper_ids)
|
delete_operation_log = DeleteOperLogModel(operIds=oper_ids)
|
||||||
delete_operation_log_result = await OperationLogService.delete_operation_log_services(
|
delete_operation_log_result = await OperationLogService.delete_operation_log_services(
|
||||||
query_db, delete_operation_log
|
query_db, delete_operation_log
|
||||||
@@ -62,13 +90,27 @@ async def delete_system_operation_log(request: Request, oper_ids: str, query_db:
|
|||||||
return ResponseUtil.success(msg=delete_operation_log_result.message)
|
return ResponseUtil.success(msg=delete_operation_log_result.message)
|
||||||
|
|
||||||
|
|
||||||
@logController.post('/operlog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))])
|
@log_controller.post(
|
||||||
|
'/operlog/export',
|
||||||
|
summary='导出操作日志接口',
|
||||||
|
description='用于导出当前符合查询条件的操作日志数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回操作日志列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:operlog:export')],
|
||||||
|
)
|
||||||
@Log(title='操作日志', business_type=BusinessType.EXPORT)
|
@Log(title='操作日志', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_operation_log_list(
|
async def export_system_operation_log_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
operation_log_page_query: OperLogPageQueryModel = Form(),
|
operation_log_page_query: Annotated[OperLogPageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
operation_log_query_result = await OperationLogService.get_operation_log_list_services(
|
operation_log_query_result = await OperationLogService.get_operation_log_list_services(
|
||||||
query_db, operation_log_page_query, is_page=False
|
query_db, operation_log_page_query, is_page=False
|
||||||
@@ -81,16 +123,18 @@ async def export_system_operation_log_list(
|
|||||||
return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result))
|
return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result))
|
||||||
|
|
||||||
|
|
||||||
@logController.get(
|
@log_controller.get(
|
||||||
'/logininfor/list',
|
'/logininfor/list',
|
||||||
response_model=PageResponseModel,
|
summary='获取登录日志分页列表接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:list'))],
|
description='用于获取登录日志分页列表',
|
||||||
|
response_model=PageResponseModel[LogininforModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:list')],
|
||||||
)
|
)
|
||||||
async def get_system_login_log_list(
|
async def get_system_login_log_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_query),
|
login_log_page_query: Annotated[LoginLogPageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
login_log_page_query_result = await LoginLogService.get_login_log_list_services(
|
login_log_page_query_result = await LoginLogService.get_login_log_list_services(
|
||||||
query_db, login_log_page_query, is_page=True
|
query_db, login_log_page_query, is_page=True
|
||||||
@@ -100,20 +144,36 @@ async def get_system_login_log_list(
|
|||||||
return ResponseUtil.success(model_content=login_log_page_query_result)
|
return ResponseUtil.success(model_content=login_log_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@logController.delete('/logininfor/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))])
|
@log_controller.delete(
|
||||||
|
'/logininfor/clean',
|
||||||
|
summary='清空登录日志接口',
|
||||||
|
description='用于清空所有登录日志',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:remove')],
|
||||||
|
)
|
||||||
@Log(title='登录日志', business_type=BusinessType.CLEAN)
|
@Log(title='登录日志', business_type=BusinessType.CLEAN)
|
||||||
async def clear_system_login_log(request: Request, query_db: AsyncSession = Depends(get_db)):
|
async def clear_system_login_log(
|
||||||
|
request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
|
||||||
|
) -> Response:
|
||||||
clear_login_log_result = await LoginLogService.clear_login_log_services(query_db)
|
clear_login_log_result = await LoginLogService.clear_login_log_services(query_db)
|
||||||
logger.info(clear_login_log_result.message)
|
logger.info(clear_login_log_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=clear_login_log_result.message)
|
return ResponseUtil.success(msg=clear_login_log_result.message)
|
||||||
|
|
||||||
|
|
||||||
@logController.delete(
|
@log_controller.delete(
|
||||||
'/logininfor/{info_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]
|
'/logininfor/{info_ids}',
|
||||||
|
summary='删除登录日志接口',
|
||||||
|
description='用于删除登录日志',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:remove')],
|
||||||
)
|
)
|
||||||
@Log(title='登录日志', business_type=BusinessType.DELETE)
|
@Log(title='登录日志', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_login_log(request: Request, info_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_login_log(
|
||||||
|
request: Request,
|
||||||
|
info_ids: Annotated[str, Path(description='需要删除的访问ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_login_log = DeleteLoginLogModel(infoIds=info_ids)
|
delete_login_log = DeleteLoginLogModel(infoIds=info_ids)
|
||||||
delete_login_log_result = await LoginLogService.delete_login_log_services(query_db, delete_login_log)
|
delete_login_log_result = await LoginLogService.delete_login_log_services(query_db, delete_login_log)
|
||||||
logger.info(delete_login_log_result.message)
|
logger.info(delete_login_log_result.message)
|
||||||
@@ -121,11 +181,19 @@ async def delete_system_login_log(request: Request, info_ids: str, query_db: Asy
|
|||||||
return ResponseUtil.success(msg=delete_login_log_result.message)
|
return ResponseUtil.success(msg=delete_login_log_result.message)
|
||||||
|
|
||||||
|
|
||||||
@logController.get(
|
@log_controller.get(
|
||||||
'/logininfor/unlock/{user_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:unlock'))]
|
'/logininfor/unlock/{user_name}',
|
||||||
|
summary='解锁账户接口',
|
||||||
|
description='用于解锁指定用户账户',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:unlock')],
|
||||||
)
|
)
|
||||||
@Log(title='账户解锁', business_type=BusinessType.OTHER)
|
@Log(title='账户解锁', business_type=BusinessType.OTHER)
|
||||||
async def unlock_system_user(request: Request, user_name: str, query_db: AsyncSession = Depends(get_db)):
|
async def unlock_system_user(
|
||||||
|
request: Request,
|
||||||
|
user_name: Annotated[str, Path(description='用户名称')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
unlock_user = UnlockUser(userName=user_name)
|
unlock_user = UnlockUser(userName=user_name)
|
||||||
unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user)
|
unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user)
|
||||||
logger.info(unlock_user_result.message)
|
logger.info(unlock_user_result.message)
|
||||||
@@ -133,13 +201,27 @@ async def unlock_system_user(request: Request, user_name: str, query_db: AsyncSe
|
|||||||
return ResponseUtil.success(msg=unlock_user_result.message)
|
return ResponseUtil.success(msg=unlock_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@logController.post('/logininfor/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))])
|
@log_controller.post(
|
||||||
|
'/logininfor/export',
|
||||||
|
summary='导出登录日志接口',
|
||||||
|
description='用于导出当前符合查询条件的登录日志数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回登录日志列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:export')],
|
||||||
|
)
|
||||||
@Log(title='登录日志', business_type=BusinessType.EXPORT)
|
@Log(title='登录日志', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_login_log_list(
|
async def export_system_login_log_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
login_log_page_query: LoginLogPageQueryModel = Form(),
|
login_log_page_query: Annotated[LoginLogPageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
login_log_query_result = await LoginLogService.get_login_log_list_services(
|
login_log_query_result = await LoginLogService.get_login_log_list_services(
|
||||||
query_db, login_log_page_query, is_page=False
|
query_db, login_log_page_query, is_page=False
|
||||||
|
|||||||
@@ -1,35 +1,42 @@
|
|||||||
import jwt
|
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from fastapi import APIRouter, Depends, Request
|
from typing import Annotated, Optional
|
||||||
|
|
||||||
|
import jwt
|
||||||
|
from fastapi import Depends, Request, Response
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from typing import Optional
|
|
||||||
from config.enums import BusinessType, RedisInitKeyConfig
|
from common.annotation.log_annotation import Log
|
||||||
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
|
from common.aspect.pre_auth import CurrentUserDependency
|
||||||
|
from common.enums import BusinessType, RedisInitKeyConfig
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import CrudResponseModel, DataResponseModel, DynamicResponseModel, ResponseBaseModel
|
||||||
from config.env import AppConfig, JwtConfig
|
from config.env import AppConfig, JwtConfig
|
||||||
from config.get_db import get_db
|
from module_admin.entity.vo.login_vo import RouterModel, Token, UserLogin, UserRegister
|
||||||
from module_admin.annotation.log_annotation import Log
|
|
||||||
from module_admin.entity.vo.common_vo import CrudResponseModel
|
|
||||||
from module_admin.entity.vo.login_vo import UserLogin, UserRegister, Token
|
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel, EditUserModel
|
from module_admin.entity.vo.user_vo import CurrentUserModel, EditUserModel
|
||||||
from module_admin.service.login_service import CustomOAuth2PasswordRequestForm, LoginService, oauth2_scheme
|
from module_admin.service.login_service import CustomOAuth2PasswordRequestForm, LoginService, oauth2_scheme
|
||||||
from module_admin.service.user_service import UserService
|
from module_admin.service.user_service import UserService
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
login_controller = APIRouterPro(order_num=1, tags=['登录模块'])
|
||||||
loginController = APIRouter()
|
|
||||||
|
|
||||||
|
|
||||||
@loginController.post('/login', response_model=Token)
|
@login_controller.post(
|
||||||
|
'/login',
|
||||||
|
summary='登录接口',
|
||||||
|
description='用于用户登录',
|
||||||
|
response_model=DynamicResponseModel[Token],
|
||||||
|
)
|
||||||
@Log(title='用户登录', business_type=BusinessType.OTHER, log_type='login')
|
@Log(title='用户登录', business_type=BusinessType.OTHER, log_type='login')
|
||||||
async def login(
|
async def login(
|
||||||
request: Request, form_data: CustomOAuth2PasswordRequestForm = Depends(), query_db: AsyncSession = Depends(get_db)
|
request: Request,
|
||||||
):
|
form_data: Annotated[CustomOAuth2PasswordRequestForm, Depends()],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
captcha_enabled = (
|
captcha_enabled = (
|
||||||
True
|
await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') == 'true'
|
||||||
if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled')
|
|
||||||
== 'true'
|
|
||||||
else False
|
|
||||||
)
|
)
|
||||||
user = UserLogin(
|
user = UserLogin(
|
||||||
userName=form_data.username,
|
userName=form_data.username,
|
||||||
@@ -77,37 +84,56 @@ async def login(
|
|||||||
return ResponseUtil.success(msg='登录成功', dict_content={'token': access_token})
|
return ResponseUtil.success(msg='登录成功', dict_content={'token': access_token})
|
||||||
|
|
||||||
|
|
||||||
@loginController.get('/getInfo', response_model=CurrentUserModel)
|
@login_controller.get(
|
||||||
|
'/getInfo',
|
||||||
|
summary='获取用户信息接口',
|
||||||
|
description='用于获取当前登录用户的信息',
|
||||||
|
response_model=DynamicResponseModel[CurrentUserModel],
|
||||||
|
)
|
||||||
async def get_login_user_info(
|
async def get_login_user_info(
|
||||||
request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user)
|
request: Request, current_user: Annotated[CurrentUserModel, CurrentUserDependency()]
|
||||||
):
|
) -> Response:
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(model_content=current_user)
|
return ResponseUtil.success(model_content=current_user)
|
||||||
|
|
||||||
|
|
||||||
@loginController.get('/getRouters')
|
@login_controller.get(
|
||||||
|
'/getRouters',
|
||||||
|
summary='获取用户路由接口',
|
||||||
|
description='用于获取当前登录用户的路由信息',
|
||||||
|
response_model=DataResponseModel[list[RouterModel]],
|
||||||
|
)
|
||||||
async def get_login_user_routers(
|
async def get_login_user_routers(
|
||||||
request: Request,
|
request: Request,
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
user_routers = await LoginService.get_current_user_routers(current_user.user.user_id, query_db)
|
user_routers = await LoginService.get_current_user_routers(current_user.user.user_id, query_db)
|
||||||
|
|
||||||
return ResponseUtil.success(data=user_routers)
|
return ResponseUtil.success(data=user_routers)
|
||||||
|
|
||||||
|
|
||||||
@loginController.post('/register', response_model=CrudResponseModel)
|
@login_controller.post(
|
||||||
async def register_user(request: Request, user_register: UserRegister, query_db: AsyncSession = Depends(get_db)):
|
'/register',
|
||||||
|
summary='注册接口',
|
||||||
|
description='用于用户注册',
|
||||||
|
response_model=DataResponseModel[CrudResponseModel],
|
||||||
|
)
|
||||||
|
async def register_user(
|
||||||
|
request: Request,
|
||||||
|
user_register: UserRegister,
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
user_register_result = await LoginService.register_user_services(request, query_db, user_register)
|
user_register_result = await LoginService.register_user_services(request, query_db, user_register)
|
||||||
logger.info(user_register_result.message)
|
logger.info(user_register_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(data=user_register_result, msg=user_register_result.message)
|
return ResponseUtil.success(data=user_register_result, msg=user_register_result.message)
|
||||||
|
|
||||||
|
|
||||||
# @loginController.post("/getSmsCode", response_model=SmsCode)
|
# @login_controller.post("/getSmsCode", response_model=SmsCode)
|
||||||
# async def get_sms_code(request: Request, user: ResetUserModel, query_db: AsyncSession = Depends(get_db)):
|
# async def get_sms_code(request: Request, user: ResetUserModel, query_db: AsyncSession = DBSessionDependency()):
|
||||||
# try:
|
# try:
|
||||||
# sms_result = await LoginService.get_sms_code_services(request, query_db, user)
|
# sms_result = await LoginService.get_sms_code_services(request, query_db, user)
|
||||||
# if sms_result.is_success:
|
# if sms_result.is_success:
|
||||||
@@ -121,8 +147,8 @@ async def register_user(request: Request, user_register: UserRegister, query_db:
|
|||||||
# return ResponseUtil.error(msg=str(e))
|
# return ResponseUtil.error(msg=str(e))
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
# @loginController.post("/forgetPwd", response_model=CrudResponseModel)
|
# @login_controller.post("/forgetPwd", response_model=CrudResponseModel)
|
||||||
# async def forget_user_pwd(request: Request, forget_user: ResetUserModel, query_db: AsyncSession = Depends(get_db)):
|
# async def forget_user_pwd(request: Request, forget_user: ResetUserModel, query_db: AsyncSession = DBSessionDependency()):
|
||||||
# try:
|
# try:
|
||||||
# forget_user_result = await LoginService.forget_user_services(request, query_db, forget_user)
|
# forget_user_result = await LoginService.forget_user_services(request, query_db, forget_user)
|
||||||
# if forget_user_result.is_success:
|
# if forget_user_result.is_success:
|
||||||
@@ -136,8 +162,13 @@ async def register_user(request: Request, user_register: UserRegister, query_db:
|
|||||||
# return ResponseUtil.error(msg=str(e))
|
# return ResponseUtil.error(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
@loginController.post('/logout')
|
@login_controller.post(
|
||||||
async def logout(request: Request, token: Optional[str] = Depends(oauth2_scheme)):
|
'/logout',
|
||||||
|
summary='退出登录接口',
|
||||||
|
description='用于用户退出登录',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
)
|
||||||
|
async def logout(request: Request, token: Annotated[Optional[str], Depends(oauth2_scheme)]) -> Response:
|
||||||
payload = jwt.decode(
|
payload = jwt.decode(
|
||||||
token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False}
|
token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,72 +1,98 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Path, Query, Request, Response
|
||||||
from pydantic_validation_decorator import ValidateFields
|
from pydantic_validation_decorator import ValidateFields
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from typing import List
|
|
||||||
from config.enums import BusinessType
|
from common.annotation.log_annotation import Log
|
||||||
from config.get_db import get_db
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuModel, MenuQueryModel
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, DynamicResponseModel, ResponseBaseModel
|
||||||
|
from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuModel, MenuQueryModel, MenuTreeModel
|
||||||
|
from module_admin.entity.vo.role_vo import RoleMenuQueryModel
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from module_admin.service.menu_service import MenuService
|
from module_admin.service.menu_service import MenuService
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
menu_controller = APIRouterPro(
|
||||||
menuController = APIRouter(prefix='/system/menu', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/system/menu', order_num=5, tags=['系统管理-菜单管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@menuController.get('/treeselect')
|
@menu_controller.get(
|
||||||
|
'/treeselect',
|
||||||
|
summary='获取菜单树接口',
|
||||||
|
description='用于获取当前用户可见的菜单树',
|
||||||
|
response_model=DataResponseModel[list[MenuTreeModel]],
|
||||||
|
)
|
||||||
async def get_system_menu_tree(
|
async def get_system_menu_tree(
|
||||||
request: Request,
|
request: Request,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
menu_query_result = await MenuService.get_menu_tree_services(query_db, current_user)
|
menu_query_result = await MenuService.get_menu_tree_services(query_db, current_user)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=menu_query_result)
|
return ResponseUtil.success(data=menu_query_result)
|
||||||
|
|
||||||
|
|
||||||
@menuController.get('/roleMenuTreeselect/{role_id}')
|
@menu_controller.get(
|
||||||
|
'/roleMenuTreeselect/{role_id}',
|
||||||
|
summary='获取角色菜单树接口',
|
||||||
|
description='用于获取指定角色可见的菜单树',
|
||||||
|
response_model=DynamicResponseModel[RoleMenuQueryModel],
|
||||||
|
)
|
||||||
async def get_system_role_menu_tree(
|
async def get_system_role_menu_tree(
|
||||||
request: Request,
|
request: Request,
|
||||||
role_id: int,
|
role_id: Annotated[int, Path(description='角色ID')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
role_menu_query_result = await MenuService.get_role_menu_tree_services(query_db, role_id, current_user)
|
role_menu_query_result = await MenuService.get_role_menu_tree_services(query_db, role_id, current_user)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(model_content=role_menu_query_result)
|
return ResponseUtil.success(model_content=role_menu_query_result)
|
||||||
|
|
||||||
|
|
||||||
@menuController.get(
|
@menu_controller.get(
|
||||||
'/list', response_model=List[MenuModel], dependencies=[Depends(CheckUserInterfaceAuth('system:menu:list'))]
|
'/list',
|
||||||
|
summary='获取菜单列表接口',
|
||||||
|
description='用于获取当前用户可见的菜单列表',
|
||||||
|
response_model=DataResponseModel[list[MenuModel]],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:menu:list')],
|
||||||
)
|
)
|
||||||
async def get_system_menu_list(
|
async def get_system_menu_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
menu_query: MenuQueryModel = Depends(MenuQueryModel.as_query),
|
menu_query: Annotated[MenuQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
menu_query_result = await MenuService.get_menu_list_services(query_db, menu_query, current_user)
|
menu_query_result = await MenuService.get_menu_list_services(query_db, menu_query, current_user)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=menu_query_result)
|
return ResponseUtil.success(data=menu_query_result)
|
||||||
|
|
||||||
|
|
||||||
@menuController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))])
|
@menu_controller.post(
|
||||||
|
'',
|
||||||
|
summary='新增菜单接口',
|
||||||
|
description='用于新增菜单',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:menu:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_menu')
|
@ValidateFields(validate_model='add_menu')
|
||||||
@Log(title='菜单管理', business_type=BusinessType.INSERT)
|
@Log(title='菜单管理', business_type=BusinessType.INSERT)
|
||||||
async def add_system_menu(
|
async def add_system_menu(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_menu: MenuModel,
|
add_menu: MenuModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
add_menu.create_by = current_user.user.user_name
|
add_menu.create_by = current_user.user.user_name
|
||||||
add_menu.create_time = datetime.now()
|
add_menu.create_time = datetime.now()
|
||||||
add_menu.update_by = current_user.user.user_name
|
add_menu.update_by = current_user.user.user_name
|
||||||
@@ -77,15 +103,21 @@ async def add_system_menu(
|
|||||||
return ResponseUtil.success(msg=add_menu_result.message)
|
return ResponseUtil.success(msg=add_menu_result.message)
|
||||||
|
|
||||||
|
|
||||||
@menuController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))])
|
@menu_controller.put(
|
||||||
|
'',
|
||||||
|
summary='编辑菜单接口',
|
||||||
|
description='用于编辑菜单',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:menu:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_menu')
|
@ValidateFields(validate_model='edit_menu')
|
||||||
@Log(title='菜单管理', business_type=BusinessType.UPDATE)
|
@Log(title='菜单管理', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_menu(
|
async def edit_system_menu(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_menu: MenuModel,
|
edit_menu: MenuModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
edit_menu.update_by = current_user.user.user_name
|
edit_menu.update_by = current_user.user.user_name
|
||||||
edit_menu.update_time = datetime.now()
|
edit_menu.update_time = datetime.now()
|
||||||
edit_menu_result = await MenuService.edit_menu_services(query_db, edit_menu)
|
edit_menu_result = await MenuService.edit_menu_services(query_db, edit_menu)
|
||||||
@@ -94,9 +126,19 @@ async def edit_system_menu(
|
|||||||
return ResponseUtil.success(msg=edit_menu_result.message)
|
return ResponseUtil.success(msg=edit_menu_result.message)
|
||||||
|
|
||||||
|
|
||||||
@menuController.delete('/{menu_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))])
|
@menu_controller.delete(
|
||||||
|
'/{menu_ids}',
|
||||||
|
summary='删除菜单接口',
|
||||||
|
description='用于删除菜单',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:menu:remove')],
|
||||||
|
)
|
||||||
@Log(title='菜单管理', business_type=BusinessType.DELETE)
|
@Log(title='菜单管理', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_menu(
|
||||||
|
request: Request,
|
||||||
|
menu_ids: Annotated[str, Path(description='需要删除的菜单ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_menu = DeleteMenuModel(menuIds=menu_ids)
|
delete_menu = DeleteMenuModel(menuIds=menu_ids)
|
||||||
delete_menu_result = await MenuService.delete_menu_services(query_db, delete_menu)
|
delete_menu_result = await MenuService.delete_menu_services(query_db, delete_menu)
|
||||||
logger.info(delete_menu_result.message)
|
logger.info(delete_menu_result.message)
|
||||||
@@ -104,10 +146,18 @@ async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSes
|
|||||||
return ResponseUtil.success(msg=delete_menu_result.message)
|
return ResponseUtil.success(msg=delete_menu_result.message)
|
||||||
|
|
||||||
|
|
||||||
@menuController.get(
|
@menu_controller.get(
|
||||||
'/{menu_id}', response_model=MenuModel, dependencies=[Depends(CheckUserInterfaceAuth('system:menu:query'))]
|
'/{menu_id}',
|
||||||
|
summary='获取菜单详情接口',
|
||||||
|
description='用于获取指定菜单的详情信息',
|
||||||
|
response_model=DataResponseModel[MenuModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:menu:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_menu(request: Request, menu_id: int, query_db: AsyncSession = Depends(get_db)):
|
async def query_detail_system_menu(
|
||||||
|
request: Request,
|
||||||
|
menu_id: Annotated[int, Path(description='菜单ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
menu_detail_result = await MenuService.menu_detail_services(query_db, menu_id)
|
menu_detail_result = await MenuService.menu_detail_services(query_db, menu_id)
|
||||||
logger.info(f'获取menu_id为{menu_id}的信息成功')
|
logger.info(f'获取menu_id为{menu_id}的信息成功')
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,40 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Path, Query, Request, Response
|
||||||
from pydantic_validation_decorator import ValidateFields
|
from pydantic_validation_decorator import ValidateFields
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.get_db import get_db
|
from common.annotation.log_annotation import Log
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
|
||||||
from module_admin.entity.vo.notice_vo import DeleteNoticeModel, NoticeModel, NoticePageQueryModel
|
from module_admin.entity.vo.notice_vo import DeleteNoticeModel, NoticeModel, NoticePageQueryModel
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from module_admin.service.notice_service import NoticeService
|
from module_admin.service.notice_service import NoticeService
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
notice_controller = APIRouterPro(
|
||||||
noticeController = APIRouter(prefix='/system/notice', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/system/notice', order_num=10, tags=['系统管理-通知公告管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@noticeController.get(
|
@notice_controller.get(
|
||||||
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:list'))]
|
'/list',
|
||||||
|
summary='获取通知公告分页列表接口',
|
||||||
|
description='用于获取通知公告分页列表',
|
||||||
|
response_model=PageResponseModel[NoticeModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:notice:list')],
|
||||||
)
|
)
|
||||||
async def get_system_notice_list(
|
async def get_system_notice_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
notice_page_query: NoticePageQueryModel = Depends(NoticePageQueryModel.as_query),
|
notice_page_query: Annotated[NoticePageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
notice_page_query_result = await NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True)
|
notice_page_query_result = await NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -33,15 +42,21 @@ async def get_system_notice_list(
|
|||||||
return ResponseUtil.success(model_content=notice_page_query_result)
|
return ResponseUtil.success(model_content=notice_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@noticeController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))])
|
@notice_controller.post(
|
||||||
|
'',
|
||||||
|
summary='新增通知公告接口',
|
||||||
|
description='用于新增通知公告',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:notice:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_notice')
|
@ValidateFields(validate_model='add_notice')
|
||||||
@Log(title='通知公告', business_type=BusinessType.INSERT)
|
@Log(title='通知公告', business_type=BusinessType.INSERT)
|
||||||
async def add_system_notice(
|
async def add_system_notice(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_notice: NoticeModel,
|
add_notice: NoticeModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
add_notice.create_by = current_user.user.user_name
|
add_notice.create_by = current_user.user.user_name
|
||||||
add_notice.create_time = datetime.now()
|
add_notice.create_time = datetime.now()
|
||||||
add_notice.update_by = current_user.user.user_name
|
add_notice.update_by = current_user.user.user_name
|
||||||
@@ -52,15 +67,21 @@ async def add_system_notice(
|
|||||||
return ResponseUtil.success(msg=add_notice_result.message)
|
return ResponseUtil.success(msg=add_notice_result.message)
|
||||||
|
|
||||||
|
|
||||||
@noticeController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))])
|
@notice_controller.put(
|
||||||
|
'',
|
||||||
|
summary='编辑通知公告接口',
|
||||||
|
description='用于编辑通知公告',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:notice:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_notice')
|
@ValidateFields(validate_model='edit_notice')
|
||||||
@Log(title='通知公告', business_type=BusinessType.UPDATE)
|
@Log(title='通知公告', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_notice(
|
async def edit_system_notice(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_notice: NoticeModel,
|
edit_notice: NoticeModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
edit_notice.update_by = current_user.user.user_name
|
edit_notice.update_by = current_user.user.user_name
|
||||||
edit_notice.update_time = datetime.now()
|
edit_notice.update_time = datetime.now()
|
||||||
edit_notice_result = await NoticeService.edit_notice_services(query_db, edit_notice)
|
edit_notice_result = await NoticeService.edit_notice_services(query_db, edit_notice)
|
||||||
@@ -69,9 +90,19 @@ async def edit_system_notice(
|
|||||||
return ResponseUtil.success(msg=edit_notice_result.message)
|
return ResponseUtil.success(msg=edit_notice_result.message)
|
||||||
|
|
||||||
|
|
||||||
@noticeController.delete('/{notice_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))])
|
@notice_controller.delete(
|
||||||
|
'/{notice_ids}',
|
||||||
|
summary='删除通知公告接口',
|
||||||
|
description='用于删除通知公告',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:notice:remove')],
|
||||||
|
)
|
||||||
@Log(title='通知公告', business_type=BusinessType.DELETE)
|
@Log(title='通知公告', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_notice(request: Request, notice_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_system_notice(
|
||||||
|
request: Request,
|
||||||
|
notice_ids: Annotated[str, Path(description='需要删除的公告ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_notice = DeleteNoticeModel(noticeIds=notice_ids)
|
delete_notice = DeleteNoticeModel(noticeIds=notice_ids)
|
||||||
delete_notice_result = await NoticeService.delete_notice_services(query_db, delete_notice)
|
delete_notice_result = await NoticeService.delete_notice_services(query_db, delete_notice)
|
||||||
logger.info(delete_notice_result.message)
|
logger.info(delete_notice_result.message)
|
||||||
@@ -79,10 +110,18 @@ async def delete_system_notice(request: Request, notice_ids: str, query_db: Asyn
|
|||||||
return ResponseUtil.success(msg=delete_notice_result.message)
|
return ResponseUtil.success(msg=delete_notice_result.message)
|
||||||
|
|
||||||
|
|
||||||
@noticeController.get(
|
@notice_controller.get(
|
||||||
'/{notice_id}', response_model=NoticeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:query'))]
|
'/{notice_id}',
|
||||||
|
summary='获取通知公告详情接口',
|
||||||
|
description='用于获取指定通知公告的详细信息',
|
||||||
|
response_model=DataResponseModel[NoticeModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:notice:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_post(request: Request, notice_id: int, query_db: AsyncSession = Depends(get_db)):
|
async def query_detail_system_post(
|
||||||
|
request: Request,
|
||||||
|
notice_id: Annotated[int, Path(description='公告ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
notice_detail_result = await NoticeService.notice_detail_services(query_db, notice_id)
|
notice_detail_result = await NoticeService.notice_detail_services(query_db, notice_id)
|
||||||
logger.info(f'获取notice_id为{notice_id}的信息成功')
|
logger.info(f'获取notice_id为{notice_id}的信息成功')
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,58 @@
|
|||||||
from fastapi import APIRouter, Depends, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Path, Query, Request, Response
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.get_db import get_db
|
from common.annotation.log_annotation import Log
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
from module_admin.entity.vo.online_vo import DeleteOnlineModel, OnlineQueryModel
|
from common.aspect.pre_auth import PreAuthDependency
|
||||||
from module_admin.service.login_service import LoginService
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import ResponseBaseModel
|
||||||
|
from module_admin.entity.vo.online_vo import DeleteOnlineModel, OnlinePageResponseModel, OnlineQueryModel
|
||||||
from module_admin.service.online_service import OnlineService
|
from module_admin.service.online_service import OnlineService
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
online_controller = APIRouterPro(
|
||||||
onlineController = APIRouter(prefix='/monitor/online', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/monitor/online', order_num=12, tags=['系统监控-在线用户'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@onlineController.get(
|
@online_controller.get(
|
||||||
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:list'))]
|
'/list',
|
||||||
|
summary='获取在线用户分页列表接口',
|
||||||
|
description='用于获取在线用户分页列表',
|
||||||
|
response_model=OnlinePageResponseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:online:list')],
|
||||||
)
|
)
|
||||||
async def get_monitor_online_list(
|
async def get_monitor_online_list(
|
||||||
request: Request, online_page_query: OnlineQueryModel = Depends(OnlineQueryModel.as_query)
|
request: Request,
|
||||||
):
|
online_page_query: Annotated[OnlineQueryModel, Query()],
|
||||||
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
online_query_result = await OnlineService.get_online_list_services(request, online_page_query)
|
online_query_result = await OnlineService.get_online_list_services(request, online_page_query)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(
|
return ResponseUtil.success(
|
||||||
model_content=PageResponseModel(rows=online_query_result, total=len(online_query_result))
|
model_content=OnlinePageResponseModel(rows=online_query_result, total=len(online_query_result))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@onlineController.delete('/{token_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))])
|
@online_controller.delete(
|
||||||
|
'/{token_ids}',
|
||||||
|
summary='强退在线用户接口',
|
||||||
|
description='用于强退指定会话编号的在线用户',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:online:forceLogout')],
|
||||||
|
)
|
||||||
@Log(title='在线用户', business_type=BusinessType.FORCE)
|
@Log(title='在线用户', business_type=BusinessType.FORCE)
|
||||||
async def delete_monitor_online(request: Request, token_ids: str, query_db: AsyncSession = Depends(get_db)):
|
async def delete_monitor_online(
|
||||||
|
request: Request,
|
||||||
|
token_ids: Annotated[str, Path(description='需要强退的会话编号')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
delete_online = DeleteOnlineModel(tokenIds=token_ids)
|
delete_online = DeleteOnlineModel(tokenIds=token_ids)
|
||||||
delete_online_result = await OnlineService.delete_online_services(request, delete_online)
|
delete_online_result = await OnlineService.delete_online_services(request, delete_online)
|
||||||
logger.info(delete_online_result.message)
|
logger.info(delete_online_result.message)
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
from fastapi import APIRouter, Depends, Form, Request
|
|
||||||
from pydantic_validation_decorator import ValidateFields
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.get_db import get_db
|
|
||||||
from module_admin.annotation.log_annotation import Log
|
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from module_admin.service.post_service import PostService
|
|
||||||
from module_admin.entity.vo.post_vo import DeletePostModel, PostModel, PostPageQueryModel
|
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
|
||||||
from utils.common_util import bytes2file_response
|
|
||||||
from utils.log_util import logger
|
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.response_util import ResponseUtil
|
|
||||||
|
|
||||||
|
|
||||||
postController = APIRouter(prefix='/system/post', dependencies=[Depends(LoginService.get_current_user)])
|
|
||||||
|
|
||||||
|
|
||||||
@postController.get(
|
|
||||||
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:list'))]
|
|
||||||
)
|
|
||||||
async def get_system_post_list(
|
|
||||||
request: Request,
|
|
||||||
post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_query),
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
):
|
|
||||||
# 获取分页数据
|
|
||||||
post_page_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=True)
|
|
||||||
logger.info('获取成功')
|
|
||||||
|
|
||||||
return ResponseUtil.success(model_content=post_page_query_result)
|
|
||||||
|
|
||||||
|
|
||||||
@postController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))])
|
|
||||||
@ValidateFields(validate_model='add_post')
|
|
||||||
@Log(title='岗位管理', business_type=BusinessType.INSERT)
|
|
||||||
async def add_system_post(
|
|
||||||
request: Request,
|
|
||||||
add_post: PostModel,
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
|
||||||
):
|
|
||||||
add_post.create_by = current_user.user.user_name
|
|
||||||
add_post.create_time = datetime.now()
|
|
||||||
add_post.update_by = current_user.user.user_name
|
|
||||||
add_post.update_time = datetime.now()
|
|
||||||
add_post_result = await PostService.add_post_services(query_db, add_post)
|
|
||||||
logger.info(add_post_result.message)
|
|
||||||
|
|
||||||
return ResponseUtil.success(msg=add_post_result.message)
|
|
||||||
|
|
||||||
|
|
||||||
@postController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))])
|
|
||||||
@ValidateFields(validate_model='edit_post')
|
|
||||||
@Log(title='岗位管理', business_type=BusinessType.UPDATE)
|
|
||||||
async def edit_system_post(
|
|
||||||
request: Request,
|
|
||||||
edit_post: PostModel,
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
|
||||||
):
|
|
||||||
edit_post.update_by = current_user.user.user_name
|
|
||||||
edit_post.update_time = datetime.now()
|
|
||||||
edit_post_result = await PostService.edit_post_services(query_db, edit_post)
|
|
||||||
logger.info(edit_post_result.message)
|
|
||||||
|
|
||||||
return ResponseUtil.success(msg=edit_post_result.message)
|
|
||||||
|
|
||||||
|
|
||||||
@postController.delete('/{post_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))])
|
|
||||||
@Log(title='岗位管理', business_type=BusinessType.DELETE)
|
|
||||||
async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSession = Depends(get_db)):
|
|
||||||
delete_post = DeletePostModel(postIds=post_ids)
|
|
||||||
delete_post_result = await PostService.delete_post_services(query_db, delete_post)
|
|
||||||
logger.info(delete_post_result.message)
|
|
||||||
|
|
||||||
return ResponseUtil.success(msg=delete_post_result.message)
|
|
||||||
|
|
||||||
|
|
||||||
@postController.get(
|
|
||||||
'/{post_id}', response_model=PostModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:query'))]
|
|
||||||
)
|
|
||||||
async def query_detail_system_post(request: Request, post_id: int, query_db: AsyncSession = Depends(get_db)):
|
|
||||||
post_detail_result = await PostService.post_detail_services(query_db, post_id)
|
|
||||||
logger.info(f'获取post_id为{post_id}的信息成功')
|
|
||||||
|
|
||||||
return ResponseUtil.success(data=post_detail_result)
|
|
||||||
|
|
||||||
|
|
||||||
@postController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:post:export'))])
|
|
||||||
@Log(title='岗位管理', business_type=BusinessType.EXPORT)
|
|
||||||
async def export_system_post_list(
|
|
||||||
request: Request,
|
|
||||||
post_page_query: PostPageQueryModel = Form(),
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
):
|
|
||||||
# 获取全量数据
|
|
||||||
post_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=False)
|
|
||||||
post_export_result = await PostService.export_post_list_services(post_query_result)
|
|
||||||
logger.info('导出成功')
|
|
||||||
|
|
||||||
return ResponseUtil.streaming(data=bytes2file_response(post_export_result))
|
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Form, Path, Query, Request, Response
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
|
from pydantic_validation_decorator import ValidateFields
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.annotation.log_annotation import Log
|
||||||
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
|
||||||
|
from module_admin.entity.vo.post_vo import DeletePostModel, PostModel, PostPageQueryModel
|
||||||
|
from module_admin.entity.vo.user_vo import CurrentUserModel
|
||||||
|
from module_admin.service.post_service import PostService
|
||||||
|
from utils.common_util import bytes2file_response
|
||||||
|
from utils.log_util import logger
|
||||||
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
post_controller = APIRouterPro(
|
||||||
|
prefix='/system/post', order_num=7, tags=['系统管理-岗位管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@post_controller.get(
|
||||||
|
'/list',
|
||||||
|
summary='获取岗位分页列表接口',
|
||||||
|
description='用于获取岗位分页列表',
|
||||||
|
response_model=PageResponseModel[PostModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:post:list')],
|
||||||
|
)
|
||||||
|
async def get_system_post_list(
|
||||||
|
request: Request,
|
||||||
|
post_page_query: Annotated[PostPageQueryModel, Query()],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
|
# 获取分页数据
|
||||||
|
post_page_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=True)
|
||||||
|
logger.info('获取成功')
|
||||||
|
|
||||||
|
return ResponseUtil.success(model_content=post_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
|
@post_controller.post(
|
||||||
|
'',
|
||||||
|
summary='新增岗位接口',
|
||||||
|
description='用于新增岗位',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:post:add')],
|
||||||
|
)
|
||||||
|
@ValidateFields(validate_model='add_post')
|
||||||
|
@Log(title='岗位管理', business_type=BusinessType.INSERT)
|
||||||
|
async def add_system_post(
|
||||||
|
request: Request,
|
||||||
|
add_post: PostModel,
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
|
) -> Response:
|
||||||
|
add_post.create_by = current_user.user.user_name
|
||||||
|
add_post.create_time = datetime.now()
|
||||||
|
add_post.update_by = current_user.user.user_name
|
||||||
|
add_post.update_time = datetime.now()
|
||||||
|
add_post_result = await PostService.add_post_services(query_db, add_post)
|
||||||
|
logger.info(add_post_result.message)
|
||||||
|
|
||||||
|
return ResponseUtil.success(msg=add_post_result.message)
|
||||||
|
|
||||||
|
|
||||||
|
@post_controller.put(
|
||||||
|
'',
|
||||||
|
summary='编辑岗位接口',
|
||||||
|
description='用于编辑岗位',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:post:edit')],
|
||||||
|
)
|
||||||
|
@ValidateFields(validate_model='edit_post')
|
||||||
|
@Log(title='岗位管理', business_type=BusinessType.UPDATE)
|
||||||
|
async def edit_system_post(
|
||||||
|
request: Request,
|
||||||
|
edit_post: PostModel,
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
|
) -> Response:
|
||||||
|
edit_post.update_by = current_user.user.user_name
|
||||||
|
edit_post.update_time = datetime.now()
|
||||||
|
edit_post_result = await PostService.edit_post_services(query_db, edit_post)
|
||||||
|
logger.info(edit_post_result.message)
|
||||||
|
|
||||||
|
return ResponseUtil.success(msg=edit_post_result.message)
|
||||||
|
|
||||||
|
|
||||||
|
@post_controller.delete(
|
||||||
|
'/{post_ids}',
|
||||||
|
summary='删除岗位接口',
|
||||||
|
description='用于删除岗位',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:post:remove')],
|
||||||
|
)
|
||||||
|
@Log(title='岗位管理', business_type=BusinessType.DELETE)
|
||||||
|
async def delete_system_post(
|
||||||
|
request: Request,
|
||||||
|
post_ids: Annotated[str, Path(description='需要删除的岗位ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
|
delete_post = DeletePostModel(postIds=post_ids)
|
||||||
|
delete_post_result = await PostService.delete_post_services(query_db, delete_post)
|
||||||
|
logger.info(delete_post_result.message)
|
||||||
|
|
||||||
|
return ResponseUtil.success(msg=delete_post_result.message)
|
||||||
|
|
||||||
|
|
||||||
|
@post_controller.get(
|
||||||
|
'/{post_id}',
|
||||||
|
summary='获取岗位详情接口',
|
||||||
|
description='用于获取指定岗位的详细信息',
|
||||||
|
response_model=DataResponseModel[PostModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:post:query')],
|
||||||
|
)
|
||||||
|
async def query_detail_system_post(
|
||||||
|
request: Request,
|
||||||
|
post_id: Annotated[int, Path(description='岗位ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
|
post_detail_result = await PostService.post_detail_services(query_db, post_id)
|
||||||
|
logger.info(f'获取post_id为{post_id}的信息成功')
|
||||||
|
|
||||||
|
return ResponseUtil.success(data=post_detail_result)
|
||||||
|
|
||||||
|
|
||||||
|
@post_controller.post(
|
||||||
|
'/export',
|
||||||
|
summary='导出岗位列表接口',
|
||||||
|
description='用于导出当前符合查询条件的岗位列表数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回岗位列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:post:export')],
|
||||||
|
)
|
||||||
|
@Log(title='岗位管理', business_type=BusinessType.EXPORT)
|
||||||
|
async def export_system_post_list(
|
||||||
|
request: Request,
|
||||||
|
post_page_query: Annotated[PostPageQueryModel, Form()],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
|
# 获取全量数据
|
||||||
|
post_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=False)
|
||||||
|
post_export_result = await PostService.export_post_list_services(post_query_result)
|
||||||
|
logger.info('导出成功')
|
||||||
|
|
||||||
|
return ResponseUtil.streaming(data=bytes2file_response(post_export_result))
|
||||||
@@ -1,36 +1,54 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, Form, Request
|
from typing import Annotated
|
||||||
|
|
||||||
|
from fastapi import Form, Path, Query, Request, Response
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
from pydantic_validation_decorator import ValidateFields
|
from pydantic_validation_decorator import ValidateFields
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.get_db import get_db
|
from common.annotation.log_annotation import Log
|
||||||
from module_admin.annotation.log_annotation import Log
|
from common.aspect.data_scope import DataScopeDependency
|
||||||
from module_admin.aspect.data_scope import GetDataScope
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, DynamicResponseModel, PageResponseModel, ResponseBaseModel
|
||||||
from module_admin.entity.vo.dept_vo import DeptModel
|
from module_admin.entity.vo.dept_vo import DeptModel
|
||||||
from module_admin.entity.vo.role_vo import AddRoleModel, DeleteRoleModel, RoleModel, RolePageQueryModel
|
from module_admin.entity.vo.role_vo import (
|
||||||
from module_admin.entity.vo.user_vo import CrudUserRoleModel, CurrentUserModel, UserRolePageQueryModel
|
AddRoleModel,
|
||||||
|
DeleteRoleModel,
|
||||||
|
RoleDeptQueryModel,
|
||||||
|
RoleModel,
|
||||||
|
RolePageQueryModel,
|
||||||
|
)
|
||||||
|
from module_admin.entity.vo.user_vo import CrudUserRoleModel, CurrentUserModel, UserInfoModel, UserRolePageQueryModel
|
||||||
from module_admin.service.dept_service import DeptService
|
from module_admin.service.dept_service import DeptService
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from module_admin.service.role_service import RoleService
|
from module_admin.service.role_service import RoleService
|
||||||
from module_admin.service.user_service import UserService
|
from module_admin.service.user_service import UserService
|
||||||
from utils.common_util import bytes2file_response
|
from utils.common_util import bytes2file_response
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
role_controller = APIRouterPro(
|
||||||
roleController = APIRouter(prefix='/system/role', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/system/role', order_num=4, tags=['系统管理-角色管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@roleController.get('/deptTree/{role_id}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))])
|
@role_controller.get(
|
||||||
|
'/deptTree/{role_id}',
|
||||||
|
summary='获取自定义数据权限时可见的部门树接口',
|
||||||
|
description='用于自定义数据权限时获取当前用户可见的部门树',
|
||||||
|
response_model=DynamicResponseModel[RoleDeptQueryModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:query')],
|
||||||
|
)
|
||||||
async def get_system_role_dept_tree(
|
async def get_system_role_dept_tree(
|
||||||
request: Request,
|
request: Request,
|
||||||
role_id: int,
|
role_id: Annotated[int, Path(description='角色ID')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql)
|
dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(), data_scope_sql)
|
||||||
role_dept_query_result = await RoleService.get_role_dept_tree_services(query_db, role_id)
|
role_dept_query_result = await RoleService.get_role_dept_tree_services(query_db, role_id)
|
||||||
role_dept_query_result.depts = dept_query_result
|
role_dept_query_result.depts = dept_query_result
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
@@ -38,15 +56,19 @@ async def get_system_role_dept_tree(
|
|||||||
return ResponseUtil.success(model_content=role_dept_query_result)
|
return ResponseUtil.success(model_content=role_dept_query_result)
|
||||||
|
|
||||||
|
|
||||||
@roleController.get(
|
@role_controller.get(
|
||||||
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]
|
'/list',
|
||||||
|
summary='获取角色分页列表接口',
|
||||||
|
description='用于获取角色分页列表',
|
||||||
|
response_model=PageResponseModel[RoleModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:list')],
|
||||||
)
|
)
|
||||||
async def get_system_role_list(
|
async def get_system_role_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query),
|
role_page_query: Annotated[RolePageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
role_page_query_result = await RoleService.get_role_list_services(
|
role_page_query_result = await RoleService.get_role_list_services(
|
||||||
query_db, role_page_query, data_scope_sql, is_page=True
|
query_db, role_page_query, data_scope_sql, is_page=True
|
||||||
)
|
)
|
||||||
@@ -55,15 +77,21 @@ async def get_system_role_list(
|
|||||||
return ResponseUtil.success(model_content=role_page_query_result)
|
return ResponseUtil.success(model_content=role_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@roleController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))])
|
@role_controller.post(
|
||||||
|
'',
|
||||||
|
summary='新增角色接口',
|
||||||
|
description='用于新增角色',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_role')
|
@ValidateFields(validate_model='add_role')
|
||||||
@Log(title='角色管理', business_type=BusinessType.INSERT)
|
@Log(title='角色管理', business_type=BusinessType.INSERT)
|
||||||
async def add_system_role(
|
async def add_system_role(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_role: AddRoleModel,
|
add_role: AddRoleModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
add_role.create_by = current_user.user.user_name
|
add_role.create_by = current_user.user.user_name
|
||||||
add_role.create_time = datetime.now()
|
add_role.create_time = datetime.now()
|
||||||
add_role.update_by = current_user.user.user_name
|
add_role.update_by = current_user.user.user_name
|
||||||
@@ -74,16 +102,22 @@ async def add_system_role(
|
|||||||
return ResponseUtil.success(msg=add_role_result.message)
|
return ResponseUtil.success(msg=add_role_result.message)
|
||||||
|
|
||||||
|
|
||||||
@roleController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
|
@role_controller.put(
|
||||||
|
'',
|
||||||
|
summary='编辑角色接口',
|
||||||
|
description='用于编辑角色',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_role')
|
@ValidateFields(validate_model='edit_role')
|
||||||
@Log(title='角色管理', business_type=BusinessType.UPDATE)
|
@Log(title='角色管理', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_role(
|
async def edit_system_role(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_role: AddRoleModel,
|
edit_role: AddRoleModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
await RoleService.check_role_allowed_services(edit_role)
|
await RoleService.check_role_allowed_services(edit_role)
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await RoleService.check_role_data_scope_services(query_db, str(edit_role.role_id), data_scope_sql)
|
await RoleService.check_role_data_scope_services(query_db, str(edit_role.role_id), data_scope_sql)
|
||||||
@@ -95,15 +129,21 @@ async def edit_system_role(
|
|||||||
return ResponseUtil.success(msg=edit_role_result.message)
|
return ResponseUtil.success(msg=edit_role_result.message)
|
||||||
|
|
||||||
|
|
||||||
@roleController.put('/dataScope', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
|
@role_controller.put(
|
||||||
|
'/dataScope',
|
||||||
|
summary='编辑角色数据权限接口',
|
||||||
|
description='用于编辑角色数据权限',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
|
||||||
|
)
|
||||||
@Log(title='角色管理', business_type=BusinessType.GRANT)
|
@Log(title='角色管理', business_type=BusinessType.GRANT)
|
||||||
async def edit_system_role_datascope(
|
async def edit_system_role_datascope(
|
||||||
request: Request,
|
request: Request,
|
||||||
role_data_scope: AddRoleModel,
|
role_data_scope: AddRoleModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
await RoleService.check_role_allowed_services(role_data_scope)
|
await RoleService.check_role_allowed_services(role_data_scope)
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await RoleService.check_role_data_scope_services(query_db, str(role_data_scope.role_id), data_scope_sql)
|
await RoleService.check_role_data_scope_services(query_db, str(role_data_scope.role_id), data_scope_sql)
|
||||||
@@ -121,15 +161,21 @@ async def edit_system_role_datascope(
|
|||||||
return ResponseUtil.success(msg=role_data_scope_result.message)
|
return ResponseUtil.success(msg=role_data_scope_result.message)
|
||||||
|
|
||||||
|
|
||||||
@roleController.delete('/{role_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))])
|
@role_controller.delete(
|
||||||
|
'/{role_ids}',
|
||||||
|
summary='删除角色接口',
|
||||||
|
description='用于删除角色',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:remove')],
|
||||||
|
)
|
||||||
@Log(title='角色管理', business_type=BusinessType.DELETE)
|
@Log(title='角色管理', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_role(
|
async def delete_system_role(
|
||||||
request: Request,
|
request: Request,
|
||||||
role_ids: str,
|
role_ids: Annotated[str, Path(description='需要删除的角色ID')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
role_id_list = role_ids.split(',') if role_ids else []
|
role_id_list = role_ids.split(',') if role_ids else []
|
||||||
if role_id_list:
|
if role_id_list:
|
||||||
for role_id in role_id_list:
|
for role_id in role_id_list:
|
||||||
@@ -143,16 +189,20 @@ async def delete_system_role(
|
|||||||
return ResponseUtil.success(msg=delete_role_result.message)
|
return ResponseUtil.success(msg=delete_role_result.message)
|
||||||
|
|
||||||
|
|
||||||
@roleController.get(
|
@role_controller.get(
|
||||||
'/{role_id}', response_model=RoleModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]
|
'/{role_id}',
|
||||||
|
summary='获取角色详情接口',
|
||||||
|
description='用于获取指定角色的详细信息',
|
||||||
|
response_model=DataResponseModel[RoleModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_role(
|
async def query_detail_system_role(
|
||||||
request: Request,
|
request: Request,
|
||||||
role_id: int,
|
role_id: Annotated[int, Path(description='角色ID')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await RoleService.check_role_data_scope_services(query_db, str(role_id), data_scope_sql)
|
await RoleService.check_role_data_scope_services(query_db, str(role_id), data_scope_sql)
|
||||||
role_detail_result = await RoleService.role_detail_services(query_db, role_id)
|
role_detail_result = await RoleService.role_detail_services(query_db, role_id)
|
||||||
@@ -161,14 +211,28 @@ async def query_detail_system_role(
|
|||||||
return ResponseUtil.success(data=role_detail_result.model_dump(by_alias=True))
|
return ResponseUtil.success(data=role_detail_result.model_dump(by_alias=True))
|
||||||
|
|
||||||
|
|
||||||
@roleController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))])
|
@role_controller.post(
|
||||||
|
'/export',
|
||||||
|
summary='导出角色列表接口',
|
||||||
|
description='用于导出当前符合查询条件的角色列表数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回角色列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:export')],
|
||||||
|
)
|
||||||
@Log(title='角色管理', business_type=BusinessType.EXPORT)
|
@Log(title='角色管理', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_role_list(
|
async def export_system_role_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
role_page_query: RolePageQueryModel = Form(),
|
role_page_query: Annotated[RolePageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
role_query_result = await RoleService.get_role_list_services(
|
role_query_result = await RoleService.get_role_list_services(
|
||||||
query_db, role_page_query, data_scope_sql, is_page=False
|
query_db, role_page_query, data_scope_sql, is_page=False
|
||||||
@@ -179,15 +243,21 @@ async def export_system_role_list(
|
|||||||
return ResponseUtil.streaming(data=bytes2file_response(role_export_result))
|
return ResponseUtil.streaming(data=bytes2file_response(role_export_result))
|
||||||
|
|
||||||
|
|
||||||
@roleController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
|
@role_controller.put(
|
||||||
|
'/changeStatus',
|
||||||
|
summary='修改角色状态接口',
|
||||||
|
description='用于修改角色状态',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
|
||||||
|
)
|
||||||
@Log(title='角色管理', business_type=BusinessType.UPDATE)
|
@Log(title='角色管理', business_type=BusinessType.UPDATE)
|
||||||
async def reset_system_role_status(
|
async def reset_system_role_status(
|
||||||
request: Request,
|
request: Request,
|
||||||
change_role: AddRoleModel,
|
change_role: AddRoleModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
await RoleService.check_role_allowed_services(change_role)
|
await RoleService.check_role_allowed_services(change_role)
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await RoleService.check_role_data_scope_services(query_db, str(change_role.role_id), data_scope_sql)
|
await RoleService.check_role_data_scope_services(query_db, str(change_role.role_id), data_scope_sql)
|
||||||
@@ -204,17 +274,19 @@ async def reset_system_role_status(
|
|||||||
return ResponseUtil.success(msg=edit_role_result.message)
|
return ResponseUtil.success(msg=edit_role_result.message)
|
||||||
|
|
||||||
|
|
||||||
@roleController.get(
|
@role_controller.get(
|
||||||
'/authUser/allocatedList',
|
'/authUser/allocatedList',
|
||||||
response_model=PageResponseModel,
|
summary='获取已分配用户分页列表接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))],
|
description='用于获取指定角色已分配的用户分页列表',
|
||||||
|
response_model=PageResponseModel[UserInfoModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:list')],
|
||||||
)
|
)
|
||||||
async def get_system_allocated_user_list(
|
async def get_system_allocated_user_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query),
|
user_role: Annotated[UserRolePageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
):
|
) -> Response:
|
||||||
role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services(
|
role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services(
|
||||||
query_db, user_role, data_scope_sql, is_page=True
|
query_db, user_role, data_scope_sql, is_page=True
|
||||||
)
|
)
|
||||||
@@ -223,17 +295,19 @@ async def get_system_allocated_user_list(
|
|||||||
return ResponseUtil.success(model_content=role_user_allocated_page_query_result)
|
return ResponseUtil.success(model_content=role_user_allocated_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@roleController.get(
|
@role_controller.get(
|
||||||
'/authUser/unallocatedList',
|
'/authUser/unallocatedList',
|
||||||
response_model=PageResponseModel,
|
summary='获取未分配用户分页列表接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))],
|
description='用于获取指定角色未分配的用户分页列表',
|
||||||
|
response_model=PageResponseModel[UserInfoModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:list')],
|
||||||
)
|
)
|
||||||
async def get_system_unallocated_user_list(
|
async def get_system_unallocated_user_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query),
|
user_role: Annotated[UserRolePageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
):
|
) -> Response:
|
||||||
role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services(
|
role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services(
|
||||||
query_db, user_role, data_scope_sql, is_page=True
|
query_db, user_role, data_scope_sql, is_page=True
|
||||||
)
|
)
|
||||||
@@ -242,15 +316,21 @@ async def get_system_unallocated_user_list(
|
|||||||
return ResponseUtil.success(model_content=role_user_unallocated_page_query_result)
|
return ResponseUtil.success(model_content=role_user_unallocated_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@roleController.put('/authUser/selectAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
|
@role_controller.put(
|
||||||
|
'/authUser/selectAll',
|
||||||
|
summary='分配用户给角色接口',
|
||||||
|
description='用于给指定角色分配用户',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
|
||||||
|
)
|
||||||
@Log(title='角色管理', business_type=BusinessType.GRANT)
|
@Log(title='角色管理', business_type=BusinessType.GRANT)
|
||||||
async def add_system_role_user(
|
async def add_system_role_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query),
|
add_role_user: Annotated[CrudUserRoleModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await RoleService.check_role_data_scope_services(query_db, str(add_role_user.role_id), data_scope_sql)
|
await RoleService.check_role_data_scope_services(query_db, str(add_role_user.role_id), data_scope_sql)
|
||||||
add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user)
|
add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user)
|
||||||
@@ -259,24 +339,38 @@ async def add_system_role_user(
|
|||||||
return ResponseUtil.success(msg=add_role_user_result.message)
|
return ResponseUtil.success(msg=add_role_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@roleController.put('/authUser/cancel', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
|
@role_controller.put(
|
||||||
|
'/authUser/cancel',
|
||||||
|
summary='取消分配用户给角色接口',
|
||||||
|
description='用于取消指定用户分配给角色',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
|
||||||
|
)
|
||||||
@Log(title='角色管理', business_type=BusinessType.GRANT)
|
@Log(title='角色管理', business_type=BusinessType.GRANT)
|
||||||
async def cancel_system_role_user(
|
async def cancel_system_role_user(
|
||||||
request: Request, cancel_user_role: CrudUserRoleModel, query_db: AsyncSession = Depends(get_db)
|
request: Request,
|
||||||
):
|
cancel_user_role: CrudUserRoleModel,
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
cancel_user_role_result = await UserService.delete_user_role_services(query_db, cancel_user_role)
|
cancel_user_role_result = await UserService.delete_user_role_services(query_db, cancel_user_role)
|
||||||
logger.info(cancel_user_role_result.message)
|
logger.info(cancel_user_role_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(msg=cancel_user_role_result.message)
|
return ResponseUtil.success(msg=cancel_user_role_result.message)
|
||||||
|
|
||||||
|
|
||||||
@roleController.put('/authUser/cancelAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
|
@role_controller.put(
|
||||||
|
'/authUser/cancelAll',
|
||||||
|
summary='批量取消分配用户给角色接口',
|
||||||
|
description='用于批量取消用户分配给角色',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
|
||||||
|
)
|
||||||
@Log(title='角色管理', business_type=BusinessType.GRANT)
|
@Log(title='角色管理', business_type=BusinessType.GRANT)
|
||||||
async def batch_cancel_system_role_user(
|
async def batch_cancel_system_role_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
batch_cancel_user_role: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query),
|
batch_cancel_user_role: Annotated[CrudUserRoleModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
):
|
) -> Response:
|
||||||
batch_cancel_user_role_result = await UserService.delete_user_role_services(query_db, batch_cancel_user_role)
|
batch_cancel_user_role_result = await UserService.delete_user_role_services(query_db, batch_cancel_user_role)
|
||||||
logger.info(batch_cancel_user_role_result.message)
|
logger.info(batch_cancel_user_role_result.message)
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,27 @@
|
|||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import Request, Response
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
|
||||||
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import PreAuthDependency
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel
|
||||||
from module_admin.entity.vo.server_vo import ServerMonitorModel
|
from module_admin.entity.vo.server_vo import ServerMonitorModel
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from module_admin.service.server_service import ServerService
|
from module_admin.service.server_service import ServerService
|
||||||
from utils.response_util import ResponseUtil
|
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
|
from utils.response_util import ResponseUtil
|
||||||
|
|
||||||
|
server_controller = APIRouterPro(
|
||||||
serverController = APIRouter(prefix='/monitor/server', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/monitor/server', order_num=14, tags=['系统监控-服务监控'], dependencies=[PreAuthDependency()]
|
||||||
|
|
||||||
|
|
||||||
@serverController.get(
|
|
||||||
'', response_model=ServerMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:server:list'))]
|
|
||||||
)
|
)
|
||||||
async def get_monitor_server_info(request: Request):
|
|
||||||
|
|
||||||
|
@server_controller.get(
|
||||||
|
'',
|
||||||
|
summary='获取服务器监控信息接口',
|
||||||
|
description='用于获取当前服务器的监控信息',
|
||||||
|
response_model=DataResponseModel[ServerMonitorModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('monitor:server:list')],
|
||||||
|
)
|
||||||
|
async def get_monitor_server_info(request: Request) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
server_info_query_result = await ServerService.get_server_monitor_info()
|
server_info_query_result = await ServerService.get_server_monitor_info()
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|||||||
@@ -1,18 +1,26 @@
|
|||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fastapi import APIRouter, Depends, File, Form, Query, Request, UploadFile
|
from typing import Annotated, Literal, Optional, Union
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
from typing import Literal, Optional, Union
|
import aiofiles
|
||||||
|
from fastapi import File, Form, Path, Query, Request, Response, UploadFile
|
||||||
|
from fastapi.responses import StreamingResponse
|
||||||
from pydantic_validation_decorator import ValidateFields
|
from pydantic_validation_decorator import ValidateFields
|
||||||
from config.get_db import get_db
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from config.enums import BusinessType
|
|
||||||
|
from common.annotation.log_annotation import Log
|
||||||
|
from common.aspect.data_scope import DataScopeDependency
|
||||||
|
from common.aspect.db_seesion import DBSessionDependency
|
||||||
|
from common.aspect.interface_auth import UserInterfaceAuthDependency
|
||||||
|
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
|
||||||
|
from common.enums import BusinessType
|
||||||
|
from common.router import APIRouterPro
|
||||||
|
from common.vo import DataResponseModel, DynamicResponseModel, PageResponseModel, ResponseBaseModel
|
||||||
from config.env import UploadConfig
|
from config.env import UploadConfig
|
||||||
from module_admin.annotation.log_annotation import Log
|
from module_admin.entity.vo.dept_vo import DeptModel, DeptTreeModel
|
||||||
from module_admin.aspect.data_scope import GetDataScope
|
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
|
||||||
from module_admin.entity.vo.dept_vo import DeptModel
|
|
||||||
from module_admin.entity.vo.user_vo import (
|
from module_admin.entity.vo.user_vo import (
|
||||||
AddUserModel,
|
AddUserModel,
|
||||||
|
AvatarModel,
|
||||||
CrudUserRoleModel,
|
CrudUserRoleModel,
|
||||||
CurrentUserModel,
|
CurrentUserModel,
|
||||||
DeleteUserModel,
|
DeleteUserModel,
|
||||||
@@ -26,41 +34,53 @@ from module_admin.entity.vo.user_vo import (
|
|||||||
UserProfileModel,
|
UserProfileModel,
|
||||||
UserRoleQueryModel,
|
UserRoleQueryModel,
|
||||||
UserRoleResponseModel,
|
UserRoleResponseModel,
|
||||||
|
UserRowModel,
|
||||||
)
|
)
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from module_admin.service.user_service import UserService
|
|
||||||
from module_admin.service.role_service import RoleService
|
|
||||||
from module_admin.service.dept_service import DeptService
|
from module_admin.service.dept_service import DeptService
|
||||||
|
from module_admin.service.role_service import RoleService
|
||||||
|
from module_admin.service.user_service import UserService
|
||||||
from utils.common_util import bytes2file_response
|
from utils.common_util import bytes2file_response
|
||||||
from utils.log_util import logger
|
from utils.log_util import logger
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from utils.pwd_util import PwdUtil
|
from utils.pwd_util import PwdUtil
|
||||||
from utils.response_util import ResponseUtil
|
from utils.response_util import ResponseUtil
|
||||||
from utils.upload_util import UploadUtil
|
from utils.upload_util import UploadUtil
|
||||||
|
|
||||||
|
user_controller = APIRouterPro(
|
||||||
userController = APIRouter(prefix='/system/user', dependencies=[Depends(LoginService.get_current_user)])
|
prefix='/system/user', order_num=3, tags=['系统管理-用户管理'], dependencies=[PreAuthDependency()]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@userController.get('/deptTree', dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))])
|
@user_controller.get(
|
||||||
|
'/deptTree',
|
||||||
|
summary='获取部门树接口',
|
||||||
|
description='用于获取当前登录用户可见的部门树',
|
||||||
|
response_model=DataResponseModel[list[DeptTreeModel]],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:list')],
|
||||||
|
)
|
||||||
async def get_system_dept_tree(
|
async def get_system_dept_tree(
|
||||||
request: Request, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))
|
request: Request,
|
||||||
):
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql)
|
data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
|
) -> Response:
|
||||||
|
dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(), data_scope_sql)
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.success(data=dept_query_result)
|
return ResponseUtil.success(data=dept_query_result)
|
||||||
|
|
||||||
|
|
||||||
@userController.get(
|
@user_controller.get(
|
||||||
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]
|
'/list',
|
||||||
|
summary='获取用户分页列表接口',
|
||||||
|
description='用于获取用户分页列表',
|
||||||
|
response_model=PageResponseModel[UserRowModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:list')],
|
||||||
)
|
)
|
||||||
async def get_system_user_list(
|
async def get_system_user_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_query),
|
user_page_query: Annotated[UserPageQueryModel, Query()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
):
|
) -> Response:
|
||||||
# 获取分页数据
|
# 获取分页数据
|
||||||
user_page_query_result = await UserService.get_user_list_services(
|
user_page_query_result = await UserService.get_user_list_services(
|
||||||
query_db, user_page_query, data_scope_sql, is_page=True
|
query_db, user_page_query, data_scope_sql, is_page=True
|
||||||
@@ -70,17 +90,23 @@ async def get_system_user_list(
|
|||||||
return ResponseUtil.success(model_content=user_page_query_result)
|
return ResponseUtil.success(model_content=user_page_query_result)
|
||||||
|
|
||||||
|
|
||||||
@userController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))])
|
@user_controller.post(
|
||||||
|
'',
|
||||||
|
summary='新增用户接口',
|
||||||
|
description='用于新增用户',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:add')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='add_user')
|
@ValidateFields(validate_model='add_user')
|
||||||
@Log(title='用户管理', business_type=BusinessType.INSERT)
|
@Log(title='用户管理', business_type=BusinessType.INSERT)
|
||||||
async def add_system_user(
|
async def add_system_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
add_user: AddUserModel,
|
add_user: AddUserModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
dept_data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
dept_data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
role_data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
role_data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql)
|
await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql)
|
||||||
await RoleService.check_role_data_scope_services(
|
await RoleService.check_role_data_scope_services(
|
||||||
@@ -97,18 +123,24 @@ async def add_system_user(
|
|||||||
return ResponseUtil.success(msg=add_user_result.message)
|
return ResponseUtil.success(msg=add_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@userController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))])
|
@user_controller.put(
|
||||||
|
'',
|
||||||
|
summary='编辑用户接口',
|
||||||
|
description='用于编辑用户',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:edit')],
|
||||||
|
)
|
||||||
@ValidateFields(validate_model='edit_user')
|
@ValidateFields(validate_model='edit_user')
|
||||||
@Log(title='用户管理', business_type=BusinessType.UPDATE)
|
@Log(title='用户管理', business_type=BusinessType.UPDATE)
|
||||||
async def edit_system_user(
|
async def edit_system_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
edit_user: EditUserModel,
|
edit_user: EditUserModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
user_data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
user_data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
dept_data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
dept_data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
role_data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
role_data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
await UserService.check_user_allowed_services(edit_user)
|
await UserService.check_user_allowed_services(edit_user)
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await UserService.check_user_data_scope_services(query_db, edit_user.user_id, user_data_scope_sql)
|
await UserService.check_user_data_scope_services(query_db, edit_user.user_id, user_data_scope_sql)
|
||||||
@@ -124,15 +156,21 @@ async def edit_system_user(
|
|||||||
return ResponseUtil.success(msg=edit_user_result.message)
|
return ResponseUtil.success(msg=edit_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@userController.delete('/{user_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))])
|
@user_controller.delete(
|
||||||
|
'/{user_ids}',
|
||||||
|
summary='删除用户接口',
|
||||||
|
description='用于删除用户',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:remove')],
|
||||||
|
)
|
||||||
@Log(title='用户管理', business_type=BusinessType.DELETE)
|
@Log(title='用户管理', business_type=BusinessType.DELETE)
|
||||||
async def delete_system_user(
|
async def delete_system_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
user_ids: str,
|
user_ids: Annotated[str, Path(description='需要删除的用户ID')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
):
|
) -> Response:
|
||||||
user_id_list = user_ids.split(',') if user_ids else []
|
user_id_list = user_ids.split(',') if user_ids else []
|
||||||
if user_id_list:
|
if user_id_list:
|
||||||
if current_user.user.user_id in list(map(int, user_id_list)):
|
if current_user.user.user_id in list(map(int, user_id_list)):
|
||||||
@@ -150,15 +188,21 @@ async def delete_system_user(
|
|||||||
return ResponseUtil.success(msg=delete_user_result.message)
|
return ResponseUtil.success(msg=delete_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@userController.put('/resetPwd', dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))])
|
@user_controller.put(
|
||||||
|
'/resetPwd',
|
||||||
|
summary='重置用户密码接口',
|
||||||
|
description='用于重置用户密码',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:resetPwd')],
|
||||||
|
)
|
||||||
@Log(title='用户管理', business_type=BusinessType.UPDATE)
|
@Log(title='用户管理', business_type=BusinessType.UPDATE)
|
||||||
async def reset_system_user_pwd(
|
async def reset_system_user_pwd(
|
||||||
request: Request,
|
request: Request,
|
||||||
reset_user: EditUserModel,
|
reset_user: EditUserModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
):
|
) -> Response:
|
||||||
await UserService.check_user_allowed_services(reset_user)
|
await UserService.check_user_allowed_services(reset_user)
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await UserService.check_user_data_scope_services(query_db, reset_user.user_id, data_scope_sql)
|
await UserService.check_user_data_scope_services(query_db, reset_user.user_id, data_scope_sql)
|
||||||
@@ -176,15 +220,21 @@ async def reset_system_user_pwd(
|
|||||||
return ResponseUtil.success(msg=edit_user_result.message)
|
return ResponseUtil.success(msg=edit_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@userController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))])
|
@user_controller.put(
|
||||||
|
'/changeStatus',
|
||||||
|
summary='修改用户状态接口',
|
||||||
|
description='用于修改用户状态',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:edit')],
|
||||||
|
)
|
||||||
@Log(title='用户管理', business_type=BusinessType.UPDATE)
|
@Log(title='用户管理', business_type=BusinessType.UPDATE)
|
||||||
async def change_system_user_status(
|
async def change_system_user_status(
|
||||||
request: Request,
|
request: Request,
|
||||||
change_user: EditUserModel,
|
change_user: EditUserModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
):
|
) -> Response:
|
||||||
await UserService.check_user_allowed_services(change_user)
|
await UserService.check_user_allowed_services(change_user)
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await UserService.check_user_data_scope_services(query_db, change_user.user_id, data_scope_sql)
|
await UserService.check_user_data_scope_services(query_db, change_user.user_id, data_scope_sql)
|
||||||
@@ -201,31 +251,44 @@ async def change_system_user_status(
|
|||||||
return ResponseUtil.success(msg=edit_user_result.message)
|
return ResponseUtil.success(msg=edit_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@userController.get('/profile', response_model=UserProfileModel)
|
@user_controller.get(
|
||||||
|
'/profile',
|
||||||
|
summary='获取用户个人信息接口',
|
||||||
|
description='用于获取当前登录用户的个人信息',
|
||||||
|
response_model=DynamicResponseModel[UserProfileModel],
|
||||||
|
)
|
||||||
async def query_detail_system_user_profile(
|
async def query_detail_system_user_profile(
|
||||||
request: Request,
|
request: Request,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
profile_user_result = await UserService.user_profile_services(query_db, current_user.user.user_id)
|
profile_user_result = await UserService.user_profile_services(query_db, current_user.user.user_id)
|
||||||
logger.info(f'获取user_id为{current_user.user.user_id}的信息成功')
|
logger.info(f'获取user_id为{current_user.user.user_id}的信息成功')
|
||||||
|
|
||||||
return ResponseUtil.success(model_content=profile_user_result)
|
return ResponseUtil.success(model_content=profile_user_result)
|
||||||
|
|
||||||
|
|
||||||
@userController.get(
|
@user_controller.get(
|
||||||
'/{user_id}', response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]
|
'/{user_id}',
|
||||||
|
summary='获取用户详情接口',
|
||||||
|
description='用于获取指定用户的详情信息',
|
||||||
|
response_model=DynamicResponseModel[UserDetailModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:query')],
|
||||||
)
|
)
|
||||||
@userController.get(
|
@user_controller.get(
|
||||||
'/', response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]
|
'/',
|
||||||
|
summary='获取用户岗位和角色列表接口',
|
||||||
|
description='用于获取当前登录用户可见的岗位和角色列表',
|
||||||
|
response_model=DynamicResponseModel[UserDetailModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:query')],
|
||||||
)
|
)
|
||||||
async def query_detail_system_user(
|
async def query_detail_system_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
|
data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
user_id: Optional[Union[int, Literal['']]] = '',
|
user_id: Optional[Union[int, Literal['']]] = '',
|
||||||
query_db: AsyncSession = Depends(get_db),
|
) -> Response:
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
|
||||||
):
|
|
||||||
if user_id and not current_user.user.admin:
|
if user_id and not current_user.user.admin:
|
||||||
await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql)
|
await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql)
|
||||||
detail_user_result = await UserService.user_detail_services(query_db, user_id)
|
detail_user_result = await UserService.user_detail_services(query_db, user_id)
|
||||||
@@ -234,14 +297,19 @@ async def query_detail_system_user(
|
|||||||
return ResponseUtil.success(model_content=detail_user_result)
|
return ResponseUtil.success(model_content=detail_user_result)
|
||||||
|
|
||||||
|
|
||||||
@userController.post('/profile/avatar')
|
@user_controller.post(
|
||||||
|
'/profile/avatar',
|
||||||
|
summary='修改用户头像接口',
|
||||||
|
description='用于修改当前登录用户的头像',
|
||||||
|
response_model=DynamicResponseModel[AvatarModel],
|
||||||
|
)
|
||||||
@Log(title='个人信息', business_type=BusinessType.UPDATE)
|
@Log(title='个人信息', business_type=BusinessType.UPDATE)
|
||||||
async def change_system_user_profile_avatar(
|
async def change_system_user_profile_avatar(
|
||||||
request: Request,
|
request: Request,
|
||||||
avatarfile: bytes = File(),
|
avatarfile: Annotated[bytes, File()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
if avatarfile:
|
if avatarfile:
|
||||||
relative_path = (
|
relative_path = (
|
||||||
f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}'
|
f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}'
|
||||||
@@ -253,8 +321,8 @@ async def change_system_user_profile_avatar(
|
|||||||
pass
|
pass
|
||||||
avatar_name = f'avatar_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.png'
|
avatar_name = f'avatar_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.png'
|
||||||
avatar_path = os.path.join(dir_path, avatar_name)
|
avatar_path = os.path.join(dir_path, avatar_name)
|
||||||
with open(avatar_path, 'wb') as f:
|
async with aiofiles.open(avatar_path, 'wb') as f:
|
||||||
f.write(avatarfile)
|
await f.write(avatarfile)
|
||||||
edit_user = EditUserModel(
|
edit_user = EditUserModel(
|
||||||
userId=current_user.user.user_id,
|
userId=current_user.user.user_id,
|
||||||
avatar=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{avatar_name}',
|
avatar=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{avatar_name}',
|
||||||
@@ -265,18 +333,23 @@ async def change_system_user_profile_avatar(
|
|||||||
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
|
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
|
||||||
logger.info(edit_user_result.message)
|
logger.info(edit_user_result.message)
|
||||||
|
|
||||||
return ResponseUtil.success(dict_content={'imgUrl': edit_user.avatar}, msg=edit_user_result.message)
|
return ResponseUtil.success(model_content=AvatarModel(imgUrl=edit_user.avatar), msg=edit_user_result.message)
|
||||||
return ResponseUtil.failure(msg='上传图片异常,请联系管理员')
|
return ResponseUtil.failure(msg='上传图片异常,请联系管理员')
|
||||||
|
|
||||||
|
|
||||||
@userController.put('/profile')
|
@user_controller.put(
|
||||||
|
'/profile',
|
||||||
|
summary='修改用户个人信息接口',
|
||||||
|
description='用于修改当前登录用户的个人信息',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
)
|
||||||
@Log(title='个人信息', business_type=BusinessType.UPDATE)
|
@Log(title='个人信息', business_type=BusinessType.UPDATE)
|
||||||
async def change_system_user_profile_info(
|
async def change_system_user_profile_info(
|
||||||
request: Request,
|
request: Request,
|
||||||
user_info: UserInfoModel,
|
user_info: UserInfoModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
edit_user = EditUserModel(
|
edit_user = EditUserModel(
|
||||||
**user_info.model_dump(exclude_unset=True, by_alias=True, exclude={'role_ids', 'post_ids'}),
|
**user_info.model_dump(exclude_unset=True, by_alias=True, exclude={'role_ids', 'post_ids'}),
|
||||||
userId=current_user.user.user_id,
|
userId=current_user.user.user_id,
|
||||||
@@ -293,14 +366,19 @@ async def change_system_user_profile_info(
|
|||||||
return ResponseUtil.success(msg=edit_user_result.message)
|
return ResponseUtil.success(msg=edit_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@userController.put('/profile/updatePwd')
|
@user_controller.put(
|
||||||
|
'/profile/updatePwd',
|
||||||
|
summary='修改用户密码接口',
|
||||||
|
description='用于修改当前登录用户的密码',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
)
|
||||||
@Log(title='个人信息', business_type=BusinessType.UPDATE)
|
@Log(title='个人信息', business_type=BusinessType.UPDATE)
|
||||||
async def reset_system_user_password(
|
async def reset_system_user_password(
|
||||||
request: Request,
|
request: Request,
|
||||||
reset_password: ResetPasswordModel,
|
reset_password: ResetPasswordModel,
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
):
|
) -> Response:
|
||||||
reset_user = ResetUserModel(
|
reset_user = ResetUserModel(
|
||||||
userId=current_user.user.user_id,
|
userId=current_user.user.user_id,
|
||||||
oldPassword=reset_password.old_password,
|
oldPassword=reset_password.old_password,
|
||||||
@@ -315,17 +393,23 @@ async def reset_system_user_password(
|
|||||||
return ResponseUtil.success(msg=reset_user_result.message)
|
return ResponseUtil.success(msg=reset_user_result.message)
|
||||||
|
|
||||||
|
|
||||||
@userController.post('/importData', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))])
|
@user_controller.post(
|
||||||
|
'/importData',
|
||||||
|
summary='批量导入用户接口',
|
||||||
|
description='用于批量导入用户数据',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:import')],
|
||||||
|
)
|
||||||
@Log(title='用户管理', business_type=BusinessType.IMPORT)
|
@Log(title='用户管理', business_type=BusinessType.IMPORT)
|
||||||
async def batch_import_system_user(
|
async def batch_import_system_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
file: UploadFile = File(...),
|
file: Annotated[UploadFile, File(...)],
|
||||||
update_support: bool = Query(alias='updateSupport'),
|
update_support: Annotated[bool, Query(alias='updateSupport')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
user_data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
user_data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
dept_data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
dept_data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
batch_import_result = await UserService.batch_import_user_services(
|
batch_import_result = await UserService.batch_import_user_services(
|
||||||
request, query_db, file, update_support, current_user, user_data_scope_sql, dept_data_scope_sql
|
request, query_db, file, update_support, current_user, user_data_scope_sql, dept_data_scope_sql
|
||||||
)
|
)
|
||||||
@@ -334,22 +418,52 @@ async def batch_import_system_user(
|
|||||||
return ResponseUtil.success(msg=batch_import_result.message)
|
return ResponseUtil.success(msg=batch_import_result.message)
|
||||||
|
|
||||||
|
|
||||||
@userController.post('/importTemplate', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))])
|
@user_controller.post(
|
||||||
async def export_system_user_template(request: Request, query_db: AsyncSession = Depends(get_db)):
|
'/importTemplate',
|
||||||
|
summary='获取用户导入模板接口',
|
||||||
|
description='用于获取用户导入模板excel文件',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回导入用户模板excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:import')],
|
||||||
|
)
|
||||||
|
async def export_system_user_template(
|
||||||
|
request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
|
||||||
|
) -> Response:
|
||||||
user_import_template_result = await UserService.get_user_import_template_services()
|
user_import_template_result = await UserService.get_user_import_template_services()
|
||||||
logger.info('获取成功')
|
logger.info('获取成功')
|
||||||
|
|
||||||
return ResponseUtil.streaming(data=bytes2file_response(user_import_template_result))
|
return ResponseUtil.streaming(data=bytes2file_response(user_import_template_result))
|
||||||
|
|
||||||
|
|
||||||
@userController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:user:export'))])
|
@user_controller.post(
|
||||||
|
'/export',
|
||||||
|
summary='导出用户列表接口',
|
||||||
|
description='用于导出当前符合查询条件的用户列表数据',
|
||||||
|
response_class=StreamingResponse,
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
'description': '流式返回用户列表excel文件',
|
||||||
|
'content': {
|
||||||
|
'application/octet-stream': {},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:export')],
|
||||||
|
)
|
||||||
@Log(title='用户管理', business_type=BusinessType.EXPORT)
|
@Log(title='用户管理', business_type=BusinessType.EXPORT)
|
||||||
async def export_system_user_list(
|
async def export_system_user_list(
|
||||||
request: Request,
|
request: Request,
|
||||||
user_page_query: UserPageQueryModel = Form(),
|
user_page_query: Annotated[UserPageQueryModel, Form()],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
):
|
) -> Response:
|
||||||
# 获取全量数据
|
# 获取全量数据
|
||||||
user_query_result = await UserService.get_user_list_services(
|
user_query_result = await UserService.get_user_list_services(
|
||||||
query_db, user_page_query, data_scope_sql, is_page=False
|
query_db, user_page_query, data_scope_sql, is_page=False
|
||||||
@@ -360,12 +474,18 @@ async def export_system_user_list(
|
|||||||
return ResponseUtil.streaming(data=bytes2file_response(user_export_result))
|
return ResponseUtil.streaming(data=bytes2file_response(user_export_result))
|
||||||
|
|
||||||
|
|
||||||
@userController.get(
|
@user_controller.get(
|
||||||
'/authRole/{user_id}',
|
'/authRole/{user_id}',
|
||||||
response_model=UserRoleResponseModel,
|
summary='获取用户已分配角色列表接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))],
|
description='用于获取指定用户已分配的角色列表',
|
||||||
|
response_model=DynamicResponseModel[UserRoleResponseModel],
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:query')],
|
||||||
)
|
)
|
||||||
async def get_system_allocated_role_list(request: Request, user_id: int, query_db: AsyncSession = Depends(get_db)):
|
async def get_system_allocated_role_list(
|
||||||
|
request: Request,
|
||||||
|
user_id: Annotated[int, Path(description='用户ID')],
|
||||||
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
|
) -> Response:
|
||||||
user_role_query = UserRoleQueryModel(userId=user_id)
|
user_role_query = UserRoleQueryModel(userId=user_id)
|
||||||
user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services(
|
user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services(
|
||||||
query_db, user_role_query
|
query_db, user_role_query
|
||||||
@@ -375,21 +495,23 @@ async def get_system_allocated_role_list(request: Request, user_id: int, query_d
|
|||||||
return ResponseUtil.success(model_content=user_role_allocated_query_result)
|
return ResponseUtil.success(model_content=user_role_allocated_query_result)
|
||||||
|
|
||||||
|
|
||||||
@userController.put(
|
@user_controller.put(
|
||||||
'/authRole',
|
'/authRole',
|
||||||
response_model=UserRoleResponseModel,
|
summary='给用户分配角色接口',
|
||||||
dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))],
|
description='用于给指定用户分配角色',
|
||||||
|
response_model=ResponseBaseModel,
|
||||||
|
dependencies=[UserInterfaceAuthDependency('system:user:edit')],
|
||||||
)
|
)
|
||||||
@Log(title='用户管理', business_type=BusinessType.GRANT)
|
@Log(title='用户管理', business_type=BusinessType.GRANT)
|
||||||
async def update_system_role_user(
|
async def update_system_role_user(
|
||||||
request: Request,
|
request: Request,
|
||||||
user_id: int = Query(alias='userId'),
|
user_id: Annotated[int, Query(alias='userId')],
|
||||||
role_ids: str = Query(alias='roleIds'),
|
role_ids: Annotated[str, Query(alias='roleIds')],
|
||||||
query_db: AsyncSession = Depends(get_db),
|
query_db: Annotated[AsyncSession, DBSessionDependency()],
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
|
||||||
user_data_scope_sql: str = Depends(GetDataScope('SysUser')),
|
user_data_scope_sql: Annotated[str, DataScopeDependency('SysUser')],
|
||||||
role_data_scope_sql: str = Depends(GetDataScope('SysDept')),
|
role_data_scope_sql: Annotated[str, DataScopeDependency('SysDept')],
|
||||||
):
|
) -> Response:
|
||||||
if not current_user.user.admin:
|
if not current_user.user.admin:
|
||||||
await UserService.check_user_data_scope_services(query_db, user_id, user_data_scope_sql)
|
await UserService.check_user_data_scope_services(query_db, user_id, user_data_scope_sql)
|
||||||
await RoleService.check_role_data_scope_services(query_db, role_ids, role_data_scope_sql)
|
await RoleService.check_role_data_scope_services(query_db, role_ids, role_data_scope_sql)
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import delete, select, update
|
from sqlalchemy import delete, select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.vo import PageModel
|
||||||
from module_admin.entity.do.config_do import SysConfig
|
from module_admin.entity.do.config_do import SysConfig
|
||||||
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel
|
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel
|
||||||
from utils.page_util import PageUtil
|
from utils.page_util import PageUtil
|
||||||
@@ -12,7 +16,7 @@ class ConfigDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_config_detail_by_id(cls, db: AsyncSession, config_id: int):
|
async def get_config_detail_by_id(cls, db: AsyncSession, config_id: int) -> Union[SysConfig, None]:
|
||||||
"""
|
"""
|
||||||
根据参数配置id获取参数配置详细信息
|
根据参数配置id获取参数配置详细信息
|
||||||
|
|
||||||
@@ -25,7 +29,7 @@ class ConfigDao:
|
|||||||
return config_info
|
return config_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_config_detail_by_info(cls, db: AsyncSession, config: ConfigModel):
|
async def get_config_detail_by_info(cls, db: AsyncSession, config: ConfigModel) -> Union[SysConfig, None]:
|
||||||
"""
|
"""
|
||||||
根据参数配置参数获取参数配置信息
|
根据参数配置参数获取参数配置信息
|
||||||
|
|
||||||
@@ -49,7 +53,9 @@ class ConfigDao:
|
|||||||
return config_info
|
return config_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_config_list(cls, db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False):
|
async def get_config_list(
|
||||||
|
cls, db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取参数配置列表信息
|
根据查询参数获取参数配置列表信息
|
||||||
|
|
||||||
@@ -74,12 +80,14 @@ class ConfigDao:
|
|||||||
.order_by(SysConfig.config_id)
|
.order_by(SysConfig.config_id)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
config_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
config_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return config_list
|
return config_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_config_dao(cls, db: AsyncSession, config: ConfigModel):
|
async def add_config_dao(cls, db: AsyncSession, config: ConfigModel) -> SysConfig:
|
||||||
"""
|
"""
|
||||||
新增参数配置数据库操作
|
新增参数配置数据库操作
|
||||||
|
|
||||||
@@ -94,7 +102,7 @@ class ConfigDao:
|
|||||||
return db_config
|
return db_config
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_config_dao(cls, db: AsyncSession, config: dict):
|
async def edit_config_dao(cls, db: AsyncSession, config: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑参数配置数据库操作
|
编辑参数配置数据库操作
|
||||||
|
|
||||||
@@ -105,7 +113,7 @@ class ConfigDao:
|
|||||||
await db.execute(update(SysConfig), [config])
|
await db.execute(update(SysConfig), [config])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_config_dao(cls, db: AsyncSession, config: ConfigModel):
|
async def delete_config_dao(cls, db: AsyncSession, config: ConfigModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除参数配置数据库操作
|
删除参数配置数据库操作
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
from collections.abc import Sequence
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from sqlalchemy import bindparam, func, or_, select, update # noqa: F401
|
from sqlalchemy import bindparam, func, or_, select, update # noqa: F401
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.util import immutabledict
|
from sqlalchemy.util import immutabledict
|
||||||
from typing import List
|
|
||||||
from module_admin.entity.do.dept_do import SysDept
|
from module_admin.entity.do.dept_do import SysDept
|
||||||
from module_admin.entity.do.role_do import SysRoleDept # noqa: F401
|
from module_admin.entity.do.role_do import SysRoleDept # noqa: F401
|
||||||
from module_admin.entity.do.user_do import SysUser
|
from module_admin.entity.do.user_do import SysUser
|
||||||
@@ -14,7 +17,7 @@ class DeptDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dept_by_id(cls, db: AsyncSession, dept_id: int):
|
async def get_dept_by_id(cls, db: AsyncSession, dept_id: int) -> Union[SysDept, None]:
|
||||||
"""
|
"""
|
||||||
根据部门id获取在用部门信息
|
根据部门id获取在用部门信息
|
||||||
|
|
||||||
@@ -27,7 +30,7 @@ class DeptDao:
|
|||||||
return dept_info
|
return dept_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dept_detail_by_id(cls, db: AsyncSession, dept_id: int):
|
async def get_dept_detail_by_id(cls, db: AsyncSession, dept_id: int) -> Union[SysDept, None]:
|
||||||
"""
|
"""
|
||||||
根据部门id获取部门详细信息
|
根据部门id获取部门详细信息
|
||||||
|
|
||||||
@@ -44,7 +47,7 @@ class DeptDao:
|
|||||||
return dept_info
|
return dept_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dept_detail_by_info(cls, db: AsyncSession, dept: DeptModel):
|
async def get_dept_detail_by_info(cls, db: AsyncSession, dept: DeptModel) -> Union[SysDept, None]:
|
||||||
"""
|
"""
|
||||||
根据部门参数获取部门信息
|
根据部门参数获取部门信息
|
||||||
|
|
||||||
@@ -68,7 +71,9 @@ class DeptDao:
|
|||||||
return dept_info
|
return dept_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dept_info_for_edit_option(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str):
|
async def get_dept_info_for_edit_option(
|
||||||
|
cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str
|
||||||
|
) -> Sequence[SysDept]:
|
||||||
"""
|
"""
|
||||||
获取部门编辑对应的在用部门列表信息
|
获取部门编辑对应的在用部门列表信息
|
||||||
|
|
||||||
@@ -101,7 +106,7 @@ class DeptDao:
|
|||||||
return dept_result
|
return dept_result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_children_dept_dao(cls, db: AsyncSession, dept_id: int):
|
async def get_children_dept_dao(cls, db: AsyncSession, dept_id: int) -> Sequence[SysDept]:
|
||||||
"""
|
"""
|
||||||
根据部门id查询当前部门的子部门列表信息
|
根据部门id查询当前部门的子部门列表信息
|
||||||
|
|
||||||
@@ -116,7 +121,9 @@ class DeptDao:
|
|||||||
return dept_result
|
return dept_result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dept_list_for_tree(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str):
|
async def get_dept_list_for_tree(
|
||||||
|
cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str
|
||||||
|
) -> Sequence[SysDept]:
|
||||||
"""
|
"""
|
||||||
获取所有在用部门列表信息
|
获取所有在用部门列表信息
|
||||||
|
|
||||||
@@ -146,7 +153,7 @@ class DeptDao:
|
|||||||
return dept_result
|
return dept_result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dept_list(cls, db: AsyncSession, page_object: DeptModel, data_scope_sql: str):
|
async def get_dept_list(cls, db: AsyncSession, page_object: DeptModel, data_scope_sql: str) -> Sequence[SysDept]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取部门列表信息
|
根据查询参数获取部门列表信息
|
||||||
|
|
||||||
@@ -177,7 +184,7 @@ class DeptDao:
|
|||||||
return dept_result
|
return dept_result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_dept_dao(cls, db: AsyncSession, dept: DeptModel):
|
async def add_dept_dao(cls, db: AsyncSession, dept: DeptModel) -> SysDept:
|
||||||
"""
|
"""
|
||||||
新增部门数据库操作
|
新增部门数据库操作
|
||||||
|
|
||||||
@@ -192,7 +199,7 @@ class DeptDao:
|
|||||||
return db_dept
|
return db_dept
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_dept_dao(cls, db: AsyncSession, dept: dict):
|
async def edit_dept_dao(cls, db: AsyncSession, dept: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑部门数据库操作
|
编辑部门数据库操作
|
||||||
|
|
||||||
@@ -203,7 +210,7 @@ class DeptDao:
|
|||||||
await db.execute(update(SysDept), [dept])
|
await db.execute(update(SysDept), [dept])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def update_dept_children_dao(cls, db: AsyncSession, update_dept: List):
|
async def update_dept_children_dao(cls, db: AsyncSession, update_dept: list) -> None:
|
||||||
"""
|
"""
|
||||||
更新子部门信息
|
更新子部门信息
|
||||||
|
|
||||||
@@ -225,7 +232,7 @@ class DeptDao:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def update_dept_status_normal_dao(cls, db: AsyncSession, dept_id_list: List):
|
async def update_dept_status_normal_dao(cls, db: AsyncSession, dept_id_list: list) -> None:
|
||||||
"""
|
"""
|
||||||
批量更新部门状态为正常
|
批量更新部门状态为正常
|
||||||
|
|
||||||
@@ -236,7 +243,7 @@ class DeptDao:
|
|||||||
await db.execute(update(SysDept).where(SysDept.dept_id.in_(dept_id_list)).values(status='0'))
|
await db.execute(update(SysDept).where(SysDept.dept_id.in_(dept_id_list)).values(status='0'))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_dept_dao(cls, db: AsyncSession, dept: DeptModel):
|
async def delete_dept_dao(cls, db: AsyncSession, dept: DeptModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除部门数据库操作
|
删除部门数据库操作
|
||||||
|
|
||||||
@@ -251,7 +258,7 @@ class DeptDao:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def count_normal_children_dept_dao(cls, db: AsyncSession, dept_id: int):
|
async def count_normal_children_dept_dao(cls, db: AsyncSession, dept_id: int) -> Union[int, None]:
|
||||||
"""
|
"""
|
||||||
根据部门id查询查询所有子部门(正常状态)的数量
|
根据部门id查询查询所有子部门(正常状态)的数量
|
||||||
|
|
||||||
@@ -270,7 +277,7 @@ class DeptDao:
|
|||||||
return normal_children_dept_count
|
return normal_children_dept_count
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def count_children_dept_dao(cls, db: AsyncSession, dept_id: int):
|
async def count_children_dept_dao(cls, db: AsyncSession, dept_id: int) -> Union[int, None]:
|
||||||
"""
|
"""
|
||||||
根据部门id查询查询所有子部门(所有状态)的数量
|
根据部门id查询查询所有子部门(所有状态)的数量
|
||||||
|
|
||||||
@@ -290,7 +297,7 @@ class DeptDao:
|
|||||||
return children_dept_count
|
return children_dept_count
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def count_dept_user_dao(cls, db: AsyncSession, dept_id: int):
|
async def count_dept_user_dao(cls, db: AsyncSession, dept_id: int) -> Union[int, None]:
|
||||||
"""
|
"""
|
||||||
根据部门id查询查询部门下的用户数量
|
根据部门id查询查询部门下的用户数量
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
|
from collections.abc import Sequence
|
||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import and_, delete, func, select, update
|
from sqlalchemy import and_, delete, func, select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from module_admin.entity.do.dict_do import SysDictType, SysDictData
|
|
||||||
|
from common.vo import PageModel
|
||||||
|
from module_admin.entity.do.dict_do import SysDictData, SysDictType
|
||||||
from module_admin.entity.vo.dict_vo import DictDataModel, DictDataPageQueryModel, DictTypeModel, DictTypePageQueryModel
|
from module_admin.entity.vo.dict_vo import DictDataModel, DictDataPageQueryModel, DictTypeModel, DictTypePageQueryModel
|
||||||
from utils.page_util import PageUtil
|
from utils.page_util import PageUtil
|
||||||
from utils.time_format_util import list_format_datetime
|
from utils.time_format_util import list_format_datetime
|
||||||
@@ -13,7 +18,7 @@ class DictTypeDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dict_type_detail_by_id(cls, db: AsyncSession, dict_id: int):
|
async def get_dict_type_detail_by_id(cls, db: AsyncSession, dict_id: int) -> Union[SysDictType, None]:
|
||||||
"""
|
"""
|
||||||
根据字典类型id获取字典类型详细信息
|
根据字典类型id获取字典类型详细信息
|
||||||
|
|
||||||
@@ -26,7 +31,7 @@ class DictTypeDao:
|
|||||||
return dict_type_info
|
return dict_type_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dict_type_detail_by_info(cls, db: AsyncSession, dict_type: DictTypeModel):
|
async def get_dict_type_detail_by_info(cls, db: AsyncSession, dict_type: DictTypeModel) -> Union[SysDictType, None]:
|
||||||
"""
|
"""
|
||||||
根据字典类型参数获取字典类型信息
|
根据字典类型参数获取字典类型信息
|
||||||
|
|
||||||
@@ -50,7 +55,7 @@ class DictTypeDao:
|
|||||||
return dict_type_info
|
return dict_type_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_all_dict_type(cls, db: AsyncSession):
|
async def get_all_dict_type(cls, db: AsyncSession) -> list[Any]:
|
||||||
"""
|
"""
|
||||||
获取所有的字典类型信息
|
获取所有的字典类型信息
|
||||||
|
|
||||||
@@ -62,7 +67,9 @@ class DictTypeDao:
|
|||||||
return list_format_datetime(dict_type_info)
|
return list_format_datetime(dict_type_info)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dict_type_list(cls, db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False):
|
async def get_dict_type_list(
|
||||||
|
cls, db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取字典类型列表信息
|
根据查询参数获取字典类型列表信息
|
||||||
|
|
||||||
@@ -87,12 +94,14 @@ class DictTypeDao:
|
|||||||
.order_by(SysDictType.dict_id)
|
.order_by(SysDictType.dict_id)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
dict_type_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
dict_type_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return dict_type_list
|
return dict_type_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel):
|
async def add_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel) -> SysDictType:
|
||||||
"""
|
"""
|
||||||
新增字典类型数据库操作
|
新增字典类型数据库操作
|
||||||
|
|
||||||
@@ -107,7 +116,7 @@ class DictTypeDao:
|
|||||||
return db_dict_type
|
return db_dict_type
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_dict_type_dao(cls, db: AsyncSession, dict_type: dict):
|
async def edit_dict_type_dao(cls, db: AsyncSession, dict_type: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑字典类型数据库操作
|
编辑字典类型数据库操作
|
||||||
|
|
||||||
@@ -118,7 +127,7 @@ class DictTypeDao:
|
|||||||
await db.execute(update(SysDictType), [dict_type])
|
await db.execute(update(SysDictType), [dict_type])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel):
|
async def delete_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除字典类型数据库操作
|
删除字典类型数据库操作
|
||||||
|
|
||||||
@@ -135,7 +144,7 @@ class DictDataDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dict_data_detail_by_id(cls, db: AsyncSession, dict_code: int):
|
async def get_dict_data_detail_by_id(cls, db: AsyncSession, dict_code: int) -> Union[SysDictData, None]:
|
||||||
"""
|
"""
|
||||||
根据字典数据id获取字典数据详细信息
|
根据字典数据id获取字典数据详细信息
|
||||||
|
|
||||||
@@ -150,7 +159,7 @@ class DictDataDao:
|
|||||||
return dict_data_info
|
return dict_data_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dict_data_detail_by_info(cls, db: AsyncSession, dict_data: DictDataModel):
|
async def get_dict_data_detail_by_info(cls, db: AsyncSession, dict_data: DictDataModel) -> Union[SysDictData, None]:
|
||||||
"""
|
"""
|
||||||
根据字典数据参数获取字典数据信息
|
根据字典数据参数获取字典数据信息
|
||||||
|
|
||||||
@@ -175,7 +184,9 @@ class DictDataDao:
|
|||||||
return dict_data_info
|
return dict_data_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_dict_data_list(cls, db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False):
|
async def get_dict_data_list(
|
||||||
|
cls, db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取字典数据列表信息
|
根据查询参数获取字典数据列表信息
|
||||||
|
|
||||||
@@ -194,12 +205,14 @@ class DictDataDao:
|
|||||||
.order_by(SysDictData.dict_sort)
|
.order_by(SysDictData.dict_sort)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
dict_data_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
dict_data_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return dict_data_list
|
return dict_data_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def query_dict_data_list(cls, db: AsyncSession, dict_type: str):
|
async def query_dict_data_list(cls, db: AsyncSession, dict_type: str) -> Sequence[SysDictData]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取字典数据列表信息
|
根据查询参数获取字典数据列表信息
|
||||||
|
|
||||||
@@ -229,7 +242,7 @@ class DictDataDao:
|
|||||||
return dict_data_list
|
return dict_data_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel):
|
async def add_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel) -> SysDictData:
|
||||||
"""
|
"""
|
||||||
新增字典数据数据库操作
|
新增字典数据数据库操作
|
||||||
|
|
||||||
@@ -244,7 +257,7 @@ class DictDataDao:
|
|||||||
return db_data_type
|
return db_data_type
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_dict_data_dao(cls, db: AsyncSession, dict_data: dict):
|
async def edit_dict_data_dao(cls, db: AsyncSession, dict_data: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑字典数据数据库操作
|
编辑字典数据数据库操作
|
||||||
|
|
||||||
@@ -255,7 +268,7 @@ class DictDataDao:
|
|||||||
await db.execute(update(SysDictData), [dict_data])
|
await db.execute(update(SysDictData), [dict_data])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel):
|
async def delete_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除字典数据数据库操作
|
删除字典数据数据库操作
|
||||||
|
|
||||||
@@ -266,7 +279,7 @@ class DictDataDao:
|
|||||||
await db.execute(delete(SysDictData).where(SysDictData.dict_code.in_([dict_data.dict_code])))
|
await db.execute(delete(SysDictData).where(SysDictData.dict_code.in_([dict_data.dict_code])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def count_dict_data_dao(cls, db: AsyncSession, dict_type: str):
|
async def count_dict_data_dao(cls, db: AsyncSession, dict_type: str) -> Union[int, None]:
|
||||||
"""
|
"""
|
||||||
根据字典类型查询字典类型关联的字典数据数量
|
根据字典类型查询字典类型关联的字典数据数量
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
|
from collections.abc import Sequence
|
||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import delete, select, update
|
from sqlalchemy import delete, select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.vo import PageModel
|
||||||
from module_admin.entity.do.job_do import SysJob
|
from module_admin.entity.do.job_do import SysJob
|
||||||
from module_admin.entity.vo.job_vo import JobModel, JobPageQueryModel
|
from module_admin.entity.vo.job_vo import JobModel, JobPageQueryModel
|
||||||
from utils.page_util import PageUtil
|
from utils.page_util import PageUtil
|
||||||
@@ -11,7 +16,7 @@ class JobDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_job_detail_by_id(cls, db: AsyncSession, job_id: int):
|
async def get_job_detail_by_id(cls, db: AsyncSession, job_id: int) -> Union[SysJob, None]:
|
||||||
"""
|
"""
|
||||||
根据定时任务id获取定时任务详细信息
|
根据定时任务id获取定时任务详细信息
|
||||||
|
|
||||||
@@ -24,7 +29,7 @@ class JobDao:
|
|||||||
return job_info
|
return job_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_job_detail_by_info(cls, db: AsyncSession, job: JobModel):
|
async def get_job_detail_by_info(cls, db: AsyncSession, job: JobModel) -> Union[SysJob, None]:
|
||||||
"""
|
"""
|
||||||
根据定时任务参数获取定时任务信息
|
根据定时任务参数获取定时任务信息
|
||||||
|
|
||||||
@@ -53,7 +58,9 @@ class JobDao:
|
|||||||
return job_info
|
return job_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_job_list(cls, db: AsyncSession, query_object: JobPageQueryModel, is_page: bool = False):
|
async def get_job_list(
|
||||||
|
cls, db: AsyncSession, query_object: JobPageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取定时任务列表信息
|
根据查询参数获取定时任务列表信息
|
||||||
|
|
||||||
@@ -72,12 +79,14 @@ class JobDao:
|
|||||||
.order_by(SysJob.job_id)
|
.order_by(SysJob.job_id)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
job_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
job_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return job_list
|
return job_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_job_list_for_scheduler(cls, db: AsyncSession):
|
async def get_job_list_for_scheduler(cls, db: AsyncSession) -> Sequence[SysJob]:
|
||||||
"""
|
"""
|
||||||
获取定时任务列表信息
|
获取定时任务列表信息
|
||||||
|
|
||||||
@@ -89,7 +98,7 @@ class JobDao:
|
|||||||
return job_list
|
return job_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_job_dao(cls, db: AsyncSession, job: JobModel):
|
async def add_job_dao(cls, db: AsyncSession, job: JobModel) -> SysJob:
|
||||||
"""
|
"""
|
||||||
新增定时任务数据库操作
|
新增定时任务数据库操作
|
||||||
|
|
||||||
@@ -104,7 +113,7 @@ class JobDao:
|
|||||||
return db_job
|
return db_job
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_job_dao(cls, db: AsyncSession, job: dict, old_job: JobModel):
|
async def edit_job_dao(cls, db: AsyncSession, job: dict, old_job: JobModel) -> None:
|
||||||
"""
|
"""
|
||||||
编辑定时任务数据库操作
|
编辑定时任务数据库操作
|
||||||
|
|
||||||
@@ -124,7 +133,7 @@ class JobDao:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_job_dao(cls, db: AsyncSession, job: JobModel):
|
async def delete_job_dao(cls, db: AsyncSession, job: JobModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除定时任务数据库操作
|
删除定时任务数据库操作
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import delete, desc, select
|
from sqlalchemy import delete, desc, select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from common.vo import PageModel
|
||||||
from module_admin.entity.do.job_do import SysJobLog
|
from module_admin.entity.do.job_do import SysJobLog
|
||||||
from module_admin.entity.vo.job_vo import JobLogModel, JobLogPageQueryModel
|
from module_admin.entity.vo.job_vo import JobLogModel, JobLogPageQueryModel
|
||||||
from utils.page_util import PageUtil
|
from utils.page_util import PageUtil
|
||||||
@@ -13,7 +17,9 @@ class JobLogDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_job_log_list(cls, db: AsyncSession, query_object: JobLogPageQueryModel, is_page: bool = False):
|
async def get_job_log_list(
|
||||||
|
cls, db: AsyncSession, query_object: JobLogPageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取定时任务日志列表信息
|
根据查询参数获取定时任务日志列表信息
|
||||||
|
|
||||||
@@ -38,12 +44,14 @@ class JobLogDao:
|
|||||||
.order_by(desc(SysJobLog.create_time))
|
.order_by(desc(SysJobLog.create_time))
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
job_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
job_log_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return job_log_list
|
return job_log_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def add_job_log_dao(cls, db: Session, job_log: JobLogModel):
|
def add_job_log_dao(cls, db: Session, job_log: JobLogModel) -> SysJobLog:
|
||||||
"""
|
"""
|
||||||
新增定时任务日志数据库操作
|
新增定时任务日志数据库操作
|
||||||
|
|
||||||
@@ -58,7 +66,7 @@ class JobLogDao:
|
|||||||
return db_job_log
|
return db_job_log
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_job_log_dao(cls, db: AsyncSession, job_log: JobLogModel):
|
async def delete_job_log_dao(cls, db: AsyncSession, job_log: JobLogModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除定时任务日志数据库操作
|
删除定时任务日志数据库操作
|
||||||
|
|
||||||
@@ -69,7 +77,7 @@ class JobLogDao:
|
|||||||
await db.execute(delete(SysJobLog).where(SysJobLog.job_log_id.in_([job_log.job_log_id])))
|
await db.execute(delete(SysJobLog).where(SysJobLog.job_log_id.in_([job_log.job_log_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def clear_job_log_dao(cls, db: AsyncSession):
|
async def clear_job_log_dao(cls, db: AsyncSession) -> None:
|
||||||
"""
|
"""
|
||||||
清除定时任务日志数据库操作
|
清除定时任务日志数据库操作
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import asc, delete, desc, select
|
from sqlalchemy import asc, delete, desc, select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.vo import PageModel
|
||||||
from module_admin.entity.do.log_do import SysLogininfor, SysOperLog
|
from module_admin.entity.do.log_do import SysLogininfor, SysOperLog
|
||||||
from module_admin.entity.vo.log_vo import LogininforModel, LoginLogPageQueryModel, OperLogModel, OperLogPageQueryModel
|
from module_admin.entity.vo.log_vo import LogininforModel, LoginLogPageQueryModel, OperLogModel, OperLogPageQueryModel
|
||||||
from utils.common_util import SnakeCaseUtil
|
from utils.common_util import SnakeCaseUtil
|
||||||
@@ -14,7 +18,9 @@ class OperationLogDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_operation_log_list(cls, db: AsyncSession, query_object: OperLogPageQueryModel, is_page: bool = False):
|
async def get_operation_log_list(
|
||||||
|
cls, db: AsyncSession, query_object: OperLogPageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取操作日志列表信息
|
根据查询参数获取操作日志列表信息
|
||||||
|
|
||||||
@@ -48,12 +54,14 @@ class OperationLogDao:
|
|||||||
.distinct()
|
.distinct()
|
||||||
.order_by(order_by_column)
|
.order_by(order_by_column)
|
||||||
)
|
)
|
||||||
operation_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
operation_log_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return operation_log_list
|
return operation_log_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel):
|
async def add_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel) -> SysOperLog:
|
||||||
"""
|
"""
|
||||||
新增操作日志数据库操作
|
新增操作日志数据库操作
|
||||||
|
|
||||||
@@ -68,7 +76,7 @@ class OperationLogDao:
|
|||||||
return db_operation_log
|
return db_operation_log
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel):
|
async def delete_operation_log_dao(cls, db: AsyncSession, operation_log: OperLogModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除操作日志数据库操作
|
删除操作日志数据库操作
|
||||||
|
|
||||||
@@ -79,7 +87,7 @@ class OperationLogDao:
|
|||||||
await db.execute(delete(SysOperLog).where(SysOperLog.oper_id.in_([operation_log.oper_id])))
|
await db.execute(delete(SysOperLog).where(SysOperLog.oper_id.in_([operation_log.oper_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def clear_operation_log_dao(cls, db: AsyncSession):
|
async def clear_operation_log_dao(cls, db: AsyncSession) -> None:
|
||||||
"""
|
"""
|
||||||
清除操作日志数据库操作
|
清除操作日志数据库操作
|
||||||
|
|
||||||
@@ -95,7 +103,9 @@ class LoginLogDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_login_log_list(cls, db: AsyncSession, query_object: LoginLogPageQueryModel, is_page: bool = False):
|
async def get_login_log_list(
|
||||||
|
cls, db: AsyncSession, query_object: LoginLogPageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取登录日志列表信息
|
根据查询参数获取登录日志列表信息
|
||||||
|
|
||||||
@@ -130,12 +140,14 @@ class LoginLogDao:
|
|||||||
.distinct()
|
.distinct()
|
||||||
.order_by(order_by_column)
|
.order_by(order_by_column)
|
||||||
)
|
)
|
||||||
login_log_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
login_log_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return login_log_list
|
return login_log_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel):
|
async def add_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel) -> SysLogininfor:
|
||||||
"""
|
"""
|
||||||
新增登录日志数据库操作
|
新增登录日志数据库操作
|
||||||
|
|
||||||
@@ -150,7 +162,7 @@ class LoginLogDao:
|
|||||||
return db_login_log
|
return db_login_log
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel):
|
async def delete_login_log_dao(cls, db: AsyncSession, login_log: LogininforModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除登录日志数据库操作
|
删除登录日志数据库操作
|
||||||
|
|
||||||
@@ -161,7 +173,7 @@ class LoginLogDao:
|
|||||||
await db.execute(delete(SysLogininfor).where(SysLogininfor.info_id.in_([login_log.info_id])))
|
await db.execute(delete(SysLogininfor).where(SysLogininfor.info_id.in_([login_log.info_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def clear_login_log_dao(cls, db: AsyncSession):
|
async def clear_login_log_dao(cls, db: AsyncSession) -> None:
|
||||||
"""
|
"""
|
||||||
清除登录日志数据库操作
|
清除登录日志数据库操作
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
from sqlalchemy import and_, select
|
from typing import Union
|
||||||
|
|
||||||
|
from sqlalchemy import Row, and_, select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from module_admin.entity.do.dept_do import SysDept
|
from module_admin.entity.do.dept_do import SysDept
|
||||||
from module_admin.entity.do.user_do import SysUser
|
from module_admin.entity.do.user_do import SysUser
|
||||||
|
|
||||||
|
|
||||||
async def login_by_account(db: AsyncSession, user_name: str):
|
async def login_by_account(db: AsyncSession, user_name: str) -> Union[Row[tuple[SysUser, SysDept]], None]:
|
||||||
"""
|
"""
|
||||||
根据用户名查询用户信息
|
根据用户名查询用户信息
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
from collections.abc import Sequence
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
from sqlalchemy import and_, delete, func, select, update
|
from sqlalchemy import and_, delete, func, select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from module_admin.entity.do.menu_do import SysMenu
|
from module_admin.entity.do.menu_do import SysMenu
|
||||||
from module_admin.entity.do.role_do import SysRole, SysRoleMenu
|
from module_admin.entity.do.role_do import SysRole, SysRoleMenu
|
||||||
from module_admin.entity.do.user_do import SysUser, SysUserRole
|
from module_admin.entity.do.user_do import SysUser, SysUserRole
|
||||||
@@ -12,7 +16,7 @@ class MenuDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_menu_detail_by_id(cls, db: AsyncSession, menu_id: int):
|
async def get_menu_detail_by_id(cls, db: AsyncSession, menu_id: int) -> Union[SysMenu, None]:
|
||||||
"""
|
"""
|
||||||
根据菜单id获取菜单详细信息
|
根据菜单id获取菜单详细信息
|
||||||
|
|
||||||
@@ -25,7 +29,7 @@ class MenuDao:
|
|||||||
return menu_info
|
return menu_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_menu_detail_by_info(cls, db: AsyncSession, menu: MenuModel):
|
async def get_menu_detail_by_info(cls, db: AsyncSession, menu: MenuModel) -> Union[SysMenu, None]:
|
||||||
"""
|
"""
|
||||||
根据菜单参数获取菜单信息
|
根据菜单参数获取菜单信息
|
||||||
|
|
||||||
@@ -50,7 +54,7 @@ class MenuDao:
|
|||||||
return menu_info
|
return menu_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_menu_list_for_tree(cls, db: AsyncSession, user_id: int, role: list):
|
async def get_menu_list_for_tree(cls, db: AsyncSession, user_id: int, role: list) -> Sequence[SysMenu]:
|
||||||
"""
|
"""
|
||||||
根据角色信息获取所有在用菜单列表信息
|
根据角色信息获取所有在用菜单列表信息
|
||||||
|
|
||||||
@@ -94,7 +98,9 @@ class MenuDao:
|
|||||||
return menu_query_all
|
return menu_query_all
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_menu_list(cls, db: AsyncSession, page_object: MenuQueryModel, user_id: int, role: list):
|
async def get_menu_list(
|
||||||
|
cls, db: AsyncSession, page_object: MenuQueryModel, user_id: int, role: list
|
||||||
|
) -> Sequence[SysMenu]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取菜单列表信息
|
根据查询参数获取菜单列表信息
|
||||||
|
|
||||||
@@ -156,7 +162,7 @@ class MenuDao:
|
|||||||
return menu_query_all
|
return menu_query_all
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_menu_dao(cls, db: AsyncSession, menu: MenuModel):
|
async def add_menu_dao(cls, db: AsyncSession, menu: MenuModel) -> SysMenu:
|
||||||
"""
|
"""
|
||||||
新增菜单数据库操作
|
新增菜单数据库操作
|
||||||
|
|
||||||
@@ -171,7 +177,7 @@ class MenuDao:
|
|||||||
return db_menu
|
return db_menu
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_menu_dao(cls, db: AsyncSession, menu: dict):
|
async def edit_menu_dao(cls, db: AsyncSession, menu: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑菜单数据库操作
|
编辑菜单数据库操作
|
||||||
|
|
||||||
@@ -182,7 +188,7 @@ class MenuDao:
|
|||||||
await db.execute(update(SysMenu), [menu])
|
await db.execute(update(SysMenu), [menu])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_menu_dao(cls, db: AsyncSession, menu: MenuModel):
|
async def delete_menu_dao(cls, db: AsyncSession, menu: MenuModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除菜单数据库操作
|
删除菜单数据库操作
|
||||||
|
|
||||||
@@ -193,7 +199,7 @@ class MenuDao:
|
|||||||
await db.execute(delete(SysMenu).where(SysMenu.menu_id.in_([menu.menu_id])))
|
await db.execute(delete(SysMenu).where(SysMenu.menu_id.in_([menu.menu_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def has_child_by_menu_id_dao(cls, db: AsyncSession, menu_id: int):
|
async def has_child_by_menu_id_dao(cls, db: AsyncSession, menu_id: int) -> Union[int, None]:
|
||||||
"""
|
"""
|
||||||
根据菜单id查询菜单关联子菜单的数量
|
根据菜单id查询菜单关联子菜单的数量
|
||||||
|
|
||||||
@@ -208,7 +214,7 @@ class MenuDao:
|
|||||||
return menu_count
|
return menu_count
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def check_menu_exist_role_dao(cls, db: AsyncSession, menu_id: int):
|
async def check_menu_exist_role_dao(cls, db: AsyncSession, menu_id: int) -> Union[int, None]:
|
||||||
"""
|
"""
|
||||||
根据菜单id查询菜单关联角色数量
|
根据菜单id查询菜单关联角色数量
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import delete, select, update
|
from sqlalchemy import delete, select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.vo import PageModel
|
||||||
from module_admin.entity.do.notice_do import SysNotice
|
from module_admin.entity.do.notice_do import SysNotice
|
||||||
from module_admin.entity.vo.notice_vo import NoticeModel, NoticePageQueryModel
|
from module_admin.entity.vo.notice_vo import NoticeModel, NoticePageQueryModel
|
||||||
from utils.page_util import PageUtil
|
from utils.page_util import PageUtil
|
||||||
@@ -12,7 +16,7 @@ class NoticeDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_notice_detail_by_id(cls, db: AsyncSession, notice_id: int):
|
async def get_notice_detail_by_id(cls, db: AsyncSession, notice_id: int) -> Union[SysNotice, None]:
|
||||||
"""
|
"""
|
||||||
根据通知公告id获取通知公告详细信息
|
根据通知公告id获取通知公告详细信息
|
||||||
|
|
||||||
@@ -25,7 +29,7 @@ class NoticeDao:
|
|||||||
return notice_info
|
return notice_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_notice_detail_by_info(cls, db: AsyncSession, notice: NoticeModel):
|
async def get_notice_detail_by_info(cls, db: AsyncSession, notice: NoticeModel) -> Union[SysNotice, None]:
|
||||||
"""
|
"""
|
||||||
根据通知公告参数获取通知公告信息
|
根据通知公告参数获取通知公告信息
|
||||||
|
|
||||||
@@ -50,7 +54,9 @@ class NoticeDao:
|
|||||||
return notice_info
|
return notice_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_notice_list(cls, db: AsyncSession, query_object: NoticePageQueryModel, is_page: bool = False):
|
async def get_notice_list(
|
||||||
|
cls, db: AsyncSession, query_object: NoticePageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取通知公告列表信息
|
根据查询参数获取通知公告列表信息
|
||||||
|
|
||||||
@@ -75,12 +81,14 @@ class NoticeDao:
|
|||||||
.order_by(SysNotice.notice_id)
|
.order_by(SysNotice.notice_id)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
notice_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
notice_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return notice_list
|
return notice_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_notice_dao(cls, db: AsyncSession, notice: NoticeModel):
|
async def add_notice_dao(cls, db: AsyncSession, notice: NoticeModel) -> SysNotice:
|
||||||
"""
|
"""
|
||||||
新增通知公告数据库操作
|
新增通知公告数据库操作
|
||||||
|
|
||||||
@@ -95,7 +103,7 @@ class NoticeDao:
|
|||||||
return db_notice
|
return db_notice
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_notice_dao(cls, db: AsyncSession, notice: dict):
|
async def edit_notice_dao(cls, db: AsyncSession, notice: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑通知公告数据库操作
|
编辑通知公告数据库操作
|
||||||
|
|
||||||
@@ -106,7 +114,7 @@ class NoticeDao:
|
|||||||
await db.execute(update(SysNotice), [notice])
|
await db.execute(update(SysNotice), [notice])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_notice_dao(cls, db: AsyncSession, notice: NoticeModel):
|
async def delete_notice_dao(cls, db: AsyncSession, notice: NoticeModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除通知公告数据库操作
|
删除通知公告数据库操作
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import delete, func, select, update
|
from sqlalchemy import delete, func, select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.vo import PageModel
|
||||||
from module_admin.entity.do.post_do import SysPost
|
from module_admin.entity.do.post_do import SysPost
|
||||||
from module_admin.entity.do.user_do import SysUserPost
|
from module_admin.entity.do.user_do import SysUserPost
|
||||||
from module_admin.entity.vo.post_vo import PostModel, PostPageQueryModel
|
from module_admin.entity.vo.post_vo import PostModel, PostPageQueryModel
|
||||||
@@ -12,7 +16,7 @@ class PostDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_post_by_id(cls, db: AsyncSession, post_id: int):
|
async def get_post_by_id(cls, db: AsyncSession, post_id: int) -> Union[SysPost, None]:
|
||||||
"""
|
"""
|
||||||
根据岗位id获取在用岗位详细信息
|
根据岗位id获取在用岗位详细信息
|
||||||
|
|
||||||
@@ -29,7 +33,7 @@ class PostDao:
|
|||||||
return post_info
|
return post_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_post_detail_by_id(cls, db: AsyncSession, post_id: int):
|
async def get_post_detail_by_id(cls, db: AsyncSession, post_id: int) -> Union[SysPost, None]:
|
||||||
"""
|
"""
|
||||||
根据岗位id获取岗位详细信息
|
根据岗位id获取岗位详细信息
|
||||||
|
|
||||||
@@ -42,7 +46,7 @@ class PostDao:
|
|||||||
return post_info
|
return post_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_post_detail_by_info(cls, db: AsyncSession, post: PostModel):
|
async def get_post_detail_by_info(cls, db: AsyncSession, post: PostModel) -> Union[SysPost, None]:
|
||||||
"""
|
"""
|
||||||
根据岗位参数获取岗位信息
|
根据岗位参数获取岗位信息
|
||||||
|
|
||||||
@@ -67,7 +71,9 @@ class PostDao:
|
|||||||
return post_info
|
return post_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_post_list(cls, db: AsyncSession, query_object: PostPageQueryModel, is_page: bool = False):
|
async def get_post_list(
|
||||||
|
cls, db: AsyncSession, query_object: PostPageQueryModel, is_page: bool = False
|
||||||
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取岗位列表信息
|
根据查询参数获取岗位列表信息
|
||||||
|
|
||||||
@@ -86,12 +92,14 @@ class PostDao:
|
|||||||
.order_by(SysPost.post_sort)
|
.order_by(SysPost.post_sort)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
post_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
post_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return post_list
|
return post_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_post_dao(cls, db: AsyncSession, post: PostModel):
|
async def add_post_dao(cls, db: AsyncSession, post: PostModel) -> SysPost:
|
||||||
"""
|
"""
|
||||||
新增岗位数据库操作
|
新增岗位数据库操作
|
||||||
|
|
||||||
@@ -106,7 +114,7 @@ class PostDao:
|
|||||||
return db_post
|
return db_post
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_post_dao(cls, db: AsyncSession, post: dict):
|
async def edit_post_dao(cls, db: AsyncSession, post: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑岗位数据库操作
|
编辑岗位数据库操作
|
||||||
|
|
||||||
@@ -117,7 +125,7 @@ class PostDao:
|
|||||||
await db.execute(update(SysPost), [post])
|
await db.execute(update(SysPost), [post])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_post_dao(cls, db: AsyncSession, post: PostModel):
|
async def delete_post_dao(cls, db: AsyncSession, post: PostModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除岗位数据库操作
|
删除岗位数据库操作
|
||||||
|
|
||||||
@@ -128,7 +136,7 @@ class PostDao:
|
|||||||
await db.execute(delete(SysPost).where(SysPost.post_id.in_([post.post_id])))
|
await db.execute(delete(SysPost).where(SysPost.post_id.in_([post.post_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def count_user_post_dao(cls, db: AsyncSession, post_id: int):
|
async def count_user_post_dao(cls, db: AsyncSession, post_id: int) -> Union[int, None]:
|
||||||
"""
|
"""
|
||||||
根据岗位id查询岗位关联的用户数量
|
根据岗位id查询岗位关联的用户数量
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
from collections.abc import Sequence
|
||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import and_, delete, desc, func, or_, select, update # noqa: F401
|
from sqlalchemy import and_, delete, desc, func, or_, select, update # noqa: F401
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.vo import PageModel
|
||||||
from module_admin.entity.do.dept_do import SysDept
|
from module_admin.entity.do.dept_do import SysDept
|
||||||
from module_admin.entity.do.menu_do import SysMenu
|
from module_admin.entity.do.menu_do import SysMenu
|
||||||
from module_admin.entity.do.role_do import SysRole, SysRoleMenu, SysRoleDept
|
from module_admin.entity.do.role_do import SysRole, SysRoleDept, SysRoleMenu
|
||||||
from module_admin.entity.do.user_do import SysUser, SysUserRole
|
from module_admin.entity.do.user_do import SysUser, SysUserRole
|
||||||
from module_admin.entity.vo.role_vo import RoleDeptModel, RoleMenuModel, RoleModel, RolePageQueryModel
|
from module_admin.entity.vo.role_vo import RoleDeptModel, RoleMenuModel, RoleModel, RolePageQueryModel
|
||||||
from utils.page_util import PageUtil
|
from utils.page_util import PageUtil
|
||||||
@@ -15,7 +20,7 @@ class RoleDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_role_by_name(cls, db: AsyncSession, role_name: str):
|
async def get_role_by_name(cls, db: AsyncSession, role_name: str) -> Union[SysRole, None]:
|
||||||
"""
|
"""
|
||||||
根据角色名获取在用角色信息
|
根据角色名获取在用角色信息
|
||||||
|
|
||||||
@@ -39,7 +44,7 @@ class RoleDao:
|
|||||||
return query_role_info
|
return query_role_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_role_by_info(cls, db: AsyncSession, role: RoleModel):
|
async def get_role_by_info(cls, db: AsyncSession, role: RoleModel) -> Union[SysRole, None]:
|
||||||
"""
|
"""
|
||||||
根据角色参数获取角色信息
|
根据角色参数获取角色信息
|
||||||
|
|
||||||
@@ -67,7 +72,7 @@ class RoleDao:
|
|||||||
return query_role_info
|
return query_role_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_role_by_id(cls, db: AsyncSession, role_id: int):
|
async def get_role_by_id(cls, db: AsyncSession, role_id: int) -> Union[SysRole, None]:
|
||||||
"""
|
"""
|
||||||
根据角色id获取在用角色信息
|
根据角色id获取在用角色信息
|
||||||
|
|
||||||
@@ -88,7 +93,7 @@ class RoleDao:
|
|||||||
return role_info
|
return role_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_role_detail_by_id(cls, db: AsyncSession, role_id: int):
|
async def get_role_detail_by_id(cls, db: AsyncSession, role_id: int) -> Union[SysRole, None]:
|
||||||
"""
|
"""
|
||||||
根据role_id获取角色详细信息
|
根据role_id获取角色详细信息
|
||||||
|
|
||||||
@@ -105,7 +110,7 @@ class RoleDao:
|
|||||||
return query_role_info
|
return query_role_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_role_select_option_dao(cls, db: AsyncSession):
|
async def get_role_select_option_dao(cls, db: AsyncSession) -> Sequence[SysRole]:
|
||||||
"""
|
"""
|
||||||
获取编辑页面对应的在用角色列表信息
|
获取编辑页面对应的在用角色列表信息
|
||||||
|
|
||||||
@@ -127,7 +132,7 @@ class RoleDao:
|
|||||||
@classmethod
|
@classmethod
|
||||||
async def get_role_list(
|
async def get_role_list(
|
||||||
cls, db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False
|
cls, db: AsyncSession, query_object: RolePageQueryModel, data_scope_sql: str, is_page: bool = False
|
||||||
):
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取角色列表信息
|
根据查询参数获取角色列表信息
|
||||||
|
|
||||||
@@ -159,12 +164,14 @@ class RoleDao:
|
|||||||
.order_by(SysRole.role_sort)
|
.order_by(SysRole.role_sort)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
role_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
role_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return role_list
|
return role_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_role_dao(cls, db: AsyncSession, role: RoleModel):
|
async def add_role_dao(cls, db: AsyncSession, role: RoleModel) -> SysRole:
|
||||||
"""
|
"""
|
||||||
新增角色数据库操作
|
新增角色数据库操作
|
||||||
|
|
||||||
@@ -179,7 +186,7 @@ class RoleDao:
|
|||||||
return db_role
|
return db_role
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_role_dao(cls, db: AsyncSession, role: dict):
|
async def edit_role_dao(cls, db: AsyncSession, role: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑角色数据库操作
|
编辑角色数据库操作
|
||||||
|
|
||||||
@@ -190,7 +197,7 @@ class RoleDao:
|
|||||||
await db.execute(update(SysRole), [role])
|
await db.execute(update(SysRole), [role])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_role_dao(cls, db: AsyncSession, role: RoleModel):
|
async def delete_role_dao(cls, db: AsyncSession, role: RoleModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除角色数据库操作
|
删除角色数据库操作
|
||||||
|
|
||||||
@@ -205,7 +212,7 @@ class RoleDao:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_role_menu_dao(cls, db: AsyncSession, role: RoleModel):
|
async def get_role_menu_dao(cls, db: AsyncSession, role: RoleModel) -> Sequence[SysMenu]:
|
||||||
"""
|
"""
|
||||||
根据角色id获取角色菜单关联列表信息
|
根据角色id获取角色菜单关联列表信息
|
||||||
|
|
||||||
@@ -241,7 +248,7 @@ class RoleDao:
|
|||||||
return role_menu_query_all
|
return role_menu_query_all
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel):
|
async def add_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel) -> None:
|
||||||
"""
|
"""
|
||||||
新增角色菜单关联信息数据库操作
|
新增角色菜单关联信息数据库操作
|
||||||
|
|
||||||
@@ -253,7 +260,7 @@ class RoleDao:
|
|||||||
db.add(db_role_menu)
|
db.add(db_role_menu)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel):
|
async def delete_role_menu_dao(cls, db: AsyncSession, role_menu: RoleMenuModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除角色菜单关联信息数据库操作
|
删除角色菜单关联信息数据库操作
|
||||||
|
|
||||||
@@ -264,7 +271,7 @@ class RoleDao:
|
|||||||
await db.execute(delete(SysRoleMenu).where(SysRoleMenu.role_id.in_([role_menu.role_id])))
|
await db.execute(delete(SysRoleMenu).where(SysRoleMenu.role_id.in_([role_menu.role_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_role_dept_dao(cls, db: AsyncSession, role: RoleModel):
|
async def get_role_dept_dao(cls, db: AsyncSession, role: RoleModel) -> Sequence[SysDept]:
|
||||||
"""
|
"""
|
||||||
根据角色id获取角色部门关联列表信息
|
根据角色id获取角色部门关联列表信息
|
||||||
|
|
||||||
@@ -300,7 +307,7 @@ class RoleDao:
|
|||||||
return role_dept_query_all
|
return role_dept_query_all
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel):
|
async def add_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel) -> None:
|
||||||
"""
|
"""
|
||||||
新增角色部门关联信息数据库操作
|
新增角色部门关联信息数据库操作
|
||||||
|
|
||||||
@@ -312,7 +319,7 @@ class RoleDao:
|
|||||||
db.add(db_role_dept)
|
db.add(db_role_dept)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel):
|
async def delete_role_dept_dao(cls, db: AsyncSession, role_dept: RoleDeptModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除角色部门关联信息数据库操作
|
删除角色部门关联信息数据库操作
|
||||||
|
|
||||||
@@ -323,7 +330,7 @@ class RoleDao:
|
|||||||
await db.execute(delete(SysRoleDept).where(SysRoleDept.role_id.in_([role_dept.role_id])))
|
await db.execute(delete(SysRoleDept).where(SysRoleDept.role_id.in_([role_dept.role_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def count_user_role_dao(cls, db: AsyncSession, role_id: int):
|
async def count_user_role_dao(cls, db: AsyncSession, role_id: int) -> Union[int, None]:
|
||||||
"""
|
"""
|
||||||
根据角色id查询角色关联用户数量
|
根据角色id查询角色关联用户数量
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
from collections.abc import Sequence
|
||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from sqlalchemy import and_, delete, desc, func, or_, select, update
|
from sqlalchemy import and_, delete, desc, func, or_, select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
|
from common.vo import PageModel
|
||||||
from module_admin.entity.do.dept_do import SysDept
|
from module_admin.entity.do.dept_do import SysDept
|
||||||
from module_admin.entity.do.menu_do import SysMenu
|
from module_admin.entity.do.menu_do import SysMenu
|
||||||
from module_admin.entity.do.post_do import SysPost
|
from module_admin.entity.do.post_do import SysPost
|
||||||
@@ -23,7 +28,7 @@ class UserDao:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_by_name(cls, db: AsyncSession, user_name: str):
|
async def get_user_by_name(cls, db: AsyncSession, user_name: str) -> Union[SysUser, None]:
|
||||||
"""
|
"""
|
||||||
根据用户名获取用户信息
|
根据用户名获取用户信息
|
||||||
|
|
||||||
@@ -47,7 +52,7 @@ class UserDao:
|
|||||||
return query_user_info
|
return query_user_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_by_info(cls, db: AsyncSession, user: UserModel):
|
async def get_user_by_info(cls, db: AsyncSession, user: UserModel) -> Union[SysUser, None]:
|
||||||
"""
|
"""
|
||||||
根据用户参数获取用户信息
|
根据用户参数获取用户信息
|
||||||
|
|
||||||
@@ -76,7 +81,7 @@ class UserDao:
|
|||||||
return query_user_info
|
return query_user_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_by_id(cls, db: AsyncSession, user_id: int):
|
async def get_user_by_id(cls, db: AsyncSession, user_id: int) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
根据user_id获取用户信息
|
根据user_id获取用户信息
|
||||||
|
|
||||||
@@ -172,18 +177,18 @@ class UserDao:
|
|||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
results = dict(
|
results = {
|
||||||
user_basic_info=query_user_basic_info,
|
'user_basic_info': query_user_basic_info,
|
||||||
user_dept_info=query_user_dept_info,
|
'user_dept_info': query_user_dept_info,
|
||||||
user_role_info=query_user_role_info,
|
'user_role_info': query_user_role_info,
|
||||||
user_post_info=query_user_post_info,
|
'user_post_info': query_user_post_info,
|
||||||
user_menu_info=query_user_menu_info,
|
'user_menu_info': query_user_menu_info,
|
||||||
)
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_detail_by_id(cls, db: AsyncSession, user_id: int):
|
async def get_user_detail_by_id(cls, db: AsyncSession, user_id: int) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
根据user_id获取用户详细信息
|
根据user_id获取用户详细信息
|
||||||
|
|
||||||
@@ -263,20 +268,20 @@ class UserDao:
|
|||||||
.scalars()
|
.scalars()
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
results = dict(
|
results = {
|
||||||
user_basic_info=query_user_basic_info,
|
'user_basic_info': query_user_basic_info,
|
||||||
user_dept_info=query_user_dept_info,
|
'user_dept_info': query_user_dept_info,
|
||||||
user_role_info=query_user_role_info,
|
'user_role_info': query_user_role_info,
|
||||||
user_post_info=query_user_post_info,
|
'user_post_info': query_user_post_info,
|
||||||
user_menu_info=query_user_menu_info,
|
'user_menu_info': query_user_menu_info,
|
||||||
)
|
}
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_list(
|
async def get_user_list(
|
||||||
cls, db: AsyncSession, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False
|
cls, db: AsyncSession, query_object: UserPageQueryModel, data_scope_sql: str, is_page: bool = False
|
||||||
):
|
) -> Union[PageModel, list[list[dict[str, Any]]]]:
|
||||||
"""
|
"""
|
||||||
根据查询参数获取用户列表信息
|
根据查询参数获取用户列表信息
|
||||||
|
|
||||||
@@ -321,12 +326,14 @@ class UserDao:
|
|||||||
.order_by(SysUser.user_id)
|
.order_by(SysUser.user_id)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
user_list: Union[PageModel, list[list[dict[str, Any]]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return user_list
|
return user_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_user_dao(cls, db: AsyncSession, user: UserModel):
|
async def add_user_dao(cls, db: AsyncSession, user: UserModel) -> SysUser:
|
||||||
"""
|
"""
|
||||||
新增用户数据库操作
|
新增用户数据库操作
|
||||||
|
|
||||||
@@ -341,7 +348,7 @@ class UserDao:
|
|||||||
return db_user
|
return db_user
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_user_dao(cls, db: AsyncSession, user: dict):
|
async def edit_user_dao(cls, db: AsyncSession, user: dict) -> None:
|
||||||
"""
|
"""
|
||||||
编辑用户数据库操作
|
编辑用户数据库操作
|
||||||
|
|
||||||
@@ -352,7 +359,7 @@ class UserDao:
|
|||||||
await db.execute(update(SysUser), [user])
|
await db.execute(update(SysUser), [user])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_user_dao(cls, db: AsyncSession, user: UserModel):
|
async def delete_user_dao(cls, db: AsyncSession, user: UserModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除用户数据库操作
|
删除用户数据库操作
|
||||||
|
|
||||||
@@ -367,7 +374,9 @@ class UserDao:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_role_allocated_list_by_user_id(cls, db: AsyncSession, query_object: UserRoleQueryModel):
|
async def get_user_role_allocated_list_by_user_id(
|
||||||
|
cls, db: AsyncSession, query_object: UserRoleQueryModel
|
||||||
|
) -> Sequence[SysRole]:
|
||||||
"""
|
"""
|
||||||
根据用户id获取用户已分配的角色列表信息数据库操作
|
根据用户id获取用户已分配的角色列表信息数据库操作
|
||||||
|
|
||||||
@@ -400,7 +409,7 @@ class UserDao:
|
|||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_role_allocated_list_by_role_id(
|
async def get_user_role_allocated_list_by_role_id(
|
||||||
cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False
|
cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False
|
||||||
):
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据角色id获取已分配的用户列表信息
|
根据角色id获取已分配的用户列表信息
|
||||||
|
|
||||||
@@ -424,14 +433,16 @@ class UserDao:
|
|||||||
)
|
)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
allocated_user_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
|
allocated_user_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
|
)
|
||||||
|
|
||||||
return allocated_user_list
|
return allocated_user_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_role_unallocated_list_by_role_id(
|
async def get_user_role_unallocated_list_by_role_id(
|
||||||
cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False
|
cls, db: AsyncSession, query_object: UserRolePageQueryModel, data_scope_sql: str, is_page: bool = False
|
||||||
):
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
根据角色id获取未分配的用户列表信息
|
根据角色id获取未分配的用户列表信息
|
||||||
|
|
||||||
@@ -463,14 +474,14 @@ class UserDao:
|
|||||||
)
|
)
|
||||||
.distinct()
|
.distinct()
|
||||||
)
|
)
|
||||||
unallocated_user_list = await PageUtil.paginate(
|
unallocated_user_list: Union[PageModel, list[dict[str, Any]]] = await PageUtil.paginate(
|
||||||
db, query, query_object.page_num, query_object.page_size, is_page
|
db, query, query_object.page_num, query_object.page_size, is_page
|
||||||
)
|
)
|
||||||
|
|
||||||
return unallocated_user_list
|
return unallocated_user_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel):
|
async def add_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel) -> None:
|
||||||
"""
|
"""
|
||||||
新增用户角色关联信息数据库操作
|
新增用户角色关联信息数据库操作
|
||||||
|
|
||||||
@@ -482,7 +493,7 @@ class UserDao:
|
|||||||
db.add(db_user_role)
|
db.add(db_user_role)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel):
|
async def delete_user_role_dao(cls, db: AsyncSession, user_role: UserRoleModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除用户角色关联信息数据库操作
|
删除用户角色关联信息数据库操作
|
||||||
|
|
||||||
@@ -493,7 +504,7 @@ class UserDao:
|
|||||||
await db.execute(delete(SysUserRole).where(SysUserRole.user_id.in_([user_role.user_id])))
|
await db.execute(delete(SysUserRole).where(SysUserRole.user_id.in_([user_role.user_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_user_role_by_user_and_role_dao(cls, db: AsyncSession, user_role: UserRoleModel):
|
async def delete_user_role_by_user_and_role_dao(cls, db: AsyncSession, user_role: UserRoleModel) -> None:
|
||||||
"""
|
"""
|
||||||
根据用户id及角色id删除用户角色关联信息数据库操作
|
根据用户id及角色id删除用户角色关联信息数据库操作
|
||||||
|
|
||||||
@@ -509,7 +520,7 @@ class UserDao:
|
|||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_role_detail(cls, db: AsyncSession, user_role: UserRoleModel):
|
async def get_user_role_detail(cls, db: AsyncSession, user_role: UserRoleModel) -> Union[SysUserRole, None]:
|
||||||
"""
|
"""
|
||||||
根据用户角色关联获取用户角色关联详细信息
|
根据用户角色关联获取用户角色关联详细信息
|
||||||
|
|
||||||
@@ -532,7 +543,7 @@ class UserDao:
|
|||||||
return user_role_info
|
return user_role_info
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel):
|
async def add_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel) -> None:
|
||||||
"""
|
"""
|
||||||
新增用户岗位关联信息数据库操作
|
新增用户岗位关联信息数据库操作
|
||||||
|
|
||||||
@@ -544,7 +555,7 @@ class UserDao:
|
|||||||
db.add(db_user_post)
|
db.add(db_user_post)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel):
|
async def delete_user_post_dao(cls, db: AsyncSession, user_post: UserPostModel) -> None:
|
||||||
"""
|
"""
|
||||||
删除用户岗位关联信息数据库操作
|
删除用户岗位关联信息数据库操作
|
||||||
|
|
||||||
@@ -555,7 +566,7 @@ class UserDao:
|
|||||||
await db.execute(delete(SysUserPost).where(SysUserPost.user_id.in_([user_post.user_id])))
|
await db.execute(delete(SysUserPost).where(SysUserPost.user_id.in_([user_post.user_id])))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_user_dept_info(cls, db: AsyncSession, dept_id: int):
|
async def get_user_dept_info(cls, db: AsyncSession, dept_id: int) -> Union[SysDept, None]:
|
||||||
dept_basic_info = (
|
dept_basic_info = (
|
||||||
(
|
(
|
||||||
await db.execute(
|
await db.execute(
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import CHAR, Column, DateTime, Integer, String
|
from sqlalchemy import CHAR, Column, DateTime, Integer, String
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, String
|
|
||||||
|
from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, String
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, String
|
|
||||||
|
from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, String
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import BigInteger, CHAR, Column, DateTime, DOUBLE, Index, LargeBinary, String
|
|
||||||
|
from sqlalchemy import CHAR, DOUBLE, BigInteger, Column, DateTime, Float, Index, LargeBinary, String, Unicode
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
@@ -65,9 +67,11 @@ class ApschedulerJobs(Base):
|
|||||||
|
|
||||||
__tablename__ = 'apscheduler_jobs'
|
__tablename__ = 'apscheduler_jobs'
|
||||||
|
|
||||||
id = Column(String(191), primary_key=True, nullable=False)
|
id = Column(Unicode(191), primary_key=True, nullable=False)
|
||||||
next_run_time = Column(
|
next_run_time = Column(
|
||||||
DOUBLE, nullable=True, server_default=SqlalchemyUtil.get_server_default_null(DataBaseConfig.db_type, False)
|
DOUBLE if DataBaseConfig.db_type == 'mysql' else Float(25),
|
||||||
|
nullable=True,
|
||||||
|
server_default=SqlalchemyUtil.get_server_default_null(DataBaseConfig.db_type, False),
|
||||||
)
|
)
|
||||||
job_state = Column(LargeBinary, nullable=False)
|
job_state = Column(LargeBinary, nullable=False)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import BigInteger, CHAR, Column, DateTime, Index, Integer, String
|
|
||||||
|
from sqlalchemy import CHAR, BigInteger, Column, DateTime, Index, Integer, String
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
|
|
||||||
|
|
||||||
@@ -38,7 +40,9 @@ class SysOperLog(Base):
|
|||||||
business_type = Column(Integer, nullable=True, server_default='0', comment='业务类型(0其它 1新增 2修改 3删除)')
|
business_type = Column(Integer, nullable=True, server_default='0', comment='业务类型(0其它 1新增 2修改 3删除)')
|
||||||
method = Column(String(100), nullable=True, server_default="''", comment='方法名称')
|
method = Column(String(100), nullable=True, server_default="''", comment='方法名称')
|
||||||
request_method = Column(String(10), nullable=True, server_default="''", comment='请求方式')
|
request_method = Column(String(10), nullable=True, server_default="''", comment='请求方式')
|
||||||
operator_type = Column(Integer, nullable=True, server_default='0', comment='操作类别(0其它 1后台用户 2手机端用户)')
|
operator_type = Column(
|
||||||
|
Integer, nullable=True, server_default='0', comment='操作类别(0其它 1后台用户 2手机端用户)'
|
||||||
|
)
|
||||||
oper_name = Column(String(50), nullable=True, server_default="''", comment='操作人员')
|
oper_name = Column(String(50), nullable=True, server_default="''", comment='操作人员')
|
||||||
dept_name = Column(String(50), nullable=True, server_default="''", comment='部门名称')
|
dept_name = Column(String(50), nullable=True, server_default="''", comment='部门名称')
|
||||||
oper_url = Column(String(255), nullable=True, server_default="''", comment='请求URL')
|
oper_url = Column(String(255), nullable=True, server_default="''", comment='请求URL')
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, String
|
|
||||||
|
from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, String
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import CHAR, Column, DateTime, Integer, LargeBinary, String
|
from sqlalchemy import CHAR, Column, DateTime, Integer, LargeBinary, String
|
||||||
from sqlalchemy.dialects import mysql
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, String
|
|
||||||
|
from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, String
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import BigInteger, CHAR, Column, DateTime, Integer, SmallInteger, String
|
|
||||||
|
from sqlalchemy import CHAR, BigInteger, Column, DateTime, Integer, SmallInteger, String
|
||||||
from sqlalchemy.dialects import mysql
|
from sqlalchemy.dialects import mysql
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import BigInteger, CHAR, Column, DateTime, String
|
|
||||||
|
from sqlalchemy import CHAR, BigInteger, Column, DateTime, String
|
||||||
|
|
||||||
from config.database import Base
|
from config.database import Base
|
||||||
from config.env import DataBaseConfig
|
from config.env import DataBaseConfig
|
||||||
from utils.common_util import SqlalchemyUtil
|
from utils.common_util import SqlalchemyUtil
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from typing import Any, List, Optional
|
|
||||||
|
|
||||||
|
|
||||||
class CacheMonitorModel(BaseModel):
|
class CacheMonitorModel(BaseModel):
|
||||||
@@ -10,7 +11,7 @@ class CacheMonitorModel(BaseModel):
|
|||||||
|
|
||||||
model_config = ConfigDict(alias_generator=to_camel)
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
command_stats: Optional[List] = Field(default=[], description='命令统计')
|
command_stats: Optional[list] = Field(default=[], description='命令统计')
|
||||||
db_size: Optional[int] = Field(default=None, description='Key数量')
|
db_size: Optional[int] = Field(default=None, description='Key数量')
|
||||||
info: Optional[dict] = Field(default={}, description='Redis信息')
|
info: Optional[dict] = Field(default={}, description='Redis信息')
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from typing import Any, Optional
|
|
||||||
|
|
||||||
|
|
||||||
class CrudResponseModel(BaseModel):
|
|
||||||
"""
|
|
||||||
操作响应模型
|
|
||||||
"""
|
|
||||||
|
|
||||||
is_success: bool = Field(description='操作是否成功')
|
|
||||||
message: str = Field(description='响应信息')
|
|
||||||
result: Optional[Any] = Field(default=None, description='响应结果')
|
|
||||||
|
|
||||||
|
|
||||||
class UploadResponseModel(BaseModel):
|
class UploadResponseModel(BaseModel):
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import NotBlank, Size
|
from pydantic_validation_decorator import NotBlank, Size
|
||||||
from typing import Literal, Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigModel(BaseModel):
|
class ConfigModel(BaseModel):
|
||||||
@@ -26,20 +26,20 @@ class ConfigModel(BaseModel):
|
|||||||
|
|
||||||
@NotBlank(field_name='config_key', message='参数名称不能为空')
|
@NotBlank(field_name='config_key', message='参数名称不能为空')
|
||||||
@Size(field_name='config_key', min_length=0, max_length=100, message='参数名称长度不能超过100个字符')
|
@Size(field_name='config_key', min_length=0, max_length=100, message='参数名称长度不能超过100个字符')
|
||||||
def get_config_key(self):
|
def get_config_key(self) -> Union[str, None]:
|
||||||
return self.config_key
|
return self.config_key
|
||||||
|
|
||||||
@NotBlank(field_name='config_name', message='参数键名不能为空')
|
@NotBlank(field_name='config_name', message='参数键名不能为空')
|
||||||
@Size(field_name='config_name', min_length=0, max_length=100, message='参数键名长度不能超过100个字符')
|
@Size(field_name='config_name', min_length=0, max_length=100, message='参数键名长度不能超过100个字符')
|
||||||
def get_config_name(self):
|
def get_config_name(self) -> Union[str, None]:
|
||||||
return self.config_name
|
return self.config_name
|
||||||
|
|
||||||
@NotBlank(field_name='config_value', message='参数键值不能为空')
|
@NotBlank(field_name='config_value', message='参数键值不能为空')
|
||||||
@Size(field_name='config_value', min_length=0, max_length=500, message='参数键值长度不能超过500个字符')
|
@Size(field_name='config_value', min_length=0, max_length=500, message='参数键值长度不能超过500个字符')
|
||||||
def get_config_value(self):
|
def get_config_value(self) -> Union[str, None]:
|
||||||
return self.config_value
|
return self.config_value
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_config_key()
|
self.get_config_key()
|
||||||
self.get_config_name()
|
self.get_config_name()
|
||||||
self.get_config_value()
|
self.get_config_value()
|
||||||
@@ -54,7 +54,6 @@ class ConfigQueryModel(ConfigModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class ConfigPageQueryModel(ConfigQueryModel):
|
class ConfigPageQueryModel(ConfigQueryModel):
|
||||||
"""
|
"""
|
||||||
参数配置管理分页查询模型
|
参数配置管理分页查询模型
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import Network, NotBlank, Size
|
from pydantic_validation_decorator import Network, NotBlank, Size
|
||||||
from typing import Literal, Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class DeptModel(BaseModel):
|
class DeptModel(BaseModel):
|
||||||
@@ -30,30 +30,29 @@ class DeptModel(BaseModel):
|
|||||||
|
|
||||||
@NotBlank(field_name='dept_name', message='部门名称不能为空')
|
@NotBlank(field_name='dept_name', message='部门名称不能为空')
|
||||||
@Size(field_name='dept_name', min_length=0, max_length=30, message='部门名称长度不能超过30个字符')
|
@Size(field_name='dept_name', min_length=0, max_length=30, message='部门名称长度不能超过30个字符')
|
||||||
def get_dept_name(self):
|
def get_dept_name(self) -> Union[str, None]:
|
||||||
return self.dept_name
|
return self.dept_name
|
||||||
|
|
||||||
@NotBlank(field_name='order_num', message='显示顺序不能为空')
|
@NotBlank(field_name='order_num', message='显示顺序不能为空')
|
||||||
def get_order_num(self):
|
def get_order_num(self) -> Union[int, None]:
|
||||||
return self.order_num
|
return self.order_num
|
||||||
|
|
||||||
@Size(field_name='phone', min_length=0, max_length=11, message='联系电话长度不能超过11个字符')
|
@Size(field_name='phone', min_length=0, max_length=11, message='联系电话长度不能超过11个字符')
|
||||||
def get_phone(self):
|
def get_phone(self) -> Union[str, None]:
|
||||||
return self.phone
|
return self.phone
|
||||||
|
|
||||||
@Network(field_name='email', field_type='EmailStr', message='邮箱格式不正确')
|
@Network(field_name='email', field_type='EmailStr', message='邮箱格式不正确')
|
||||||
@Size(field_name='email', min_length=0, max_length=50, message='邮箱长度不能超过50个字符')
|
@Size(field_name='email', min_length=0, max_length=50, message='邮箱长度不能超过50个字符')
|
||||||
def get_email(self):
|
def get_email(self) -> Union[str, None]:
|
||||||
return self.email
|
return self.email
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_dept_name()
|
self.get_dept_name()
|
||||||
self.get_order_num()
|
self.get_order_num()
|
||||||
self.get_phone()
|
self.get_phone()
|
||||||
self.get_email()
|
self.get_email()
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class DeptQueryModel(DeptModel):
|
class DeptQueryModel(DeptModel):
|
||||||
"""
|
"""
|
||||||
部门管理不分页查询模型
|
部门管理不分页查询模型
|
||||||
@@ -63,6 +62,19 @@ class DeptQueryModel(DeptModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
|
class DeptTreeModel(BaseModel):
|
||||||
|
"""
|
||||||
|
部门树模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
|
id: int = Field(description='部门id')
|
||||||
|
label: str = Field(description='部门名称')
|
||||||
|
parent_id: int = Field(description='父部门id')
|
||||||
|
children: Optional[list['DeptTreeModel']] = Field(default=None, description='子部门树')
|
||||||
|
|
||||||
|
|
||||||
class DeleteDeptModel(BaseModel):
|
class DeleteDeptModel(BaseModel):
|
||||||
"""
|
"""
|
||||||
删除部门模型
|
删除部门模型
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import NotBlank, Pattern, Size
|
from pydantic_validation_decorator import NotBlank, Pattern, Size
|
||||||
from typing import Literal, Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class DictTypeModel(BaseModel):
|
class DictTypeModel(BaseModel):
|
||||||
@@ -25,7 +25,7 @@ class DictTypeModel(BaseModel):
|
|||||||
|
|
||||||
@NotBlank(field_name='dict_name', message='字典名称不能为空')
|
@NotBlank(field_name='dict_name', message='字典名称不能为空')
|
||||||
@Size(field_name='dict_name', min_length=0, max_length=100, message='字典类型名称长度不能超过100个字符')
|
@Size(field_name='dict_name', min_length=0, max_length=100, message='字典类型名称长度不能超过100个字符')
|
||||||
def get_dict_name(self):
|
def get_dict_name(self) -> Union[str, None]:
|
||||||
return self.dict_name
|
return self.dict_name
|
||||||
|
|
||||||
@NotBlank(field_name='dict_type', message='字典类型不能为空')
|
@NotBlank(field_name='dict_type', message='字典类型不能为空')
|
||||||
@@ -35,10 +35,10 @@ class DictTypeModel(BaseModel):
|
|||||||
regexp='^[a-z][a-z0-9_]*$',
|
regexp='^[a-z][a-z0-9_]*$',
|
||||||
message='字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)',
|
message='字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)',
|
||||||
)
|
)
|
||||||
def get_dict_type(self):
|
def get_dict_type(self) -> Union[str, None]:
|
||||||
return self.dict_type
|
return self.dict_type
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_dict_name()
|
self.get_dict_name()
|
||||||
self.get_dict_type()
|
self.get_dict_type()
|
||||||
|
|
||||||
@@ -67,24 +67,24 @@ class DictDataModel(BaseModel):
|
|||||||
|
|
||||||
@NotBlank(field_name='dict_label', message='字典标签不能为空')
|
@NotBlank(field_name='dict_label', message='字典标签不能为空')
|
||||||
@Size(field_name='dict_label', min_length=0, max_length=100, message='字典标签长度不能超过100个字符')
|
@Size(field_name='dict_label', min_length=0, max_length=100, message='字典标签长度不能超过100个字符')
|
||||||
def get_dict_label(self):
|
def get_dict_label(self) -> Union[str, None]:
|
||||||
return self.dict_label
|
return self.dict_label
|
||||||
|
|
||||||
@NotBlank(field_name='dict_value', message='字典键值不能为空')
|
@NotBlank(field_name='dict_value', message='字典键值不能为空')
|
||||||
@Size(field_name='dict_value', min_length=0, max_length=100, message='字典键值长度不能超过100个字符')
|
@Size(field_name='dict_value', min_length=0, max_length=100, message='字典键值长度不能超过100个字符')
|
||||||
def get_dict_value(self):
|
def get_dict_value(self) -> Union[str, None]:
|
||||||
return self.dict_value
|
return self.dict_value
|
||||||
|
|
||||||
@NotBlank(field_name='dict_type', message='字典类型不能为空')
|
@NotBlank(field_name='dict_type', message='字典类型不能为空')
|
||||||
@Size(field_name='dict_type', min_length=0, max_length=100, message='字典类型长度不能超过100个字符')
|
@Size(field_name='dict_type', min_length=0, max_length=100, message='字典类型长度不能超过100个字符')
|
||||||
def get_dict_type(self):
|
def get_dict_type(self) -> Union[str, None]:
|
||||||
return self.dict_type
|
return self.dict_type
|
||||||
|
|
||||||
@Size(field_name='css_class', min_length=0, max_length=100, message='样式属性长度不能超过100个字符')
|
@Size(field_name='css_class', min_length=0, max_length=100, message='样式属性长度不能超过100个字符')
|
||||||
def get_css_class(self):
|
def get_css_class(self) -> Union[str, None]:
|
||||||
return self.css_class
|
return self.css_class
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_dict_label()
|
self.get_dict_label()
|
||||||
self.get_dict_value()
|
self.get_dict_value()
|
||||||
self.get_dict_type()
|
self.get_dict_type()
|
||||||
@@ -100,7 +100,6 @@ class DictTypeQueryModel(DictTypeModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class DictTypePageQueryModel(DictTypeQueryModel):
|
class DictTypePageQueryModel(DictTypeQueryModel):
|
||||||
"""
|
"""
|
||||||
字典类型管理分页查询模型
|
字典类型管理分页查询模型
|
||||||
@@ -129,7 +128,6 @@ class DictDataQueryModel(DictDataModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class DictDataPageQueryModel(DictDataQueryModel):
|
class DictDataPageQueryModel(DictDataQueryModel):
|
||||||
"""
|
"""
|
||||||
字典数据管理分页查询模型
|
字典数据管理分页查询模型
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import NotBlank, Size
|
from pydantic_validation_decorator import NotBlank, Size
|
||||||
from typing import Literal, Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class JobModel(BaseModel):
|
class JobModel(BaseModel):
|
||||||
@@ -34,15 +34,15 @@ class JobModel(BaseModel):
|
|||||||
|
|
||||||
@NotBlank(field_name='invoke_target', message='调用目标字符串不能为空')
|
@NotBlank(field_name='invoke_target', message='调用目标字符串不能为空')
|
||||||
@Size(field_name='invoke_target', min_length=0, max_length=500, message='调用目标字符串长度不能超过500个字符')
|
@Size(field_name='invoke_target', min_length=0, max_length=500, message='调用目标字符串长度不能超过500个字符')
|
||||||
def get_invoke_target(self):
|
def get_invoke_target(self) -> Union[str, None]:
|
||||||
return self.invoke_target
|
return self.invoke_target
|
||||||
|
|
||||||
@NotBlank(field_name='cron_expression', message='Cron执行表达式不能为空')
|
@NotBlank(field_name='cron_expression', message='Cron执行表达式不能为空')
|
||||||
@Size(field_name='cron_expression', min_length=0, max_length=255, message='Cron执行表达式不能超过255个字符')
|
@Size(field_name='cron_expression', min_length=0, max_length=255, message='Cron执行表达式不能超过255个字符')
|
||||||
def get_cron_expression(self):
|
def get_cron_expression(self) -> Union[str, None]:
|
||||||
return self.cron_expression
|
return self.cron_expression
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_invoke_target()
|
self.get_invoke_target()
|
||||||
self.get_cron_expression()
|
self.get_cron_expression()
|
||||||
|
|
||||||
@@ -77,7 +77,6 @@ class JobQueryModel(JobModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class JobPageQueryModel(JobQueryModel):
|
class JobPageQueryModel(JobQueryModel):
|
||||||
"""
|
"""
|
||||||
定时任务管理分页查询模型
|
定时任务管理分页查询模型
|
||||||
@@ -114,7 +113,6 @@ class JobLogQueryModel(JobLogModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class JobLogPageQueryModel(JobLogQueryModel):
|
class JobLogPageQueryModel(JobLogQueryModel):
|
||||||
"""
|
"""
|
||||||
定时任务日志管理分页查询模型
|
定时任务日志管理分页查询模型
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from typing import Literal, Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class OperLogModel(BaseModel):
|
class OperLogModel(BaseModel):
|
||||||
@@ -68,7 +68,6 @@ class OperLogQueryModel(OperLogModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class OperLogPageQueryModel(OperLogQueryModel):
|
class OperLogPageQueryModel(OperLogQueryModel):
|
||||||
"""
|
"""
|
||||||
操作日志管理分页查询模型
|
操作日志管理分页查询模型
|
||||||
@@ -101,7 +100,6 @@ class LoginLogQueryModel(LogininforModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class LoginLogPageQueryModel(LoginLogQueryModel):
|
class LoginLogPageQueryModel(LoginLogQueryModel):
|
||||||
"""
|
"""
|
||||||
登录日志管理分页查询模型
|
登录日志管理分页查询模型
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import re
|
import re
|
||||||
|
from typing import Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from typing import List, Optional, Union
|
|
||||||
from exceptions.exception import ModelValidatorException
|
from exceptions.exception import ModelValidatorException
|
||||||
from module_admin.entity.vo.menu_vo import MenuModel
|
from module_admin.entity.vo.menu_vo import MenuModel
|
||||||
|
|
||||||
@@ -31,8 +33,7 @@ class UserRegister(BaseModel):
|
|||||||
pattern = r"""^[^<>"'|\\]+$"""
|
pattern = r"""^[^<>"'|\\]+$"""
|
||||||
if self.password is None or re.match(pattern, self.password):
|
if self.password is None or re.match(pattern, self.password):
|
||||||
return self
|
return self
|
||||||
else:
|
raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |')
|
||||||
raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |')
|
|
||||||
|
|
||||||
|
|
||||||
class Token(BaseModel):
|
class Token(BaseModel):
|
||||||
@@ -57,7 +58,7 @@ class SmsCode(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class MenuTreeModel(MenuModel):
|
class MenuTreeModel(MenuModel):
|
||||||
children: Optional[Union[List['MenuTreeModel'], None]] = Field(default=None, description='子菜单')
|
children: Optional[Union[list['MenuTreeModel'], None]] = Field(default=None, description='子菜单')
|
||||||
|
|
||||||
|
|
||||||
class MetaModel(BaseModel):
|
class MetaModel(BaseModel):
|
||||||
@@ -84,4 +85,4 @@ class RouterModel(BaseModel):
|
|||||||
default=None, description='当你一个路由下面的children声明的路由大于1个时,自动会变成嵌套的模式--如组件页面'
|
default=None, description='当你一个路由下面的children声明的路由大于1个时,自动会变成嵌套的模式--如组件页面'
|
||||||
)
|
)
|
||||||
meta: Optional[MetaModel] = Field(default=None, description='其他元素')
|
meta: Optional[MetaModel] = Field(default=None, description='其他元素')
|
||||||
children: Optional[Union[List['RouterModel'], None]] = Field(default=None, description='子路由')
|
children: Optional[Union[list['RouterModel'], None]] = Field(default=None, description='子路由')
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import NotBlank, Size
|
from pydantic_validation_decorator import NotBlank, Size
|
||||||
from typing import Literal, Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class MenuModel(BaseModel):
|
class MenuModel(BaseModel):
|
||||||
@@ -36,30 +36,30 @@ class MenuModel(BaseModel):
|
|||||||
|
|
||||||
@NotBlank(field_name='menu_name', message='菜单名称不能为空')
|
@NotBlank(field_name='menu_name', message='菜单名称不能为空')
|
||||||
@Size(field_name='menu_name', min_length=0, max_length=50, message='菜单名称长度不能超过50个字符')
|
@Size(field_name='menu_name', min_length=0, max_length=50, message='菜单名称长度不能超过50个字符')
|
||||||
def get_menu_name(self):
|
def get_menu_name(self) -> Union[str, None]:
|
||||||
return self.menu_name
|
return self.menu_name
|
||||||
|
|
||||||
@NotBlank(field_name='order_num', message='显示顺序不能为空')
|
@NotBlank(field_name='order_num', message='显示顺序不能为空')
|
||||||
def get_order_num(self):
|
def get_order_num(self) -> Union[int, None]:
|
||||||
return self.order_num
|
return self.order_num
|
||||||
|
|
||||||
@Size(field_name='path', min_length=0, max_length=200, message='路由地址长度不能超过200个字符')
|
@Size(field_name='path', min_length=0, max_length=200, message='路由地址长度不能超过200个字符')
|
||||||
def get_path(self):
|
def get_path(self) -> Union[str, None]:
|
||||||
return self.path
|
return self.path
|
||||||
|
|
||||||
@Size(field_name='component', min_length=0, max_length=255, message='组件路径长度不能超过255个字符')
|
@Size(field_name='component', min_length=0, max_length=255, message='组件路径长度不能超过255个字符')
|
||||||
def get_component(self):
|
def get_component(self) -> Union[str, None]:
|
||||||
return self.component
|
return self.component
|
||||||
|
|
||||||
@NotBlank(field_name='menu_type', message='菜单类型不能为空')
|
@NotBlank(field_name='menu_type', message='菜单类型不能为空')
|
||||||
def get_menu_type(self):
|
def get_menu_type(self) -> Union[Literal['M', 'C', 'F'], None]:
|
||||||
return self.menu_type
|
return self.menu_type
|
||||||
|
|
||||||
@Size(field_name='perms', min_length=0, max_length=100, message='权限标识长度不能超过100个字符')
|
@Size(field_name='perms', min_length=0, max_length=100, message='权限标识长度不能超过100个字符')
|
||||||
def get_perms(self):
|
def get_perms(self) -> Union[str, None]:
|
||||||
return self.perms
|
return self.perms
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_menu_name()
|
self.get_menu_name()
|
||||||
self.get_order_num()
|
self.get_order_num()
|
||||||
self.get_path()
|
self.get_path()
|
||||||
@@ -68,7 +68,6 @@ class MenuModel(BaseModel):
|
|||||||
self.get_perms()
|
self.get_perms()
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class MenuQueryModel(MenuModel):
|
class MenuQueryModel(MenuModel):
|
||||||
"""
|
"""
|
||||||
菜单管理不分页查询模型
|
菜单管理不分页查询模型
|
||||||
@@ -78,6 +77,19 @@ class MenuQueryModel(MenuModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
|
class MenuTreeModel(BaseModel):
|
||||||
|
"""
|
||||||
|
菜单树模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
|
id: int = Field(description='菜单id')
|
||||||
|
label: str = Field(description='菜单名称')
|
||||||
|
parent_id: int = Field(description='父菜单id')
|
||||||
|
children: Optional[list['MenuTreeModel']] = Field(default=None, description='子菜单树')
|
||||||
|
|
||||||
|
|
||||||
class DeleteMenuModel(BaseModel):
|
class DeleteMenuModel(BaseModel):
|
||||||
"""
|
"""
|
||||||
删除菜单模型
|
删除菜单模型
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import NotBlank, Size, Xss
|
from pydantic_validation_decorator import NotBlank, Size, Xss
|
||||||
from typing import Literal, Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class NoticeModel(BaseModel):
|
class NoticeModel(BaseModel):
|
||||||
@@ -27,10 +27,10 @@ class NoticeModel(BaseModel):
|
|||||||
@Xss(field_name='notice_title', message='公告标题不能包含脚本字符')
|
@Xss(field_name='notice_title', message='公告标题不能包含脚本字符')
|
||||||
@NotBlank(field_name='notice_title', message='公告标题不能为空')
|
@NotBlank(field_name='notice_title', message='公告标题不能为空')
|
||||||
@Size(field_name='notice_title', min_length=0, max_length=50, message='公告标题不能超过50个字符')
|
@Size(field_name='notice_title', min_length=0, max_length=50, message='公告标题不能超过50个字符')
|
||||||
def get_notice_title(self):
|
def get_notice_title(self) -> Union[str, None]:
|
||||||
return self.notice_title
|
return self.notice_title
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_notice_title()
|
self.get_notice_title()
|
||||||
|
|
||||||
|
|
||||||
@@ -43,7 +43,6 @@ class NoticeQueryModel(NoticeModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class NoticePageQueryModel(NoticeQueryModel):
|
class NoticePageQueryModel(NoticeQueryModel):
|
||||||
"""
|
"""
|
||||||
通知公告管理分页查询模型
|
通知公告管理分页查询模型
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from typing import Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class OnlineModel(BaseModel):
|
class OnlineModel(BaseModel):
|
||||||
@@ -22,7 +22,6 @@ class OnlineModel(BaseModel):
|
|||||||
login_time: Optional[datetime] = Field(default=None, description='登录时间')
|
login_time: Optional[datetime] = Field(default=None, description='登录时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class OnlineQueryModel(OnlineModel):
|
class OnlineQueryModel(OnlineModel):
|
||||||
"""
|
"""
|
||||||
岗位管理不分页查询模型
|
岗位管理不分页查询模型
|
||||||
@@ -32,6 +31,17 @@ class OnlineQueryModel(OnlineModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
|
class OnlinePageResponseModel(BaseModel):
|
||||||
|
"""
|
||||||
|
在线用户分页响应模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
|
rows: list[OnlineModel] = Field(description='在线用户记录列表')
|
||||||
|
total: int = Field(description='总记录数')
|
||||||
|
|
||||||
|
|
||||||
class DeleteOnlineModel(BaseModel):
|
class DeleteOnlineModel(BaseModel):
|
||||||
"""
|
"""
|
||||||
强退在线用户模型
|
强退在线用户模型
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import NotBlank, Size
|
from pydantic_validation_decorator import NotBlank, Size
|
||||||
from typing import Literal, Optional
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class PostModel(BaseModel):
|
class PostModel(BaseModel):
|
||||||
@@ -26,19 +26,19 @@ class PostModel(BaseModel):
|
|||||||
|
|
||||||
@NotBlank(field_name='post_code', message='岗位编码不能为空')
|
@NotBlank(field_name='post_code', message='岗位编码不能为空')
|
||||||
@Size(field_name='post_code', min_length=0, max_length=64, message='岗位编码长度不能超过64个字符')
|
@Size(field_name='post_code', min_length=0, max_length=64, message='岗位编码长度不能超过64个字符')
|
||||||
def get_post_code(self):
|
def get_post_code(self) -> Union[str, None]:
|
||||||
return self.post_code
|
return self.post_code
|
||||||
|
|
||||||
@NotBlank(field_name='post_name', message='岗位名称不能为空')
|
@NotBlank(field_name='post_name', message='岗位名称不能为空')
|
||||||
@Size(field_name='post_name', min_length=0, max_length=50, message='岗位名称长度不能超过50个字符')
|
@Size(field_name='post_name', min_length=0, max_length=50, message='岗位名称长度不能超过50个字符')
|
||||||
def get_post_name(self):
|
def get_post_name(self) -> Union[str, None]:
|
||||||
return self.post_name
|
return self.post_name
|
||||||
|
|
||||||
@NotBlank(field_name='post_sort', message='显示顺序不能为空')
|
@NotBlank(field_name='post_sort', message='显示顺序不能为空')
|
||||||
def get_post_sort(self):
|
def get_post_sort(self) -> Union[int, None]:
|
||||||
return self.post_sort
|
return self.post_sort
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_post_code()
|
self.get_post_code()
|
||||||
self.get_post_name()
|
self.get_post_name()
|
||||||
self.get_post_sort()
|
self.get_post_sort()
|
||||||
@@ -53,7 +53,6 @@ class PostQueryModel(PostModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class PostPageQueryModel(PostQueryModel):
|
class PostPageQueryModel(PostQueryModel):
|
||||||
"""
|
"""
|
||||||
岗位管理分页查询模型
|
岗位管理分页查询模型
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import NotBlank, Size
|
from pydantic_validation_decorator import NotBlank, Size
|
||||||
from typing import List, Literal, Optional, Union
|
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
|
|
||||||
|
|
||||||
class RoleModel(BaseModel):
|
class RoleModel(BaseModel):
|
||||||
@@ -55,19 +55,19 @@ class RoleModel(BaseModel):
|
|||||||
|
|
||||||
@NotBlank(field_name='role_name', message='角色名称不能为空')
|
@NotBlank(field_name='role_name', message='角色名称不能为空')
|
||||||
@Size(field_name='role_name', min_length=0, max_length=30, message='角色名称长度不能超过30个字符')
|
@Size(field_name='role_name', min_length=0, max_length=30, message='角色名称长度不能超过30个字符')
|
||||||
def get_role_name(self):
|
def get_role_name(self) -> Union[str, None]:
|
||||||
return self.role_name
|
return self.role_name
|
||||||
|
|
||||||
@NotBlank(field_name='role_key', message='权限字符不能为空')
|
@NotBlank(field_name='role_key', message='权限字符不能为空')
|
||||||
@Size(field_name='role_key', min_length=0, max_length=100, message='权限字符长度不能超过100个字符')
|
@Size(field_name='role_key', min_length=0, max_length=100, message='权限字符长度不能超过100个字符')
|
||||||
def get_role_key(self):
|
def get_role_key(self) -> Union[str, None]:
|
||||||
return self.role_key
|
return self.role_key
|
||||||
|
|
||||||
@NotBlank(field_name='role_sort', message='显示顺序不能为空')
|
@NotBlank(field_name='role_sort', message='显示顺序不能为空')
|
||||||
def get_role_sort(self):
|
def get_role_sort(self) -> Union[int, None]:
|
||||||
return self.role_sort
|
return self.role_sort
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_role_name()
|
self.get_role_name()
|
||||||
self.get_role_key()
|
self.get_role_key()
|
||||||
self.get_role_sort()
|
self.get_role_sort()
|
||||||
@@ -104,7 +104,6 @@ class RoleQueryModel(RoleModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class RolePageQueryModel(RoleQueryModel):
|
class RolePageQueryModel(RoleQueryModel):
|
||||||
"""
|
"""
|
||||||
角色管理分页查询模型
|
角色管理分页查询模型
|
||||||
@@ -121,8 +120,8 @@ class RoleMenuQueryModel(BaseModel):
|
|||||||
|
|
||||||
model_config = ConfigDict(alias_generator=to_camel)
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
menus: List = Field(default=[], description='菜单信息')
|
menus: list = Field(default=[], description='菜单信息')
|
||||||
checked_keys: List[int] = Field(default=[], description='已选择的菜单ID信息')
|
checked_keys: list[int] = Field(default=[], description='已选择的菜单ID信息')
|
||||||
|
|
||||||
|
|
||||||
class RoleDeptQueryModel(BaseModel):
|
class RoleDeptQueryModel(BaseModel):
|
||||||
@@ -132,8 +131,8 @@ class RoleDeptQueryModel(BaseModel):
|
|||||||
|
|
||||||
model_config = ConfigDict(alias_generator=to_camel)
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
depts: List = Field(default=[], description='部门信息')
|
depts: list = Field(default=[], description='部门信息')
|
||||||
checked_keys: List[int] = Field(default=[], description='已选择的部门ID信息')
|
checked_keys: list[int] = Field(default=[], description='已选择的部门ID信息')
|
||||||
|
|
||||||
|
|
||||||
class AddRoleModel(RoleModel):
|
class AddRoleModel(RoleModel):
|
||||||
@@ -141,8 +140,8 @@ class AddRoleModel(RoleModel):
|
|||||||
新增角色模型
|
新增角色模型
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dept_ids: List = Field(default=[], description='部门ID信息')
|
dept_ids: list = Field(default=[], description='部门ID信息')
|
||||||
menu_ids: List = Field(default=[], description='菜单ID信息')
|
menu_ids: list = Field(default=[], description='菜单ID信息')
|
||||||
type: Optional[str] = Field(default=None, description='操作类型')
|
type: Optional[str] = Field(default=None, description='操作类型')
|
||||||
|
|
||||||
|
|
||||||
@@ -153,6 +152,6 @@ class DeleteRoleModel(BaseModel):
|
|||||||
|
|
||||||
model_config = ConfigDict(alias_generator=to_camel)
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
role_ids: str = Field(description='需要删除的菜单ID')
|
role_ids: str = Field(description='需要删除的角色ID')
|
||||||
update_by: Optional[str] = Field(default=None, description='更新者')
|
update_by: Optional[str] = Field(default=None, description='更新者')
|
||||||
update_time: Optional[datetime] = Field(default=None, description='更新时间')
|
update_time: Optional[datetime] = Field(default=None, description='更新时间')
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from typing import List, Optional
|
|
||||||
|
|
||||||
|
|
||||||
class CpuInfo(BaseModel):
|
class CpuInfo(BaseModel):
|
||||||
@@ -64,4 +65,4 @@ class ServerMonitorModel(BaseModel):
|
|||||||
py: Optional[PyInfo] = Field(description='Python相关信息')
|
py: Optional[PyInfo] = Field(description='Python相关信息')
|
||||||
mem: Optional[MemoryInfo] = Field(description='內存相关信息')
|
mem: Optional[MemoryInfo] = Field(description='內存相关信息')
|
||||||
sys: Optional[SysInfo] = Field(description='服务器相关信息')
|
sys: Optional[SysInfo] = Field(description='服务器相关信息')
|
||||||
sys_files: Optional[List[SysFiles]] = Field(description='磁盘相关信息')
|
sys_files: Optional[list[SysFiles]] = Field(description='磁盘相关信息')
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Literal, Optional, Union
|
||||||
|
|
||||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
from pydantic_validation_decorator import Network, NotBlank, Size, Xss
|
from pydantic_validation_decorator import Network, NotBlank, Size, Xss
|
||||||
from typing import List, Literal, Optional, Union
|
|
||||||
from exceptions.exception import ModelValidatorException
|
from exceptions.exception import ModelValidatorException
|
||||||
from module_admin.annotation.pydantic_annotation import as_query
|
|
||||||
from module_admin.entity.vo.dept_vo import DeptModel
|
from module_admin.entity.vo.dept_vo import DeptModel
|
||||||
from module_admin.entity.vo.post_vo import PostModel
|
from module_admin.entity.vo.post_vo import PostModel
|
||||||
from module_admin.entity.vo.role_vo import RoleModel
|
from module_admin.entity.vo.role_vo import RoleModel
|
||||||
@@ -53,8 +54,7 @@ class UserModel(BaseModel):
|
|||||||
pattern = r"""^[^<>"'|\\]+$"""
|
pattern = r"""^[^<>"'|\\]+$"""
|
||||||
if self.password is None or re.match(pattern, self.password):
|
if self.password is None or re.match(pattern, self.password):
|
||||||
return self
|
return self
|
||||||
else:
|
raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |')
|
||||||
raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |')
|
|
||||||
|
|
||||||
@model_validator(mode='after')
|
@model_validator(mode='after')
|
||||||
def check_admin(self) -> 'UserModel':
|
def check_admin(self) -> 'UserModel':
|
||||||
@@ -67,30 +67,38 @@ class UserModel(BaseModel):
|
|||||||
@Xss(field_name='user_name', message='用户账号不能包含脚本字符')
|
@Xss(field_name='user_name', message='用户账号不能包含脚本字符')
|
||||||
@NotBlank(field_name='user_name', message='用户账号不能为空')
|
@NotBlank(field_name='user_name', message='用户账号不能为空')
|
||||||
@Size(field_name='user_name', min_length=0, max_length=30, message='用户账号长度不能超过30个字符')
|
@Size(field_name='user_name', min_length=0, max_length=30, message='用户账号长度不能超过30个字符')
|
||||||
def get_user_name(self):
|
def get_user_name(self) -> Union[str, None]:
|
||||||
return self.user_name
|
return self.user_name
|
||||||
|
|
||||||
@Xss(field_name='nick_name', message='用户昵称不能包含脚本字符')
|
@Xss(field_name='nick_name', message='用户昵称不能包含脚本字符')
|
||||||
@Size(field_name='nick_name', min_length=0, max_length=30, message='用户昵称长度不能超过30个字符')
|
@Size(field_name='nick_name', min_length=0, max_length=30, message='用户昵称长度不能超过30个字符')
|
||||||
def get_nick_name(self):
|
def get_nick_name(self) -> Union[str, None]:
|
||||||
return self.nick_name
|
return self.nick_name
|
||||||
|
|
||||||
@Network(field_name='email', field_type='EmailStr', message='邮箱格式不正确')
|
@Network(field_name='email', field_type='EmailStr', message='邮箱格式不正确')
|
||||||
@Size(field_name='email', min_length=0, max_length=50, message='邮箱长度不能超过50个字符')
|
@Size(field_name='email', min_length=0, max_length=50, message='邮箱长度不能超过50个字符')
|
||||||
def get_email(self):
|
def get_email(self) -> Union[str, None]:
|
||||||
return self.email
|
return self.email
|
||||||
|
|
||||||
@Size(field_name='phonenumber', min_length=0, max_length=11, message='手机号码长度不能超过11个字符')
|
@Size(field_name='phonenumber', min_length=0, max_length=11, message='手机号码长度不能超过11个字符')
|
||||||
def get_phonenumber(self):
|
def get_phonenumber(self) -> Union[str, None]:
|
||||||
return self.phonenumber
|
return self.phonenumber
|
||||||
|
|
||||||
def validate_fields(self):
|
def validate_fields(self) -> None:
|
||||||
self.get_user_name()
|
self.get_user_name()
|
||||||
self.get_nick_name()
|
self.get_nick_name()
|
||||||
self.get_email()
|
self.get_email()
|
||||||
self.get_phonenumber()
|
self.get_phonenumber()
|
||||||
|
|
||||||
|
|
||||||
|
class UserRowModel(UserModel):
|
||||||
|
"""
|
||||||
|
用户列表行数据模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
dept: Optional[DeptModel] = Field(default=None, description='部门信息')
|
||||||
|
|
||||||
|
|
||||||
class UserRoleModel(BaseModel):
|
class UserRoleModel(BaseModel):
|
||||||
"""
|
"""
|
||||||
用户和角色关联表对应pydantic模型
|
用户和角色关联表对应pydantic模型
|
||||||
@@ -117,14 +125,14 @@ class UserInfoModel(UserModel):
|
|||||||
post_ids: Optional[Union[str, None]] = Field(default=None, description='岗位ID信息')
|
post_ids: Optional[Union[str, None]] = Field(default=None, description='岗位ID信息')
|
||||||
role_ids: Optional[Union[str, None]] = Field(default=None, description='角色ID信息')
|
role_ids: Optional[Union[str, None]] = Field(default=None, description='角色ID信息')
|
||||||
dept: Optional[Union[DeptModel, None]] = Field(default=None, description='部门信息')
|
dept: Optional[Union[DeptModel, None]] = Field(default=None, description='部门信息')
|
||||||
role: Optional[List[Union[RoleModel, None]]] = Field(default=[], description='角色信息')
|
role: Optional[list[Union[RoleModel, None]]] = Field(default=[], description='角色信息')
|
||||||
|
|
||||||
|
|
||||||
class CurrentUserModel(BaseModel):
|
class CurrentUserModel(BaseModel):
|
||||||
model_config = ConfigDict(alias_generator=to_camel)
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
permissions: List = Field(description='权限信息')
|
permissions: list = Field(description='权限信息')
|
||||||
roles: List = Field(description='角色信息')
|
roles: list = Field(description='角色信息')
|
||||||
user: Union[UserInfoModel, None] = Field(description='用户信息')
|
user: Union[UserInfoModel, None] = Field(description='用户信息')
|
||||||
is_default_modify_pwd: bool = Field(default=False, description='是否初始密码修改提醒')
|
is_default_modify_pwd: bool = Field(default=False, description='是否初始密码修改提醒')
|
||||||
is_password_expired: bool = Field(default=False, description='密码是否过期提醒')
|
is_password_expired: bool = Field(default=False, description='密码是否过期提醒')
|
||||||
@@ -138,10 +146,10 @@ class UserDetailModel(BaseModel):
|
|||||||
model_config = ConfigDict(alias_generator=to_camel)
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
data: Optional[Union[UserInfoModel, None]] = Field(default=None, description='用户信息')
|
data: Optional[Union[UserInfoModel, None]] = Field(default=None, description='用户信息')
|
||||||
post_ids: Optional[List] = Field(default=None, description='岗位ID信息')
|
post_ids: Optional[list] = Field(default=None, description='岗位ID信息')
|
||||||
posts: List[Union[PostModel, None]] = Field(description='岗位信息')
|
posts: list[Union[PostModel, None]] = Field(description='岗位信息')
|
||||||
role_ids: Optional[List] = Field(default=None, description='角色ID信息')
|
role_ids: Optional[list] = Field(default=None, description='角色ID信息')
|
||||||
roles: List[Union[RoleModel, None]] = Field(description='角色信息')
|
roles: list[Union[RoleModel, None]] = Field(description='角色信息')
|
||||||
|
|
||||||
|
|
||||||
class UserProfileModel(BaseModel):
|
class UserProfileModel(BaseModel):
|
||||||
@@ -156,6 +164,16 @@ class UserProfileModel(BaseModel):
|
|||||||
role_group: Union[str, None] = Field(description='角色信息')
|
role_group: Union[str, None] = Field(description='角色信息')
|
||||||
|
|
||||||
|
|
||||||
|
class AvatarModel(BaseModel):
|
||||||
|
"""
|
||||||
|
上传头像响应模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
|
img_url: str = Field(description='头像地址')
|
||||||
|
|
||||||
|
|
||||||
class UserQueryModel(UserModel):
|
class UserQueryModel(UserModel):
|
||||||
"""
|
"""
|
||||||
用户管理不分页查询模型
|
用户管理不分页查询模型
|
||||||
@@ -165,7 +183,6 @@ class UserQueryModel(UserModel):
|
|||||||
end_time: Optional[str] = Field(default=None, description='结束时间')
|
end_time: Optional[str] = Field(default=None, description='结束时间')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class UserPageQueryModel(UserQueryModel):
|
class UserPageQueryModel(UserQueryModel):
|
||||||
"""
|
"""
|
||||||
用户管理分页查询模型
|
用户管理分页查询模型
|
||||||
@@ -180,8 +197,8 @@ class AddUserModel(UserModel):
|
|||||||
新增用户模型
|
新增用户模型
|
||||||
"""
|
"""
|
||||||
|
|
||||||
role_ids: Optional[List] = Field(default=[], description='角色ID信息')
|
role_ids: Optional[list] = Field(default=[], description='角色ID信息')
|
||||||
post_ids: Optional[List] = Field(default=[], description='岗位ID信息')
|
post_ids: Optional[list] = Field(default=[], description='岗位ID信息')
|
||||||
type: Optional[str] = Field(default=None, description='操作类型')
|
type: Optional[str] = Field(default=None, description='操作类型')
|
||||||
|
|
||||||
|
|
||||||
@@ -190,7 +207,7 @@ class EditUserModel(AddUserModel):
|
|||||||
编辑用户模型
|
编辑用户模型
|
||||||
"""
|
"""
|
||||||
|
|
||||||
role: Optional[List] = Field(default=[], description='角色信息')
|
role: Optional[list] = Field(default=[], description='角色信息')
|
||||||
|
|
||||||
|
|
||||||
class ResetPasswordModel(BaseModel):
|
class ResetPasswordModel(BaseModel):
|
||||||
@@ -208,8 +225,7 @@ class ResetPasswordModel(BaseModel):
|
|||||||
pattern = r"""^[^<>"'|\\]+$"""
|
pattern = r"""^[^<>"'|\\]+$"""
|
||||||
if self.new_password is None or re.match(pattern, self.new_password):
|
if self.new_password is None or re.match(pattern, self.new_password):
|
||||||
return self
|
return self
|
||||||
else:
|
raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |')
|
||||||
raise ModelValidatorException(message='密码不能包含非法字符:< > " \' \\ |')
|
|
||||||
|
|
||||||
|
|
||||||
class ResetUserModel(UserModel):
|
class ResetUserModel(UserModel):
|
||||||
@@ -242,7 +258,6 @@ class UserRoleQueryModel(UserModel):
|
|||||||
role_id: Optional[int] = Field(default=None, description='角色ID')
|
role_id: Optional[int] = Field(default=None, description='角色ID')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class UserRolePageQueryModel(UserRoleQueryModel):
|
class UserRolePageQueryModel(UserRoleQueryModel):
|
||||||
"""
|
"""
|
||||||
用户角色关联管理分页查询模型
|
用户角色关联管理分页查询模型
|
||||||
@@ -267,11 +282,10 @@ class UserRoleResponseModel(BaseModel):
|
|||||||
|
|
||||||
model_config = ConfigDict(alias_generator=to_camel)
|
model_config = ConfigDict(alias_generator=to_camel)
|
||||||
|
|
||||||
roles: List[Union[SelectedRoleModel, None]] = Field(default=[], description='角色信息')
|
roles: list[Union[SelectedRoleModel, None]] = Field(default=[], description='角色信息')
|
||||||
user: UserInfoModel = Field(description='用户信息')
|
user: UserInfoModel = Field(description='用户信息')
|
||||||
|
|
||||||
|
|
||||||
@as_query
|
|
||||||
class CrudUserRoleModel(BaseModel):
|
class CrudUserRoleModel(BaseModel):
|
||||||
"""
|
"""
|
||||||
新增、删除用户关联角色及角色关联用户模型
|
新增、删除用户关联角色及角色关联用户模型
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from config.enums import RedisInitKeyConfig
|
|
||||||
|
from common.enums import RedisInitKeyConfig
|
||||||
|
from common.vo import CrudResponseModel
|
||||||
from config.get_redis import RedisUtil
|
from config.get_redis import RedisUtil
|
||||||
from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel
|
from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel
|
||||||
from module_admin.entity.vo.common_vo import CrudResponseModel
|
|
||||||
|
|
||||||
|
|
||||||
class CacheService:
|
class CacheService:
|
||||||
@@ -11,7 +12,7 @@ class CacheService:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_cache_monitor_statistical_info_services(cls, request: Request):
|
async def get_cache_monitor_statistical_info_services(cls, request: Request) -> CacheMonitorModel:
|
||||||
"""
|
"""
|
||||||
获取缓存监控信息service
|
获取缓存监控信息service
|
||||||
|
|
||||||
@@ -22,34 +23,33 @@ class CacheService:
|
|||||||
db_size = await request.app.state.redis.dbsize()
|
db_size = await request.app.state.redis.dbsize()
|
||||||
command_stats_dict = await request.app.state.redis.info('commandstats')
|
command_stats_dict = await request.app.state.redis.info('commandstats')
|
||||||
command_stats = [
|
command_stats = [
|
||||||
dict(name=key.split('_')[1], value=str(value.get('calls'))) for key, value in command_stats_dict.items()
|
{'name': key.split('_')[1], 'value': str(value.get('calls'))} for key, value in command_stats_dict.items()
|
||||||
]
|
]
|
||||||
result = CacheMonitorModel(commandStats=command_stats, dbSize=db_size, info=info)
|
result = CacheMonitorModel(commandStats=command_stats, dbSize=db_size, info=info)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_cache_monitor_cache_name_services(cls):
|
async def get_cache_monitor_cache_name_services(cls) -> list[CacheInfoModel]:
|
||||||
"""
|
"""
|
||||||
获取缓存名称列表信息service
|
获取缓存名称列表信息service
|
||||||
|
|
||||||
:return: 缓存名称列表信息
|
:return: 缓存名称列表信息
|
||||||
"""
|
"""
|
||||||
name_list = []
|
name_list = [
|
||||||
for key_config in RedisInitKeyConfig:
|
CacheInfoModel(
|
||||||
name_list.append(
|
cacheKey='',
|
||||||
CacheInfoModel(
|
cacheName=key_config.key,
|
||||||
cacheKey='',
|
cacheValue='',
|
||||||
cacheName=key_config.key,
|
remark=key_config.remark,
|
||||||
cacheValue='',
|
|
||||||
remark=key_config.remark,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
for key_config in RedisInitKeyConfig
|
||||||
|
]
|
||||||
|
|
||||||
return name_list
|
return name_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_cache_monitor_cache_key_services(cls, request: Request, cache_name: str):
|
async def get_cache_monitor_cache_key_services(cls, request: Request, cache_name: str) -> list[str]:
|
||||||
"""
|
"""
|
||||||
获取缓存键名列表信息service
|
获取缓存键名列表信息service
|
||||||
|
|
||||||
@@ -57,13 +57,15 @@ class CacheService:
|
|||||||
:param cache_name: 缓存名称
|
:param cache_name: 缓存名称
|
||||||
:return: 缓存键名列表信息
|
:return: 缓存键名列表信息
|
||||||
"""
|
"""
|
||||||
cache_keys = await request.app.state.redis.keys(f'{cache_name}*')
|
cache_keys: list[str] = await request.app.state.redis.keys(f'{cache_name}*')
|
||||||
cache_key_list = [key.split(':', 1)[1] for key in cache_keys if key.startswith(f'{cache_name}:')]
|
cache_key_list = [key.split(':', 1)[1] for key in cache_keys if key.startswith(f'{cache_name}:')]
|
||||||
|
|
||||||
return cache_key_list
|
return cache_key_list
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_cache_monitor_cache_value_services(cls, request: Request, cache_name: str, cache_key: str):
|
async def get_cache_monitor_cache_value_services(
|
||||||
|
cls, request: Request, cache_name: str, cache_key: str
|
||||||
|
) -> CacheInfoModel:
|
||||||
"""
|
"""
|
||||||
获取缓存内容信息service
|
获取缓存内容信息service
|
||||||
|
|
||||||
@@ -77,7 +79,7 @@ class CacheService:
|
|||||||
return CacheInfoModel(cacheKey=cache_key, cacheName=cache_name, cacheValue=cache_value, remark='')
|
return CacheInfoModel(cacheKey=cache_key, cacheName=cache_name, cacheValue=cache_value, remark='')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def clear_cache_monitor_cache_name_services(cls, request: Request, cache_name: str):
|
async def clear_cache_monitor_cache_name_services(cls, request: Request, cache_name: str) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
清除缓存名称对应所有键值service
|
清除缓存名称对应所有键值service
|
||||||
|
|
||||||
@@ -92,7 +94,7 @@ class CacheService:
|
|||||||
return CrudResponseModel(is_success=True, message=f'{cache_name}对应键值清除成功')
|
return CrudResponseModel(is_success=True, message=f'{cache_name}对应键值清除成功')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def clear_cache_monitor_cache_key_services(cls, request: Request, cache_key: str):
|
async def clear_cache_monitor_cache_key_services(cls, request: Request, cache_key: str) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
清除缓存名称对应所有键值service
|
清除缓存名称对应所有键值service
|
||||||
|
|
||||||
@@ -107,7 +109,7 @@ class CacheService:
|
|||||||
return CrudResponseModel(is_success=True, message=f'{cache_key}清除成功')
|
return CrudResponseModel(is_success=True, message=f'{cache_key}清除成功')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def clear_cache_monitor_all_services(cls, request: Request):
|
async def clear_cache_monitor_all_services(cls, request: Request) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
清除所有缓存service
|
清除所有缓存service
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import base64
|
|||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ class CaptchaService:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create_captcha_image_service(cls):
|
async def create_captcha_image_service(cls) -> list[str, int]:
|
||||||
# 创建空白图像
|
# 创建空白图像
|
||||||
image = Image.new('RGB', (160, 60), color='#EAEAEA')
|
image = Image.new('RGB', (160, 60), color='#EAEAEA')
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
import aiofiles
|
||||||
from fastapi import BackgroundTasks, Request, UploadFile
|
from fastapi import BackgroundTasks, Request, UploadFile
|
||||||
|
|
||||||
|
from common.vo import CrudResponseModel
|
||||||
from config.env import UploadConfig
|
from config.env import UploadConfig
|
||||||
from exceptions.exception import ServiceException
|
from exceptions.exception import ServiceException
|
||||||
from module_admin.entity.vo.common_vo import CrudResponseModel, UploadResponseModel
|
from module_admin.entity.vo.common_vo import UploadResponseModel
|
||||||
from utils.upload_util import UploadUtil
|
from utils.upload_util import UploadUtil
|
||||||
|
|
||||||
|
|
||||||
@@ -13,7 +17,7 @@ class CommonService:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def upload_service(cls, request: Request, file: UploadFile):
|
async def upload_service(cls, request: Request, file: UploadFile) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
通用上传service
|
通用上传service
|
||||||
|
|
||||||
@@ -23,33 +27,39 @@ class CommonService:
|
|||||||
"""
|
"""
|
||||||
if not UploadUtil.check_file_extension(file):
|
if not UploadUtil.check_file_extension(file):
|
||||||
raise ServiceException(message='文件类型不合法')
|
raise ServiceException(message='文件类型不合法')
|
||||||
else:
|
relative_path = (
|
||||||
relative_path = f'upload/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}'
|
f'upload/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}'
|
||||||
dir_path = os.path.join(UploadConfig.UPLOAD_PATH, relative_path)
|
)
|
||||||
try:
|
dir_path = os.path.join(UploadConfig.UPLOAD_PATH, relative_path)
|
||||||
os.makedirs(dir_path)
|
try:
|
||||||
except FileExistsError:
|
os.makedirs(dir_path)
|
||||||
pass
|
except FileExistsError:
|
||||||
filename = f'{file.filename.rsplit(".", 1)[0]}_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.{file.filename.rsplit(".")[-1]}'
|
pass
|
||||||
filepath = os.path.join(dir_path, filename)
|
filename = f'{file.filename.rsplit(".", 1)[0]}_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.{file.filename.rsplit(".")[-1]}'
|
||||||
with open(filepath, 'wb') as f:
|
filepath = os.path.join(dir_path, filename)
|
||||||
# 流式写出大型文件,这里的10代表10MB
|
async with aiofiles.open(filepath, 'wb') as f:
|
||||||
for chunk in iter(lambda: file.file.read(1024 * 1024 * 10), b''):
|
# 流式写出大型文件,这里的10代表10MB
|
||||||
f.write(chunk)
|
while True:
|
||||||
|
chunk = await file.read(1024 * 1024 * 10)
|
||||||
|
if not chunk:
|
||||||
|
break
|
||||||
|
await f.write(chunk)
|
||||||
|
|
||||||
return CrudResponseModel(
|
return CrudResponseModel(
|
||||||
is_success=True,
|
is_success=True,
|
||||||
result=UploadResponseModel(
|
result=UploadResponseModel(
|
||||||
fileName=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{filename}',
|
fileName=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{filename}',
|
||||||
newFileName=filename,
|
newFileName=filename,
|
||||||
originalFilename=file.filename,
|
originalFilename=file.filename,
|
||||||
url=f'{request.base_url}{UploadConfig.UPLOAD_PREFIX[1:]}/{relative_path}/{filename}',
|
url=f'{request.base_url}{UploadConfig.UPLOAD_PREFIX[1:]}/{relative_path}/{filename}',
|
||||||
),
|
),
|
||||||
message='上传成功',
|
message='上传成功',
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def download_services(cls, background_tasks: BackgroundTasks, file_name, delete: bool):
|
async def download_services(
|
||||||
|
cls, background_tasks: BackgroundTasks, file_name: str, delete: bool
|
||||||
|
) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
下载下载目录文件service
|
下载下载目录文件service
|
||||||
|
|
||||||
@@ -61,15 +71,14 @@ class CommonService:
|
|||||||
filepath = os.path.join(UploadConfig.DOWNLOAD_PATH, file_name)
|
filepath = os.path.join(UploadConfig.DOWNLOAD_PATH, file_name)
|
||||||
if '..' in file_name:
|
if '..' in file_name:
|
||||||
raise ServiceException(message='文件名称不合法')
|
raise ServiceException(message='文件名称不合法')
|
||||||
elif not UploadUtil.check_file_exists(filepath):
|
if not UploadUtil.check_file_exists(filepath):
|
||||||
raise ServiceException(message='文件不存在')
|
raise ServiceException(message='文件不存在')
|
||||||
else:
|
if delete:
|
||||||
if delete:
|
background_tasks.add_task(UploadUtil.delete_file, filepath)
|
||||||
background_tasks.add_task(UploadUtil.delete_file, filepath)
|
return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功')
|
||||||
return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功')
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def download_resource_services(cls, resource: str):
|
async def download_resource_services(cls, resource: str) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
下载上传目录文件service
|
下载上传目录文件service
|
||||||
|
|
||||||
@@ -85,7 +94,6 @@ class CommonService:
|
|||||||
or not UploadUtil.check_file_random_code(filename)
|
or not UploadUtil.check_file_random_code(filename)
|
||||||
):
|
):
|
||||||
raise ServiceException(message='文件名称不合法')
|
raise ServiceException(message='文件名称不合法')
|
||||||
elif not UploadUtil.check_file_exists(filepath):
|
if not UploadUtil.check_file_exists(filepath):
|
||||||
raise ServiceException(message='文件不存在')
|
raise ServiceException(message='文件不存在')
|
||||||
else:
|
return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功')
|
||||||
return CrudResponseModel(is_success=True, result=UploadUtil.generate_file(filepath), message='下载成功')
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
|
from typing import Any, Union
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
|
from redis import asyncio as aioredis
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from typing import List
|
|
||||||
from config.constant import CommonConstant
|
from common.constant import CommonConstant
|
||||||
from config.enums import RedisInitKeyConfig
|
from common.enums import RedisInitKeyConfig
|
||||||
|
from common.vo import CrudResponseModel, PageModel
|
||||||
from exceptions.exception import ServiceException
|
from exceptions.exception import ServiceException
|
||||||
from module_admin.dao.config_dao import ConfigDao
|
from module_admin.dao.config_dao import ConfigDao
|
||||||
from module_admin.entity.vo.common_vo import CrudResponseModel
|
|
||||||
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel
|
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel
|
||||||
from utils.common_util import CamelCaseUtil
|
from utils.common_util import CamelCaseUtil
|
||||||
from utils.excel_util import ExcelUtil
|
from utils.excel_util import ExcelUtil
|
||||||
@@ -19,7 +22,7 @@ class ConfigService:
|
|||||||
@classmethod
|
@classmethod
|
||||||
async def get_config_list_services(
|
async def get_config_list_services(
|
||||||
cls, query_db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False
|
cls, query_db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False
|
||||||
):
|
) -> Union[PageModel, list[dict[str, Any]]]:
|
||||||
"""
|
"""
|
||||||
获取参数配置列表信息service
|
获取参数配置列表信息service
|
||||||
|
|
||||||
@@ -33,7 +36,7 @@ class ConfigService:
|
|||||||
return config_list_result
|
return config_list_result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def init_cache_sys_config_services(cls, query_db: AsyncSession, redis):
|
async def init_cache_sys_config_services(cls, query_db: AsyncSession, redis: aioredis.Redis) -> None:
|
||||||
"""
|
"""
|
||||||
应用初始化:获取所有参数配置对应的键值对信息并缓存service
|
应用初始化:获取所有参数配置对应的键值对信息并缓存service
|
||||||
|
|
||||||
@@ -46,15 +49,15 @@ class ConfigService:
|
|||||||
# 删除匹配的键
|
# 删除匹配的键
|
||||||
if keys:
|
if keys:
|
||||||
await redis.delete(*keys)
|
await redis.delete(*keys)
|
||||||
config_all = await ConfigDao.get_config_list(query_db, ConfigPageQueryModel(**dict()), is_page=False)
|
config_all = await ConfigDao.get_config_list(query_db, ConfigPageQueryModel(), is_page=False)
|
||||||
for config_obj in config_all:
|
for config_obj in config_all:
|
||||||
await redis.set(
|
await redis.set(
|
||||||
f"{RedisInitKeyConfig.SYS_CONFIG.key}:{config_obj.get('configKey')}",
|
f'{RedisInitKeyConfig.SYS_CONFIG.key}:{config_obj.get("configKey")}',
|
||||||
config_obj.get('configValue'),
|
config_obj.get('configValue'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def query_config_list_from_cache_services(cls, redis, config_key: str):
|
async def query_config_list_from_cache_services(cls, redis: aioredis.Redis, config_key: str) -> Any:
|
||||||
"""
|
"""
|
||||||
从缓存获取参数键名对应值service
|
从缓存获取参数键名对应值service
|
||||||
|
|
||||||
@@ -67,7 +70,7 @@ class ConfigService:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def check_config_key_unique_services(cls, query_db: AsyncSession, page_object: ConfigModel):
|
async def check_config_key_unique_services(cls, query_db: AsyncSession, page_object: ConfigModel) -> bool:
|
||||||
"""
|
"""
|
||||||
校验参数键名是否唯一service
|
校验参数键名是否唯一service
|
||||||
|
|
||||||
@@ -82,7 +85,9 @@ class ConfigService:
|
|||||||
return CommonConstant.UNIQUE
|
return CommonConstant.UNIQUE
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def add_config_services(cls, request: Request, query_db: AsyncSession, page_object: ConfigModel):
|
async def add_config_services(
|
||||||
|
cls, request: Request, query_db: AsyncSession, page_object: ConfigModel
|
||||||
|
) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
新增参数配置信息service
|
新增参数配置信息service
|
||||||
|
|
||||||
@@ -93,20 +98,21 @@ class ConfigService:
|
|||||||
"""
|
"""
|
||||||
if not await cls.check_config_key_unique_services(query_db, page_object):
|
if not await cls.check_config_key_unique_services(query_db, page_object):
|
||||||
raise ServiceException(message=f'新增参数{page_object.config_name}失败,参数键名已存在')
|
raise ServiceException(message=f'新增参数{page_object.config_name}失败,参数键名已存在')
|
||||||
else:
|
try:
|
||||||
try:
|
await ConfigDao.add_config_dao(query_db, page_object)
|
||||||
await ConfigDao.add_config_dao(query_db, page_object)
|
await query_db.commit()
|
||||||
await query_db.commit()
|
await request.app.state.redis.set(
|
||||||
await request.app.state.redis.set(
|
f'{RedisInitKeyConfig.SYS_CONFIG.key}:{page_object.config_key}', page_object.config_value
|
||||||
f'{RedisInitKeyConfig.SYS_CONFIG.key}:{page_object.config_key}', page_object.config_value
|
)
|
||||||
)
|
return CrudResponseModel(is_success=True, message='新增成功')
|
||||||
return CrudResponseModel(is_success=True, message='新增成功')
|
except Exception as e:
|
||||||
except Exception as e:
|
await query_db.rollback()
|
||||||
await query_db.rollback()
|
raise e
|
||||||
raise e
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def edit_config_services(cls, request: Request, query_db: AsyncSession, page_object: ConfigModel):
|
async def edit_config_services(
|
||||||
|
cls, request: Request, query_db: AsyncSession, page_object: ConfigModel
|
||||||
|
) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
编辑参数配置信息service
|
编辑参数配置信息service
|
||||||
|
|
||||||
@@ -120,26 +126,27 @@ class ConfigService:
|
|||||||
if config_info.config_id:
|
if config_info.config_id:
|
||||||
if not await cls.check_config_key_unique_services(query_db, page_object):
|
if not await cls.check_config_key_unique_services(query_db, page_object):
|
||||||
raise ServiceException(message=f'修改参数{page_object.config_name}失败,参数键名已存在')
|
raise ServiceException(message=f'修改参数{page_object.config_name}失败,参数键名已存在')
|
||||||
else:
|
try:
|
||||||
try:
|
await ConfigDao.edit_config_dao(query_db, edit_config)
|
||||||
await ConfigDao.edit_config_dao(query_db, edit_config)
|
await query_db.commit()
|
||||||
await query_db.commit()
|
if config_info.config_key != page_object.config_key:
|
||||||
if config_info.config_key != page_object.config_key:
|
await request.app.state.redis.delete(
|
||||||
await request.app.state.redis.delete(
|
f'{RedisInitKeyConfig.SYS_CONFIG.key}:{config_info.config_key}'
|
||||||
f'{RedisInitKeyConfig.SYS_CONFIG.key}:{config_info.config_key}'
|
|
||||||
)
|
|
||||||
await request.app.state.redis.set(
|
|
||||||
f'{RedisInitKeyConfig.SYS_CONFIG.key}:{page_object.config_key}', page_object.config_value
|
|
||||||
)
|
)
|
||||||
return CrudResponseModel(is_success=True, message='更新成功')
|
await request.app.state.redis.set(
|
||||||
except Exception as e:
|
f'{RedisInitKeyConfig.SYS_CONFIG.key}:{page_object.config_key}', page_object.config_value
|
||||||
await query_db.rollback()
|
)
|
||||||
raise e
|
return CrudResponseModel(is_success=True, message='更新成功')
|
||||||
|
except Exception as e:
|
||||||
|
await query_db.rollback()
|
||||||
|
raise e
|
||||||
else:
|
else:
|
||||||
raise ServiceException(message='参数配置不存在')
|
raise ServiceException(message='参数配置不存在')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def delete_config_services(cls, request: Request, query_db: AsyncSession, page_object: DeleteConfigModel):
|
async def delete_config_services(
|
||||||
|
cls, request: Request, query_db: AsyncSession, page_object: DeleteConfigModel
|
||||||
|
) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
删除参数配置信息service
|
删除参数配置信息service
|
||||||
|
|
||||||
@@ -156,9 +163,8 @@ class ConfigService:
|
|||||||
config_info = await cls.config_detail_services(query_db, int(config_id))
|
config_info = await cls.config_detail_services(query_db, int(config_id))
|
||||||
if config_info.config_type == CommonConstant.YES:
|
if config_info.config_type == CommonConstant.YES:
|
||||||
raise ServiceException(message=f'内置参数{config_info.config_key}不能删除')
|
raise ServiceException(message=f'内置参数{config_info.config_key}不能删除')
|
||||||
else:
|
await ConfigDao.delete_config_dao(query_db, ConfigModel(configId=int(config_id)))
|
||||||
await ConfigDao.delete_config_dao(query_db, ConfigModel(configId=int(config_id)))
|
delete_config_key_list.append(f'{RedisInitKeyConfig.SYS_CONFIG.key}:{config_info.config_key}')
|
||||||
delete_config_key_list.append(f'{RedisInitKeyConfig.SYS_CONFIG.key}:{config_info.config_key}')
|
|
||||||
await query_db.commit()
|
await query_db.commit()
|
||||||
if delete_config_key_list:
|
if delete_config_key_list:
|
||||||
await request.app.state.redis.delete(*delete_config_key_list)
|
await request.app.state.redis.delete(*delete_config_key_list)
|
||||||
@@ -170,7 +176,7 @@ class ConfigService:
|
|||||||
raise ServiceException(message='传入参数配置id为空')
|
raise ServiceException(message='传入参数配置id为空')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def config_detail_services(cls, query_db: AsyncSession, config_id: int):
|
async def config_detail_services(cls, query_db: AsyncSession, config_id: int) -> ConfigModel:
|
||||||
"""
|
"""
|
||||||
获取参数配置详细信息service
|
获取参数配置详细信息service
|
||||||
|
|
||||||
@@ -179,15 +185,12 @@ class ConfigService:
|
|||||||
:return: 参数配置id对应的信息
|
:return: 参数配置id对应的信息
|
||||||
"""
|
"""
|
||||||
config = await ConfigDao.get_config_detail_by_id(query_db, config_id=config_id)
|
config = await ConfigDao.get_config_detail_by_id(query_db, config_id=config_id)
|
||||||
if config:
|
result = ConfigModel(**CamelCaseUtil.transform_result(config)) if config else ConfigModel()
|
||||||
result = ConfigModel(**CamelCaseUtil.transform_result(config))
|
|
||||||
else:
|
|
||||||
result = ConfigModel(**dict())
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def export_config_list_services(config_list: List):
|
async def export_config_list_services(config_list: list) -> bytes:
|
||||||
"""
|
"""
|
||||||
导出参数配置信息service
|
导出参数配置信息service
|
||||||
|
|
||||||
@@ -218,7 +221,7 @@ class ConfigService:
|
|||||||
return binary_data
|
return binary_data
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def refresh_sys_config_services(cls, request: Request, query_db: AsyncSession):
|
async def refresh_sys_config_services(cls, request: Request, query_db: AsyncSession) -> CrudResponseModel:
|
||||||
"""
|
"""
|
||||||
刷新字典缓存信息service
|
刷新字典缓存信息service
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user