83 Commits

Author SHA1 Message Date
柳翼
924a7674fa Pre Merge pull request !405 from 柳翼/master 2025-05-09 06:02:18 +00:00
RuoYi
3915c77391 优化导航栏显示昵称&设置 2025-05-09 14:02:09 +08:00
RuoYi
b80932ceb4 菜单搜索支持键盘选择&悬浮主题背景 2025-05-07 13:27:13 +08:00
RuoYi
056cf94082 图片上传组件新增disabled属性 2025-05-06 19:14:54 +08:00
RuoYi
0dcd3e6183 add columnName Drag 2025-05-06 14:54:44 +08:00
RuoYi
07be5ceb26 修复上传组件被多次引用拖动仅对第一个有效的问题 2025-05-06 13:46:21 +08:00
RuoYi
cc59502d7c update icon 2025-05-05 11:22:35 +08:00
RuoYi
98738f23ad 上传组件新增拖动排序属性 2025-04-30 10:31:03 +08:00
RuoYi
57fe1c663e 优化Excel匹配数值型.0结尾 2025-04-28 11:20:48 +08:00
RuoYi
7b6fdb3a89 remove all semicolons 2025-04-27 11:56:21 +08:00
wangbing
7320bda521 修改部分文件的字符编码;修改使用Docker启动容器时的问题 2025-04-26 10:09:53 +08:00
wangbing
646247503e Merge remote-tracking branch 'origin/master' 2025-04-25 20:35:02 +08:00
wangbing
8a55aaec91 字符编码GBK和项目的编码UTF-8不一致,将文本改为UTF-8编码字符 2025-04-25 20:34:27 +08:00
RuoYi
79c885decb 使用Gateway CacheRequestBody代替CacheRequestFilter 2025-04-25 15:11:17 +08:00
RuoYi
1a0f37a2dc 富文本复制粘贴图片上传至url 2025-04-24 18:19:16 +08:00
RuoYi
02de344d8c update package.json 2025-04-24 18:18:44 +08:00
RuoYi
189100f74e 优化低版本node无法启动的问题 2025-04-22 12:07:07 +08:00
RuoYi
e29284e687 优化代码 2025-04-22 12:06:59 +08:00
RuoYi
d4af286f41 显隐列组件支持全选/全不选 2025-04-21 15:30:32 +08:00
RuoYi
60e2d55a23 优化菜单搜索查询页 2025-04-21 13:28:32 +08:00
RuoYi
bbd112d5a3 支持文件&图片组件自定义地址&参数 2025-04-18 13:25:28 +08:00
RuoYi
90922844ea 优化角色禁用不允许分配 2025-04-17 15:36:18 +08:00
RuoYi
3a9f56f04b update status name 2025-04-17 15:35:58 +08:00
RuoYi
a1ec1d57d4 remove dev runjs 2025-03-18 16:01:46 +08:00
RuoYi
060959a7c5 登录页和注册页表头使用VUE_APP_TITLE配置值 2025-03-18 16:01:20 +08:00
RuoYi
43e1d8d573 升级tomcat到最新版本9.0.102 2025-03-14 16:12:40 +08:00
RuoYi
67cf51ba77 update handleTree 2025-03-14 16:12:29 +08:00
RuoYi
a256618d5d 优化代码 2025-03-11 12:52:17 +08:00
若依
a6bcebb62b !397 修复actuator暴漏问题
Merge pull request !397 from 威士忌的纯度/N/A
2025-03-10 03:45:34 +00:00
威士忌的纯度
1cb262daa3 修复actuator暴漏问题
Signed-off-by: 威士忌的纯度 <whr888888@vip.qq.com>
2025-03-07 10:22:52 +00:00
RuoYi
8c096cba8d 优化isAdmin方法,避免脱敏模块security依赖 2025-03-07 12:56:31 +08:00
RuoYi
088cec8adf 菜单管理新增路由名称 2025-03-06 11:09:34 +08:00
RuoYi
85ff6a9910 优化顶部菜单搜索栏为多层级显示 2025-03-05 18:14:13 +08:00
RuoYi
cab5beaca7 文件上传组件新增disabled属性&类型 2025-03-05 18:13:40 +08:00
RuoYi
fc8069a250 优化导出Excel日期格式双击离开后与设定的格式不一致问题 2025-03-05 18:13:12 +08:00
RuoYi
924e705dca 代码生成列表支持按时间排序 2025-03-05 18:12:52 +08:00
RuoYi
049ba453d1 优化空指针异常时无法获取错误信息问题 2025-03-05 18:10:56 +08:00
RuoYi
4aa261e8f7 优化定时任务字符包含多个括号导致数据错误 2025-03-05 18:10:12 +08:00
RuoYi
914a6620f5 升级tomcat到最新版本9.0.98 2025-03-05 18:08:29 +08:00
RuoYi
3dcee7057d 优化代码 2025-03-05 18:01:33 +08:00
RuoYi
0467631319 update ry_config.sql 2025-02-24 16:24:36 +08:00
若依
a11df90255 !393 config(nacos):增加nacos2.5.0配置文件sql
Merge pull request !393 from 牟雷/master
2025-02-18 00:33:39 +00:00
牟雷
596e4fe756 config(nacos):增加nacos2.5.0配置文件sql 2025-02-17 20:19:22 +08:00
RuoYi
37219e4ae6 copyright 2025 2025-01-07 10:55:58 +08:00
RuoYi
adaa3e1db8 代码生成新增配置是否允许文件覆盖到本地 2024-12-25 16:30:44 +08:00
RuoYi
88ad5a2c19 优化导入带标题文件关闭清理 2024-12-25 16:24:38 +08:00
RuoYi
b45dc2ec25 update sqlkeyword 2024-12-25 16:24:02 +08:00
RuoYi
67b17da06f 优化特殊字符密码修改失败问题 2024-12-17 14:28:17 +08:00
RuoYi
b25a280ebb 优化TopNav内链菜单点击没有高亮(IB8WHJ) 2024-12-17 11:57:05 +08:00
RuoYi
cc026e75a3 优化菜单管理切换Mini布局错乱问题 2024-12-17 11:25:03 +08:00
RuoYi
7216b56a56 用户管理过滤掉已禁用部门 2024-12-11 11:43:00 +08:00
RuoYi
a326e880a1 修改主题样式本地读取 2024-12-07 17:08:53 +08:00
RuoYi
92c6d21855 优化文件异常输入流未关闭的问题 2024-12-05 14:27:54 +08:00
RuoYi
2335157f6e 白名单支持对通配符路径匹配 2024-12-04 08:52:13 +08:00
RuoYi
6c3b01c3c5 Excel注解支持wrapText是否允许内容换行 2024-12-03 09:07:04 +08:00
RuoYi
8faea60191 修复导出子列表对象只能在最后的问题 2024-12-02 20:37:12 +08:00
RuoYi
28a16d9878 修复默认关闭Tags-Views时,内链页面打不开 2024-11-27 19:49:12 +08:00
RuoYi
dd3cf18e27 修复TopNav无法正确获取active的问题 2024-11-27 09:02:26 +08:00
RuoYi
65d03dc014 优化代码 2024-11-25 22:30:03 +08:00
RuoYi
7912fd81bd 面板兼容移动端显示 2024-11-25 15:41:00 +08:00
RuoYi
e2175e5b9d 参数键值更换为多行文本 2024-11-25 12:15:49 +08:00
RuoYi
c0e119f8e0 菜单面包屑导航支持多层级显示 2024-11-22 20:45:08 +08:00
RuoYi
fa77b2a08c 分栏参数微调 2024-11-22 14:46:59 +08:00
RuoYi
a222c24796 用户管理支持分栏拖动 2024-11-22 13:58:37 +08:00
RuoYi
08f4b877ce 优化代码 2024-11-20 11:13:24 +08:00
RuoYi
aa607d135c update .env.staging 2024-11-20 10:43:07 +08:00
RuoYi
6d34cdb8a3 若依 3.6.5 2024-11-13 08:38:24 +08:00
RuoYi
d47352253e 升级spring-cloud相关组件到最新版 2024-11-12 15:12:01 +08:00
RuoYi
61cbd470e1 update datascope 2024-11-12 15:10:47 +08:00
RuoYi
b3ef4adfed 支持自定义显示Excel属性列 2024-11-07 22:25:48 +08:00
RuoYi
856c471472 优化代码 2024-11-06 10:20:18 +08:00
RuoYi
bec5600f16 优化无用户编号不校验数据权限 2024-11-05 16:30:15 +08:00
RuoYi
5b485e7934 校检文件名是否包含特殊字符 2024-11-05 12:50:12 +08:00
RuoYi
73a752d3ab 优化身份证脱敏正则 2024-10-21 17:16:01 +08:00
RuoYi
1899a832b9 优化权限更新后同步缓存 2024-10-21 17:15:30 +08:00
RuoYi
e6796c0954 操作日志记录DELETE请求参数 2024-10-17 13:17:25 +08:00
RuoYi
4987289a98 升级quill到最新版本2.0.2 2024-10-15 16:21:20 +08:00
RuoYi
18409922a5 修改代码生成上级菜单字段类型 2024-09-27 16:23:36 +08:00
RuoYi
3dca02b306 修复角色禁用权限不失效问题 2024-09-21 12:08:41 +08:00
RuoYi
75f3275e15 修复角色禁用权限不失效问题 2024-09-21 12:01:48 +08:00
RuoYi
b2e4a7046b update ry_config 2024-09-02 20:21:30 +08:00
RuoYi
60618c1da9 优化提示 2024-09-02 20:21:15 +08:00
RuoYi
3b499b1344 使用SpringDoc代替Swagger 2024-08-30 11:26:57 +08:00
192 changed files with 3892 additions and 4053 deletions

View File

