mirror of
https://gitee.com/y_project/RuoYi-Cloud.git
synced 2026-04-26 17:27:51 +08:00
Compare commits
166 Commits
5ee971821b
...
v3.6.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63a556bd3a | ||
|
|
d94b7d1a5f | ||
|
|
385fc50c19 | ||
|
|
50fc2989ee | ||
|
|
80483dd17c | ||
|
|
ab77b8cb8d | ||
|
|
14e8885fba | ||
|
|
c29f5e2c04 | ||
|
|
b33ea72445 | ||
|
|
543d169827 | ||
|
|
9ddcb875a1 | ||
|
|
aa5530f51b | ||
|
|
0017cc8862 | ||
|
|
88c2e4979a | ||
|
|
b43048a589 | ||
|
|
0025941824 | ||
|
|
784fe5c399 | ||
|
|
af2d446a5f | ||
|
|
1f8dd5feb5 | ||
|
|
d3b5e93952 | ||
|
|
8d84783daf | ||
|
|
0bf6679753 | ||
|
|
e1e8b541db | ||
|
|
d30a6450c9 | ||
|
|
571a25d486 | ||
|
|
b0ff5a01a1 | ||
|
|
39c1dafced | ||
|
|
33694fe082 | ||
|
|
8c122a9609 | ||
|
|
de1dbe61a5 | ||
|
|
156471d638 | ||
|
|
661e8cf7b4 | ||
|
|
28be96930c | ||
|
|
6c6a2c0623 | ||
|
|
7d821ed043 | ||
|
|
5d54693b27 | ||
|
|
cfd619fa4f | ||
|
|
e942847b89 | ||
|
|
0b09d7c1da | ||
|
|
1c0562ba18 | ||
|
|
da65996e69 | ||
|
|
873444dd0b | ||
|
|
2301280c4d | ||
|
|
4eebb27956 | ||
|
|
c2ff461ff0 | ||
|
|
eb489bda83 | ||
|
|
1db2086163 | ||
|
|
839e4f35f5 | ||
|
|
f53b783049 | ||
|
|
97f30a5415 | ||
|
|
ad1d009165 | ||
|
|
90cbabb7a7 | ||
|
|
1c4dbb1e46 | ||
|
|
a3eefb6bad | ||
|
|
09e8e9995a | ||
|
|
381151bc50 | ||
|
|
66e502727a | ||
|
|
4265f8ecb7 | ||
|
|
2c82079d04 | ||
|
|
6aecd35a4f | ||
|
|
ac92ae3ae6 | ||
|
|
1d2c8378f7 | ||
|
|
50a9337ee8 | ||
|
|
e6a3415a71 | ||
|
|
7919af54da | ||
|
|
3503005f9d | ||
|
|
b304a41194 | ||
|
|
a39ae33c82 | ||
|
|
b9a27657c5 | ||
|
|
2e009841ca | ||
|
|
2cbe4a8234 | ||
|
|
4b37049713 | ||
|
|
e549210ad6 | ||
|
|
ad988d54bb | ||
|
|
51a6fce0a5 | ||
|
|
c86bfa9243 | ||
|
|
8aca11c2a2 | ||
|
|
725033e361 | ||
|
|
d29e49e23b | ||
|
|
706c3bb69b | ||
|
|
cd0ee95b9c | ||
|
|
3293e2fb56 | ||
|
|
924ec0eb6e | ||
|
|
135b1204a9 | ||
|
|
cb566a704b | ||
|
|
aadba0382e | ||
|
|
a0ce1cf33b | ||
|
|
3915c77391 | ||
|
|
b80932ceb4 | ||
|
|
056cf94082 | ||
|
|
0dcd3e6183 | ||
|
|
07be5ceb26 | ||
|
|
cc59502d7c | ||
|
|
98738f23ad | ||
|
|
57fe1c663e | ||
|
|
7b6fdb3a89 | ||
|
|
79c885decb | ||
|
|
1a0f37a2dc | ||
|
|
02de344d8c | ||
|
|
189100f74e | ||
|
|
e29284e687 | ||
|
|
d4af286f41 | ||
|
|
60e2d55a23 | ||
|
|
bbd112d5a3 | ||
|
|
90922844ea | ||
|
|
3a9f56f04b | ||
|
|
a1ec1d57d4 | ||
|
|
060959a7c5 | ||
|
|
43e1d8d573 | ||
|
|
67cf51ba77 | ||
|
|
a256618d5d | ||
|
|
a6bcebb62b | ||
|
|
1cb262daa3 | ||
|
|
8c096cba8d | ||
|
|
088cec8adf | ||
|
|
85ff6a9910 | ||
|
|
cab5beaca7 | ||
|
|
fc8069a250 | ||
|
|
924e705dca | ||
|
|
049ba453d1 | ||
|
|
4aa261e8f7 | ||
|
|
914a6620f5 | ||
|
|
3dcee7057d | ||
|
|
0467631319 | ||
|
|
a11df90255 | ||
|
|
596e4fe756 | ||
|
|
37219e4ae6 | ||
|
|
adaa3e1db8 | ||
|
|
88ad5a2c19 | ||
|
|
b45dc2ec25 | ||
|
|
67b17da06f | ||
|
|
b25a280ebb | ||
|
|
cc026e75a3 | ||
|
|
7216b56a56 | ||
|
|
a326e880a1 | ||
|
|
92c6d21855 | ||
|
|
2335157f6e | ||
|
|
6c3b01c3c5 | ||
|
|
8faea60191 | ||
|
|
28a16d9878 | ||
|
|
dd3cf18e27 | ||
|
|
65d03dc014 | ||
|
|
7912fd81bd | ||
|
|
e2175e5b9d | ||
|
|
c0e119f8e0 | ||
|
|
fa77b2a08c | ||
|
|
a222c24796 | ||
|
|
08f4b877ce | ||
|
|
aa607d135c | ||
|
|
6d34cdb8a3 | ||
|
|
d47352253e | ||
|
|
61cbd470e1 | ||
|
|
b3ef4adfed | ||
|
|
856c471472 | ||
|
|
bec5600f16 | ||
|
|
5b485e7934 | ||
|
|
73a752d3ab | ||
|
|
1899a832b9 | ||
|
|
e6796c0954 | ||
|
|
4987289a98 | ||
|
|
18409922a5 | ||
|
|
3dca02b306 | ||
|
|
75f3275e15 | ||
|
|
b2e4a7046b | ||
|
|
60618c1da9 | ||
|
|
3b499b1344 |
14
README.md
14
README.md
@@ -1,11 +1,11 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-b99b286755aef70355a7084753f89cdb7c9.png">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.7</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.6.8</h1>
|
||||
<h4 align="center">基于 Vue/Element UI 和 Spring Boot/Spring Cloud & Alibaba 前后端分离的分布式微服务架构</h4>
|
||||
<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"><img src="https://img.shields.io/badge/RuoYi-v3.6.7-brightgreen.svg"></a>
|
||||
<a href="https://gitee.com/y_project/RuoYi-Cloud"><img src="https://img.shields.io/badge/RuoYi-v3.6.8-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>
|
||||
</p>
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
|
||||
若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
|
||||
|
||||
* 本仓库为RuoYi-Cloud的Spring Boot 3 的版本,保持同步更新。
|
||||
* 后端采用Spring Boot3、Spring Cloud & Alibaba。
|
||||
* 采用前后端分离的模式,微服务版本前端(基于 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue))。
|
||||
* 后端采用Spring Boot、Spring Cloud & Alibaba。
|
||||
* 注册中心、配置中心选型Nacos,权限认证使用Redis。
|
||||
* 流量控制框架选型Sentinel,分布式事务选型Seata。
|
||||
* 阿里云优惠券:[点我进入](http://aly.ruoyi.vip),腾讯云优惠券:[点我进入](http://txy.ruoyi.vip)
|
||||
@@ -23,11 +23,11 @@
|
||||
|
||||
RuoYi-Cloud 后端项目提供 Spring Boot 2.x / 3.x / 4.x 多版本分支的并行维护。
|
||||
|
||||
| 名称 | 说明 | 地址 |
|
||||
| :---------------- | :------------------------ | :-------------------------------------------------------- |
|
||||
| 名称 | 说明 | 地址 |
|
||||
| :---------------- | :----------------------------------- | :-------------------------------------------------------- |
|
||||
| master 默认分支 | Spring Boot 4.x (JDK 17+、Nacos 3.x) | https://gitee.com/y_project/RuoYi-Cloud |
|
||||
| springboot3 分支 | Spring Boot 3.x (JDK 17+、Nacos 3.x) | https://gitee.com/y_project/RuoYi-Cloud/tree/springboot3 |
|
||||
| springboot2 分支 | Spring Boot 2.x (JDK 8+、Nacos 2.x) | https://gitee.com/y_project/RuoYi-Cloud/tree/springboot2 |
|
||||
| springboot2 分支 | Spring Boot 2.x (JDK 8+、 Nacos 2.x) | https://gitee.com/y_project/RuoYi-Cloud/tree/springboot2 |
|
||||
|
||||
RuoYi-Cloud 前端项目提供 Vue 2.x / 3.x / JavaScript TypeScript 版本均可混用搭配
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ usage() {
|
||||
|
||||
# copy sql
|
||||
echo "begin copy sql "
|
||||
cp ../sql/ry_20250523.sql ./mysql/db
|
||||
cp ../sql/ry_config_20250902.sql ./mysql/db
|
||||
cp ../sql/ry_20260321.sql ./mysql/db
|
||||
cp ../sql/ry_config_20260311.sql ./mysql/db
|
||||
|
||||
# copy html
|
||||
echo "begin copy html "
|
||||
|
||||
24
pom.xml
24
pom.xml
@@ -6,25 +6,25 @@
|
||||
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
|
||||
<name>ruoyi</name>
|
||||
<url>http://www.ruoyi.vip</url>
|
||||
<description>若依微服务系统</description>
|
||||
|
||||
<properties>
|
||||
<ruoyi.version>3.6.7</ruoyi.version>
|
||||
<ruoyi.version>3.6.8</ruoyi.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<spring-boot.version>3.5.11</spring-boot.version>
|
||||
<spring-cloud.version>2025.0.1</spring-cloud.version>
|
||||
<spring-cloud-alibaba.version>2025.0.0.0</spring-cloud-alibaba.version>
|
||||
<spring-boot-admin.version>3.5.8</spring-boot-admin.version>
|
||||
<mybatis-spring.version>3.0.5</mybatis-spring.version>
|
||||
<spring-boot.version>4.0.3</spring-boot.version>
|
||||
<spring-cloud.version>2025.1.0</spring-cloud.version>
|
||||
<spring-cloud-alibaba.version>2025.1.0.0</spring-cloud-alibaba.version>
|
||||
<spring-boot-admin.version>4.0.2</spring-boot-admin.version>
|
||||
<mybatis-spring-boot.version>4.0.1</mybatis-spring-boot.version>
|
||||
<kaptcha.version>2.3.3</kaptcha.version>
|
||||
<pagehelper.boot.version>2.1.0</pagehelper.boot.version>
|
||||
<druid.version>1.2.27</druid.version>
|
||||
<druid.version>1.2.28</druid.version>
|
||||
<dynamic-ds.version>4.5.0</dynamic-ds.version>
|
||||
<commons.io.version>2.21.0</commons.io.version>
|
||||
<velocity.version>2.3</velocity.version>
|
||||
@@ -32,7 +32,7 @@
|
||||
<jjwt.version>0.9.1</jjwt.version>
|
||||
<minio.version>8.2.2</minio.version>
|
||||
<poi.version>4.1.2</poi.version>
|
||||
<springdoc.version>2.8.16</springdoc.version>
|
||||
<springdoc.version>3.0.2</springdoc.version>
|
||||
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
|
||||
</properties>
|
||||
|
||||
@@ -95,9 +95,9 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
<version>${mybatis-spring.version}</version>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${mybatis-spring-boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- io常用工具类 -->
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-api</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<!-- SpringBoot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Actuator -->
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.ruoyi.auth;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
||||
import com.ruoyi.common.security.annotation.EnableRyFeignClients;
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -55,8 +55,8 @@
|
||||
|
||||
<!-- Mybatis Spring -->
|
||||
<dependency>
|
||||
<groupId>org.mybatis</groupId>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Hibernate Validator -->
|
||||
@@ -68,7 +68,7 @@
|
||||
<!-- Spring Aop -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<artifactId>spring-boot-starter-aspectj</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Jackson -->
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.ruoyi.common.core.utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.apache.commons.lang3.Strings;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import com.ruoyi.common.core.constant.Constants;
|
||||
import com.ruoyi.common.core.text.StrFormatter;
|
||||
@@ -367,12 +371,87 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
|
||||
return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转set
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param sep 分隔符
|
||||
* @return set集合
|
||||
*/
|
||||
public static final Set<String> str2Set(String str, String sep)
|
||||
{
|
||||
return new HashSet<String>(str2List(str, sep, true, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转list
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param sep 分隔符
|
||||
* @return list集合
|
||||
*/
|
||||
public static final List<String> str2List(String str, String sep)
|
||||
{
|
||||
return str2List(str, sep, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转list
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param sep 分隔符
|
||||
* @param filterBlank 过滤纯空白
|
||||
* @param trim 去掉首尾空白
|
||||
* @return list集合
|
||||
*/
|
||||
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
|
||||
{
|
||||
List<String> list = new ArrayList<String>();
|
||||
if (StringUtils.isEmpty(str))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
// 过滤空白字符串
|
||||
if (filterBlank && StringUtils.isBlank(str))
|
||||
{
|
||||
return list;
|
||||
}
|
||||
String[] split = str.split(sep);
|
||||
for (String string : split)
|
||||
{
|
||||
if (filterBlank && StringUtils.isBlank(string))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (trim)
|
||||
{
|
||||
string = string.trim();
|
||||
}
|
||||
list.add(string);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查子字符串是否存在
|
||||
*
|
||||
* @param seq 检查的字符串
|
||||
* @param searchSeq 查找的字符串
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean contains(final CharSequence seq, final CharSequence searchSeq)
|
||||
{
|
||||
return Strings.CS.contains(seq, searchSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
|
||||
*
|
||||
* @param collection 给定的集合
|
||||
* @param array 给定的数组
|
||||
* @return boolean 结果
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean containsAny(Collection<String> collection, String... array)
|
||||
{
|
||||
@@ -393,6 +472,198 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否包含给定数组中的任意一个。
|
||||
*
|
||||
* @param cs 要判断的字符串
|
||||
* @param searchCharSequences 要判断的数组
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean containsAny(final CharSequence cs, final CharSequence... searchCharSequences)
|
||||
{
|
||||
return Strings.CS.containsAny(cs, searchCharSequences);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
|
||||
*
|
||||
* @param cs 指定字符串
|
||||
* @param searchCharSequences 需要检查的字符串数组
|
||||
* @return 是否包含任意一个字符串
|
||||
*/
|
||||
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
|
||||
{
|
||||
if (isEmpty(cs) || isEmpty(searchCharSequences))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (CharSequence testStr : searchCharSequences)
|
||||
{
|
||||
if (containsIgnoreCase(cs, testStr))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否包含要搜索的字符串,忽略大小写
|
||||
*
|
||||
* @param str 要检查的字符串
|
||||
* @param searchStr 要查找的字符串
|
||||
* @return 如果包含要搜索的字符串(忽略大小写)则返回true,如果不包含或返回false
|
||||
*/
|
||||
public static boolean containsIgnoreCase(final CharSequence str, final CharSequence searchStr)
|
||||
{
|
||||
return Strings.CI.contains(str, searchStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查字符串是否以任意前缀开始
|
||||
*
|
||||
* @param sequence 要检查的字符串
|
||||
* @param searchStrings 区分大小写的字符串前缀数组
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean startsWithAny(final CharSequence sequence, final CharSequence... searchStrings)
|
||||
{
|
||||
return Strings.CS.startsWithAny(sequence, searchStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* 不区分大小写地检查一个字符串是否以指定前缀开头。
|
||||
*
|
||||
* @param str 待检查的字符串
|
||||
* @param 要查找的前缀
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean startsWithIgnoreCase(final CharSequence str, final CharSequence prefix)
|
||||
{
|
||||
return Strings.CI.startsWith(str, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个字符串是否相同
|
||||
*
|
||||
* @param cs1 第一个字符串
|
||||
* @param cs2 第二个字符串
|
||||
* @return 如果给定对象与字符串相等,则返回 true;否则返回 false
|
||||
*/
|
||||
public static boolean equals(final CharSequence cs1, final CharSequence cs2)
|
||||
{
|
||||
return Strings.CS.equals(cs1, cs2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换字符串中所有匹配的字符
|
||||
*
|
||||
* @param text 要搜索和替换的文本
|
||||
* @param searchString 要搜索的字符串
|
||||
* @param replacement 用于替换的字符串
|
||||
* @return 处理完所有替换后的文本
|
||||
*/
|
||||
public static String replace(final String text, final String searchString, final String replacement)
|
||||
{
|
||||
return Strings.CS.replace(text, searchString, replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅当子字符串位于源字符串末尾时才将其移除,否则返回源字符串。
|
||||
* @param str 要搜索的源字符串
|
||||
* @param remove 要搜索并移除的字符串
|
||||
* @return 如果找到并移除了字符串,则返回移除后的子字符串
|
||||
*/
|
||||
public static String removeEnd(final String str, final String remove)
|
||||
{
|
||||
return Strings.CS.removeEnd(str, remove);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找字符串首次出现位置的索引
|
||||
*
|
||||
* @param seq 要检查的字符串
|
||||
* @param searchSeq 要查找的字符串
|
||||
* @return 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1
|
||||
*/
|
||||
public static int indexOf(final CharSequence seq, final CharSequence searchSeq)
|
||||
{
|
||||
return Strings.CS.indexOf(seq, searchSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查字符串是否以指定的后缀结尾
|
||||
*
|
||||
* @param str 要检查的字符
|
||||
* @param suffix 要检查的后缀
|
||||
* @return 若参数与该字符串末尾相符 true;否则 false
|
||||
*/
|
||||
public static boolean endsWith(final CharSequence str, final CharSequence suffix)
|
||||
{
|
||||
return Strings.CS.endsWith(str, suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将给定的字符串与数组进行比较
|
||||
*
|
||||
* @param string 要比较的字符串
|
||||
* @param searchStrings 字符串数组
|
||||
* @return 如果字符串等于(区分大小写){@code searchStrings}中的任意其他元素,则返回true;如果{@code searchStrings}为null或不包含匹配项,则返回false
|
||||
*/
|
||||
public static boolean equalsAny(final CharSequence string, final CharSequence... searchStrings)
|
||||
{
|
||||
return Strings.CS.equalsAny(string, searchStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查一个字符串是否以任意提供的区分大小写的后缀结尾。
|
||||
*
|
||||
* @param sequence 要检查的字符串
|
||||
* @param searchStrings 要查找的区分大小写的字符串数组
|
||||
* @return 如果输入参数{@code sequence}为null且未提供任何{@code searchStrings},或者输入{@code sequence}以任意提供的区分大小写的{@code searchStrings}结尾,则返回{@code true}。
|
||||
*/
|
||||
public static boolean endsWithAny(final CharSequence sequence, final CharSequence... searchStrings)
|
||||
{
|
||||
return Strings.CS.endsWithAny(sequence, searchStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* 不区分大小写地检查字符序列是否以指定的后缀结尾
|
||||
*
|
||||
* @param str 要检查的字符序列
|
||||
* @param suffix 要查找的后缀
|
||||
* @return 如果字符序列以该后缀结尾(不区分大小写),或两者均为{@code null},则返回{@code true}
|
||||
*/
|
||||
public static boolean endsWithIgnoreCase(final CharSequence str, final CharSequence suffix)
|
||||
{
|
||||
return Strings.CI.endsWith(str, suffix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定范围内查找字符串,忽略大小写
|
||||
*
|
||||
* @param str 要检查的字符串
|
||||
* @param searchStr 要查找的字符串
|
||||
* @return 搜索字符串的第一个索引,如果未找到匹配项则返回 -1
|
||||
*/
|
||||
public static int indexOfIgnoreCase(final CharSequence str, final CharSequence searchStr)
|
||||
{
|
||||
return Strings.CI.indexOf(str, searchStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares given {@code string} to a CharSequences vararg of {@code searchStrings},
|
||||
* returning {@code true} if the {@code string} is equal to any of the {@code searchStrings}, ignoring case.
|
||||
*
|
||||
* @param string to compare, may be {@code null}.
|
||||
* @param searchStrings a vararg of strings, may be {@code null}.
|
||||
* @return {@code true} if the string is equal (case-insensitive) to any other element of {@code searchStrings};
|
||||
*/
|
||||
public static boolean equalsAnyIgnoreCase(final CharSequence string, final CharSequence... searchStrings)
|
||||
{
|
||||
return Strings.CI.equalsAny(string, searchStrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转下划线命名
|
||||
*/
|
||||
@@ -464,6 +735,22 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除最后一个字符串
|
||||
*
|
||||
* @param str 输入字符串
|
||||
* @param spit 以什么类型结尾的
|
||||
* @return 截取后的字符串
|
||||
*/
|
||||
public static String lastStringDel(String str, String spit)
|
||||
{
|
||||
if (!StringUtils.isEmpty(str) && str.endsWith(spit))
|
||||
{
|
||||
return str.subSequence(0, str.length() - 1).toString();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
|
||||
*
|
||||
|
||||
@@ -7,13 +7,13 @@ import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Date;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.poi.ss.usermodel.DateUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import com.ruoyi.common.core.utils.DateUtils;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
|
||||
|
||||
@@ -7,12 +7,17 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.ruoyi.common.core.constant.HttpStatus;
|
||||
import com.ruoyi.common.core.utils.DateUtils;
|
||||
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.page.PageDomain;
|
||||
import com.ruoyi.common.core.web.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.web.page.TableSupport;
|
||||
|
||||
/**
|
||||
* web层通用数据处理
|
||||
@@ -48,6 +53,19 @@ public class BaseController
|
||||
PageUtils.startPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求排序数据
|
||||
*/
|
||||
protected void startOrderBy()
|
||||
{
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
|
||||
{
|
||||
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
|
||||
PageHelper.orderBy(orderBy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理分页的线程变量
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,15 +20,21 @@
|
||||
<!-- Druid -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||
<artifactId>druid-spring-boot-4-starter</artifactId>
|
||||
<version>${druid.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Dynamic DataSource -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
<artifactId>dynamic-datasource-spring-boot4-starter</artifactId>
|
||||
<version>${dynamic-ds.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>mybatis-spring</artifactId>
|
||||
<groupId>org.mybatis</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.ruoyi.common.redis.configure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
@@ -15,15 +14,15 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@AutoConfigureBefore(RedisAutoConfiguration.class)
|
||||
@SuppressWarnings("deprecation")
|
||||
public class RedisConfig extends CachingConfigurerSupport
|
||||
{
|
||||
@Bean
|
||||
@Bean(name = "ruoyiRedisTemplate")
|
||||
@Primary
|
||||
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
|
||||
public RedisTemplate<Object, Object> ruoyiRedisTemplate(RedisConnectionFactory connectionFactory)
|
||||
{
|
||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.ruoyi.common.security.annotation;
|
||||
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
@@ -17,6 +18,7 @@ public @interface EnableRyFeignClients
|
||||
{
|
||||
String[] value() default {};
|
||||
|
||||
@AliasFor(annotation = EnableFeignClients.class, attribute = "basePackages")
|
||||
String[] basePackages() default { "com.ruoyi" };
|
||||
|
||||
Class<?>[] basePackageClasses() default {};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.ruoyi.common.security.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import java.util.TimeZone;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
@@ -15,8 +16,11 @@ public class ApplicationConfig
|
||||
* 时区配置
|
||||
*/
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
|
||||
public ObjectMapper objectMapper()
|
||||
{
|
||||
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
|
||||
ObjectMapper objectMapper = JsonMapper.builder().build();
|
||||
objectMapper.findAndRegisterModules();
|
||||
objectMapper.setTimeZone(TimeZone.getDefault());
|
||||
return objectMapper;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<!-- SpringBoot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringDoc webmvc -->
|
||||
|
||||
@@ -2,8 +2,6 @@ package com.ruoyi.common.swagger.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.springdoc.core.configuration.SpringDocConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@@ -21,7 +19,6 @@ import io.swagger.v3.oas.models.servers.Server;
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@AutoConfiguration(before = SpringDocConfiguration.class)
|
||||
@EnableConfigurationProperties(SpringDocProperties.class)
|
||||
@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class SpringDocAutoConfiguration
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.ruoyi.gateway;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* 网关启动程序
|
||||
|
||||
@@ -3,12 +3,12 @@ package com.ruoyi.gateway.handler;
|
||||
import org.springframework.cloud.gateway.support.NotFoundException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebExceptionHandler;
|
||||
import com.ruoyi.common.core.utils.ServletUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -19,7 +19,7 @@ import reactor.core.publisher.Mono;
|
||||
*/
|
||||
@Order(-1)
|
||||
@Configuration
|
||||
public class GatewayExceptionHandler implements ErrorWebExceptionHandler
|
||||
public class GatewayExceptionHandler implements WebExceptionHandler
|
||||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<!-- SpringBoot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Minio -->
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.ruoyi.file;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration;
|
||||
|
||||
/**
|
||||
* 文件服务
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -228,11 +230,7 @@ public class GenTableServiceImpl implements IGenTableService
|
||||
@Override
|
||||
public byte[] downloadCode(String tableName)
|
||||
{
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
ZipOutputStream zip = new ZipOutputStream(outputStream);
|
||||
generatorCode(tableName, zip);
|
||||
IOUtils.closeQuietly(zip);
|
||||
return outputStream.toByteArray();
|
||||
return downloadCode(new String[] { tableName });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,9 +341,14 @@ public class GenTableServiceImpl implements IGenTableService
|
||||
{
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
ZipOutputStream zip = new ZipOutputStream(outputStream);
|
||||
Map<String, StringBuffer> typeFiles = new HashMap<>();
|
||||
for (String tableName : tableNames)
|
||||
{
|
||||
generatorCode(tableName, zip);
|
||||
generatorCode(tableName, zip, typeFiles);
|
||||
}
|
||||
for (Map.Entry<String, StringBuffer> entry : typeFiles.entrySet())
|
||||
{
|
||||
writeToZip(zip, entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
IOUtils.closeQuietly(zip);
|
||||
return outputStream.toByteArray();
|
||||
@@ -354,7 +357,7 @@ public class GenTableServiceImpl implements IGenTableService
|
||||
/**
|
||||
* 查询表信息并生成代码
|
||||
*/
|
||||
private void generatorCode(String tableName, ZipOutputStream zip)
|
||||
private void generatorCode(String tableName, ZipOutputStream zip, Map<String, StringBuffer> typeFiles)
|
||||
{
|
||||
// 查询表信息
|
||||
GenTable table = genTableMapper.selectGenTableByName(tableName);
|
||||
@@ -375,22 +378,49 @@ public class GenTableServiceImpl implements IGenTableService
|
||||
StringWriter sw = new StringWriter();
|
||||
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
|
||||
tpl.merge(context, sw);
|
||||
try
|
||||
String fileName = VelocityUtils.getFileName(template, table);
|
||||
// index-bak.ts 模版,追加内容
|
||||
if (fileName.contains("index-bak.ts"))
|
||||
{
|
||||
// 添加到zip
|
||||
zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
|
||||
IOUtils.write(sw.toString(), zip, Constants.UTF8);
|
||||
IOUtils.closeQuietly(sw);
|
||||
zip.flush();
|
||||
zip.closeEntry();
|
||||
if (!typeFiles.containsKey(fileName))
|
||||
{
|
||||
typeFiles.put(fileName, new StringBuffer(sw.toString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrays.stream(sw.toString().split("\n")).filter(line -> line.startsWith("export * from")).forEach(line -> typeFiles.get(fileName).append("\n").append(line));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
else
|
||||
{
|
||||
log.error("渲染模板失败,表名:" + table.getTableName(), e);
|
||||
// 其他文件正常添加
|
||||
writeToZip(zip, fileName, sw.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串内容写入ZIP输出流
|
||||
*
|
||||
* @param zip ZIP输出流
|
||||
* @param fileName ZIP条目名称(即文件名)
|
||||
* @param content 要写入的内容
|
||||
*/
|
||||
private void writeToZip(ZipOutputStream zip, String fileName, String content)
|
||||
{
|
||||
try
|
||||
{
|
||||
zip.putNextEntry(new ZipEntry(fileName));
|
||||
IOUtils.write(content, zip, Constants.UTF8);
|
||||
zip.flush();
|
||||
zip.closeEntry();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.error("写入ZIP文件失败,文件名: " + fileName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存参数校验
|
||||
*
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -43,14 +43,8 @@
|
||||
|
||||
<!-- Quartz -->
|
||||
<dependency>
|
||||
<groupId>org.quartz-scheduler</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.mchange</groupId>
|
||||
<artifactId>c3p0</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Mysql Connector -->
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ruoyi",
|
||||
"version": "3.6.7",
|
||||
"version": "3.6.8",
|
||||
"description": "若依管理系统",
|
||||
"author": "若依",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -74,6 +74,8 @@
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis !important;
|
||||
white-space: nowrap !important;
|
||||
height: 44px !important;
|
||||
line-height: 44px !important;
|
||||
}
|
||||
|
||||
// menu hover
|
||||
@@ -105,6 +107,96 @@
|
||||
background-color: $base-sub-menu-hover !important;
|
||||
}
|
||||
}
|
||||
|
||||
// theme-dark 深色主题
|
||||
&.theme-dark {
|
||||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.4);
|
||||
border-right: none;
|
||||
|
||||
.el-menu-item.is-active {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: var(--current-color-dark-bg, rgba(64, 158, 255, 0.2));
|
||||
border-right: 3px solid var(--current-color, #409eff);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.el-submenu.is-active > .el-submenu__title {
|
||||
color: var(--current-color, #409eff) !important;
|
||||
}
|
||||
|
||||
.el-menu-item:not(.is-active),
|
||||
.submenu-title-noDropdown,
|
||||
.el-submenu__title {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: transparent;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
background-color: var(--current-color-dark-bg, rgba(64, 158, 255, 0.2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// theme-light 浅色主题
|
||||
&.theme-light {
|
||||
border-right: 1px solid #e8eaf0;
|
||||
box-shadow: none;
|
||||
|
||||
.el-menu-item,
|
||||
.el-submenu__title {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
.el-menu-item.is-active {
|
||||
color: var(--current-color, #409eff) !important;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-color: var(--current-color-light, #ecf5ff);
|
||||
border-right: 3px solid var(--current-color, #409eff);
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.el-submenu.is-active > .el-submenu__title {
|
||||
color: var(--current-color, #409eff) !important;
|
||||
}
|
||||
|
||||
.el-menu-item:not(.is-active):hover,
|
||||
.submenu-title-noDropdown:hover,
|
||||
.el-submenu__title:hover {
|
||||
background-color: #f5f7fa !important;
|
||||
color: rgba(0, 0, 0, 0.85) !important;
|
||||
}
|
||||
|
||||
.nest-menu .el-submenu > .el-submenu__title,
|
||||
.el-submenu .el-menu-item {
|
||||
background-color: #fafafa !important;
|
||||
|
||||
&:hover {
|
||||
background-color: #f0f5ff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hideSidebar {
|
||||
|
||||
@@ -9,32 +9,17 @@ $yellow:#FEC171;
|
||||
$panGreen: #30B08F;
|
||||
|
||||
// 默认菜单主题风格
|
||||
$base-menu-color:#bfcbd9;
|
||||
$base-menu-color-active:#f4f4f5;
|
||||
$base-menu-background:#304156;
|
||||
$base-menu-color: #bfcbd9;
|
||||
$base-menu-color-active: #ffffff;
|
||||
$base-menu-background: #1a1f2e;
|
||||
$base-logo-title-color: #ffffff;
|
||||
|
||||
$base-menu-light-color:rgba(0,0,0,.70);
|
||||
$base-menu-light-background:#ffffff;
|
||||
$base-logo-light-title-color: #001529;
|
||||
|
||||
$base-sub-menu-background:#1f2d3d;
|
||||
$base-sub-menu-hover:#001528;
|
||||
|
||||
// 自定义暗色菜单风格
|
||||
/**
|
||||
$base-menu-color:hsla(0,0%,100%,.65);
|
||||
$base-menu-color-active:#fff;
|
||||
$base-menu-background:#001529;
|
||||
$base-logo-title-color: #ffffff;
|
||||
|
||||
$base-menu-light-color:rgba(0,0,0,.70);
|
||||
$base-menu-light-background:#ffffff;
|
||||
$base-logo-light-title-color: #001529;
|
||||
|
||||
$base-sub-menu-background:#000c17;
|
||||
$base-sub-menu-hover:#001528;
|
||||
*/
|
||||
$base-sub-menu-background: #141824;
|
||||
$base-sub-menu-hover: rgba(255,255,255,.06);
|
||||
|
||||
$base-sidebar-width: 200px;
|
||||
|
||||
|
||||
@@ -1,170 +1,170 @@
|
||||
<template>
|
||||
<el-color-picker
|
||||
v-model="theme"
|
||||
:predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
|
||||
class="theme-picker"
|
||||
popper-class="theme-picker-dropdown"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const ORIGINAL_THEME = '#409EFF' // default color
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
chalk: '', // content of theme-chalk css
|
||||
theme: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
defaultTheme() {
|
||||
return this.$store.state.settings.theme
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
defaultTheme: {
|
||||
handler: function(val, oldVal) {
|
||||
this.theme = val
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
async theme(val) {
|
||||
await this.setTheme(val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if(this.defaultTheme !== ORIGINAL_THEME) {
|
||||
this.setTheme(this.defaultTheme)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async setTheme(val) {
|
||||
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
|
||||
if (typeof val !== 'string') return
|
||||
const themeCluster = this.getThemeCluster(val.replace('#', ''))
|
||||
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
|
||||
|
||||
const getHandler = (variable, id) => {
|
||||
return () => {
|
||||
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
|
||||
const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
|
||||
|
||||
let styleTag = document.getElementById(id)
|
||||
if (!styleTag) {
|
||||
styleTag = document.createElement('style')
|
||||
styleTag.setAttribute('id', id)
|
||||
document.head.appendChild(styleTag)
|
||||
}
|
||||
styleTag.innerText = newStyle
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.chalk) {
|
||||
const url = `/styles/theme-chalk/index.css`
|
||||
await this.getCSSString(url, 'chalk')
|
||||
}
|
||||
|
||||
const chalkHandler = getHandler('chalk', 'chalk-style')
|
||||
chalkHandler()
|
||||
|
||||
const styles = [].slice.call(document.querySelectorAll('style'))
|
||||
.filter(style => {
|
||||
const text = style.innerText
|
||||
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
|
||||
})
|
||||
styles.forEach(style => {
|
||||
const { innerText } = style
|
||||
if (typeof innerText !== 'string') return
|
||||
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
|
||||
})
|
||||
|
||||
this.$emit('change', val)
|
||||
},
|
||||
|
||||
updateStyle(style, oldCluster, newCluster) {
|
||||
let newStyle = style
|
||||
oldCluster.forEach((color, index) => {
|
||||
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
|
||||
})
|
||||
return newStyle
|
||||
},
|
||||
|
||||
getCSSString(url, variable) {
|
||||
return new Promise(resolve => {
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
xhr.open('GET', url)
|
||||
xhr.send()
|
||||
})
|
||||
},
|
||||
|
||||
getThemeCluster(theme) {
|
||||
const tintColor = (color, tint) => {
|
||||
let red = parseInt(color.slice(0, 2), 16)
|
||||
let green = parseInt(color.slice(2, 4), 16)
|
||||
let blue = parseInt(color.slice(4, 6), 16)
|
||||
|
||||
if (tint === 0) { // when primary color is in its rgb space
|
||||
return [red, green, blue].join(',')
|
||||
} else {
|
||||
red += Math.round(tint * (255 - red))
|
||||
green += Math.round(tint * (255 - green))
|
||||
blue += Math.round(tint * (255 - blue))
|
||||
|
||||
red = red.toString(16)
|
||||
green = green.toString(16)
|
||||
blue = blue.toString(16)
|
||||
|
||||
return `#${red}${green}${blue}`
|
||||
}
|
||||
}
|
||||
|
||||
const shadeColor = (color, shade) => {
|
||||
let red = parseInt(color.slice(0, 2), 16)
|
||||
let green = parseInt(color.slice(2, 4), 16)
|
||||
let blue = parseInt(color.slice(4, 6), 16)
|
||||
|
||||
red = Math.round((1 - shade) * red)
|
||||
green = Math.round((1 - shade) * green)
|
||||
blue = Math.round((1 - shade) * blue)
|
||||
|
||||
red = red.toString(16)
|
||||
green = green.toString(16)
|
||||
blue = blue.toString(16)
|
||||
|
||||
return `#${red}${green}${blue}`
|
||||
}
|
||||
|
||||
const clusters = [theme]
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
|
||||
}
|
||||
clusters.push(shadeColor(theme, 0.1))
|
||||
return clusters
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.theme-message,
|
||||
.theme-picker-dropdown {
|
||||
z-index: 99999 !important;
|
||||
}
|
||||
|
||||
.theme-picker .el-color-picker__trigger {
|
||||
height: 26px !important;
|
||||
width: 26px !important;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.theme-picker-dropdown .el-color-dropdown__link-btn {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<el-color-picker
|
||||
v-model="theme"
|
||||
:predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
|
||||
class="theme-picker"
|
||||
popper-class="theme-picker-dropdown"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const ORIGINAL_THEME = '#409EFF' // default color
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
chalk: '', // content of theme-chalk css
|
||||
theme: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
defaultTheme() {
|
||||
return this.$store.state.settings.theme
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
defaultTheme: {
|
||||
handler: function(val, oldVal) {
|
||||
this.theme = val
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
async theme(val) {
|
||||
await this.setTheme(val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if(this.defaultTheme !== ORIGINAL_THEME) {
|
||||
this.setTheme(this.defaultTheme)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async setTheme(val) {
|
||||
const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
|
||||
if (typeof val !== 'string') return
|
||||
const themeCluster = this.getThemeCluster(val.replace('#', ''))
|
||||
const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
|
||||
|
||||
const getHandler = (variable, id) => {
|
||||
return () => {
|
||||
const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
|
||||
const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
|
||||
|
||||
let styleTag = document.getElementById(id)
|
||||
if (!styleTag) {
|
||||
styleTag = document.createElement('style')
|
||||
styleTag.setAttribute('id', id)
|
||||
document.head.appendChild(styleTag)
|
||||
}
|
||||
styleTag.innerText = newStyle
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.chalk) {
|
||||
const url = `/styles/theme-chalk/index.css`
|
||||
await this.getCSSString(url, 'chalk')
|
||||
}
|
||||
|
||||
const chalkHandler = getHandler('chalk', 'chalk-style')
|
||||
chalkHandler()
|
||||
|
||||
const styles = [].slice.call(document.querySelectorAll('style'))
|
||||
.filter(style => {
|
||||
const text = style.innerText
|
||||
return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
|
||||
})
|
||||
styles.forEach(style => {
|
||||
const { innerText } = style
|
||||
if (typeof innerText !== 'string') return
|
||||
style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
|
||||
})
|
||||
|
||||
this.$emit('change', val)
|
||||
},
|
||||
|
||||
updateStyle(style, oldCluster, newCluster) {
|
||||
let newStyle = style
|
||||
oldCluster.forEach((color, index) => {
|
||||
newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
|
||||
})
|
||||
return newStyle
|
||||
},
|
||||
|
||||
getCSSString(url, variable) {
|
||||
return new Promise(resolve => {
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
|
||||
resolve()
|
||||
}
|
||||
}
|
||||
xhr.open('GET', url)
|
||||
xhr.send()
|
||||
})
|
||||
},
|
||||
|
||||
getThemeCluster(theme) {
|
||||
const tintColor = (color, tint) => {
|
||||
let red = parseInt(color.slice(0, 2), 16)
|
||||
let green = parseInt(color.slice(2, 4), 16)
|
||||
let blue = parseInt(color.slice(4, 6), 16)
|
||||
|
||||
if (tint === 0) { // when primary color is in its rgb space
|
||||
return [red, green, blue].join(',')
|
||||
} else {
|
||||
red += Math.round(tint * (255 - red))
|
||||
green += Math.round(tint * (255 - green))
|
||||
blue += Math.round(tint * (255 - blue))
|
||||
|
||||
red = red.toString(16)
|
||||
green = green.toString(16)
|
||||
blue = blue.toString(16)
|
||||
|
||||
return `#${red}${green}${blue}`
|
||||
}
|
||||
}
|
||||
|
||||
const shadeColor = (color, shade) => {
|
||||
let red = parseInt(color.slice(0, 2), 16)
|
||||
let green = parseInt(color.slice(2, 4), 16)
|
||||
let blue = parseInt(color.slice(4, 6), 16)
|
||||
|
||||
red = Math.round((1 - shade) * red)
|
||||
green = Math.round((1 - shade) * green)
|
||||
blue = Math.round((1 - shade) * blue)
|
||||
|
||||
red = red.toString(16)
|
||||
green = green.toString(16)
|
||||
blue = blue.toString(16)
|
||||
|
||||
return `#${red}${green}${blue}`
|
||||
}
|
||||
|
||||
const clusters = [theme]
|
||||
for (let i = 0; i <= 9; i++) {
|
||||
clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
|
||||
}
|
||||
clusters.push(shadeColor(theme, 0.1))
|
||||
return clusters
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.theme-message,
|
||||
.theme-picker-dropdown {
|
||||
z-index: 99999 !important;
|
||||
}
|
||||
|
||||
.theme-picker .el-color-picker__trigger {
|
||||
height: 26px !important;
|
||||
width: 26px !important;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.theme-picker-dropdown .el-color-dropdown__link-btn {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
|
||||
<div :class="['sidebar-theme-wrapper', {'has-logo':showLogo}, settings.sideTheme]" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
|
||||
<logo v-if="showLogo" :collapse="isCollapse" />
|
||||
<el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
|
||||
<el-menu
|
||||
|
||||
@@ -41,7 +41,10 @@
|
||||
<el-dropdown-item command="closeLeft" :disabled="isFirstView()" icon="el-icon-back">关闭左侧</el-dropdown-item>
|
||||
<el-dropdown-item command="closeRight" :disabled="isLastView()" icon="el-icon-right">关闭右侧</el-dropdown-item>
|
||||
<el-dropdown-item command="closeAll" icon="el-icon-circle-close">全部关闭</el-dropdown-item>
|
||||
<el-dropdown-item command="fullscreen" icon="el-icon-full-screen" divided>全屏显示</el-dropdown-item>
|
||||
<el-dropdown-item command="fullscreen" divided>
|
||||
<template v-if="!isFullscreen"><i class="el-icon-full-screen"></i>全屏显示</template>
|
||||
<template v-else><i class="el-icon-close"></i>退出全屏</template>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
||||
@@ -77,7 +80,8 @@ export default {
|
||||
affixTags: [],
|
||||
canScrollLeft: false,
|
||||
canScrollRight: false,
|
||||
isFullscreen: false
|
||||
isFullscreen: false,
|
||||
hiddenElements: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -119,13 +123,19 @@ export default {
|
||||
this.initTags()
|
||||
this.addTags()
|
||||
window.addEventListener('resize', this.updateArrowState)
|
||||
document.addEventListener('fullscreenchange', this.onFullscreenChange)
|
||||
window.addEventListener('keydown', this.handleKeyDown)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', this.updateArrowState)
|
||||
document.removeEventListener('fullscreenchange', this.onFullscreenChange)
|
||||
window.removeEventListener('keydown', this.handleKeyDown)
|
||||
},
|
||||
methods: {
|
||||
handleKeyDown(event) {
|
||||
// 当按下Esc键且处于全屏状态时,退出全屏
|
||||
if (event.key === 'Escape' && this.isFullscreen) {
|
||||
this.toggleFullscreen()
|
||||
}
|
||||
},
|
||||
isActive(route) {
|
||||
return route.path === this.$route.path
|
||||
},
|
||||
@@ -225,18 +235,40 @@ export default {
|
||||
})
|
||||
},
|
||||
toggleFullscreen() {
|
||||
if (!document.fullscreenElement) {
|
||||
const appMain = document.querySelector('.app-main')
|
||||
if (appMain) {
|
||||
appMain.requestFullscreen()
|
||||
}
|
||||
const mainContainer = document.querySelector('.main-container')
|
||||
const navbar = document.querySelector('.navbar')
|
||||
const sidebar = document.querySelector('.sidebar-container')
|
||||
if (!mainContainer) return
|
||||
|
||||
if (!this.isFullscreen) {
|
||||
mainContainer.classList.add('fullscreen-mode')
|
||||
document.body.style.overflow = 'hidden'
|
||||
const elementsToHide = [
|
||||
{ el: navbar, originalDisplay: (navbar && navbar.style.display) || '' },
|
||||
{ el: sidebar, originalDisplay: (sidebar && sidebar.style.display) || '' }
|
||||
]
|
||||
elementsToHide.forEach(item => {
|
||||
if (item.el && item.el.style.display !== 'none') {
|
||||
item.originalDisplay = item.el.style.display
|
||||
item.el.style.display = 'none'
|
||||
this.hiddenElements.push(item)
|
||||
}
|
||||
})
|
||||
this.isFullscreen = true
|
||||
} else {
|
||||
document.exitFullscreen()
|
||||
mainContainer.classList.remove('fullscreen-mode')
|
||||
document.body.style.overflow = ''
|
||||
this.hiddenElements.forEach(item => {
|
||||
if (item.el) {
|
||||
item.el.style.display = item.originalDisplay
|
||||
}
|
||||
})
|
||||
this.hiddenElements = []
|
||||
const btn = document.querySelector('.tags-action-btn')
|
||||
if (btn) btn.blur()
|
||||
this.isFullscreen = false
|
||||
}
|
||||
},
|
||||
onFullscreenChange() {
|
||||
this.isFullscreen = !!document.fullscreenElement
|
||||
},
|
||||
handleDropdownCommand(command) {
|
||||
const tag = this.selectedDropdownTag
|
||||
this.selectedTag = tag
|
||||
@@ -505,4 +537,41 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 页签全屏模式样式 */
|
||||
.main-container.fullscreen-mode {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.main-container.fullscreen-mode .fixed-header {
|
||||
display: block !important;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100% !important;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.main-container.fullscreen-mode .fixed-header .navbar {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.main-container.fullscreen-mode .app-main {
|
||||
position: fixed;
|
||||
top: 34px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
height: calc(100vh - 34px) !important;
|
||||
min-height: calc(100vh - 34px) !important;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
|
||||
<div :class="classObj" class="app-wrapper" :style="{'--current-color': theme, '--current-color-light': theme + '1a', '--current-color-dark-bg': theme + '33'}">
|
||||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
||||
<sidebar v-if="!sidebar.hide" class="sidebar-container"/>
|
||||
<div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
|
||||
|
||||
@@ -5,6 +5,10 @@ export default {
|
||||
// 刷新当前tab页签
|
||||
refreshPage(obj) {
|
||||
const { path, query, matched } = router.currentRoute
|
||||
// 防止在重定向过程中重复刷新
|
||||
if (path.startsWith('/redirect/')) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
if (obj === undefined) {
|
||||
matched.forEach((m) => {
|
||||
if (m.components && m.components.default && m.components.default.name) {
|
||||
|
||||
@@ -108,6 +108,41 @@
|
||||
<span>更新日志</span>
|
||||
</div>
|
||||
<el-collapse accordion>
|
||||
<el-collapse-item title="v3.6.8 - 2026-03-30">
|
||||
<ol>
|
||||
<li>新增锁定屏幕功能</li>
|
||||
<li>首页新增通知公告消息提醒</li>
|
||||
<li>添加持久化标签页开关功能</li>
|
||||
<li>菜单搜索支持文本高亮&数量提示</li>
|
||||
<li>添加菜单路由地址和名称的校验规则</li>
|
||||
<li>字典类型列表新增抽屉效果详细信息</li>
|
||||
<li>升级axios到最新版本0.30.3</li>
|
||||
<li>升级spring-cloud到最新版2025.1.0</li>
|
||||
<li>升级spring-cloud-alibaba到最新版2025.1.0.0</li>
|
||||
<li>升级spring-boot-admin到最新版4.0.2</li>
|
||||
<li>升级dynamic-ds到最新版本4.5.0</li>
|
||||
<li>升级springdoc到最新版本3.0.2</li>
|
||||
<li>升级transmittable-thread-local到最新版本2.14.5</li>
|
||||
<li>升级spring-boot到最新版本4.0.3</li>
|
||||
<li>升级druid到最新版本1.2.28</li>
|
||||
<li>升级pagehelper到最新版2.1.1</li>
|
||||
<li>优化操作日志详细页面</li>
|
||||
<li>部门管理支持批量保存排序</li>
|
||||
<li>菜单管理支持批量保存排序</li>
|
||||
<li>菜单管理列表新增类型显示</li>
|
||||
<li>代码生成模板支持TypeScript版本</li>
|
||||
<li>优化菜单主题风格显示</li>
|
||||
<li>优化点击任务名称查看详细</li>
|
||||
<li>优化字典类型属性提醒说明</li>
|
||||
<li>优化防重提交间隔时间可自定义</li>
|
||||
<li>优化页签功能&支持全屏按钮操作</li>
|
||||
<li>优化RightToolbar搜索栏切换动画</li>
|
||||
<li>修复Excel自定义格式样式污染问题</li>
|
||||
<li>优化isAdmin方法统一到SecurityUtils</li>
|
||||
<li>优化定时任务详情页展示&补充执行时间字段</li>
|
||||
<li>其他细节优化</li>
|
||||
</ol>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="v3.6.7 - 2025-12-22">
|
||||
<ol>
|
||||
<li>支持防盗链功能</li>
|
||||
@@ -987,7 +1022,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
// 版本号
|
||||
version: "3.6.7"
|
||||
version: "3.6.8"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -66,10 +66,19 @@
|
||||
:default-expand-all="isExpandAll"
|
||||
:tree-props="{children: 'children', hasChildren: 'hasChildren'}"
|
||||
>
|
||||
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
|
||||
<el-table-column prop="icon" label="图标" align="center" width="100">
|
||||
<el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="220">
|
||||
<template slot-scope="scope">
|
||||
<svg-icon :icon-class="scope.row.icon" />
|
||||
<svg-icon :icon-class="scope.row.icon" />
|
||||
<span class="ml5">{{ scope.row.menuName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="menuName" label="类型" :show-overflow-tooltip="true" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.menuType === 'M' && scope.row.isFrame === '0'" type="danger" size="small">外链</el-tag>
|
||||
<el-tag v-else-if="scope.row.menuType === 'M'" type="primary" size="small">目录</el-tag>
|
||||
<el-tag v-else-if="scope.row.menuType === 'C' && scope.row.isFrame === '0'" type="danger" size="small">外链</el-tag>
|
||||
<el-tag v-else-if="scope.row.menuType === 'C'" type="success" size="small">菜单</el-tag>
|
||||
<el-tag v-else-if="scope.row.menuType === 'F'" type="warning" size="small">按钮</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="orderNum" label="排序" width="200">
|
||||
@@ -77,16 +86,11 @@
|
||||
<el-input-number v-model="scope.row.orderNum" controls-position="right" :min="0" size="mini" style="width: 88px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
|
||||
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
|
||||
<el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true" />
|
||||
<el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true" />
|
||||
<el-table-column prop="status" label="状态" width="80">
|
||||
<template slot-scope="scope">
|
||||
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" align="center" prop="createTime">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
<dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-visual</artifactId>
|
||||
<version>3.6.7</version>
|
||||
<version>3.6.8</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<!-- SpringBoot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Security -->
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
|
||||
|
||||
/**
|
||||
* 监控权限配置
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
|
||||
@@ -34,7 +34,7 @@ CREATE TABLE `config_info` (
|
||||
|
||||
insert into config_info(id, data_id, group_id, content, md5, gmt_create, gmt_modified, src_user, src_ip, app_name, tenant_id, c_desc, c_use, effect, type, c_schema, encrypted_data_key) values
|
||||
(1,'application-dev.yml','DEFAULT_GROUP','spring:\n autoconfigure:\n exclude: com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure\n\n# feign 配置\nfeign:\n sentinel:\n enabled: true\n okhttp:\n enabled: true\n httpclient:\n enabled: false\n client:\n config:\n default:\n connectTimeout: 10000\n readTimeout: 10000\n compression:\n request:\n enabled: true\n min-request-size: 8192\n response:\n enabled: true\n\n# 暴露监控端点\nmanagement:\n endpoints:\n web:\n exposure:\n include: \'*\'\n','9928f41dfb10386ad38b3254af5692e0','2020-05-20 12:00:00','2024-08-29 12:14:45','nacos','0:0:0:0:0:0:0:1','','','通用配置','null','null','yaml','',''),
|
||||
(2,'ruoyi-gateway-dev.yml','DEFAULT_GROUP','spring:\n data:\n redis:\n host: localhost\n port: 6379\n password: \n cloud:\n gateway:\n server:\n webflux:\n discovery:\n locator:\n lowerCaseServiceId: true\n enabled: true\n routes:\n # 认证中心\n - id: ruoyi-auth\n uri: lb://ruoyi-auth\n predicates:\n - Path=/auth/**\n filters:\n # 验证码处理\n - CacheRequestBody\n - ValidateCodeFilter\n - StripPrefix=1\n # 代码生成\n - id: ruoyi-gen\n uri: lb://ruoyi-gen\n predicates:\n - Path=/code/**\n filters:\n - StripPrefix=1\n # 定时任务\n - id: ruoyi-job\n uri: lb://ruoyi-job\n predicates:\n - Path=/schedule/**\n filters:\n - StripPrefix=1\n # 系统模块\n - id: ruoyi-system\n uri: lb://ruoyi-system\n predicates:\n - Path=/system/**\n filters:\n - StripPrefix=1\n # 文件服务\n - id: ruoyi-file\n uri: lb://ruoyi-file\n predicates:\n - Path=/file/**\n filters:\n - StripPrefix=1\n\n# 安全配置\nsecurity:\n # 验证码\n captcha:\n enabled: true\n type: math\n # 防止XSS攻击\n xss:\n enabled: true\n excludeUrls:\n - /system/notice\n\n # 不校验白名单\n ignore:\n whites:\n - /auth/logout\n - /auth/login\n - /auth/register\n - /*/v2/api-docs\n - /*/v3/api-docs\n - /csrf\n\n# springdoc配置\nspringdoc:\n webjars:\n # 访问前缀\n prefix:\n','1650061c268e8065f4ca40a1ee99808d','2020-05-14 14:17:55','2026-03-10 10:57:46','nacos_namespace_migrate','192.168.137.1','','','网关模块',NULL,NULL,'yaml',NULL,''),
|
||||
(2,'ruoyi-gateway-dev.yml','DEFAULT_GROUP','spring:\n data:\n redis:\n host: localhost\n port: 6379\n password: \n cloud:\n gateway:\n server:\n webflux:\n discovery:\n locator:\n lowerCaseServiceId: true\n enabled: true\n routes:\n # 认证中心\n - id: ruoyi-auth\n uri: lb://ruoyi-auth\n predicates:\n - Path=/auth/**\n filters:\n # 验证码处理\n - name: CacheRequestBody\n args:\n bodyClass: java.lang.String\n - ValidateCodeFilter\n - StripPrefix=1\n # 代码生成\n - id: ruoyi-gen\n uri: lb://ruoyi-gen\n predicates:\n - Path=/code/**\n filters:\n - StripPrefix=1\n # 定时任务\n - id: ruoyi-job\n uri: lb://ruoyi-job\n predicates:\n - Path=/schedule/**\n filters:\n - StripPrefix=1\n # 系统模块\n - id: ruoyi-system\n uri: lb://ruoyi-system\n predicates:\n - Path=/system/**\n filters:\n - StripPrefix=1\n # 文件服务\n - id: ruoyi-file\n uri: lb://ruoyi-file\n predicates:\n - Path=/file/**\n filters:\n - StripPrefix=1\n\n# 安全配置\nsecurity:\n # 验证码\n captcha:\n enabled: true\n type: math\n # 防止XSS攻击\n xss:\n enabled: true\n excludeUrls:\n - /system/notice\n\n # 不校验白名单\n ignore:\n whites:\n - /auth/logout\n - /auth/login\n - /auth/register\n - /*/v2/api-docs\n - /*/v3/api-docs\n - /csrf\n\n# springdoc配置\nspringdoc:\n webjars:\n # 访问前缀\n prefix:\n','1650061c268e8065f4ca40a1ee99808d','2020-05-14 14:17:55','2026-03-10 10:57:46','nacos_namespace_migrate','192.168.137.1','','','网关模块',NULL,NULL,'yaml',NULL,''),
|
||||
(3,'ruoyi-auth-dev.yml','DEFAULT_GROUP','spring:\n data:\n redis:\n host: localhost\n port: 6379\n password: \n','72565b1a725e013154ee57c8fd3045c4','2020-11-20 00:00:00','2024-09-14 04:49:42','nacos','0:0:0:0:0:0:0:1','','','认证中心','null','null','yaml','',''),
|
||||
(4,'ruoyi-monitor-dev.yml','DEFAULT_GROUP','# spring\nspring:\n security:\n user:\n name: ruoyi\n password: 123456\n boot:\n admin:\n ui:\n title: 若依服务状态监控\n','6f122fd2bfb8d45f858e7d6529a9cd44','2020-11-20 00:00:00','2024-08-29 12:15:11','nacos','0:0:0:0:0:0:0:1','','','监控中心','null','null','yaml','',''),
|
||||
(5,'ruoyi-system-dev.yml','DEFAULT_GROUP','# spring配置\nspring:\n data:\n redis:\n host: localhost\n port: 6379\n password: \n datasource:\n druid:\n stat-view-servlet:\n enabled: true\n loginUsername: ruoyi\n loginPassword: 123456\n dynamic:\n druid:\n initial-size: 5\n min-idle: 5\n maxActive: 20\n maxWait: 60000\n connectTimeout: 30000\n socketTimeout: 60000\n timeBetweenEvictionRunsMillis: 60000\n minEvictableIdleTimeMillis: 300000\n validationQuery: SELECT 1 FROM DUAL\n testWhileIdle: true\n testOnBorrow: false\n testOnReturn: false\n poolPreparedStatements: true\n maxPoolPreparedStatementPerConnectionSize: 20\n filters: stat,slf4j\n connectionProperties: druid.stat.mergeSql\\=true;druid.stat.slowSqlMillis\\=5000\n datasource:\n # 主库数据源\n master:\n driver-class-name: com.mysql.cj.jdbc.Driver\n url: jdbc:mysql://localhost:3306/ry-cloud?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8\n username: root\n password: password\n # 从库数据源\n # slave:\n # username: \n # password: \n # url: \n # driver-class-name: \n\n# mybatis配置\nmybatis:\n # 搜索指定包别名\n typeAliasesPackage: com.ruoyi.system\n # 配置mapper的扫描,找到所有的mapper.xml映射文件\n mapperLocations: classpath:mapper/**/*.xml\n\n# springdoc配置\nspringdoc:\n gatewayUrl: http://localhost:8080/${spring.application.name}\n api-docs:\n # 是否开启接口文档\n enabled: true\n info:\n # 标题\n title: \'系统模块接口文档\'\n # 描述\n description: \'系统模块接口描述\'\n # 作者信息\n contact:\n name: RuoYi\n url: https://ruoyi.vip\n','a79ae256018abb7f3bbaba923baeb6af','2020-11-20 00:00:00','2024-09-14 04:49:54','nacos','0:0:0:0:0:0:0:1','','','系统模块','null','null','yaml','',''),
|
||||
Reference in New Issue
Block a user