@@ -1,11 +1,11 @@
<p align="center"> <p align="center">
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-b99b286755aef70355a7084753f89cdb7c9.png"> <img alt="logo" src="https://oscimg.oschina.net/oscnet/up-b99b286755aef70355a7084753f89cdb7c9.png">
</p> </p>
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.4</h1> <h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.5</h1>
<h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4> <h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4>
<p align="center"> <p align="center">
<a href="https://gitee.com/y_project/RuoYi-Cloud/stargazers"><img src="https://gitee.com/y_project/RuoYi-Cloud/badge/star.svg?theme=dark"></a> <a href="https://gitee.com/y_project/RuoYi-Cloud/stargazers"><img src="https://gitee.com/y_project/RuoYi-Cloud/badge/star.svg?theme=dark"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.4-brightgreen.svg"></a> <a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.5-brightgreen.svg"></a>
<a href="https://gitee.com/y_project/RuoYi-Cloud/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a> <a href="https://gitee.com/y_project/RuoYi-Cloud/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
</p> </p>
@@ -17,12 +17,9 @@
* 后端采用Spring Boot、Spring Cloud & Alibaba。 * 后端采用Spring Boot、Spring Cloud & Alibaba。
* 注册中心、配置中心选型Nacos权限认证使用Redis。 * 注册中心、配置中心选型Nacos权限认证使用Redis。
* 流量控制框架选型Sentinel分布式事务选型Seata。 * 流量控制框架选型Sentinel分布式事务选型Seata。
* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Cloud-Vue3](https://github.com/yangzongzhuan/RuoYi-Cloud-Vue3),保持同步更新。 * 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Cloud-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Cloud-Vue3),保持同步更新。
* 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi),如需分离应用,请移步 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) * 如需不分离应用,请移步 [RuoYi](https://gitee.com/y_project/RuoYi),如需分离应用,请移步 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue)
* 阿里云折扣场[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp; * 阿里云优惠券[点我进入](http://aly.ruoyi.vip),腾讯云优惠券[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;
* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)&nbsp;&nbsp;
#### 友情链接 [若依/RuoYi-Cloud](https://gitee.com/zhangmrit/ruoyi-cloud) Ant Design版本。
## 系统模块 ## 系统模块
@@ -41,6 +38,7 @@ com.ruoyi
│ └── ruoyi-common-redis // 缓存服务 │ └── ruoyi-common-redis // 缓存服务
│ └── ruoyi-common-seata // 分布式事务 │ └── ruoyi-common-seata // 分布式事务
│ └── ruoyi-common-security // 安全模块 │ └── ruoyi-common-security // 安全模块
│ └── ruoyi-common-sensitive // 数据脱敏
│ └── ruoyi-common-swagger // 系统接口 │ └── ruoyi-common-swagger // 系统接口
├── ruoyi-modules // 业务模块 ├── ruoyi-modules // 业务模块
│ └── ruoyi-system // 系统模块 [9201] │ └── ruoyi-system // 系统模块 [9201]

View File

@@ -1,6 +1,6 @@
@echo off @echo off
echo. echo.
echo [信息] 清理工程target生成路径。 echo [信息] 清理工程target生成路径。
echo. echo.
%~d0 %~d0

45
docker/copy.ps1 Normal file
View File

@@ -0,0 +1,45 @@
#!/usr/bin/env pwsh
<#
.SYNOPSIS
复制项目的文件到对应docker路径便于一键生成镜像。
#>
# 复制SQL文件
Write-Host "begin copy sql"
Copy-Item -Path "../sql/ry_20250425.sql" -Destination "./mysql/db" -Force
Copy-Item -Path "../sql/ry_config_20250224.sql" -Destination "./mysql/db" -Force
# 复制HTML文件
Write-Host "begin copy html"
if (Test-Path "../ruoyi-ui/dist") {
Remove-Item -Path "./nginx/html/dist" -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path "./nginx/html/dist" -Force | Out-Null
Copy-Item -Path "../ruoyi-ui/dist/*" -Destination "./nginx/html/dist" -Recurse -Force
} else {
Write-Host "Warning: ../ruoyi-ui/dist directory not found"
}
# 复制JAR文件
Write-Host "begin copy ruoyi-gateway"
Copy-Item -Path "../ruoyi-gateway/target/ruoyi-gateway.jar" -Destination "./ruoyi/gateway/jar" -Force
Write-Host "begin copy ruoyi-auth"
Copy-Item -Path "../ruoyi-auth/target/ruoyi-auth.jar" -Destination "./ruoyi/auth/jar" -Force
Write-Host "begin copy ruoyi-visual"
Copy-Item -Path "../ruoyi-visual/ruoyi-monitor/target/ruoyi-visual-monitor.jar" -Destination "./ruoyi/visual/monitor/jar" -Force
Write-Host "begin copy ruoyi-modules-system"
Copy-Item -Path "../ruoyi-modules/ruoyi-system/target/ruoyi-modules-system.jar" -Destination "./ruoyi/modules/system/jar" -Force
Write-Host "begin copy ruoyi-modules-file"
Copy-Item -Path "../ruoyi-modules/ruoyi-file/target/ruoyi-modules-file.jar" -Destination "./ruoyi/modules/file/jar" -Force
Write-Host "begin copy ruoyi-modules-job"
Copy-Item -Path "../ruoyi-modules/ruoyi-job/target/ruoyi-modules-job.jar" -Destination "./ruoyi/modules/job/jar" -Force
Write-Host "begin copy ruoyi-modules-gen"
Copy-Item -Path "../ruoyi-modules/ruoyi-gen/target/ruoyi-modules-gen.jar" -Destination "./ruoyi/modules/gen/jar" -Force
Write-Host "copy completed"

View File

@@ -9,8 +9,8 @@ usage() {
# copy sql # copy sql
echo "begin copy sql " echo "begin copy sql "
cp ../sql/ry_20231130.sql ./mysql/db cp ../sql/ry_20240629.sql ./mysql/db
cp ../sql/ry_config_20231204.sql ./mysql/db cp ../sql/ry_config_20250224.sql ./mysql/db
# copy html # copy html
echo "begin copy html " echo "begin copy html "

View File

@@ -2,7 +2,6 @@ version : '3.8'
services: services:
ruoyi-nacos: ruoyi-nacos:
container_name: ruoyi-nacos container_name: ruoyi-nacos
image: nacos/nacos-server
build: build:
context: ./nacos context: ./nacos
environment: environment:
@@ -18,7 +17,6 @@ services:
- ruoyi-mysql - ruoyi-mysql
ruoyi-mysql: ruoyi-mysql:
container_name: ruoyi-mysql container_name: ruoyi-mysql
image: mysql:5.7
build: build:
context: ./mysql context: ./mysql
ports: ports:
@@ -40,7 +38,6 @@ services:
MYSQL_ROOT_PASSWORD: password MYSQL_ROOT_PASSWORD: password
ruoyi-redis: ruoyi-redis:
container_name: ruoyi-redis container_name: ruoyi-redis
image: redis
build: build:
context: ./redis context: ./redis
ports: ports:

View File

@@ -1,7 +1,7 @@
# 基础镜像 # 基础镜像
FROM mysql:5.7 FROM mysql:5.7
# author # author
MAINTAINER ruoyi MAINTAINER ruoyi
# 执行sql脚本 # 执行sql脚本
ADD ./db/*.sql /docker-entrypoint-initdb.d/ ADD ./db/*.sql /docker-entrypoint-initdb.d/

View File

@@ -1 +1 @@
存放sql目录下的所有脚本用于docker自动执行。 存放sql目录下的所有脚本用于docker自动执行。

View File

@@ -29,7 +29,7 @@ http {
} }
# 避免actuator暴露 # 避免actuator暴露
if ($request_uri ~ "/actuator") { if ($uri ~ "/actuator") {
return 403; return 403;
} }

View File

@@ -1 +0,0 @@
存放前端ruoyi-ui构建好的静态文件用于nginx请求访问。

View File

@@ -1 +1 @@
存放认证中心打包好的jar文件用于docker启动应用。 存放认证中心打包好的jar文件用于docker启动应用。

View File

@@ -1 +1 @@
存放网关模块打包好的jar文件用于docker启动应用。 存放网关模块打包好的jar文件用于docker启动应用。

View File

@@ -1 +1 @@
存放监控中心打包好的jar文件用于docker启动应用。 存放监控中心打包好的jar文件用于docker启动应用。

70
pom.xml
View File

@@ -6,43 +6,46 @@
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
<name>ruoyi</name> <name>ruoyi</name>
<url>http://www.ruoyi.vip</url> <url>http://www.ruoyi.vip</url>
<description>若依微服务系统</description> <description>若依微服务系统</description>
<properties> <properties>
<ruoyi.version>3.6.4</ruoyi.version> <ruoyi.version>3.6.5</ruoyi.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<spring-boot.version>2.7.18</spring-boot.version> <spring-boot.version>2.7.18</spring-boot.version>
<spring-cloud.version>2021.0.8</spring-cloud.version> <spring-cloud.version>2021.0.9</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.5.0</spring-cloud-alibaba.version> <spring-cloud-alibaba.version>2021.0.6.1</spring-cloud-alibaba.version>
<spring-framework.version>5.3.33</spring-framework.version> <spring-boot-admin.version>2.7.16</spring-boot-admin.version>
<spring-boot-admin.version>2.7.15</spring-boot-admin.version>
<swagger.fox.version>3.0.0</swagger.fox.version>
<swagger.core.version>1.6.2</swagger.core.version>
<tobato.version>1.27.2</tobato.version> <tobato.version>1.27.2</tobato.version>
<kaptcha.version>2.3.3</kaptcha.version> <kaptcha.version>2.3.3</kaptcha.version>
<pagehelper.boot.version>2.0.0</pagehelper.boot.version> <pagehelper.boot.version>2.0.0</pagehelper.boot.version>
<druid.version>1.2.23</druid.version> <druid.version>1.2.23</druid.version>
<dynamic-ds.version>4.2.0</dynamic-ds.version> <dynamic-ds.version>4.3.1</dynamic-ds.version>
<commons.io.version>2.13.0</commons.io.version> <commons.io.version>2.13.0</commons.io.version>
<velocity.version>2.3</velocity.version> <velocity.version>2.3</velocity.version>
<fastjson.version>2.0.43</fastjson.version> <fastjson.version>2.0.53</fastjson.version>
<jjwt.version>0.9.1</jjwt.version> <jjwt.version>0.9.1</jjwt.version>
<minio.version>8.2.2</minio.version> <minio.version>8.2.2</minio.version>
<poi.version>4.1.2</poi.version> <poi.version>4.1.2</poi.version>
<springdoc.version>1.6.9</springdoc.version>
<transmittable-thread-local.version>2.14.4</transmittable-thread-local.version> <transmittable-thread-local.version>2.14.4</transmittable-thread-local.version>
<!-- override dependency version -->
<tomcat.version>9.0.102</tomcat.version>
<logback.version>1.2.13</logback.version>
<spring-framework.version>5.3.39</spring-framework.version>
</properties> </properties>
<!-- 依赖声明 --> <!-- 依赖声明 -->
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<!-- SpringFramework的依赖配置--> <!-- 覆盖SpringFramework的依赖配置-->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId> <artifactId>spring-framework-bom</artifactId>
@@ -78,6 +81,38 @@
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<!-- 覆盖logback的依赖配置-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<!-- 覆盖tomcat的依赖配置-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-el</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>${tomcat.version}</version>
</dependency>
<!-- FastDFS 分布式文件系统 --> <!-- FastDFS 分布式文件系统 -->
<dependency> <dependency>
<groupId>com.github.tobato</groupId> <groupId>com.github.tobato</groupId>
@@ -85,16 +120,11 @@
<version>${tobato.version}</version> <version>${tobato.version}</version>
</dependency> </dependency>
<!-- Swagger 依赖配置 --> <!-- Springdoc webmvc 依赖配置 -->
<dependency> <dependency>
<groupId>io.swagger</groupId> <groupId>org.springdoc</groupId>
<artifactId>swagger-models</artifactId> <artifactId>springdoc-openapi-ui</artifactId>
<version>${swagger.core.version}</version> <version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>${swagger.core.version}</version>
</dependency> </dependency>
<!-- 验证码 --> <!-- 验证码 -->

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-api</artifactId> <artifactId>ruoyi-api</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -8,6 +8,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.core.annotation.Excel; import com.ruoyi.common.core.annotation.Excel;
import com.ruoyi.common.core.annotation.Excel.ColumnType; import com.ruoyi.common.core.annotation.Excel.ColumnType;
import com.ruoyi.common.core.annotation.Excel.Type; import com.ruoyi.common.core.annotation.Excel.Type;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.annotation.Excels; import com.ruoyi.common.core.annotation.Excels;
import com.ruoyi.common.core.web.domain.BaseEntity; import com.ruoyi.common.core.web.domain.BaseEntity;
import com.ruoyi.common.core.xss.Xss; import com.ruoyi.common.core.xss.Xss;
@@ -55,8 +56,8 @@ public class SysUser extends BaseEntity
/** 密码 */ /** 密码 */
private String password; private String password;
/** 号状态0正常 1停用 */ /** 号状态0正常 1停用 */
@Excel(name = "号状态", readConverterExp = "0=正常,1=停用") @Excel(name = "号状态", readConverterExp = "0=正常,1=停用")
private String status; private String status;
/** 删除标志0代表存在 2代表删除 */ /** 删除标志0代表存在 2代表删除 */
@@ -116,7 +117,7 @@ public class SysUser extends BaseEntity
public static boolean isAdmin(Long userId) public static boolean isAdmin(Long userId)
{ {
return userId != null && 1L == userId; return UserConstants.isAdmin(userId);
} }
public Long getDeptId() public Long getDeptId()
@@ -296,6 +297,7 @@ public class SysUser extends BaseEntity
{ {
this.roleId = roleId; this.roleId = roleId;
} }
@Override @Override
public String toString() { public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -74,17 +74,11 @@ public class SysLoginService
// 查询用户信息 // 查询用户信息
R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER); R<LoginUser> userResult = remoteUserService.getUserInfo(username, SecurityConstants.INNER);
if (StringUtils.isNull(userResult) || StringUtils.isNull(userResult.getData()))
{
recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在");
throw new ServiceException("登录用户:" + username + " 不存在");
}
if (R.FAIL == userResult.getCode()) if (R.FAIL == userResult.getCode())
{ {
throw new ServiceException(userResult.getMsg()); throw new ServiceException(userResult.getMsg());
} }
LoginUser userInfo = userResult.getData(); LoginUser userInfo = userResult.getData();
SysUser user = userResult.getData().getSysUser(); SysUser user = userResult.getData().getSysUser();
if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -107,12 +107,6 @@
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
</dependency> </dependency>
<!-- Swagger -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -78,6 +78,11 @@ public @interface Excel
*/ */
public String prompt() default ""; public String prompt() default "";
/**
* 是否允许内容换行
*/
public boolean wrapText() default false;
/** /**
* 设置只能选择不能输入的列内容. * 设置只能选择不能输入的列内容.
*/ */

View File

@@ -20,7 +20,7 @@ public class SecurityConstants
/** /**
* 授权信息字段 * 授权信息字段
*/ */
public static final String AUTHORIZATION_HEADER = "authorization"; public static final String AUTHORIZATION_HEADER = "Authorization";
/** /**
* 请求来源 * 请求来源

View File

@@ -7,11 +7,6 @@ package com.ruoyi.common.core.constant;
*/ */
public class TokenConstants public class TokenConstants
{ {
/**
* 令牌自定义标识
*/
public static final String AUTHENTICATION = "Authorization";
/** /**
* 令牌前缀 * 令牌前缀
*/ */

View File

@@ -21,6 +21,9 @@ public class UserConstants
/** 用户封禁状态 */ /** 用户封禁状态 */
public static final String USER_DISABLE = "1"; public static final String USER_DISABLE = "1";
/** 角色正常状态 */
public static final String ROLE_NORMAL = "0";
/** 角色封禁状态 */ /** 角色封禁状态 */
public static final String ROLE_DISABLE = "1"; public static final String ROLE_DISABLE = "1";
@@ -77,4 +80,9 @@ public class UserConstants
public static final int PASSWORD_MIN_LENGTH = 5; public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20; public static final int PASSWORD_MAX_LENGTH = 20;
public static boolean isAdmin(Long userId)
{
return userId != null && 1L == userId;
}
} }

View File

@@ -540,9 +540,9 @@ public class Convert
/** /**
* 转换为boolean<br> * 转换为boolean<br>
* String支持的值为true、false、yes、ok、no1,0 如果给定的值为空,或者转换失败,返回默认值<br> * String支持的值为true、false、yes、ok、no、1、0、是、否, 如果给定的值为空,或者转换失败,返回默认值<br>
* 转换失败不会报错 * 转换失败不会报错
* *
* @param value 被转换的值 * @param value 被转换的值
* @param defaultValue 转换错误时的默认值 * @param defaultValue 转换错误时的默认值
* @return 结果 * @return 结果
@@ -569,10 +569,12 @@ public class Convert
case "yes": case "yes":
case "ok": case "ok":
case "1": case "1":
case "":
return true; return true;
case "false": case "false":
case "no": case "no":
case "0": case "0":
case "":
return false; return false;
default: default:
return defaultValue; return defaultValue;

View File

@@ -283,6 +283,32 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
return str.substring(start, end); return str.substring(start, end);
} }
/**
* 在字符串中查找第一个出现的 `open` 和最后一个出现的 `close` 之间的子字符串
*
* @param str 要截取的字符串
* @param open 起始字符串
* @param close 结束字符串
* @return 截取结果
*/
public static String substringBetweenLast(final String str, final String open, final String close)
{
if (isEmpty(str) || isEmpty(open) || isEmpty(close))
{
return NULLSTR;
}
final int start = str.indexOf(open);
if (start != INDEX_NOT_FOUND)
{
final int end = str.lastIndexOf(close);
if (end != INDEX_NOT_FOUND)
{
return str.substring(start + open.length(), end);
}
}
return NULLSTR;
}
/** /**
* 判断是否为空,并且不是空白字符 * 判断是否为空,并且不是空白字符
* *

View File

@@ -167,6 +167,11 @@ public class ExcelUtil<T>
*/ */
public Class<T> clazz; public Class<T> clazz;
/**
* 需要显示列属性
*/
public String[] includeFields;
/** /**
* 需要排除列属性 * 需要排除列属性
*/ */
@@ -177,11 +182,20 @@ public class ExcelUtil<T>
this.clazz = clazz; this.clazz = clazz;
} }
/**
* 仅在Excel中显示列属性
*
* @param fields 列属性名 示例[单个"name"/多个"id","name"]
*/
public void showColumn(String... fields)
{
this.includeFields = fields;
}
/** /**
* 隐藏Excel中列属性 * 隐藏Excel中列属性
* *
* @param fields 列属性名 示例[单个"name"/多个"id","name"] * @param fields 列属性名 示例[单个"name"/多个"id","name"]
* @throws Exception
*/ */
public void hideColumn(String... fields) public void hideColumn(String... fields)
{ {
@@ -211,8 +225,6 @@ public class ExcelUtil<T>
{ {
if (StringUtils.isNotEmpty(title)) if (StringUtils.isNotEmpty(title))
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
int titleLastCol = this.fields.size() - 1; int titleLastCol = this.fields.size() - 1;
if (isSubList()) if (isSubList())
{ {
@@ -223,7 +235,7 @@ public class ExcelUtil<T>
Cell titleCell = titleRow.createCell(0); Cell titleCell = titleRow.createCell(0);
titleCell.setCellStyle(styles.get("title")); titleCell.setCellStyle(styles.get("title"));
titleCell.setCellValue(title); titleCell.setCellValue(title);
sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(), titleLastCol)); sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
} }
} }
@@ -234,23 +246,31 @@ public class ExcelUtil<T>
{ {
if (isSubList()) if (isSubList())
{ {
subMergedFirstRowNum++;
subMergedLastRowNum++;
Row subRow = sheet.createRow(rownum); Row subRow = sheet.createRow(rownum);
int excelNum = 0; int column = 0;
int subFieldSize = subFields != null ? subFields.size() : 0;
for (Object[] objects : fields) for (Object[] objects : fields)
{ {
Field field = (Field) objects[0];
Excel attr = (Excel) objects[1]; Excel attr = (Excel) objects[1];
Cell headCell1 = subRow.createCell(excelNum); if (Collection.class.isAssignableFrom(field.getType()))
headCell1.setCellValue(attr.name()); {
headCell1.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor()))); Cell cell = subRow.createCell(column);
excelNum++; cell.setCellValue(attr.name());
} cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
int headFirstRow = excelNum - 1; if (subFieldSize > 1)
int headLastRow = headFirstRow + subFields.size() - 1; {
if (headLastRow > headFirstRow) CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
{ sheet.addMergedRegion(cellAddress);
sheet.addMergedRegion(new CellRangeAddress(rownum, rownum, headFirstRow, headLastRow)); }
column += subFieldSize;
}
else
{
Cell cell = subRow.createCell(column++);
cell.setCellValue(attr.name());
cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
}
} }
rownum++; rownum++;
} }
@@ -263,11 +283,23 @@ public class ExcelUtil<T>
* @return 转换后集合 * @return 转换后集合
*/ */
public List<T> importExcel(InputStream is) public List<T> importExcel(InputStream is)
{
return importExcel(is, 0);
}
/**
* 对excel表单默认第一个索引名转换成list
*
* @param is 输入流
* @param titleNum 标题占用行数
* @return 转换后集合
*/
public List<T> importExcel(InputStream is, int titleNum)
{ {
List<T> list = null; List<T> list = null;
try try
{ {
list = importExcel(is, 0); list = importExcel(StringUtils.EMPTY, is, titleNum);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -281,18 +313,6 @@ public class ExcelUtil<T>
return list; return list;
} }
/**
* 对excel表单默认第一个索引名转换成list
*
* @param is 输入流
* @param titleNum 标题占用行数
* @return 转换后集合
*/
public List<T> importExcel(InputStream is, int titleNum) throws Exception
{
return importExcel(StringUtils.EMPTY, is, titleNum);
}
/** /**
* 对excel表单指定表格索引名转换成list * 对excel表单指定表格索引名转换成list
* *
@@ -370,7 +390,7 @@ public class ExcelUtil<T>
if (String.class == fieldType) if (String.class == fieldType)
{ {
String s = Convert.toStr(val); String s = Convert.toStr(val);
if (StringUtils.endsWith(s, ".0")) if (s.matches("^\\d+\\.0$"))
{ {
val = StringUtils.substringBefore(s, ".0"); val = StringUtils.substringBefore(s, ".0");
} }
@@ -575,64 +595,91 @@ public class ExcelUtil<T>
{ {
int startNo = index * sheetSize; int startNo = index * sheetSize;
int endNo = Math.min(startNo + sheetSize, list.size()); int endNo = Math.min(startNo + sheetSize, list.size());
int rowNo = (1 + rownum) - startNo; int currentRowNum = rownum + 1; // 从标题行后开始
for (int i = startNo; i < endNo; i++) for (int i = startNo; i < endNo; i++)
{ {
rowNo = isSubList() ? (i > 1 ? rowNo + 1 : rowNo + i) : i + 1 + rownum - startNo; row = sheet.createRow(currentRowNum);
row = sheet.createRow(rowNo);
// 得到导出对象.
T vo = (T) list.get(i); T vo = (T) list.get(i);
Collection<?> subList = null;
if (isSubList())
{
if (isSubListValue(vo))
{
subList = getListCellValue(vo);
subMergedLastRowNum = subMergedLastRowNum + subList.size();
}
else
{
subMergedFirstRowNum++;
subMergedLastRowNum++;
}
}
int column = 0; int column = 0;
int maxSubListSize = getCurrentMaxSubListSize(vo);
for (Object[] os : fields) for (Object[] os : fields)
{ {
Field field = (Field) os[0]; Field field = (Field) os[0];
Excel excel = (Excel) os[1]; Excel excel = (Excel) os[1];
if (Collection.class.isAssignableFrom(field.getType()) && StringUtils.isNotNull(subList)) if (Collection.class.isAssignableFrom(field.getType()))
{ {
boolean subFirst = false; try
for (Object obj : subList)
{ {
if (subFirst) Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
if (subList != null && !subList.isEmpty())
{ {
rowNo++; int subIndex = 0;
row = sheet.createRow(rowNo); for (Object subVo : subList)
}
List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(obj.getClass(), Excel.class);
int subIndex = 0;
for (Field subField : subFields)
{
if (subField.isAnnotationPresent(Excel.class))
{ {
subField.setAccessible(true); Row subRow = sheet.getRow(currentRowNum + subIndex);
Excel attr = subField.getAnnotation(Excel.class); if (subRow == null)
this.addCell(attr, row, (T) obj, subField, column + subIndex); {
subRow = sheet.createRow(currentRowNum + subIndex);
}
int subColumn = column;
for (Field subField : subFields)
{
Excel subExcel = subField.getAnnotation(Excel.class);
addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
}
subIndex++;
} }
subIndex++; column += subFields.size();
} }
subFirst = true;
} }
this.subMergedFirstRowNum = this.subMergedFirstRowNum + subList.size(); catch (Exception e)
{
log.error("填充集合数据失败", e);
}
} }
else else
{ {
this.addCell(excel, row, vo, field, column++); // 创建单元格并设置值
addCell(excel, row, vo, field, column);
if (maxSubListSize > 1 && excel.needMerge())
{
sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
}
column++;
}
}
currentRowNum += maxSubListSize;
}
}
/**
* 获取子列表最大数
*/
private int getCurrentMaxSubListSize(T vo)
{
int maxSubListSize = 1;
for (Object[] os : fields)
{
Field field = (Field) os[0];
if (Collection.class.isAssignableFrom(field.getType()))
{
try
{
Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);
if (subList != null && !subList.isEmpty())
{
maxSubListSize = Math.max(maxSubListSize, subList.size());
}
}
catch (Exception e)
{
log.error("获取集合大小失败", e);
} }
} }
} }
return maxSubListSize;
} }
/** /**
@@ -767,7 +814,7 @@ public class ExcelUtil<T>
*/ */
public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel) public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)
{ {
String key = StringUtils.format("data_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType()); String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
if (!styles.containsKey(key)) if (!styles.containsKey(key))
{ {
CellStyle style = wb.createCellStyle(); CellStyle style = wb.createCellStyle();
@@ -783,6 +830,7 @@ public class ExcelUtil<T>
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
style.setFillPattern(FillPatternType.SOLID_FOREGROUND); style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setFillForegroundColor(excel.backgroundColor().getIndex()); style.setFillForegroundColor(excel.backgroundColor().getIndex());
style.setWrapText(excel.wrapText());
Font dataFont = wb.createFont(); Font dataFont = wb.createFont();
dataFont.setFontName("Arial"); dataFont.setFontName("Arial");
dataFont.setFontHeightInPoints((short) 10); dataFont.setFontHeightInPoints((short) 10);
@@ -811,7 +859,7 @@ public class ExcelUtil<T>
if (isSubList()) if (isSubList())
{ {
// 填充默认样式,防止合并单元格样式失效 // 填充默认样式,防止合并单元格样式失效
sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
if (attr.needMerge()) if (attr.needMerge())
{ {
sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column)); sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
@@ -938,10 +986,12 @@ public class ExcelUtil<T>
cell = row.createCell(column); cell = row.createCell(column);
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge()) if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
{ {
CellRangeAddress cellAddress = new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column); if (subMergedLastRowNum >= subMergedFirstRowNum)
sheet.addMergedRegion(cellAddress); {
sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
}
} }
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType()))); cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
// 用于读取对象中的属性 // 用于读取对象中的属性
Object value = getTargetValue(vo, field, attr); Object value = getTargetValue(vo, field, attr);
@@ -950,6 +1000,7 @@ public class ExcelUtil<T>
String separator = attr.separator(); String separator = attr.separator();
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
{ {
cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat));
cell.setCellValue(parseDateToStr(dateFormat, value)); cell.setCellValue(parseDateToStr(dateFormat, value));
} }
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
@@ -1221,6 +1272,7 @@ public class ExcelUtil<T>
*/ */
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
{ {
field.setAccessible(true);
Object o = field.get(vo); Object o = field.get(vo);
if (StringUtils.isNotEmpty(excel.targetAttr())) if (StringUtils.isNotEmpty(excel.targetAttr()))
{ {
@@ -1280,46 +1332,83 @@ public class ExcelUtil<T>
List<Field> tempFields = new ArrayList<>(); List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : tempFields) if (StringUtils.isNotEmpty(includeFields))
{ {
if (!ArrayUtils.contains(this.excludeFields, field.getName())) for (Field field : tempFields)
{ {
// 单注解 if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))
if (field.isAnnotationPresent(Excel.class))
{ {
Excel attr = field.getAnnotation(Excel.class); addField(fields, field);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) }
}
}
else if (StringUtils.isNotEmpty(excludeFields))
{
for (Field field : tempFields)
{
if (!ArrayUtils.contains(this.excludeFields, field.getName()))
{
addField(fields, field);
}
}
}
else
{
for (Field field : tempFields)
{
addField(fields, field);
}
}
return fields;
}
/**
* 添加字段信息
*/
public void addField(List<Object[]> fields, Field field)
{
// 单注解
if (field.isAnnotationPresent(Excel.class))
{
Excel attr = field.getAnnotation(Excel.class);
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
{
fields.add(new Object[] { field, attr });
}
if (Collection.class.isAssignableFrom(field.getType()))
{
subMethod = getSubMethod(field.getName(), clazz);
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
}
}
// 多注解
if (field.isAnnotationPresent(Excels.class))
{
Excels attrs = field.getAnnotation(Excels.class);
Excel[] excels = attrs.value();
for (Excel attr : excels)
{
if (StringUtils.isNotEmpty(includeFields))
{
if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr())
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{ {
field.setAccessible(true);
fields.add(new Object[] { field, attr }); fields.add(new Object[] { field, attr });
} }
if (Collection.class.isAssignableFrom(field.getType()))
{
subMethod = getSubMethod(field.getName(), clazz);
ParameterizedType pt = (ParameterizedType) field.getGenericType();
Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
}
} }
else
// 多注解
if (field.isAnnotationPresent(Excels.class))
{ {
Excels attrs = field.getAnnotation(Excels.class); if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
Excel[] excels = attrs.value(); && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
for (Excel attr : excels)
{ {
if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr()) fields.add(new Object[] { field, attr });
&& (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
{
field.setAccessible(true);
fields.add(new Object[] { field, attr });
}
} }
} }
} }
} }
return fields;
} }
/** /**

View File

@@ -13,7 +13,7 @@ public class SqlUtil
/** /**
* 定义常用的 sql关键字 * 定义常用的 sql关键字
*/ */
public static String SQL_REGEX = "and |extractvalue|updatexml|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |+|user()"; public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
/** /**
* 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)

View File

@@ -343,25 +343,25 @@ public final class UUID implements java.io.Serializable, Comparable<UUID>
final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36); final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
// time_low // time_low
builder.append(digits(mostSigBits >> 32, 8)); builder.append(digits(mostSigBits >> 32, 8));
if (false == isSimple) if (!isSimple)
{ {
builder.append('-'); builder.append('-');
} }
// time_mid // time_mid
builder.append(digits(mostSigBits >> 16, 4)); builder.append(digits(mostSigBits >> 16, 4));
if (false == isSimple) if (!isSimple)
{ {
builder.append('-'); builder.append('-');
} }
// time_high_and_version // time_high_and_version
builder.append(digits(mostSigBits, 4)); builder.append(digits(mostSigBits, 4));
if (false == isSimple) if (!isSimple)
{ {
builder.append('-'); builder.append('-');
} }
// variant_and_sequence // variant_and_sequence
builder.append(digits(leastSigBits >> 48, 4)); builder.append(digits(leastSigBits >> 48, 4));
if (false == isSimple) if (!isSimple)
{ {
builder.append('-'); builder.append('-');
} }

View File

@@ -7,12 +7,17 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo; import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.constant.HttpStatus; import com.ruoyi.common.core.constant.HttpStatus;
import com.ruoyi.common.core.utils.DateUtils; import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.PageUtils; import com.ruoyi.common.core.utils.PageUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.sql.SqlUtil;
import com.ruoyi.common.core.web.domain.AjaxResult; import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.PageDomain;
import com.ruoyi.common.core.web.page.TableDataInfo; import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.core.web.page.TableSupport;
/** /**
* web层通用数据处理 * web层通用数据处理
@@ -48,6 +53,19 @@ public class BaseController
PageUtils.startPage(); PageUtils.startPage();
} }
/**
* 设置请求排序数据
*/
protected void startOrderBy()
{
PageDomain pageDomain = TableSupport.buildPageRequest();
if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
{
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
PageHelper.orderBy(orderBy);
}
}
/** /**
* 清理分页的线程变量 * 清理分页的线程变量
*/ */

View File

@@ -37,7 +37,7 @@ public class TableDataInfo implements Serializable
* @param list 列表数据 * @param list 列表数据
* @param total 总记录数 * @param total 总记录数
*/ */
public TableDataInfo(List<?> list, int total) public TableDataInfo(List<?> list, long total)
{ {
this.rows = list; this.rows = list;
this.total = total; this.total = total;

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -6,6 +6,7 @@ import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.context.SecurityContextHolder; import com.ruoyi.common.core.context.SecurityContextHolder;
import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
@@ -73,8 +74,7 @@ public class DataScopeAspect
if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin()) if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
{ {
String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), SecurityContextHolder.getPermission()); String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), SecurityContextHolder.getPermission());
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), permission);
controllerDataScope.userAlias(), permission);
} }
} }
} }
@@ -94,7 +94,7 @@ public class DataScopeAspect
List<String> conditions = new ArrayList<String>(); List<String> conditions = new ArrayList<String>();
List<String> scopeCustomIds = new ArrayList<String>(); List<String> scopeCustomIds = new ArrayList<String>();
user.getRoles().forEach(role -> { user.getRoles().forEach(role -> {
if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission))) if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
{ {
scopeCustomIds.add(Convert.toStr(role.getRoleId())); scopeCustomIds.add(Convert.toStr(role.getRoleId()));
} }
@@ -103,7 +103,7 @@ public class DataScopeAspect
for (SysRole role : user.getRoles()) for (SysRole role : user.getRoles())
{ {
String dataScope = role.getDataScope(); String dataScope = role.getDataScope();
if (conditions.contains(dataScope)) if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE))
{ {
continue; continue;
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -19,6 +19,8 @@ import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.core.utils.ExceptionUtil;
import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.ServletUtils;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.ip.IpUtils; import com.ruoyi.common.core.utils.ip.IpUtils;
@@ -53,7 +55,7 @@ public class LogAspect
* 处理请求前执行 * 处理请求前执行
*/ */
@Before(value = "@annotation(controllerLog)") @Before(value = "@annotation(controllerLog)")
public void boBefore(JoinPoint joinPoint, Log controllerLog) public void doBefore(JoinPoint joinPoint, Log controllerLog)
{ {
TIME_THREADLOCAL.set(System.currentTimeMillis()); TIME_THREADLOCAL.set(System.currentTimeMillis());
} }
@@ -101,7 +103,7 @@ public class LogAspect
if (e != null) if (e != null)
{ {
operLog.setStatus(BusinessStatus.FAIL.ordinal()); operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); operLog.setErrorMsg(StringUtils.substring(Convert.toStr(e.getMessage(), ExceptionUtil.getExceptionMessage(e)), 0, 2000));
} }
// 设置方法名称 // 设置方法名称
String className = joinPoint.getTarget().getClass().getName(); String className = joinPoint.getTarget().getClass().getName();
@@ -164,10 +166,9 @@ public class LogAspect
*/ */
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
{ {
String requestMethod = operLog.getRequestMethod();
Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest()); Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
if (StringUtils.isEmpty(paramsMap) String requestMethod = operLog.getRequestMethod();
&& (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))) if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name()))
{ {
String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames); String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
operLog.setOperParam(StringUtils.substring(params, 0, 2000)); operLog.setOperParam(StringUtils.substring(params, 0, 2000));

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -56,16 +56,8 @@ public class PreAuthorizeAspect
// 注解鉴权 // 注解鉴权
MethodSignature signature = (MethodSignature) joinPoint.getSignature(); MethodSignature signature = (MethodSignature) joinPoint.getSignature();
checkMethodAnnotation(signature.getMethod()); checkMethodAnnotation(signature.getMethod());
try // 执行原有逻辑
{ return joinPoint.proceed();
// 执行原有逻辑
Object obj = joinPoint.proceed();
return obj;
}
catch (Throwable e)
{
throw e;
}
} }
/** /**

View File

@@ -36,11 +36,11 @@ public class TokenService
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
private final static long expireTime = CacheConstants.EXPIRATION; private final static long TOKEN_EXPIRE_TIME = CacheConstants.EXPIRATION;
private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY; private final static String ACCESS_TOKEN = CacheConstants.LOGIN_TOKEN_KEY;
private final static Long MILLIS_MINUTE_TEN = CacheConstants.REFRESH_TIME * MILLIS_MINUTE; private final static Long TOKEN_REFRESH_THRESHOLD_MINUTES = CacheConstants.REFRESH_TIME * MILLIS_MINUTE;
/** /**
* 创建令牌 * 创建令牌
@@ -65,7 +65,7 @@ public class TokenService
// 接口返回信息 // 接口返回信息
Map<String, Object> rspMap = new HashMap<String, Object>(); Map<String, Object> rspMap = new HashMap<String, Object>();
rspMap.put("access_token", JwtUtils.createToken(claimsMap)); rspMap.put("access_token", JwtUtils.createToken(claimsMap));
rspMap.put("expires_in", expireTime); rspMap.put("expires_in", TOKEN_EXPIRE_TIME);
return rspMap; return rspMap;
} }
@@ -147,7 +147,7 @@ public class TokenService
{ {
long expireTime = loginUser.getExpireTime(); long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN) if (expireTime - currentTime <= TOKEN_REFRESH_THRESHOLD_MINUTES)
{ {
refreshToken(loginUser); refreshToken(loginUser);
} }
@@ -161,10 +161,10 @@ public class TokenService
public void refreshToken(LoginUser loginUser) public void refreshToken(LoginUser loginUser)
{ {
loginUser.setLoginTime(System.currentTimeMillis()); loginUser.setLoginTime(System.currentTimeMillis());
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); loginUser.setExpireTime(loginUser.getLoginTime() + TOKEN_EXPIRE_TIME * MILLIS_MINUTE);
// 根据uuid将loginUser缓存 // 根据uuid将loginUser缓存
String userKey = getTokenKey(loginUser.getToken()); String userKey = getTokenKey(loginUser.getToken());
redisService.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); redisService.setCacheObject(userKey, loginUser, TOKEN_EXPIRE_TIME, TimeUnit.MINUTES);
} }
private String getTokenKey(String token) private String getTokenKey(String token)

View File

@@ -62,7 +62,7 @@ public class SecurityUtils
public static String getToken(HttpServletRequest request) public static String getToken(HttpServletRequest request)
{ {
// 从header获取token标识 // 从header获取token标识
String token = request.getHeader(TokenConstants.AUTHENTICATION); String token = request.getHeader(SecurityConstants.AUTHORIZATION_HEADER);
return replaceTokenPrefix(token); return replaceTokenPrefix(token);
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -17,10 +17,10 @@
<dependencies> <dependencies>
<!-- RuoYi Common Security --> <!-- RuoYi Common Core -->
<dependency> <dependency>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-security</artifactId> <artifactId>ruoyi-common-core</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -8,10 +8,10 @@ import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer; import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.context.SecurityContextHolder;
import com.ruoyi.common.sensitive.annotation.Sensitive; import com.ruoyi.common.sensitive.annotation.Sensitive;
import com.ruoyi.common.sensitive.enums.DesensitizedType; import com.ruoyi.common.sensitive.enums.DesensitizedType;
import com.ruoyi.system.api.model.LoginUser;
/** /**
* 数据脱敏序列化过滤 * 数据脱敏序列化过滤
@@ -55,9 +55,9 @@ public class SensitiveJsonSerializer extends JsonSerializer<String> implements C
{ {
try try
{ {
LoginUser securityUser = SecurityUtils.getLoginUser(); Long userId = SecurityContextHolder.getUserId();
// 管理员不脱敏 // 管理员不脱敏
return !securityUser.getSysUser().isAdmin(); return !UserConstants.isAdmin(userId);
} }
catch (Exception e) catch (Exception e)
{ {

View File

@@ -23,7 +23,7 @@ public enum DesensitizedType
/** /**
* 身份证中间10位星号替换 * 身份证中间10位星号替换
*/ */
ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{4})", "$1** **** ****$2")), ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")),
/** /**
* 手机号中间4位星号替换 * 手机号中间4位星号替换

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId> <artifactId>ruoyi-common</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -23,11 +23,10 @@
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<!-- Swagger --> <!-- SpringDoc webmvc -->
<dependency> <dependency>
<groupId>io.springfox</groupId> <groupId>org.springdoc</groupId>
<artifactId>springfox-swagger2</artifactId> <artifactId>springdoc-openapi-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -1,20 +0,0 @@
package com.ruoyi.common.swagger.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
import com.ruoyi.common.swagger.config.SwaggerAutoConfiguration;
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({ SwaggerAutoConfiguration.class })
public @interface EnableCustomSwagger2
{
}

View File

@@ -0,0 +1,63 @@
package com.ruoyi.common.swagger.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import com.ruoyi.common.swagger.config.properties.SpringDocProperties;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
/**
* Swagger 文档配置
*
* @author ruoyi
*/
@EnableConfigurationProperties(SpringDocProperties.class)
@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
public class SpringDocAutoConfiguration
{
@Bean
@ConditionalOnMissingBean(OpenAPI.class)
public OpenAPI openApi(SpringDocProperties properties)
{
return new OpenAPI().components(new Components()
// 设置认证的请求头
.addSecuritySchemes("apikey", securityScheme()))
.addSecurityItem(new SecurityRequirement().addList("apikey"))
.info(convertInfo(properties.getInfo()))
.servers(servers(properties.getGatewayUrl()));
}
public SecurityScheme securityScheme()
{
return new SecurityScheme().type(SecurityScheme.Type.APIKEY)
.name("Authorization")
.in(SecurityScheme.In.HEADER)
.scheme("Bearer");
}
private Info convertInfo(SpringDocProperties.InfoProperties infoProperties)
{
Info info = new Info();
info.setTitle(infoProperties.getTitle());
info.setDescription(infoProperties.getDescription());
info.setContact(infoProperties.getContact());
info.setLicense(infoProperties.getLicense());
info.setVersion(infoProperties.getVersion());
return info;
}
public List<Server> servers(String gatewayUrl)
{
List<Server> serverList = new ArrayList<>();
serverList.add(new Server().url(gatewayUrl));
return serverList;
}
}

View File

@@ -1,123 +0,0 @@
package com.ruoyi.common.swagger.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
@EnableConfigurationProperties(SwaggerProperties.class)
@ConditionalOnProperty(name = "swagger.enabled", matchIfMissing = true)
@Import({SwaggerBeanPostProcessor.class, SwaggerWebConfiguration.class})
public class SwaggerAutoConfiguration
{
/**
* 默认的排除路径排除Spring Boot默认的错误处理路径和端点
*/
private static final List<String> DEFAULT_EXCLUDE_PATH = Arrays.asList("/error", "/actuator/**");
private static final String BASE_PATH = "/**";
@Bean
public Docket api(SwaggerProperties swaggerProperties)
{
// base-path处理
if (swaggerProperties.getBasePath().isEmpty())
{
swaggerProperties.getBasePath().add(BASE_PATH);
}
// noinspection unchecked
List<Predicate<String>> basePath = new ArrayList<Predicate<String>>();
swaggerProperties.getBasePath().forEach(path -> basePath.add(PathSelectors.ant(path)));
// exclude-path处理
if (swaggerProperties.getExcludePath().isEmpty())
{
swaggerProperties.getExcludePath().addAll(DEFAULT_EXCLUDE_PATH);
}
List<Predicate<String>> excludePath = new ArrayList<>();
swaggerProperties.getExcludePath().forEach(path -> excludePath.add(PathSelectors.ant(path)));
ApiSelectorBuilder builder = new Docket(DocumentationType.SWAGGER_2).host(swaggerProperties.getHost())
.apiInfo(apiInfo(swaggerProperties)).select()
.apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()));
swaggerProperties.getBasePath().forEach(p -> builder.paths(PathSelectors.ant(p)));
swaggerProperties.getExcludePath().forEach(p -> builder.paths(PathSelectors.ant(p).negate()));
return builder.build().securitySchemes(securitySchemes()).securityContexts(securityContexts()).pathMapping("/");
}
/**
* 安全模式这里指定token通过Authorization头请求头传递
*/
private List<SecurityScheme> securitySchemes()
{
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
return apiKeyList;
}
/**
* 安全上下文
*/
private List<SecurityContext> securityContexts()
{
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(
SecurityContext.builder()
.securityReferences(defaultAuth())
.operationSelector(o -> o.requestMappingPattern().matches("/.*"))
.build());
return securityContexts;
}
/**
* 默认的全局鉴权策略
*
* @return
*/
private List<SecurityReference> defaultAuth()
{
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
return securityReferences;
}
private ApiInfo apiInfo(SwaggerProperties swaggerProperties)
{
return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.license(swaggerProperties.getLicense())
.licenseUrl(swaggerProperties.getLicenseUrl())
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
.version(swaggerProperties.getVersion())
.build();
}
}

View File

@@ -1,52 +0,0 @@
package com.ruoyi.common.swagger.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;
/**
* swagger 在 springboot 2.6.x 不兼容问题的处理
*
* @author ruoyi
*/
public class SwaggerBeanPostProcessor implements BeanPostProcessor
{
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
{
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider)
{
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings)
{
List<T> copy = mappings.stream().filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean)
{
try
{
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
}
catch (IllegalArgumentException | IllegalAccessException e)
{
throw new IllegalStateException(e);
}
}
}

View File

@@ -1,343 +0,0 @@
package com.ruoyi.common.swagger.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("swagger")
public class SwaggerProperties
{
/**
* 是否开启swagger
*/
private Boolean enabled;
/**
* swagger会解析的包路径
**/
private String basePackage = "";
/**
* swagger会解析的url规则
**/
private List<String> basePath = new ArrayList<>();
/**
* 在basePath基础上需要排除的url规则
**/
private List<String> excludePath = new ArrayList<>();
/**
* 标题
**/
private String title = "";
/**
* 描述
**/
private String description = "";
/**
* 版本
**/
private String version = "";
/**
* 许可证
**/
private String license = "";
/**
* 许可证URL
**/
private String licenseUrl = "";
/**
* 服务条款URL
**/
private String termsOfServiceUrl = "";
/**
* host信息
**/
private String host = "";
/**
* 联系人信息
*/
private Contact contact = new Contact();
/**
* 全局统一鉴权配置
**/
private Authorization authorization = new Authorization();
public Boolean getEnabled()
{
return enabled;
}
public void setEnabled(Boolean enabled)
{
this.enabled = enabled;
}
public String getBasePackage()
{
return basePackage;
}
public void setBasePackage(String basePackage)
{
this.basePackage = basePackage;
}
public List<String> getBasePath()
{
return basePath;
}
public void setBasePath(List<String> basePath)
{
this.basePath = basePath;
}
public List<String> getExcludePath()
{
return excludePath;
}
public void setExcludePath(List<String> excludePath)
{
this.excludePath = excludePath;
}
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public String getVersion()
{
return version;
}
public void setVersion(String version)
{
this.version = version;
}
public String getLicense()
{
return license;
}
public void setLicense(String license)
{
this.license = license;
}
public String getLicenseUrl()
{
return licenseUrl;
}
public void setLicenseUrl(String licenseUrl)
{
this.licenseUrl = licenseUrl;
}
public String getTermsOfServiceUrl()
{
return termsOfServiceUrl;
}
public void setTermsOfServiceUrl(String termsOfServiceUrl)
{
this.termsOfServiceUrl = termsOfServiceUrl;
}
public String getHost()
{
return host;
}
public void setHost(String host)
{
this.host = host;
}
public Contact getContact()
{
return contact;
}
public void setContact(Contact contact)
{
this.contact = contact;
}
public Authorization getAuthorization()
{
return authorization;
}
public void setAuthorization(Authorization authorization)
{
this.authorization = authorization;
}
public static class Contact
{
/**
* 联系人
**/
private String name = "";
/**
* 联系人url
**/
private String url = "";
/**
* 联系人email
**/
private String email = "";
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getUrl()
{
return url;
}
public void setUrl(String url)
{
this.url = url;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
}
public static class Authorization
{
/**
* 鉴权策略ID需要和SecurityReferences ID保持一致
*/
private String name = "";
/**
* 需要开启鉴权URL的正则
*/
private String authRegex = "^.*$";
/**
* 鉴权作用域列表
*/
private List<AuthorizationScope> authorizationScopeList = new ArrayList<>();
private List<String> tokenUrlList = new ArrayList<>();
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAuthRegex()
{
return authRegex;
}
public void setAuthRegex(String authRegex)
{
this.authRegex = authRegex;
}
public List<AuthorizationScope> getAuthorizationScopeList()
{
return authorizationScopeList;
}
public void setAuthorizationScopeList(List<AuthorizationScope> authorizationScopeList)
{
this.authorizationScopeList = authorizationScopeList;
}
public List<String> getTokenUrlList()
{
return tokenUrlList;
}
public void setTokenUrlList(List<String> tokenUrlList)
{
this.tokenUrlList = tokenUrlList;
}
}
public static class AuthorizationScope
{
/**
* 作用域名称
*/
private String scope = "";
/**
* 作用域描述
*/
private String description = "";
public String getScope()
{
return scope;
}
public void setScope(String scope)
{
this.scope = scope;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
}
}

View File

@@ -1,20 +0,0 @@
package com.ruoyi.common.swagger.config;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* swagger 资源映射路径
*
* @author ruoyi
*/
public class SwaggerWebConfiguration implements WebMvcConfigurer
{
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
/** swagger-ui 地址 */
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
}
}

View File

@@ -0,0 +1,135 @@
package com.ruoyi.common.swagger.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.License;
/**
* Swagger 配置属性
*
* @author ruoyi
*/
@ConfigurationProperties(prefix = "springdoc")
public class SpringDocProperties
{
/**
* 网关
*/
private String gatewayUrl;
/**
* 文档基本信息
*/
@NestedConfigurationProperty
private InfoProperties info = new InfoProperties();
/**
* <p>
* 文档的基础属性信息
* </p>
*
* @see io.swagger.v3.oas.models.info.Info
*
* 为了 springboot 自动生产配置提示信息,所以这里复制一个类出来
*/
public static class InfoProperties
{
/**
* 标题
*/
private String title = null;
/**
* 描述
*/
private String description = null;
/**
* 联系人信息
*/
@NestedConfigurationProperty
private Contact contact = null;
/**
* 许可证
*/
@NestedConfigurationProperty
private License license = null;
/**
* 版本
*/
private String version = null;
public String getTitle()
{
return title;
}
public void setTitle(String title)
{
this.title = title;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public Contact getContact()
{
return contact;
}
public void setContact(Contact contact)
{
this.contact = contact;
}
public License getLicense()
{
return license;
}
public void setLicense(License license)
{
this.license = license;
}
public String getVersion()
{
return version;
}
public void setVersion(String version)
{
this.version = version;
}
}
public String getGatewayUrl()
{
return gatewayUrl;
}
public void setGatewayUrl(String gatewayUrl)
{
this.gatewayUrl = gatewayUrl;
}
public InfoProperties getInfo()
{
return info;
}
public void setInfo(InfoProperties info)
{
this.info = info;
}
}

View File

@@ -1,3 +1 @@
# com.ruoyi.common.swagger.config.SwaggerAutoConfiguration com.ruoyi.common.swagger.config.SpringDocAutoConfiguration
# com.ruoyi.common.swagger.config.SwaggerWebConfiguration
# com.ruoyi.common.swagger.config.SwaggerBeanPostProcessor

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -76,16 +76,11 @@
<artifactId>ruoyi-common-redis</artifactId> <artifactId>ruoyi-common-redis</artifactId>
</dependency> </dependency>
<!-- Swagger --> <!-- Springdoc -->
<dependency> <dependency>
<groupId>io.springfox</groupId> <groupId>org.springdoc</groupId>
<artifactId>springfox-swagger-ui</artifactId> <artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>${swagger.fox.version}</version> <version>${springdoc.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.fox.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -0,0 +1,93 @@
package com.ruoyi.gateway.config;
import java.util.Set;
import java.util.stream.Collectors;
import org.springdoc.core.AbstractSwaggerUiConfigProperties;
import org.springdoc.core.SwaggerUiConfigProperties;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.annotation.Configuration;
import com.alibaba.nacos.client.naming.event.InstancesChangeEvent;
import com.alibaba.nacos.common.notify.Event;
import com.alibaba.nacos.common.notify.NotifyCenter;
import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.ruoyi.common.core.utils.StringUtils;
/**
* SpringDoc配置类
*
* @author ruoyi
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "springdoc.api-docs.enabled", matchIfMissing = true)
public class SpringDocConfig implements InitializingBean
{
@Autowired
private SwaggerUiConfigProperties swaggerUiConfigProperties;
@Autowired
private DiscoveryClient discoveryClient;
/**
* 在初始化后调用的方法
*/
@Override
public void afterPropertiesSet()
{
NotifyCenter.registerSubscriber(new SwaggerDocRegister(swaggerUiConfigProperties, discoveryClient));
}
}
/**
* Swagger文档注册器
*/
class SwaggerDocRegister extends Subscriber<InstancesChangeEvent>
{
@Autowired
private SwaggerUiConfigProperties swaggerUiConfigProperties;
@Autowired
private DiscoveryClient discoveryClient;
private final static String[] EXCLUDE_ROUTES = new String[] { "ruoyi-gateway", "ruoyi-auth", "ruoyi-file", "ruoyi-monitor" };
public SwaggerDocRegister(SwaggerUiConfigProperties swaggerUiConfigProperties, DiscoveryClient discoveryClient)
{
this.swaggerUiConfigProperties = swaggerUiConfigProperties;
this.discoveryClient = discoveryClient;
}
/**
* 事件回调方法处理InstancesChangeEvent事件
* @param event 事件对象
*/
@Override
public void onEvent(InstancesChangeEvent event)
{
Set<AbstractSwaggerUiConfigProperties.SwaggerUrl> swaggerUrlSet = discoveryClient.getServices()
.stream()
.flatMap(serviceId -> discoveryClient.getInstances(serviceId).stream())
.filter(instance -> !StringUtils.equalsAnyIgnoreCase(instance.getServiceId(), EXCLUDE_ROUTES))
.map(instance -> {
AbstractSwaggerUiConfigProperties.SwaggerUrl swaggerUrl = new AbstractSwaggerUiConfigProperties.SwaggerUrl();
swaggerUrl.setName(instance.getServiceId());
swaggerUrl.setUrl(String.format("/%s/v3/api-docs", instance.getServiceId()));
return swaggerUrl;
})
.collect(Collectors.toSet());
swaggerUiConfigProperties.setUrls(swaggerUrlSet);
}
/**
* 订阅类型方法,返回订阅的事件类型
* @return 订阅的事件类型
*/
@Override
public Class<? extends Event> subscribeType()
{
return InstancesChangeEvent.class;
}
}

View File

@@ -1,79 +0,0 @@
package com.ruoyi.gateway.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.config.ResourceHandlerRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
/**
* 聚合系统接口
*
* @author ruoyi
*/
@Component
public class SwaggerProvider implements SwaggerResourcesProvider, WebFluxConfigurer
{
/**
* Swagger2默认的url后缀
*/
public static final String SWAGGER2URL = "/v2/api-docs";
/**
* 网关路由
*/
@Lazy
@Autowired
private RouteLocator routeLocator;
@Autowired
private GatewayProperties gatewayProperties;
/**
* 聚合其他服务接口
*
* @return
*/
@Override
public List<SwaggerResource> get()
{
List<SwaggerResource> resourceList = new ArrayList<>();
List<String> routes = new ArrayList<>();
// 获取网关中配置的route
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
gatewayProperties.getRoutes().stream()
.filter(routeDefinition -> routes
.contains(routeDefinition.getId()))
.forEach(routeDefinition -> routeDefinition.getPredicates().stream()
.filter(predicateDefinition -> "Path".equalsIgnoreCase(predicateDefinition.getName()))
.filter(predicateDefinition -> !"ruoyi-auth".equalsIgnoreCase(routeDefinition.getId()))
.forEach(predicateDefinition -> resourceList
.add(swaggerResource(routeDefinition.getId(), predicateDefinition.getArgs()
.get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("/**", SWAGGER2URL)))));
return resourceList;
}
private SwaggerResource swaggerResource(String name, String location)
{
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
/** swagger-ui 地址 */
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
}
}

View File

@@ -101,7 +101,7 @@ public class AuthFilter implements GlobalFilter, Ordered
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg)
{ {
log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath()); log.error("[鉴权异常处理]请求路径:{},错误信息:{}", exchange.getRequest().getPath(), msg);
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED); return ServletUtils.webFluxResponseWriter(exchange.getResponse(), msg, HttpStatus.UNAUTHORIZED);
} }
@@ -118,7 +118,7 @@ public class AuthFilter implements GlobalFilter, Ordered
*/ */
private String getToken(ServerHttpRequest request) private String getToken(ServerHttpRequest request)
{ {
String token = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION); String token = request.getHeaders().getFirst(SecurityConstants.AUTHORIZATION_HEADER);
// 如果前端设置了令牌前缀,则裁剪掉前缀 // 如果前端设置了令牌前缀,则裁剪掉前缀
if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX)) if (StringUtils.isNotEmpty(token) && token.startsWith(TokenConstants.PREFIX))
{ {

View File

@@ -1,87 +0,0 @@
package com.ruoyi.gateway.filter;
import java.util.Collections;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 获取body请求数据解决流不能重复读取问题
*
* @author ruoyi
*/
@Component
public class CacheRequestFilter extends AbstractGatewayFilterFactory<CacheRequestFilter.Config>
{
public CacheRequestFilter()
{
super(Config.class);
}
@Override
public String name()
{
return "CacheRequestFilter";
}
@Override
public GatewayFilter apply(Config config)
{
CacheRequestGatewayFilter cacheRequestGatewayFilter = new CacheRequestGatewayFilter();
Integer order = config.getOrder();
if (order == null)
{
return cacheRequestGatewayFilter;
}
return new OrderedGatewayFilter(cacheRequestGatewayFilter, order);
}
public static class CacheRequestGatewayFilter implements GatewayFilter
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
// GET DELETE 不过滤
HttpMethod method = exchange.getRequest().getMethod();
if (method == null || method == HttpMethod.GET || method == HttpMethod.DELETE)
{
return chain.filter(exchange);
}
return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange, (serverHttpRequest) -> {
if (serverHttpRequest == exchange.getRequest())
{
return chain.filter(exchange);
}
return chain.filter(exchange.mutate().request(serverHttpRequest).build());
});
}
}
@Override
public List<String> shortcutFieldOrder()
{
return Collections.singletonList("order");
}
static class Config
{
private Integer order;
public Integer getOrder()
{
return order;
}
public void setOrder(Integer order)
{
this.order = order;
}
}
}

View File

@@ -1,56 +0,0 @@
package com.ruoyi.gateway.handler;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerHandler
{
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
@Autowired(required = false)
private UiConfiguration uiConfiguration;
private final SwaggerResourcesProvider swaggerResources;
@Autowired
public SwaggerHandler(SwaggerResourcesProvider swaggerResources)
{
this.swaggerResources = swaggerResources;
}
@GetMapping("/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration()
{
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()),
HttpStatus.OK));
}
@GetMapping("/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration()
{
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@SuppressWarnings("rawtypes")
@GetMapping("")
public Mono<ResponseEntity> swaggerResources()
{
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
}

View File

@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId> <artifactId>ruoyi</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -40,6 +40,12 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<!-- SpringBoot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- FastDFS --> <!-- FastDFS -->
<dependency> <dependency>
@@ -60,12 +66,6 @@
<artifactId>ruoyi-api-system</artifactId> <artifactId>ruoyi-api-system</artifactId>
</dependency> </dependency>
<!-- RuoYi Common Swagger -->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common-swagger</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -3,14 +3,12 @@ package com.ruoyi.file;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
/** /**
* 文件服务 * 文件服务
* *
* @author ruoyi * @author ruoyi
*/ */
@EnableCustomSwagger2
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class RuoYiFileApplication public class RuoYiFileApplication
{ {

View File

@@ -37,10 +37,20 @@ public class FastDfsSysFileServiceImpl implements ISysFileService
@Override @Override
public String uploadFile(MultipartFile file) throws Exception public String uploadFile(MultipartFile file) throws Exception
{ {
InputStream inputStream = file.getInputStream(); InputStream inputStream = null;
StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(), try
FileTypeUtils.getExtension(file), null); {
IoUtils.closeQuietly(inputStream); inputStream = file.getInputStream();
return domain + "/" + storePath.getFullPath(); StorePath storePath = storageClient.uploadFile(inputStream, file.getSize(), FileTypeUtils.getExtension(file), null);
return domain + "/" + storePath.getFullPath();
}
catch (Exception e)
{
throw new RuntimeException("FastDfs Failed to upload file", e);
}
finally
{
IoUtils.closeQuietly(inputStream);
}
} }
} }

View File

@@ -34,16 +34,27 @@ public class MinioSysFileServiceImpl implements ISysFileService
@Override @Override
public String uploadFile(MultipartFile file) throws Exception public String uploadFile(MultipartFile file) throws Exception
{ {
String fileName = FileUploadUtils.extractFilename(file); InputStream inputStream = null;
InputStream inputStream = file.getInputStream(); try
PutObjectArgs args = PutObjectArgs.builder() {
.bucket(minioConfig.getBucketName()) String fileName = FileUploadUtils.extractFilename(file);
.object(fileName) inputStream = file.getInputStream();
.stream(inputStream, file.getSize(), -1) PutObjectArgs args = PutObjectArgs.builder()
.contentType(file.getContentType()) .bucket(minioConfig.getBucketName())
.build(); .object(fileName)
client.putObject(args); .stream(inputStream, file.getSize(), -1)
IoUtils.closeQuietly(inputStream); .contentType(file.getContentType())
return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName; .build();
client.putObject(args);
return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
}
catch (Exception e)
{
throw new RuntimeException("Minio Failed to upload file", e);
}
finally
{
IoUtils.closeQuietly(inputStream);
}
} }
} }

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -40,13 +40,6 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<!-- Swagger UI -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<!-- Apache Velocity --> <!-- Apache Velocity -->
<dependency> <dependency>

View File

@@ -4,7 +4,6 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.ruoyi.common.security.annotation.EnableCustomConfig; import com.ruoyi.common.security.annotation.EnableCustomConfig;
import com.ruoyi.common.security.annotation.EnableRyFeignClients; import com.ruoyi.common.security.annotation.EnableRyFeignClients;
import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
/** /**
* 代码生成 * 代码生成
@@ -12,7 +11,6 @@ import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
* @author ruoyi * @author ruoyi
*/ */
@EnableCustomConfig @EnableCustomConfig
@EnableCustomSwagger2
@EnableRyFeignClients @EnableRyFeignClients
@SpringBootApplication @SpringBootApplication
public class RuoYiGenApplication public class RuoYiGenApplication

View File

@@ -18,12 +18,15 @@ public class GenConfig
/** 生成包路径 */ /** 生成包路径 */
public static String packageName; public static String packageName;
/** 自动去除表前缀默认是false */ /** 自动去除表前缀 */
public static boolean autoRemovePre; public static boolean autoRemovePre;
/** 表前缀(类名不会包含表前缀) */ /** 表前缀 */
public static String tablePrefix; public static String tablePrefix;
/** 是否允许生成文件覆盖到本地(自定义路径) */
public static boolean allowOverwrite;
public static String getAuthor() public static String getAuthor()
{ {
return author; return author;
@@ -63,4 +66,14 @@ public class GenConfig
{ {
GenConfig.tablePrefix = tablePrefix; GenConfig.tablePrefix = tablePrefix;
} }
public static boolean isAllowOverwrite()
{
return allowOverwrite;
}
public void setAllowOverwrite(boolean allowOverwrite)
{
GenConfig.allowOverwrite = allowOverwrite;
}
} }

View File

@@ -23,6 +23,7 @@ import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log; import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.gen.config.GenConfig;
import com.ruoyi.gen.domain.GenTable; import com.ruoyi.gen.domain.GenTable;
import com.ruoyi.gen.domain.GenTableColumn; import com.ruoyi.gen.domain.GenTableColumn;
import com.ruoyi.gen.service.IGenTableColumnService; import com.ruoyi.gen.service.IGenTableColumnService;
@@ -56,7 +57,7 @@ public class GenController extends BaseController
} }
/** /**
* 修改代码生成业务 * 获取代码生成信息
*/ */
@RequiresPermissions("tool:gen:query") @RequiresPermissions("tool:gen:query")
@GetMapping(value = "/{tableId}") @GetMapping(value = "/{tableId}")
@@ -168,6 +169,10 @@ public class GenController extends BaseController
@GetMapping("/genCode/{tableName}") @GetMapping("/genCode/{tableName}")
public AjaxResult genCode(@PathVariable("tableName") String tableName) public AjaxResult genCode(@PathVariable("tableName") String tableName)
{ {
if (!GenConfig.isAllowOverwrite())
{
return AjaxResult.error("【系统预设】不允许生成文件覆盖到本地");
}
genTableService.generatorCode(tableName); genTableService.generatorCode(tableName);
return success(); return success();
} }

View File

@@ -93,7 +93,7 @@ public class GenTable extends BaseEntity
private String treeName; private String treeName;
/** 上级菜单ID字段 */ /** 上级菜单ID字段 */
private String parentMenuId; private Long parentMenuId;
/** 上级菜单名称字段 */ /** 上级菜单名称字段 */
private String parentMenuName; private String parentMenuName;
@@ -317,12 +317,12 @@ public class GenTable extends BaseEntity
this.treeName = treeName; this.treeName = treeName;
} }
public String getParentMenuId() public Long getParentMenuId()
{ {
return parentMenuId; return parentMenuId;
} }
public void setParentMenuId(String parentMenuId) public void setParentMenuId(Long parentMenuId)
{ {
this.parentMenuId = parentMenuId; this.parentMenuId = parentMenuId;
} }

View File

@@ -1,7 +1,6 @@
package com.ruoyi.gen.domain; package com.ruoyi.gen.domain;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.domain.BaseEntity; import com.ruoyi.common.core.web.domain.BaseEntity;

View File

@@ -129,9 +129,9 @@ public class GenTableServiceImpl implements IGenTableService
int row = genTableMapper.updateGenTable(genTable); int row = genTableMapper.updateGenTable(genTable);
if (row > 0) if (row > 0)
{ {
for (GenTableColumn cenTableColumn : genTable.getColumns()) for (GenTableColumn genTableColumn : genTable.getColumns())
{ {
genTableColumnMapper.updateGenTableColumn(cenTableColumn); genTableColumnMapper.updateGenTableColumn(genTableColumn);
} }
} }
} }
@@ -414,16 +414,16 @@ public class GenTableServiceImpl implements IGenTableService
{ {
throw new ServiceException("树名称字段不能为空"); throw new ServiceException("树名称字段不能为空");
} }
else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory())) }
else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
{
if (StringUtils.isEmpty(genTable.getSubTableName()))
{ {
if (StringUtils.isEmpty(genTable.getSubTableName())) throw new ServiceException("关联子表的表名不能为空");
{ }
throw new ServiceException("关联子表的表名不能为空"); else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
} {
else if (StringUtils.isEmpty(genTable.getSubTableFkName())) throw new ServiceException("子表关联的外键名不能为空");
{
throw new ServiceException("子表关联的外键名不能为空");
}
} }
} }
} }
@@ -491,7 +491,7 @@ public class GenTableServiceImpl implements IGenTableService
String treeCode = paramsObj.getString(GenConstants.TREE_CODE); String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE); String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
String treeName = paramsObj.getString(GenConstants.TREE_NAME); String treeName = paramsObj.getString(GenConstants.TREE_NAME);
String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID); Long parentMenuId = paramsObj.getLongValue(GenConstants.PARENT_MENU_ID);
String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME); String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
genTable.setTreeCode(treeCode); genTable.setTreeCode(treeCode);

View File

@@ -71,9 +71,9 @@ public class ${ClassName} extends ${Entity}
{ {
return $column.javaField; return $column.javaField;
} }
#end
#end
#end
#end
#if($table.sub) #if($table.sub)
public List<${subClassName}> get${subClassName}List() public List<${subClassName}> get${subClassName}List()
{ {

View File

@@ -75,7 +75,7 @@
icon="el-icon-plus" icon="el-icon-plus"
size="mini" size="mini"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${permissionPrefix}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
@@ -144,21 +144,21 @@
type="text" type="text"
icon="el-icon-edit" icon="el-icon-edit"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${permissionPrefix}:edit']"
>修改</el-button> >修改</el-button>
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
icon="el-icon-plus" icon="el-icon-plus"
@click="handleAdd(scope.row)" @click="handleAdd(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${permissionPrefix}:add']"
>新增</el-button> >新增</el-button>
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
icon="el-icon-delete" icon="el-icon-delete"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:remove']" v-hasPermi="['${permissionPrefix}:remove']"
>删除</el-button> >删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -283,9 +283,9 @@
</template> </template>
<script> <script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"; import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
import Treeselect from "@riophae/vue-treeselect"; import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; import "@riophae/vue-treeselect/dist/vue-treeselect.css"
export default { export default {
name: "${BusinessName}", name: "${BusinessName}",
@@ -346,18 +346,18 @@ export default {
#end #end
#end #end
} }
}; }
}, },
created() { created() {
this.getList(); this.getList()
}, },
methods: { methods: {
/** 查询${functionName}列表 */ /** 查询${functionName}列表 */
getList() { getList() {
this.loading = true; this.loading = true
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
this.queryParams.params = {}; this.queryParams.params = {}
#break #break
#end #end
#end #end
@@ -365,40 +365,40 @@ export default {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) { if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]; this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]
this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]; this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]
} }
#end #end
#end #end
list${BusinessName}(this.queryParams).then(response => { list${BusinessName}(this.queryParams).then(response => {
this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}"); this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
this.loading = false; this.loading = false
}); })
}, },
/** 转换${functionName}数据结构 */ /** 转换${functionName}数据结构 */
normalizer(node) { normalizer(node) {
if (node.children && !node.children.length) { if (node.children && !node.children.length) {
delete node.children; delete node.children
} }
return { return {
id: node.${treeCode}, id: node.${treeCode},
label: node.${treeName}, label: node.${treeName},
children: node.children children: node.children
}; }
}, },
/** 查询${functionName}下拉树结构 */ /** 查询${functionName}下拉树结构 */
getTreeselect() { getTreeselect() {
list${BusinessName}().then(response => { list${BusinessName}().then(response => {
this.${businessName}Options = []; this.${businessName}Options = []
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }; const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }
data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}"); data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}")
this.${businessName}Options.push(data); this.${businessName}Options.push(data)
}); })
}, },
// 取消按钮 // 取消按钮
cancel() { cancel() {
this.open = false; this.open = false
this.reset(); this.reset()
}, },
// 表单重置 // 表单重置
reset() { reset() {
@@ -410,61 +410,61 @@ export default {
$column.javaField: null#if($foreach.count != $columns.size()),#end $column.javaField: null#if($foreach.count != $columns.size()),#end
#end #end
#end #end
}; }
this.resetForm("form"); this.resetForm("form")
}, },
/** 搜索按钮操作 */ /** 搜索按钮操作 */
handleQuery() { handleQuery() {
this.getList(); this.getList()
}, },
/** 重置按钮操作 */ /** 重置按钮操作 */
resetQuery() { resetQuery() {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
this.daterange${AttrName} = []; this.daterange${AttrName} = []
#end #end
#end #end
this.resetForm("queryForm"); this.resetForm("queryForm")
this.handleQuery(); this.handleQuery()
}, },
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd(row) { handleAdd(row) {
this.reset(); this.reset()
this.getTreeselect(); this.getTreeselect()
if (row != null && row.${treeCode}) { if (row != null && row.${treeCode}) {
this.form.${treeParentCode} = row.${treeCode}; this.form.${treeParentCode} = row.${treeCode}
} else { } else {
this.form.${treeParentCode} = 0; this.form.${treeParentCode} = 0
} }
this.open = true; this.open = true
this.title = "添加${functionName}"; this.title = "添加${functionName}"
}, },
/** 展开/折叠操作 */ /** 展开/折叠操作 */
toggleExpandAll() { toggleExpandAll() {
this.refreshTable = false; this.refreshTable = false
this.isExpandAll = !this.isExpandAll; this.isExpandAll = !this.isExpandAll
this.$nextTick(() => { this.$nextTick(() => {
this.refreshTable = true; this.refreshTable = true
}); })
}, },
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset()
this.getTreeselect(); this.getTreeselect()
if (row != null) { if (row != null) {
this.form.${treeParentCode} = row.${treeCode}; this.form.${treeParentCode} = row.${treeParentCode}
} }
get${BusinessName}(row.${pkColumn.javaField}).then(response => { get${BusinessName}(row.${pkColumn.javaField}).then(response => {
this.form = response.data; this.form = response.data
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(","); this.form.$column.javaField = this.form.${column.javaField}.split(",")
#end #end
#end #end
this.open = true; this.open = true
this.title = "修改${functionName}"; this.title = "修改${functionName}"
}); })
}, },
/** 提交按钮 */ /** 提交按钮 */
submitForm() { submitForm() {
@@ -472,34 +472,34 @@ export default {
if (valid) { if (valid) {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(","); this.form.$column.javaField = this.form.${column.javaField}.join(",")
#end #end
#end #end
if (this.form.${pkColumn.javaField} != null) { if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => { update${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("修改成功"); this.#[[$modal]]#.msgSuccess("修改成功")
this.open = false; this.open = false
this.getList(); this.getList()
}); })
} else { } else {
add${BusinessName}(this.form).then(response => { add${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("新增成功"); this.#[[$modal]]#.msgSuccess("新增成功")
this.open = false; this.open = false
this.getList(); this.getList()
}); })
} }
} }
}); })
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() { this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
return del${BusinessName}(row.${pkColumn.javaField}); return del${BusinessName}(row.${pkColumn.javaField})
}).then(() => { }).then(() => {
this.getList(); this.getList()
this.#[[$modal]]#.msgSuccess("删除成功"); this.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {}); }).catch(() => {})
} }
} }
}; }
</script> </script>

View File

@@ -75,7 +75,7 @@
icon="el-icon-plus" icon="el-icon-plus"
size="mini" size="mini"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${permissionPrefix}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
@@ -86,7 +86,7 @@
size="mini" size="mini"
:disabled="single" :disabled="single"
@click="handleUpdate" @click="handleUpdate"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${permissionPrefix}:edit']"
>修改</el-button> >修改</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
@@ -97,7 +97,7 @@
size="mini" size="mini"
:disabled="multiple" :disabled="multiple"
@click="handleDelete" @click="handleDelete"
v-hasPermi="['${moduleName}:${businessName}:remove']" v-hasPermi="['${permissionPrefix}:remove']"
>删除</el-button> >删除</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
@@ -107,7 +107,7 @@
icon="el-icon-download" icon="el-icon-download"
size="mini" size="mini"
@click="handleExport" @click="handleExport"
v-hasPermi="['${moduleName}:${businessName}:export']" v-hasPermi="['${permissionPrefix}:export']"
>导出</el-button> >导出</el-button>
</el-col> </el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
@@ -158,14 +158,14 @@
type="text" type="text"
icon="el-icon-edit" icon="el-icon-edit"
@click="handleUpdate(scope.row)" @click="handleUpdate(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${permissionPrefix}:edit']"
>修改</el-button> >修改</el-button>
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
icon="el-icon-delete" icon="el-icon-delete"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
v-hasPermi="['${moduleName}:${businessName}:remove']" v-hasPermi="['${permissionPrefix}:remove']"
>删除</el-button> >删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
@@ -353,7 +353,7 @@
</template> </template>
<script> <script>
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"; import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
export default { export default {
name: "${BusinessName}", name: "${BusinessName}",
@@ -423,18 +423,18 @@ export default {
#end #end
#end #end
} }
}; }
}, },
created() { created() {
this.getList(); this.getList()
}, },
methods: { methods: {
/** 查询${functionName}列表 */ /** 查询${functionName}列表 */
getList() { getList() {
this.loading = true; this.loading = true
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
this.queryParams.params = {}; this.queryParams.params = {}
#break #break
#end #end
#end #end
@@ -442,21 +442,21 @@ export default {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) { if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]; this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0]
this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]; this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1]
} }
#end #end
#end #end
list${BusinessName}(this.queryParams).then(response => { list${BusinessName}(this.queryParams).then(response => {
this.${businessName}List = response.rows; this.${businessName}List = response.rows
this.total = response.total; this.total = response.total
this.loading = false; this.loading = false
}); })
}, },
// 取消按钮 // 取消按钮
cancel() { cancel() {
this.open = false; this.open = false
this.reset(); this.reset()
}, },
// 表单重置 // 表单重置
reset() { reset() {
@@ -468,27 +468,27 @@ export default {
$column.javaField: null#if($foreach.count != $columns.size()),#end $column.javaField: null#if($foreach.count != $columns.size()),#end
#end #end
#end #end
}; }
#if($table.sub) #if($table.sub)
this.${subclassName}List = []; this.${subclassName}List = []
#end #end
this.resetForm("form"); this.resetForm("form")
}, },
/** 搜索按钮操作 */ /** 搜索按钮操作 */
handleQuery() { handleQuery() {
this.queryParams.pageNum = 1; this.queryParams.pageNum = 1
this.getList(); this.getList()
}, },
/** 重置按钮操作 */ /** 重置按钮操作 */
resetQuery() { resetQuery() {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
this.daterange${AttrName} = []; this.daterange${AttrName} = []
#end #end
#end #end
this.resetForm("queryForm"); this.resetForm("queryForm")
this.handleQuery(); this.handleQuery()
}, },
// 多选框选中数据 // 多选框选中数据
handleSelectionChange(selection) { handleSelectionChange(selection) {
@@ -498,27 +498,27 @@ export default {
}, },
/** 新增按钮操作 */ /** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset(); this.reset()
this.open = true; this.open = true
this.title = "添加${functionName}"; this.title = "添加${functionName}"
}, },
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
this.reset(); this.reset()
const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
get${BusinessName}(${pkColumn.javaField}).then(response => { get${BusinessName}(${pkColumn.javaField}).then(response => {
this.form = response.data; this.form = response.data
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.split(","); this.form.$column.javaField = this.form.${column.javaField}.split(",")
#end #end
#end #end
#if($table.sub) #if($table.sub)
this.${subclassName}List = response.data.${subclassName}List; this.${subclassName}List = response.data.${subclassName}List
#end #end
this.open = true; this.open = true
this.title = "修改${functionName}"; this.title = "修改${functionName}"
}); })
}, },
/** 提交按钮 */ /** 提交按钮 */
submitForm() { submitForm() {
@@ -526,64 +526,64 @@ export default {
if (valid) { if (valid) {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
this.form.$column.javaField = this.form.${column.javaField}.join(","); this.form.$column.javaField = this.form.${column.javaField}.join(",")
#end #end
#end #end
#if($table.sub) #if($table.sub)
this.form.${subclassName}List = this.${subclassName}List; this.form.${subclassName}List = this.${subclassName}List
#end #end
if (this.form.${pkColumn.javaField} != null) { if (this.form.${pkColumn.javaField} != null) {
update${BusinessName}(this.form).then(response => { update${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("修改成功"); this.#[[$modal]]#.msgSuccess("修改成功")
this.open = false; this.open = false
this.getList(); this.getList()
}); })
} else { } else {
add${BusinessName}(this.form).then(response => { add${BusinessName}(this.form).then(response => {
this.#[[$modal]]#.msgSuccess("新增成功"); this.#[[$modal]]#.msgSuccess("新增成功")
this.open = false; this.open = false
this.getList(); this.getList()
}); })
} }
} }
}); })
}, },
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids; const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids
this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() { this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
return del${BusinessName}(${pkColumn.javaField}s); return del${BusinessName}(${pkColumn.javaField}s)
}).then(() => { }).then(() => {
this.getList(); this.getList()
this.#[[$modal]]#.msgSuccess("删除成功"); this.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {}); }).catch(() => {})
}, },
#if($table.sub) #if($table.sub)
/** ${subTable.functionName}序号 */ /** ${subTable.functionName}序号 */
row${subClassName}Index({ row, rowIndex }) { row${subClassName}Index({ row, rowIndex }) {
row.index = rowIndex + 1; row.index = rowIndex + 1
}, },
/** ${subTable.functionName}添加按钮操作 */ /** ${subTable.functionName}添加按钮操作 */
handleAdd${subClassName}() { handleAdd${subClassName}() {
let obj = {}; let obj = {}
#foreach($column in $subTable.columns) #foreach($column in $subTable.columns)
#if($column.pk || $column.javaField == ${subTableFkclassName}) #if($column.pk || $column.javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField) #elseif($column.list && "" != $javaField)
obj.$column.javaField = ""; obj.$column.javaField = ""
#end #end
#end #end
this.${subclassName}List.push(obj); this.${subclassName}List.push(obj)
}, },
/** ${subTable.functionName}删除按钮操作 */ /** ${subTable.functionName}删除按钮操作 */
handleDelete${subClassName}() { handleDelete${subClassName}() {
if (this.checked${subClassName}.length == 0) { if (this.checked${subClassName}.length == 0) {
this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据"); this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据")
} else { } else {
const ${subclassName}List = this.${subclassName}List; const ${subclassName}List = this.${subclassName}List
const checked${subClassName} = this.checked${subClassName}; const checked${subClassName} = this.checked${subClassName}
this.${subclassName}List = ${subclassName}List.filter(function(item) { this.${subclassName}List = ${subclassName}List.filter(function(item) {
return checked${subClassName}.indexOf(item.index) == -1 return checked${subClassName}.indexOf(item.index) == -1
}); })
} }
}, },
/** 复选框选中数据 */ /** 复选框选中数据 */
@@ -598,5 +598,5 @@ export default {
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`) }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
} }
} }
}; }
</script> </script>

View File

@@ -73,7 +73,7 @@
plain plain
icon="Plus" icon="Plus"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${permissionPrefix}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
@@ -136,9 +136,9 @@
#end #end
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button> <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${permissionPrefix}:edit']">修改</el-button>
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button> <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${permissionPrefix}:add']">新增</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button> <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${permissionPrefix}:remove']">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -271,26 +271,26 @@
</template> </template>
<script setup name="${BusinessName}"> <script setup name="${BusinessName}">
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"; import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance()
#if(${dicts} != '') #if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", "")) #set($dictsNoSymbol=$dicts.replace("'", ""))
const { ${dictsNoSymbol} } = proxy.useDict(${dicts}); const { ${dictsNoSymbol} } = proxy.useDict(${dicts})
#end #end
const ${businessName}List = ref([]); const ${businessName}List = ref([])
const ${businessName}Options = ref([]); const ${businessName}Options = ref([])
const open = ref(false); const open = ref(false)
const loading = ref(true); const loading = ref(true)
const showSearch = ref(true); const showSearch = ref(true)
const title = ref(""); const title = ref("")
const isExpandAll = ref(true); const isExpandAll = ref(true)
const refreshTable = ref(true); const refreshTable = ref(true)
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const daterange${AttrName} = ref([]); const daterange${AttrName} = ref([])
#end #end
#end #end
@@ -318,16 +318,16 @@ const data = reactive({
#end #end
#end #end
} }
}); })
const { queryParams, form, rules } = toRefs(data); const { queryParams, form, rules } = toRefs(data)
/** 查询${functionName}列表 */ /** 查询${functionName}列表 */
function getList() { function getList() {
loading.value = true; loading.value = true
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
queryParams.value.params = {}; queryParams.value.params = {}
#break #break
#end #end
#end #end
@@ -335,31 +335,31 @@ function getList() {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != daterange${AttrName} && '' != daterange${AttrName}) { if (null != daterange${AttrName} && '' != daterange${AttrName}) {
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]; queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]; queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]
} }
#end #end
#end #end
list${BusinessName}(queryParams.value).then(response => { list${BusinessName}(queryParams.value).then(response => {
${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}"); ${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}")
loading.value = false; loading.value = false
}); })
} }
/** 查询${functionName}下拉树结构 */ /** 查询${functionName}下拉树结构 */
function getTreeselect() { function getTreeselect() {
list${BusinessName}().then(response => { list${BusinessName}().then(response => {
${businessName}Options.value = []; ${businessName}Options.value = []
const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }; const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] }
data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}"); data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}")
${businessName}Options.value.push(data); ${businessName}Options.value.push(data)
}); })
} }
// 取消按钮 // 取消按钮
function cancel() { function cancel() {
open.value = false; open.value = false
reset(); reset()
} }
// 表单重置 // 表单重置
@@ -372,13 +372,13 @@ function reset() {
$column.javaField: null#if($foreach.count != $columns.size()),#end $column.javaField: null#if($foreach.count != $columns.size()),#end
#end #end
#end #end
}; }
proxy.resetForm("${businessName}Ref"); proxy.resetForm("${businessName}Ref")
} }
/** 搜索按钮操作 */ /** 搜索按钮操作 */
function handleQuery() { function handleQuery() {
getList(); getList()
} }
/** 重置按钮操作 */ /** 重置按钮操作 */
@@ -386,52 +386,52 @@ function resetQuery() {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
daterange${AttrName}.value = []; daterange${AttrName}.value = []
#end #end
#end #end
proxy.resetForm("queryRef"); proxy.resetForm("queryRef")
handleQuery(); handleQuery()
} }
/** 新增按钮操作 */ /** 新增按钮操作 */
function handleAdd(row) { function handleAdd(row) {
reset(); reset()
getTreeselect(); getTreeselect()
if (row != null && row.${treeCode}) { if (row != null && row.${treeCode}) {
form.value.${treeParentCode} = row.${treeCode}; form.value.${treeParentCode} = row.${treeCode}
} else { } else {
form.value.${treeParentCode} = 0; form.value.${treeParentCode} = 0
} }
open.value = true; open.value = true
title.value = "添加${functionName}"; title.value = "添加${functionName}"
} }
/** 展开/折叠操作 */ /** 展开/折叠操作 */
function toggleExpandAll() { function toggleExpandAll() {
refreshTable.value = false; refreshTable.value = false
isExpandAll.value = !isExpandAll.value; isExpandAll.value = !isExpandAll.value
nextTick(() => { nextTick(() => {
refreshTable.value = true; refreshTable.value = true
}); })
} }
/** 修改按钮操作 */ /** 修改按钮操作 */
async function handleUpdate(row) { async function handleUpdate(row) {
reset(); reset()
await getTreeselect(); await getTreeselect()
if (row != null) { if (row != null) {
form.value.${treeParentCode} = row.${treeCode}; form.value.${treeParentCode} = row.${treeParentCode}
} }
get${BusinessName}(row.${pkColumn.javaField}).then(response => { get${BusinessName}(row.${pkColumn.javaField}).then(response => {
form.value = response.data; form.value = response.data
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.split(","); form.value.$column.javaField = form.value.${column.javaField}.split(",")
#end #end
#end #end
open.value = true; open.value = true
title.value = "修改${functionName}"; title.value = "修改${functionName}"
}); })
} }
/** 提交按钮 */ /** 提交按钮 */
@@ -440,35 +440,35 @@ function submitForm() {
if (valid) { if (valid) {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.join(","); form.value.$column.javaField = form.value.${column.javaField}.join(",")
#end #end
#end #end
if (form.value.${pkColumn.javaField} != null) { if (form.value.${pkColumn.javaField} != null) {
update${BusinessName}(form.value).then(response => { update${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("修改成功"); proxy.#[[$modal]]#.msgSuccess("修改成功")
open.value = false; open.value = false
getList(); getList()
}); })
} else { } else {
add${BusinessName}(form.value).then(response => { add${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("新增成功"); proxy.#[[$modal]]#.msgSuccess("新增成功")
open.value = false; open.value = false
getList(); getList()
}); })
} }
} }
}); })
} }
/** 删除按钮操作 */ /** 删除按钮操作 */
function handleDelete(row) { function handleDelete(row) {
proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() { proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
return del${BusinessName}(row.${pkColumn.javaField}); return del${BusinessName}(row.${pkColumn.javaField})
}).then(() => { }).then(() => {
getList(); getList()
proxy.#[[$modal]]#.msgSuccess("删除成功"); proxy.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {}); }).catch(() => {})
} }
getList(); getList()
</script> </script>

View File

@@ -73,7 +73,7 @@
plain plain
icon="Plus" icon="Plus"
@click="handleAdd" @click="handleAdd"
v-hasPermi="['${moduleName}:${businessName}:add']" v-hasPermi="['${permissionPrefix}:add']"
>新增</el-button> >新增</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
@@ -83,7 +83,7 @@
icon="Edit" icon="Edit"
:disabled="single" :disabled="single"
@click="handleUpdate" @click="handleUpdate"
v-hasPermi="['${moduleName}:${businessName}:edit']" v-hasPermi="['${permissionPrefix}:edit']"
>修改</el-button> >修改</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
@@ -93,7 +93,7 @@
icon="Delete" icon="Delete"
:disabled="multiple" :disabled="multiple"
@click="handleDelete" @click="handleDelete"
v-hasPermi="['${moduleName}:${businessName}:remove']" v-hasPermi="['${permissionPrefix}:remove']"
>删除</el-button> >删除</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
@@ -102,7 +102,7 @@
plain plain
icon="Download" icon="Download"
@click="handleExport" @click="handleExport"
v-hasPermi="['${moduleName}:${businessName}:export']" v-hasPermi="['${permissionPrefix}:export']"
>导出</el-button> >导出</el-button>
</el-col> </el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
@@ -148,8 +148,8 @@
#end #end
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button> <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${permissionPrefix}:edit']">修改</el-button>
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button> <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${permissionPrefix}:remove']">删除</el-button>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@@ -343,33 +343,33 @@
</template> </template>
<script setup name="${BusinessName}"> <script setup name="${BusinessName}">
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"; import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}"
const { proxy } = getCurrentInstance(); const { proxy } = getCurrentInstance()
#if(${dicts} != '') #if(${dicts} != '')
#set($dictsNoSymbol=$dicts.replace("'", "")) #set($dictsNoSymbol=$dicts.replace("'", ""))
const { ${dictsNoSymbol} } = proxy.useDict(${dicts}); const { ${dictsNoSymbol} } = proxy.useDict(${dicts})
#end #end
const ${businessName}List = ref([]); const ${businessName}List = ref([])
#if($table.sub) #if($table.sub)
const ${subclassName}List = ref([]); const ${subclassName}List = ref([])
#end #end
const open = ref(false); const open = ref(false)
const loading = ref(true); const loading = ref(true)
const showSearch = ref(true); const showSearch = ref(true)
const ids = ref([]); const ids = ref([])
#if($table.sub) #if($table.sub)
const checked${subClassName} = ref([]); const checked${subClassName} = ref([])
#end #end
const single = ref(true); const single = ref(true)
const multiple = ref(true); const multiple = ref(true)
const total = ref(0); const total = ref(0)
const title = ref(""); const title = ref("")
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
const daterange${AttrName} = ref([]); const daterange${AttrName} = ref([])
#end #end
#end #end
@@ -399,16 +399,16 @@ const data = reactive({
#end #end
#end #end
} }
}); })
const { queryParams, form, rules } = toRefs(data); const { queryParams, form, rules } = toRefs(data)
/** 查询${functionName}列表 */ /** 查询${functionName}列表 */
function getList() { function getList() {
loading.value = true; loading.value = true
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
queryParams.value.params = {}; queryParams.value.params = {}
#break #break
#end #end
#end #end
@@ -416,22 +416,22 @@ function getList() {
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
if (null != daterange${AttrName} && '' != daterange${AttrName}) { if (null != daterange${AttrName} && '' != daterange${AttrName}) {
queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]; queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0]
queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]; queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1]
} }
#end #end
#end #end
list${BusinessName}(queryParams.value).then(response => { list${BusinessName}(queryParams.value).then(response => {
${businessName}List.value = response.rows; ${businessName}List.value = response.rows
total.value = response.total; total.value = response.total
loading.value = false; loading.value = false
}); })
} }
// 取消按钮 // 取消按钮
function cancel() { function cancel() {
open.value = false; open.value = false
reset(); reset()
} }
// 表单重置 // 表单重置
@@ -444,17 +444,17 @@ function reset() {
$column.javaField: null#if($foreach.count != $columns.size()),#end $column.javaField: null#if($foreach.count != $columns.size()),#end
#end #end
#end #end
}; }
#if($table.sub) #if($table.sub)
${subclassName}List.value = []; ${subclassName}List.value = []
#end #end
proxy.resetForm("${businessName}Ref"); proxy.resetForm("${businessName}Ref")
} }
/** 搜索按钮操作 */ /** 搜索按钮操作 */
function handleQuery() { function handleQuery() {
queryParams.value.pageNum = 1; queryParams.value.pageNum = 1
getList(); getList()
} }
/** 重置按钮操作 */ /** 重置按钮操作 */
@@ -462,44 +462,44 @@ function resetQuery() {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN") #if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
daterange${AttrName}.value = []; daterange${AttrName}.value = []
#end #end
#end #end
proxy.resetForm("queryRef"); proxy.resetForm("queryRef")
handleQuery(); handleQuery()
} }
// 多选框选中数据 // 多选框选中数据
function handleSelectionChange(selection) { function handleSelectionChange(selection) {
ids.value = selection.map(item => item.${pkColumn.javaField}); ids.value = selection.map(item => item.${pkColumn.javaField})
single.value = selection.length != 1; single.value = selection.length != 1
multiple.value = !selection.length; multiple.value = !selection.length
} }
/** 新增按钮操作 */ /** 新增按钮操作 */
function handleAdd() { function handleAdd() {
reset(); reset()
open.value = true; open.value = true
title.value = "添加${functionName}"; title.value = "添加${functionName}"
} }
/** 修改按钮操作 */ /** 修改按钮操作 */
function handleUpdate(row) { function handleUpdate(row) {
reset(); reset()
const _${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value const _${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value
get${BusinessName}(_${pkColumn.javaField}).then(response => { get${BusinessName}(_${pkColumn.javaField}).then(response => {
form.value = response.data; form.value = response.data
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.split(","); form.value.$column.javaField = form.value.${column.javaField}.split(",")
#end #end
#end #end
#if($table.sub) #if($table.sub)
${subclassName}List.value = response.data.${subclassName}List; ${subclassName}List.value = response.data.${subclassName}List
#end #end
open.value = true; open.value = true
title.value = "修改${functionName}"; title.value = "修改${functionName}"
}); })
} }
/** 提交按钮 */ /** 提交按钮 */
@@ -508,68 +508,68 @@ function submitForm() {
if (valid) { if (valid) {
#foreach ($column in $columns) #foreach ($column in $columns)
#if($column.htmlType == "checkbox") #if($column.htmlType == "checkbox")
form.value.$column.javaField = form.value.${column.javaField}.join(","); form.value.$column.javaField = form.value.${column.javaField}.join(",")
#end #end
#end #end
#if($table.sub) #if($table.sub)
form.value.${subclassName}List = ${subclassName}List.value; form.value.${subclassName}List = ${subclassName}List.value
#end #end
if (form.value.${pkColumn.javaField} != null) { if (form.value.${pkColumn.javaField} != null) {
update${BusinessName}(form.value).then(response => { update${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("修改成功"); proxy.#[[$modal]]#.msgSuccess("修改成功")
open.value = false; open.value = false
getList(); getList()
}); })
} else { } else {
add${BusinessName}(form.value).then(response => { add${BusinessName}(form.value).then(response => {
proxy.#[[$modal]]#.msgSuccess("新增成功"); proxy.#[[$modal]]#.msgSuccess("新增成功")
open.value = false; open.value = false
getList(); getList()
}); })
} }
} }
}); })
} }
/** 删除按钮操作 */ /** 删除按钮操作 */
function handleDelete(row) { function handleDelete(row) {
const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value; const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value
proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + _${pkColumn.javaField}s + '"的数据项?').then(function() { proxy.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + _${pkColumn.javaField}s + '"的数据项?').then(function() {
return del${BusinessName}(_${pkColumn.javaField}s); return del${BusinessName}(_${pkColumn.javaField}s)
}).then(() => { }).then(() => {
getList(); getList()
proxy.#[[$modal]]#.msgSuccess("删除成功"); proxy.#[[$modal]]#.msgSuccess("删除成功")
}).catch(() => {}); }).catch(() => {})
} }
#if($table.sub) #if($table.sub)
/** ${subTable.functionName}序号 */ /** ${subTable.functionName}序号 */
function row${subClassName}Index({ row, rowIndex }) { function row${subClassName}Index({ row, rowIndex }) {
row.index = rowIndex + 1; row.index = rowIndex + 1
} }
/** ${subTable.functionName}添加按钮操作 */ /** ${subTable.functionName}添加按钮操作 */
function handleAdd${subClassName}() { function handleAdd${subClassName}() {
let obj = {}; let obj = {}
#foreach($column in $subTable.columns) #foreach($column in $subTable.columns)
#if($column.pk || $column.javaField == ${subTableFkclassName}) #if($column.pk || $column.javaField == ${subTableFkclassName})
#elseif($column.list && "" != $javaField) #elseif($column.list && "" != $javaField)
obj.$column.javaField = ""; obj.$column.javaField = ""
#end #end
#end #end
${subclassName}List.value.push(obj); ${subclassName}List.value.push(obj)
} }
/** ${subTable.functionName}删除按钮操作 */ /** ${subTable.functionName}删除按钮操作 */
function handleDelete${subClassName}() { function handleDelete${subClassName}() {
if (checked${subClassName}.value.length == 0) { if (checked${subClassName}.value.length == 0) {
proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据"); proxy.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据")
} else { } else {
const ${subclassName}s = ${subclassName}List.value; const ${subclassName}s = ${subclassName}List.value
const checked${subClassName}s = checked${subClassName}.value; const checked${subClassName}s = checked${subClassName}.value
${subclassName}List.value = ${subclassName}s.filter(function(item) { ${subclassName}List.value = ${subclassName}s.filter(function(item) {
return checked${subClassName}s.indexOf(item.index) == -1 return checked${subClassName}s.indexOf(item.index) == -1
}); })
} }
} }
@@ -586,5 +586,5 @@ function handleExport() {
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`) }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
} }
getList(); getList()
</script> </script>

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -40,14 +40,7 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<!-- Swagger UI -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<!-- Quartz --> <!-- Quartz -->
<dependency> <dependency>
<groupId>org.quartz-scheduler</groupId> <groupId>org.quartz-scheduler</groupId>

View File

@@ -4,7 +4,6 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.ruoyi.common.security.annotation.EnableCustomConfig; import com.ruoyi.common.security.annotation.EnableCustomConfig;
import com.ruoyi.common.security.annotation.EnableRyFeignClients; import com.ruoyi.common.security.annotation.EnableRyFeignClients;
import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
/** /**
* 定时任务 * 定时任务
@@ -12,7 +11,6 @@ import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
* @author ruoyi * @author ruoyi
*/ */
@EnableCustomConfig @EnableCustomConfig
@EnableCustomSwagger2
@EnableRyFeignClients @EnableRyFeignClients
@SpringBootApplication @SpringBootApplication
public class RuoYiJobApplication public class RuoYiJobApplication

View File

@@ -178,7 +178,7 @@ public class SysJobController extends BaseController
@RequiresPermissions("monitor:job:remove") @RequiresPermissions("monitor:job:remove")
@Log(title = "定时任务", businessType = BusinessType.DELETE) @Log(title = "定时任务", businessType = BusinessType.DELETE)
@DeleteMapping("/{jobIds}") @DeleteMapping("/{jobIds}")
public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException
{ {
jobService.deleteJobByIds(jobIds); jobService.deleteJobByIds(jobIds);
return success(); return success();

View File

@@ -3,7 +3,6 @@ package com.ruoyi.job.util;
import java.util.Date; import java.util.Date;
import org.quartz.Job; import org.quartz.Job;
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.ruoyi.common.core.constant.ScheduleConstants; import com.ruoyi.common.core.constant.ScheduleConstants;
@@ -30,7 +29,7 @@ public abstract class AbstractQuartzJob implements Job
private static ThreadLocal<Date> threadLocal = new ThreadLocal<>(); private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
@Override @Override
public void execute(JobExecutionContext context) throws JobExecutionException public void execute(JobExecutionContext context)
{ {
SysJob sysJob = new SysJob(); SysJob sysJob = new SysJob();
BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES)); BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));

View File

@@ -105,7 +105,7 @@ public class JobInvokeUtil
*/ */
public static List<Object[]> getMethodParams(String invokeTarget) public static List<Object[]> getMethodParams(String invokeTarget)
{ {
String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); String methodStr = StringUtils.substringBetweenLast(invokeTarget, "(", ")");
if (StringUtils.isEmpty(methodStr)) if (StringUtils.isEmpty(methodStr))
{ {
return null; return null;

View File

@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.ruoyi</groupId> <groupId>com.ruoyi</groupId>
<artifactId>ruoyi-modules</artifactId> <artifactId>ruoyi-modules</artifactId>
<version>3.6.4</version> <version>3.6.5</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -40,14 +40,7 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId> <artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependency>
<!-- Swagger UI -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.fox.version}</version>
</dependency>
<!-- Mysql Connector --> <!-- Mysql Connector -->
<dependency> <dependency>
<groupId>com.mysql</groupId> <groupId>com.mysql</groupId>

View File

@@ -4,7 +4,6 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.ruoyi.common.security.annotation.EnableCustomConfig; import com.ruoyi.common.security.annotation.EnableCustomConfig;
import com.ruoyi.common.security.annotation.EnableRyFeignClients; import com.ruoyi.common.security.annotation.EnableRyFeignClients;
import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
/** /**
* 系统模块 * 系统模块
@@ -12,7 +11,6 @@ import com.ruoyi.common.swagger.annotation.EnableCustomSwagger2;
* @author ruoyi * @author ruoyi
*/ */
@EnableCustomConfig @EnableCustomConfig
@EnableCustomSwagger2
@EnableRyFeignClients @EnableRyFeignClients
@SpringBootApplication @SpringBootApplication
public class RuoYiSystemApplication public class RuoYiSystemApplication

View File

@@ -1,6 +1,7 @@
package com.ruoyi.system.controller; package com.ruoyi.system.controller;
import java.util.Arrays; import java.util.Arrays;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@@ -93,11 +94,13 @@ public class SysProfileController extends BaseController
*/ */
@Log(title = "个人信息", businessType = BusinessType.UPDATE) @Log(title = "个人信息", businessType = BusinessType.UPDATE)
@PutMapping("/updatePwd") @PutMapping("/updatePwd")
public AjaxResult updatePwd(String oldPassword, String newPassword) public AjaxResult updatePwd(@RequestBody Map<String, String> params)
{ {
String username = SecurityUtils.getUsername(); String oldPassword = params.get("oldPassword");
SysUser user = userService.selectUserByUserName(username); String newPassword = params.get("newPassword");
String password = user.getPassword(); LoginUser loginUser = SecurityUtils.getLoginUser();
String userName = loginUser.getUsername();
String password = loginUser.getSysUser().getPassword();
if (!SecurityUtils.matchesPassword(oldPassword, password)) if (!SecurityUtils.matchesPassword(oldPassword, password))
{ {
return error("修改密码失败,旧密码错误"); return error("修改密码失败,旧密码错误");
@@ -107,10 +110,9 @@ public class SysProfileController extends BaseController
return error("新密码不能与旧密码相同"); return error("新密码不能与旧密码相同");
} }
newPassword = SecurityUtils.encryptPassword(newPassword); newPassword = SecurityUtils.encryptPassword(newPassword);
if (userService.resetUserPwd(username, newPassword) > 0) if (userService.resetUserPwd(userName, newPassword) > 0)
{ {
// 更新缓存用户密码 // 更新缓存用户密码
LoginUser loginUser = SecurityUtils.getLoginUser();
loginUser.getSysUser().setPassword(newPassword); loginUser.getSysUser().setPassword(newPassword);
tokenService.setLoginUser(loginUser); tokenService.setLoginUser(loginUser);
return success(); return success();

View File

@@ -27,6 +27,7 @@ import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType; import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.InnerAuth; import com.ruoyi.common.security.annotation.InnerAuth;
import com.ruoyi.common.security.annotation.RequiresPermissions; import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.security.utils.SecurityUtils; import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.domain.SysDept; import com.ruoyi.system.api.domain.SysDept;
import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysRole;
@@ -66,6 +67,9 @@ public class SysUserController extends BaseController
@Autowired @Autowired
private ISysConfigService configService; private ISysConfigService configService;
@Autowired
private TokenService tokenService;
/** /**
* 获取用户列表 * 获取用户列表
*/ */
@@ -167,11 +171,17 @@ public class SysUserController extends BaseController
@GetMapping("getInfo") @GetMapping("getInfo")
public AjaxResult getInfo() public AjaxResult getInfo()
{ {
SysUser user = userService.selectUserById(SecurityUtils.getUserId()); LoginUser loginUser = SecurityUtils.getLoginUser();
SysUser user = loginUser.getSysUser();
// 角色集合 // 角色集合
Set<String> roles = permissionService.getRolePermission(user); Set<String> roles = permissionService.getRolePermission(user);
// 权限集合 // 权限集合
Set<String> permissions = permissionService.getMenuPermission(user); Set<String> permissions = permissionService.getMenuPermission(user);
if (!loginUser.getPermissions().equals(permissions))
{
loginUser.setPermissions(permissions);
tokenService.refreshToken(loginUser);
}
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
ajax.put("user", user); ajax.put("user", user);
ajax.put("roles", roles); ajax.put("roles", roles);
@@ -186,18 +196,18 @@ public class SysUserController extends BaseController
@GetMapping(value = { "/", "/{userId}" }) @GetMapping(value = { "/", "/{userId}" })
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{ {
userService.checkUserDataScope(userId);
AjaxResult ajax = AjaxResult.success(); AjaxResult ajax = AjaxResult.success();
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll());
if (StringUtils.isNotNull(userId)) if (StringUtils.isNotNull(userId))
{ {
userService.checkUserDataScope(userId);
SysUser sysUser = userService.selectUserById(userId); SysUser sysUser = userService.selectUserById(userId);
ajax.put(AjaxResult.DATA_TAG, sysUser); ajax.put(AjaxResult.DATA_TAG, sysUser);
ajax.put("postIds", postService.selectPostListByUserId(userId)); ajax.put("postIds", postService.selectPostListByUserId(userId));
ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList())); ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
} }
List<SysRole> roles = roleService.selectRoleAll();
ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
ajax.put("posts", postService.selectPostAll());
return ajax; return ajax;
} }

View File

@@ -4,6 +4,8 @@ import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.system.api.domain.SysDept; import com.ruoyi.system.api.domain.SysDept;
import com.ruoyi.system.domain.SysMenu; import com.ruoyi.system.domain.SysMenu;
@@ -22,6 +24,9 @@ public class TreeSelect implements Serializable
/** 节点名称 */ /** 节点名称 */
private String label; private String label;
/** 节点禁用 */
private boolean disabled = false;
/** 子节点 */ /** 子节点 */
@JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<TreeSelect> children; private List<TreeSelect> children;
@@ -35,6 +40,7 @@ public class TreeSelect implements Serializable
{ {
this.id = dept.getDeptId(); this.id = dept.getDeptId();
this.label = dept.getDeptName(); this.label = dept.getDeptName();
this.disabled = StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus());
this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList()); this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
} }
@@ -65,6 +71,16 @@ public class TreeSelect implements Serializable
this.label = label; this.label = label;
} }
public boolean isDisabled()
{
return disabled;
}
public void setDisabled(boolean disabled)
{
this.disabled = disabled;
}
public List<TreeSelect> getChildren() public List<TreeSelect> getChildren()
{ {
return children; return children;

View File

@@ -365,7 +365,7 @@ public class SysMenuServiceImpl implements ISysMenuService
/** /**
* 获取路由名称,如没有配置路由名称则取路由地址 * 获取路由名称,如没有配置路由名称则取路由地址
* *
* @param routerName 路由名称 * @param name 路由名称
* @param path 路由地址 * @param path 路由地址
* @return 路由名称(驼峰格式) * @return 路由名称(驼峰格式)
*/ */

View File

@@ -6,6 +6,8 @@ import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import com.ruoyi.common.core.constant.UserConstants;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.system.api.domain.SysRole; import com.ruoyi.system.api.domain.SysRole;
import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.service.ISysMenuService; import com.ruoyi.system.service.ISysMenuService;
@@ -71,9 +73,12 @@ public class SysPermissionServiceImpl implements ISysPermissionService
// 多角色设置permissions属性以便数据权限匹配权限 // 多角色设置permissions属性以便数据权限匹配权限
for (SysRole role : roles) for (SysRole role : roles)
{ {
Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId()); if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && !role.isAdmin())
role.setPermissions(rolePerms); {
perms.addAll(rolePerms); Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
role.setPermissions(rolePerms);
perms.addAll(rolePerms);
}
} }
} }
else else

View File

@@ -178,7 +178,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
update sys_user update sys_user
<set> <set>
<if test="deptId != null and deptId != 0">dept_id = #{deptId},</if> <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
<if test="userName != null and userName != ''">user_name = #{userName},</if>
<if test="nickName != null and nickName != ''">nick_name = #{nickName},</if> <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
<if test="email != null ">email = #{email},</if> <if test="email != null ">email = #{email},</if>
<if test="phonenumber != null ">phonenumber = #{phonenumber},</if> <if test="phonenumber != null ">phonenumber = #{phonenumber},</if>

View File

@@ -1,6 +1,8 @@
# 页面标题 # 页面标题
VUE_APP_TITLE = 若依管理系统 VUE_APP_TITLE = 若依管理系统
BABEL_ENV = production
NODE_ENV = production NODE_ENV = production
# 测试环境配置 # 测试环境配置

View File

@@ -1,6 +1,6 @@
{ {
"name": "ruoyi", "name": "ruoyi",
"version": "3.6.4", "version": "3.6.5",
"description": "若依管理系统", "description": "若依管理系统",
"author": "若依", "author": "若依",
"license": "MIT", "license": "MIT",
@@ -49,9 +49,10 @@
"js-cookie": "3.0.1", "js-cookie": "3.0.1",
"jsencrypt": "3.0.0-rc.1", "jsencrypt": "3.0.0-rc.1",
"nprogress": "0.2.0", "nprogress": "0.2.0",
"quill": "1.3.7", "quill": "2.0.2",
"screenfull": "5.0.2", "screenfull": "5.0.2",
"sortablejs": "1.10.2", "sortablejs": "1.10.2",
"splitpanes": "2.4.1",
"vue": "2.6.12", "vue": "2.6.12",
"vue-count-to": "1.0.13", "vue-count-to": "1.0.13",
"vue-cropper": "0.5.5", "vue-cropper": "0.5.5",
@@ -72,7 +73,6 @@
"eslint": "7.15.0", "eslint": "7.15.0",
"eslint-plugin-vue": "7.2.0", "eslint-plugin-vue": "7.2.0",
"lint-staged": "10.5.3", "lint-staged": "10.5.3",
"runjs": "4.4.2",
"sass": "1.32.13", "sass": "1.32.13",
"sass-loader": "10.1.1", "sass-loader": "10.1.1",
"script-ext-html-webpack-plugin": "2.1.5", "script-ext-html-webpack-plugin": "2.1.5",

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@
</template> </template>
<script> <script>
import ThemePicker from "@/components/ThemePicker"; import ThemePicker from "@/components/ThemePicker"
export default { export default {
name: "App", name: "App",
@@ -19,7 +19,7 @@ export default {
} }
} }
} }
}; }
</script> </script>
<style scoped> <style scoped>
#app .theme-picker { #app .theme-picker {

View File

@@ -96,7 +96,7 @@ export function updateUserPwd(oldPassword, newPassword) {
return request({ return request({
url: '/system/user/profile/updatePwd', url: '/system/user/profile/updatePwd',
method: 'put', method: 'put',
params: data data: data
}) })
} }

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746590936918" class="icon" viewBox="0 0 1194 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5378" xmlns:xlink="http://www.w3.org/1999/xlink" width="233.203125" height="200"><path d="M1151.9144 325.11999969V89.12a57.04000031 57.04000031 0 0 0-28.8-49.44 58.15999969 58.15999969 0 0 0-57.76000031 0 57.04000031 57.04000031 0 0 0-28.8 49.44v235.99999969c0.24 84.31999969-33.6 152.56000031-94.08 212.00000062-60.07999969 59.83999969-141.84 80.64-227.04 80.4H225.91440031L388.07439969 457.11999969a56.80000031 56.80000031 0 0 0 12.40000031-62.16 57.76000031 57.76000031 0 0 0-94.00000031-18.63999938L48.8744 631.20000031a56.88 56.88 0 0 0 0 80.79999938l264.96 262.56a58.08 58.08 0 0 0 96.55999969-25.59999938 56.80000031 56.80000031 0 0 0-14.95999969-55.2L232.07439969 731.67999969h483.44000062c116.56000031 0 226.15999969-32.08000031 308.64-113.76 82.15999969-80.80000031 128.23999969-178.15999969 127.83999938-292.87999969" p-id="5379"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746760911144" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12537" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M395.21211 182.914448c0 62.669318 49.541323 113.472378 110.642936 113.472378 61.093427 0 110.652146-50.80306 110.65214601-113.472378 0-62.685691-49.559742-113.487727-110.65214601-113.487727C444.75241 69.426721 395.21211 120.22978 395.21211 182.914448zM395.21211 523.34693101c0 62.668295 49.541323 113.487727 110.642936 113.48772699 61.093427 0 110.652146-50.820456 110.652146-113.487727 0-62.669318-49.559742-113.472378-110.652146-113.472378C444.75241 409.874553 395.21211 460.67761301 395.21211 523.34693101zM395.21211 841.084529c0 62.686714 49.541323 113.488751 110.642936 113.488751 61.093427 0 110.652146-50.80203599 110.65214601-113.488751 0-62.669318-49.559742-113.471354-110.65214601-113.471354C444.75241 727.614198 395.21211 778.416234 395.21211 841.084529z" p-id="12538"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -129,10 +129,6 @@ aside {
position: relative; position: relative;
} }
.pagination-container {
margin-top: 30px;
}
.text-center { .text-center {
text-align: center text-align: center
} }

View File

@@ -117,11 +117,9 @@
/** 表格布局 **/ /** 表格布局 **/
.pagination-container { .pagination-container {
position: relative; display: flex;
height: 25px; justify-content: flex-end;
margin-bottom: 10px; margin-top: 20px;
margin-top: 15px;
padding: 10px 20px !important;
} }
/* tree border */ /* tree border */
@@ -132,11 +130,6 @@
border-radius: 4px; border-radius: 4px;
} }
.pagination-container .el-pagination {
right: 0;
position: absolute;
}
@media (max-width: 768px) { @media (max-width: 768px) {
.pagination-container .el-pagination > .el-pagination__jump { .pagination-container .el-pagination > .el-pagination__jump {
display: none !important; display: none !important;
@@ -201,8 +194,6 @@
} }
.card-box { .card-box {
padding-right: 15px;
padding-left: 15px;
margin-bottom: 10px; margin-bottom: 10px;
} }
@@ -289,3 +280,8 @@
position: relative; position: relative;
float: right; float: right;
} }
/* 分割面板样式 */
.splitpanes.default-theme .splitpanes__pane {
background-color: #fff!important;
}

View File

@@ -25,7 +25,7 @@
z-index: 1001; z-index: 1001;
overflow: hidden; overflow: hidden;
-webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35); -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
box-shadow: 2px 0 6px rgba(0,21,41,.35); box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
// reset element-ui css // reset element-ui css
.horizontal-collapse-transition { .horizontal-collapse-transition {

Some files were not shown because too many files have changed in this diff Show More