Browse Source

Merge remote-tracking branch 'origin/dev' into dev

xingyu 2 years ago
parent
commit
70970eeb18
24 changed files with 517 additions and 282 deletions
  1. 4 4
      README.md
  2. 1 0
      sql/optional/visualization/jimureport.mysql5.7.create.sql
  3. 10 3
      yudao-dependencies/pom.xml
  4. 15 1
      yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
  5. 5 0
      yudao-framework/yudao-spring-boot-starter-web/pom.xml
  6. 37 3
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java
  7. 80 0
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java
  8. 15 0
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java
  9. 5 2
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java
  10. 50 95
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java
  11. 59 0
      yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java
  12. 8 1
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java
  13. 2 0
      yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java
  14. 2 2
      yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java
  15. 3 2
      yudao-module-visualization/yudao-module-visualization-biz/src/main/java/cn/iocoder/yudao/module/visualization/framework/jmreport/config/JmReportConfiguration.java
  16. 72 18
      yudao-module-visualization/yudao-module-visualization-biz/src/main/java/cn/iocoder/yudao/module/visualization/framework/jmreport/core/service/JmReportTokenServiceImpl.java
  17. 1 1
      yudao-ui-admin-vue3/README.md
  18. 11 11
      yudao-ui-admin-vue3/package.json
  19. 127 133
      yudao-ui-admin-vue3/pnpm-lock.yaml
  20. 1 1
      yudao-ui-admin/src/styles/index.scss
  21. 2 2
      yudao-ui-admin/src/views/infra/redis/index.vue
  22. 1 1
      yudao-ui-app/api/auth.js
  23. 1 0
      yudao-ui-app/store/getters.js
  24. 5 2
      yudao-ui-app/utils/request/responseInterceptors.js

+ 4 - 4
README.md

@@ -191,19 +191,19 @@ ps:核心功能已经实现,正在对接微信小程序中...
 | [Spring Boot](https://spring.io/projects/spring-boot)                                       | 应用开发框架           | 2.7.7       | [文档](https://github.com/YunaiV/SpringBoot-Labs)                |
 | [MySQL](https://www.mysql.com/cn/)                                                          | 数据库服务器           | 5.7 / 8.0+  |                                                                |
 | [Druid](https://github.com/alibaba/druid)                                                   | JDBC 连接池、监控组件    | 1.2.15      | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
-| [MyBatis Plus](https://mp.baomidou.com/)                                                    | MyBatis 增强工具包    | 3.5.3       | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao)         |
+| [MyBatis Plus](https://mp.baomidou.com/)                                                    | MyBatis 增强工具包    | 3.5.3.1     | [文档](http://www.iocoder.cn/Spring-Boot/MyBatis/?yudao)         |
 | [Dynamic Datasource](https://dynamic-datasource.com/)                                       | 动态数据源            | 3.6.1       | [文档](http://www.iocoder.cn/Spring-Boot/datasource-pool/?yudao) |
 | [Redis](https://redis.io/)                                                                  | key-value 数据库    | 5.0 / 6.0   |                                                                |
 | [Redisson](https://github.com/redisson/redisson)                                            | Redis 客户端        | 3.18.0      | [文档](http://www.iocoder.cn/Spring-Boot/Redis/?yudao)           |
 | [Spring MVC](https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc) | MVC 框架           | 5.3.24      | [文档](http://www.iocoder.cn/SpringMVC/MVC/?yudao)               |
-| [Spring Security](https://github.com/spring-projects/spring-security)                       | Spring 安全框架      | 5.7.5       | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
+| [Spring Security](https://github.com/spring-projects/spring-security)                       | Spring 安全框架      | 5.7.6       | [文档](http://www.iocoder.cn/Spring-Boot/Spring-Security/?yudao) |
 | [Hibernate Validator](https://github.com/hibernate/hibernate-validator)                     | 参数校验组件           | 6.2.5       | [文档](http://www.iocoder.cn/Spring-Boot/Validation/?yudao)      |
 | [Flowable](https://github.com/flowable/flowable-engine)                                     | 工作流引擎            | 6.8.0       | [文档](https://doc.iocoder.cn/bpm/)                              |
 | [Quartz](https://github.com/quartz-scheduler)                                               | 任务调度组件           | 2.3.2       | [文档](http://www.iocoder.cn/Spring-Boot/Job/?yudao)             |
 | [Knife4j](https://gitee.com/xiaoym/knife4j)                                                 | Swagger 增强 UI 实现 | 3.0.3       | [文档](http://www.iocoder.cn/Spring-Boot/Swagger/?yudao)         |
 | [Resilience4j](https://github.com/resilience4j/resilience4j)                                | 服务保障组件           | 1.7.1       | [文档](http://www.iocoder.cn/Spring-Boot/Resilience4j/?yudao)    |
 | [SkyWalking](https://skywalking.apache.org/)                                                | 分布式应用追踪系统        | 8.12.0      | [文档](http://www.iocoder.cn/Spring-Boot/SkyWalking/?yudao)      |
-| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin)                       | Spring Boot 监控平台 | 2.7.9       | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao)           |
+| [Spring Boot Admin](https://github.com/codecentric/spring-boot-admin)                       | Spring Boot 监控平台 | 2.7.10      | [文档](http://www.iocoder.cn/Spring-Boot/Admin/?yudao)           |
 | [Jackson](https://github.com/FasterXML/jackson)                                             | JSON 工具库         | 2.13.3      |                                                                |
 | [MapStruct](https://mapstruct.org/)                                                         | Java Bean 转换     | 1.5.3.Final | [文档](http://www.iocoder.cn/Spring-Boot/MapStruct/?yudao)       |
 | [Lombok](https://projectlombok.org/)                                                        | 消除冗长的 Java 代码    | 1.18.24     | [文档](http://www.iocoder.cn/Spring-Boot/Lombok/?yudao)          |
@@ -227,7 +227,7 @@ ps:核心功能已经实现,正在对接微信小程序中...
 | [TypeScript](https://www.typescriptlang.org/docs/)                   |  TypeScript  | 4.9.4  |
 | [pinia](https://pinia.vuejs.org/)                                    |    vuex5     | 2.0.28 |
 | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) |     国际化      | 9.2.2  |
-| [vxe-table](https://vxetable.cn/)                                    |   vue最强表单    | 4.3.7  |
+| [vxe-table](https://vxetable.cn/)                                    |   vue最强表单    | 4.3.9  |
 
 ### [管理后台 uni-app 跨端](./yudao-ui-admin-uniapp)
 

+ 1 - 0
sql/optional/visualization/jimureport.mysql5.7.create.sql

@@ -1344,6 +1344,7 @@ CREATE TABLE `jimu_report_share`  (
   `last_update_time` datetime NULL DEFAULT NULL COMMENT '最后更新时间',
   `term_of_validity` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '有效期(0:永久有效,1:1天,2:7天)',
   `status` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否过期(0未过期,1已过期)',
+  `preview_lock_status` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码锁状态',
   PRIMARY KEY (`id`) USING BTREE
 ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '积木报表预览权限表' ROW_FORMAT = Dynamic;
 

+ 10 - 3
yudao-dependencies/pom.xml

@@ -32,7 +32,7 @@
         <resilience4j.version>1.7.1</resilience4j.version>
         <!-- 监控相关 -->
         <skywalking.version>8.12.0</skywalking.version>
-        <spring-boot-admin.version>2.7.9</spring-boot-admin.version>
+        <spring-boot-admin.version>2.7.10</spring-boot-admin.version>
         <opentracing.version>0.33.0</opentracing.version>
         <!-- Test 测试相关 -->
         <podam.version>7.2.11.RELEASE</podam.version>
@@ -41,10 +41,11 @@
         <!-- Bpm 工作流相关 -->
         <flowable.version>6.8.0</flowable.version>
         <!-- 工具类相关 -->
+        <jsoup.version>1.15.3</jsoup.version>
         <lombok.version>1.18.24</lombok.version>
         <mapstruct.version>1.5.3.Final</mapstruct.version>
         <hutool.version>5.8.11</hutool.version>
-        <easyexcel.verion>3.1.4</easyexcel.verion>
+        <easyexcel.verion>3.1.5</easyexcel.verion>
         <velocity.version>2.3</velocity.version>
         <screw.version>1.0.5</screw.version>
         <fastjson.version>1.2.83</fastjson.version>
@@ -63,7 +64,7 @@
         <minio.version>8.4.6</minio.version>
         <aliyun-java-sdk-core.version>4.6.3</aliyun-java-sdk-core.version>
         <aliyun-java-sdk-dysmsapi.version>2.2.1</aliyun-java-sdk-dysmsapi.version>
-        <tencentcloud-sdk-java.version>3.1.660</tencentcloud-sdk-java.version>
+        <tencentcloud-sdk-java.version>3.1.667</tencentcloud-sdk-java.version>
         <justauth.version>1.4.0</justauth.version>
         <jimureport.version>1.5.6</jimureport.version>
         <xercesImpl.version>2.12.2</xercesImpl.version>
@@ -522,6 +523,12 @@
                 <version>${ip2region.version}</version>
             </dependency>
 
+            <dependency>
+                <groupId>org.jsoup</groupId>
+                <artifactId>jsoup</artifactId>
+                <version>${jsoup.version}</version>
+            </dependency>
+
             <!-- 三方云服务相关 -->
             <dependency>
                 <groupId>com.squareup.okio</groupId>

+ 15 - 1
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.framework.mybatis.core.mapper;
 
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -10,6 +9,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import com.baomidou.mybatisplus.extension.toolkit.Db;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Collection;
@@ -92,8 +92,22 @@ public interface BaseMapperX<T> extends BaseMapper<T> {
         entities.forEach(this::insert);
     }
 
+    /**
+     * 批量插入,适合大量数据插入
+     *
+     * @param entities 实体们
+     * @param size     插入数量 Db.saveBatch 默认为1000
+     */
+    default void insertBatch(Collection<T> entities, int size) {
+        Db.saveBatch(entities, size);
+    }
+
     default void updateBatch(T update) {
         update(update, new QueryWrapper<>());
     }
 
+    default void updateBatch(Collection<T> entities, int size) {
+        Db.updateBatchById(entities, size);
+    }
+
 }

+ 5 - 0
yudao-framework/yudao-spring-boot-starter-web/pom.xml

@@ -67,6 +67,11 @@
             <scope>provided</scope> <!-- 设置为 provided,主要是 GlobalExceptionHandler 使用 -->
         </dependency>
 
+        <!-- xss -->
+        <dependency>
+            <groupId>org.jsoup</groupId>
+            <artifactId>jsoup</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 37 - 3
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/YudaoWebAutoConfiguration.java

@@ -2,15 +2,22 @@ package cn.iocoder.yudao.framework.web.config;
 
 import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
 import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
+import cn.iocoder.yudao.framework.web.core.clean.JsoupXssCleaner;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
 import cn.iocoder.yudao.framework.web.core.filter.CacheRequestBodyFilter;
 import cn.iocoder.yudao.framework.web.core.filter.DemoFilter;
 import cn.iocoder.yudao.framework.web.core.filter.XssFilter;
 import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
 import cn.iocoder.yudao.framework.web.core.handler.GlobalResponseBodyHandler;
+import cn.iocoder.yudao.framework.web.core.json.XssStringJsonDeserializer;
 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
@@ -48,7 +55,7 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
      * 设置 API 前缀,仅仅匹配 controller 包下的
      *
      * @param configurer 配置
-     * @param api API 配置
+     * @param api        API 配置
      */
     private void configurePathMatch(PathMatchConfigurer configurer, WebProperties.Api api) {
         AntPathMatcher antPathMatcher = new AntPathMatcher(".");
@@ -104,8 +111,9 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
      * 创建 XssFilter Bean,解决 Xss 安全问题
      */
     @Bean
-    public FilterRegistrationBean<XssFilter> xssFilter(XssProperties properties, PathMatcher pathMatcher) {
-        return createFilterBean(new XssFilter(properties, pathMatcher), WebFilterOrderEnum.XSS_FILTER);
+    @ConditionalOnBean(XssCleaner.class)
+    public FilterRegistrationBean<XssFilter> xssFilter(XssProperties properties, PathMatcher pathMatcher, XssCleaner xssCleaner) {
+        return createFilterBean(new XssFilter(properties, pathMatcher, xssCleaner), WebFilterOrderEnum.XSS_FILTER);
     }
 
     /**
@@ -117,6 +125,32 @@ public class YudaoWebAutoConfiguration implements WebMvcConfigurer {
         return createFilterBean(new DemoFilter(), WebFilterOrderEnum.DEMO_FILTER);
     }
 
+
+    /**
+     * Xss 清理者
+     *
+     * @return XssCleaner
+     */
+    @Bean
+    @ConditionalOnMissingBean(XssCleaner.class)
+    public XssCleaner xssCleaner() {
+        return new JsoupXssCleaner();
+    }
+
+    /**
+     * 注册 Jackson 的序列化器,用于处理 json 类型参数的 xss 过滤
+     *
+     * @return Jackson2ObjectMapperBuilderCustomizer
+     */
+    @Bean
+    @ConditionalOnMissingBean(name = "xssJacksonCustomizer")
+    @ConditionalOnBean(ObjectMapper.class)
+    @ConditionalOnProperty(value = "yudao.xss.enable", havingValue = "true")
+    public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(XssCleaner xssCleaner) {
+        // 在反序列化时进行 xss 过滤,可以替换使用 XssStringJsonSerializer,在序列化时进行处理
+        return builder -> builder.deserializerByType(String.class, new XssStringJsonDeserializer(xssCleaner));
+    }
+
     private static <T extends Filter> FilterRegistrationBean<T> createFilterBean(T filter, Integer order) {
         FilterRegistrationBean<T> bean = new FilterRegistrationBean<>(filter);
         bean.setOrder(order);

+ 80 - 0
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/JsoupXssCleaner.java

@@ -0,0 +1,80 @@
+package cn.iocoder.yudao.framework.web.core.clean;
+
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.safety.Safelist;
+
+/**
+ * jsonp 过滤字符串
+ */
+public class JsoupXssCleaner implements XssCleaner {
+
+    private final Safelist safelist;
+
+    /**
+     * 用于在 src 属性使用相对路径时,强制转换为绝对路径。 为空时不处理,值应为绝对路径的前缀(包含协议部分)
+     */
+    private final String baseUri;
+
+    /**
+     * 无参构造,默认使用 {@link JsoupXssCleaner#buildSafelist} 方法构建一个安全列表
+     */
+    public JsoupXssCleaner() {
+        this.safelist = buildSafelist();
+        this.baseUri = "";
+    }
+
+    public JsoupXssCleaner(Safelist safelist) {
+        this.safelist = safelist;
+        this.baseUri = "";
+    }
+
+    public JsoupXssCleaner(String baseUri) {
+        this.safelist = buildSafelist();
+        this.baseUri = baseUri;
+    }
+
+    public JsoupXssCleaner(Safelist safelist, String baseUri) {
+        this.safelist = safelist;
+        this.baseUri = baseUri;
+    }
+
+    /**
+     * 构建一个 Xss 清理的 Safelist 规则。
+     * 基于 Safelist#relaxed() 的基础上:
+     * 1. 扩展支持了 style 和 class 属性
+     * 2. a 标签额外支持了 target 属性
+     * 3. img 标签额外支持了 data 协议,便于支持 base64
+     *
+     * @return Safelist
+     */
+    private Safelist buildSafelist() {
+        // 使用 jsoup 提供的默认的
+        Safelist relaxedSafelist = Safelist.relaxed();
+        // 富文本编辑时一些样式是使用 style 来进行实现的
+        // 比如红色字体 style="color:red;", 所以需要给所有标签添加 style 属性
+        // 注意:style 属性会有注入风险 <img STYLE="background-image:url(javascript:alert('XSS'))">
+        relaxedSafelist.addAttributes(":all", "style", "class");
+        // 保留 a 标签的 target 属性
+        relaxedSafelist.addAttributes("a", "target");
+        // 支持img 为base64
+        relaxedSafelist.addProtocols("img", "src", "data");
+
+        // 保留相对路径, 保留相对路径时,必须提供对应的 baseUri 属性,否则依然会被删除
+        // WHITELIST.preserveRelativeLinks(false);
+
+        // 移除 a 标签和 img 标签的一些协议限制,这会导致 xss 防注入失效,如 <img src=javascript:alert("xss")>
+        // 虽然可以重写 WhiteList#isSafeAttribute 来处理,但是有隐患,所以暂时不支持相对路径
+        // WHITELIST.removeProtocols("a", "href", "ftp", "http", "https", "mailto");
+        // WHITELIST.removeProtocols("img", "src", "http", "https");
+
+        return relaxedSafelist;
+    }
+
+    @Override
+    public String clean(String html) {
+        return Jsoup.clean(html, baseUri, safelist, new Document.OutputSettings().prettyPrint(false));
+    }
+
+}
+

+ 15 - 0
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/clean/XssCleaner.java

@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.framework.web.core.clean;
+
+/**
+ * 对 html 文本中的有 Xss 风险的数据进行清理
+ */
+public interface XssCleaner {
+
+    /**
+     * 清理有 Xss 风险的文本
+     *
+     * @param html 原 html
+     * @return 清理后的 html
+     */
+    String clean(String html);
+}

+ 5 - 2
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssFilter.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.framework.web.core.filter;
 
 import cn.iocoder.yudao.framework.web.config.XssProperties;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
 import lombok.AllArgsConstructor;
 import org.springframework.util.PathMatcher;
 import org.springframework.web.filter.OncePerRequestFilter;
@@ -13,7 +14,7 @@ import java.io.IOException;
 
 /**
  * Xss 过滤器
- *
+ * <p>
  * 对 Xss 不了解的胖友,可以看看 http://www.iocoder.cn/Fight/The-new-girl-asked-me-why-AJAX-requests-are-not-secure-I-did-not-answer/
  *
  * @author 芋道源码
@@ -30,10 +31,12 @@ public class XssFilter extends OncePerRequestFilter {
      */
     private final PathMatcher pathMatcher;
 
+    private final XssCleaner xssCleaner;
+
     @Override
     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
             throws IOException, ServletException {
-        filterChain.doFilter(new XssRequestWrapper(request), response);
+        filterChain.doFilter(new XssRequestWrapper(request, xssCleaner), response);
     }
 
     @Override

+ 50 - 95
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/XssRequestWrapper.java

@@ -1,21 +1,10 @@
 package cn.iocoder.yudao.framework.web.core.filter;
 
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ReflectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.http.HTMLFilter;
-import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
 
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 /**
@@ -24,113 +13,79 @@ import java.util.Map;
  * @author 芋道源码
  */
 public class XssRequestWrapper extends HttpServletRequestWrapper {
+    private final XssCleaner xssCleaner;
 
-    /**
-     * 基于线程级别的 HTMLFilter 对象,因为它线程非安全
-     */
-    private static final ThreadLocal<HTMLFilter> HTML_FILTER = ThreadLocal.withInitial(() -> {
-        HTMLFilter htmlFilter = new HTMLFilter();
-        // 反射修改 encodeQuotes 属性为 false,避免 " 被转移成 &quot; 字符
-        ReflectUtil.setFieldValue(htmlFilter, "encodeQuotes", false);
-        return htmlFilter;
-    });
-
-    public XssRequestWrapper(HttpServletRequest request) {
+    public XssRequestWrapper(HttpServletRequest request, XssCleaner xssCleaner) {
         super(request);
+        this.xssCleaner = xssCleaner;
     }
 
-    private static String filterXss(String content) {
-        if (StrUtil.isEmpty(content)) {
-            return content;
-        }
-        return HTML_FILTER.get().filter(content);
-    }
-
-    // ========== IO 流相关 ==========
-
+    // ============================ parameter ============================
     @Override
-    public BufferedReader getReader() throws IOException {
-        return new BufferedReader(new InputStreamReader(this.getInputStream()));
+    public Map<String, String[]> getParameterMap() {
+        Map<String, String[]> map = new LinkedHashMap<>();
+        Map<String, String[]> parameters = super.getParameterMap();
+        for (Map.Entry<String, String[]> entry : parameters.entrySet()) {
+            String[] values = entry.getValue();
+            for (int i = 0; i < values.length; i++) {
+                values[i] = xssCleaner.clean(values[i]);
+            }
+            map.put(entry.getKey(), values);
+        }
+        return map;
     }
 
     @Override
-    public ServletInputStream getInputStream() throws IOException {
-        // 如果非 json 请求,不进行 Xss 处理
-        if (!ServletUtils.isJsonRequest(this)) {
-            return super.getInputStream();
+    public String[] getParameterValues(String name) {
+        String[] values = super.getParameterValues(name);
+        if (values == null) {
+            return null;
         }
-
-        // 读取内容,并过滤
-        String content = IoUtil.readUtf8(super.getInputStream());
-        content = filterXss(content);
-        final ByteArrayInputStream newInputStream = new ByteArrayInputStream(content.getBytes());
-        // 返回 ServletInputStream
-        return new ServletInputStream() {
-
-            @Override
-            public int read() {
-                return newInputStream.read();
-            }
-
-            @Override
-            public boolean isFinished() {
-                return true;
-            }
-
-            @Override
-            public boolean isReady() {
-                return true;
-            }
-
-            @Override
-            public void setReadListener(ReadListener readListener) {}
-
-        };
+        int count = values.length;
+        String[] encodedValues = new String[count];
+        for (int i = 0; i < count; i++) {
+            encodedValues[i] = xssCleaner.clean(values[i]);
+        }
+        return encodedValues;
     }
 
-    // ========== Param 相关 ==========
-
     @Override
     public String getParameter(String name) {
         String value = super.getParameter(name);
-        return filterXss(value);
+        if (value == null) {
+            return null;
+        }
+        return xssCleaner.clean(value);
     }
 
+    // ============================ attribute ============================
     @Override
-    public String[] getParameterValues(String name) {
-        String[] values = super.getParameterValues(name);
-        if (ArrayUtil.isEmpty(values)) {
-            return values;
-        }
-        // 过滤处理
-        for (int i = 0; i < values.length; i++) {
-            values[i] = filterXss(values[i]);
+    public Object getAttribute(String name) {
+        Object value = super.getAttribute(name);
+        if (value instanceof String) {
+            xssCleaner.clean((String) value);
         }
-        return values;
+        return value;
     }
 
+    // ============================ header ============================
     @Override
-    public Map<String, String[]> getParameterMap() {
-        Map<String, String[]> valueMap = super.getParameterMap();
-        if (CollUtil.isEmpty(valueMap)) {
-            return valueMap;
-        }
-        // 过滤处理
-        for (Map.Entry<String, String[]> entry : valueMap.entrySet()) {
-            String[] values = entry.getValue();
-            for (int i = 0; i < values.length; i++) {
-                values[i] = filterXss(values[i]);
-            }
+    public String getHeader(String name) {
+        String value = super.getHeader(name);
+        if (value == null) {
+            return null;
         }
-        return valueMap;
+        return xssCleaner.clean(value);
     }
 
-    // ========== Header 相关 ==========
-
+    // ============================ queryString ============================
     @Override
-    public String getHeader(String name) {
-        String value = super.getHeader(name);
-        return filterXss(value);
+    public String getQueryString() {
+        String value = super.getQueryString();
+        if (value == null) {
+            return null;
+        }
+        return xssCleaner.clean(value);
     }
 
 }

+ 59 - 0
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/json/XssStringJsonDeserializer.java

@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.framework.web.core.json;
+
+import cn.iocoder.yudao.framework.web.core.clean.XssCleaner;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+
+/**
+ * XSS 过滤 jackson 反序列化器。
+ * 在反序列化的过程中,会对字符串进行 XSS 过滤。
+ *
+ * @author Hccake
+ */
+@Slf4j
+@AllArgsConstructor
+public class XssStringJsonDeserializer extends StringDeserializer {
+
+    private final XssCleaner xssCleaner;
+
+    @Override
+    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
+        if (p.hasToken(JsonToken.VALUE_STRING)) {
+            return xssCleaner.clean(p.getText());
+        }
+        JsonToken t = p.currentToken();
+        // [databind#381]
+        if (t == JsonToken.START_ARRAY) {
+            return _deserializeFromArray(p, ctxt);
+        }
+        // need to gracefully handle byte[] data, as base64
+        if (t == JsonToken.VALUE_EMBEDDED_OBJECT) {
+            Object ob = p.getEmbeddedObject();
+            if (ob == null) {
+                return null;
+            }
+            if (ob instanceof byte[]) {
+                return ctxt.getBase64Variant().encode((byte[]) ob, false);
+            }
+            // otherwise, try conversion using toString()...
+            return ob.toString();
+        }
+        // 29-Jun-2020, tatu: New! "Scalar from Object" (mostly for XML)
+        if (t == JsonToken.START_OBJECT) {
+            return ctxt.extractScalarFromObject(p, this, _valueClass);
+        }
+
+        if (t.isScalarValue()) {
+            String text = p.getValueAsString();
+            return xssCleaner.clean(text);
+        }
+        return (String) ctxt.handleUnexpectedToken(_valueClass, p);
+    }
+}
+

+ 8 - 1
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/convert/codegen/CodegenConvert.java

@@ -11,9 +11,11 @@ import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenColumnDO;
 import cn.iocoder.yudao.module.infra.dal.dataobject.codegen.CodegenTableDO;
 import com.baomidou.mybatisplus.generator.config.po.TableField;
 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.Mappings;
+import org.mapstruct.Named;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
@@ -37,7 +39,7 @@ public interface CodegenConvert {
 
     @Mappings({
             @Mapping(source = "name", target = "columnName"),
-            @Mapping(source = "type", target = "dataType"),
+            @Mapping(source = "columnType", target = "dataType", qualifiedByName = "getType"),
             @Mapping(source = "comment", target = "columnComment"),
             @Mapping(source = "metaInfo.nullable", target = "nullable"),
             @Mapping(source = "keyFlag", target = "primaryKey"),
@@ -47,6 +49,11 @@ public interface CodegenConvert {
     })
     CodegenColumnDO convert(TableField bean);
 
+    @Named("getType")
+    default String getType(IColumnType jdbcType) {
+        return jdbcType.getType();
+    }
+
     // ========== CodegenTableDO 相关 ==========
 
 //    List<CodegenTableRespVO> convertList02(List<CodegenTableDO> list);

+ 2 - 0
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/dal/dataobject/codegen/CodegenColumnDO.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.infra.enums.codegen.CodegenColumnListConditionEnu
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.generator.config.po.TableField;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -42,6 +43,7 @@ public class CodegenColumnDO extends BaseDO {
     private String columnName;
     /**
      * 字段类型
+     * 关联 {@link TableField#getColumnType()}}
      */
     private String dataType;
     /**

+ 2 - 2
yudao-module-infra/yudao-module-infra-biz/src/test/java/cn/iocoder/yudao/module/infra/service/DefaultDatabaseQueryTest.java

@@ -1,7 +1,7 @@
 package cn.iocoder.yudao.module.infra.service;
 
 import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.generator.IDatabaseQuery.DefaultDatabaseQuery;
+import com.baomidou.mybatisplus.generator.query.DefaultQuery;
 import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
 import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
@@ -19,7 +19,7 @@ public class DefaultDatabaseQueryTest {
 
         ConfigBuilder builder = new ConfigBuilder(null, dataSourceConfig, null, null, null, null);
 
-        DefaultDatabaseQuery query = new DefaultDatabaseQuery(builder);
+        DefaultQuery query = new DefaultQuery(builder);
 
         long time = System.currentTimeMillis();
         List<TableInfo> tableInfos = query.queryTables();

+ 3 - 2
yudao-module-visualization/yudao-module-visualization-biz/src/main/java/cn/iocoder/yudao/module/visualization/framework/jmreport/config/JmReportConfiguration.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.visualization.framework.jmreport.config;
 
+import cn.iocoder.yudao.framework.security.config.SecurityProperties;
 import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
 import cn.iocoder.yudao.module.visualization.framework.jmreport.core.service.JmReportTokenServiceImpl;
 import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
@@ -18,8 +19,8 @@ public class JmReportConfiguration {
 
     @Bean
     @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
-    public JmReportTokenServiceI jmReportTokenService(OAuth2TokenApi oAuth2TokenApi) {
-        return new JmReportTokenServiceImpl(oAuth2TokenApi);
+    public JmReportTokenServiceI jmReportTokenService(OAuth2TokenApi oAuth2TokenApi, SecurityProperties securityProperties) {
+        return new JmReportTokenServiceImpl(oAuth2TokenApi, securityProperties);
     }
 
 }

+ 72 - 18
yudao-module-visualization/yudao-module-visualization-biz/src/main/java/cn/iocoder/yudao/module/visualization/framework/jmreport/core/service/JmReportTokenServiceImpl.java

@@ -1,7 +1,10 @@
 package cn.iocoder.yudao.module.visualization.framework.jmreport.core.service;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.exception.ServiceException;
+import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import cn.iocoder.yudao.framework.security.config.SecurityProperties;
 import cn.iocoder.yudao.framework.security.core.LoginUser;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
@@ -10,6 +13,10 @@ import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
 import cn.iocoder.yudao.module.system.api.oauth2.dto.OAuth2AccessTokenCheckRespDTO;
 import lombok.RequiredArgsConstructor;
 import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
+import org.springframework.http.HttpHeaders;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
 
 /**
  * {@link JmReportTokenServiceI} 实现类,提供积木报表的 Token 校验、用户信息的查询等功能
@@ -19,8 +26,37 @@ import org.jeecg.modules.jmreport.api.JmReportTokenServiceI;
 @RequiredArgsConstructor
 public class JmReportTokenServiceImpl implements JmReportTokenServiceI {
 
+    /**
+     * 积木 token head 头
+     */
+    private static final String JM_TOKEN_HEADER = "X-Access-Token";
+    /**
+     * auth 相关格式
+     */
+    private static final String AUTHORIZATION_FORMAT = SecurityFrameworkUtils.AUTHORIZATION_BEARER + " %s";
+
     private final OAuth2TokenApi oauth2TokenApi;
 
+    private final SecurityProperties securityProperties;
+
+    /**
+     * 自定义 API 数据集appian自定义 Header,解决 Token 传递。
+     * 参考 <a href="http://report.jeecg.com/2222224">api数据集token机制详解</a> 文档
+     *
+     * @return 新 head
+     */
+    @Override
+    public HttpHeaders customApiHeader() {
+        // 读取积木标标系统的 token
+        HttpServletRequest request = ServletUtils.getRequest();
+        String token = request.getHeader(JM_TOKEN_HEADER);
+
+        // 设置到 yudao 系统的 token
+        HttpHeaders headers = new HttpHeaders();
+        headers.add(securityProperties.getTokenHeader(), String.format(AUTHORIZATION_FORMAT, token));
+        return headers;
+    }
+
     /**
      * 校验 Token 是否有效,即验证通过
      *
@@ -29,8 +65,40 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI {
      */
     @Override
     public Boolean verifyToken(String token) {
+        Long userId = SecurityFrameworkUtils.getLoginUserId();
+        if (!Objects.isNull(userId)) {
+            return true;
+        }
+        return buildLoginUserByToken(token) != null;
+    }
+
+    /**
+     * 获得用户编号
+     * <p>
+     * 虽然方法名获得的是 username,实际对应到项目中是用户编号
+     *
+     * @param token JmReport 前端传递的 token
+     * @return 用户编号
+     */
+    @Override
+    public String getUsername(String token) {
+        Long userId = SecurityFrameworkUtils.getLoginUserId();
+        if (ObjectUtil.isNotNull(userId)) {
+            return String.valueOf(userId);
+        }
+        LoginUser user = buildLoginUserByToken(token);
+        return user == null ? null : String.valueOf(user.getId());
+    }
+
+    /**
+     * 基于 token 构建登录用户
+     *
+     * @param token token
+     * @return 返回 token 对应的用户信息
+     */
+    private LoginUser buildLoginUserByToken(String token) {
         if (StrUtil.isEmpty(token)) {
-            return false;
+            return null;
         }
         // TODO 如下的实现不算特别优雅,主要咱是不想搞的太复杂,所以参考对应的 Filter 先实现了
 
@@ -41,7 +109,7 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI {
         try {
             OAuth2AccessTokenCheckRespDTO accessToken = oauth2TokenApi.checkAccessToken(token);
             if (accessToken == null) {
-                return false;
+                return null;
             }
             user = new LoginUser().setId(accessToken.getUserId()).setUserType(accessToken.getUserType())
                     .setTenantId(accessToken.getTenantId()).setScopes(accessToken.getScopes());
@@ -49,7 +117,7 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI {
             // do nothing:如果报错,说明认证失败,则返回 false 即可
         }
         if (user == null) {
-            return false;
+            return null;
         }
         SecurityFrameworkUtils.setLoginUser(user, WebFrameworkUtils.getRequest());
 
@@ -57,21 +125,7 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI {
         // 目的:基于 LoginUser 获得到的租户编号,设置到 Tenant 上下文,避免查询数据库时的报错
         TenantContextHolder.setIgnore(false);
         TenantContextHolder.setTenantId(user.getTenantId());
-        return true;
-    }
-
-    /**
-     * 获得用户编号
-     *
-     * 虽然方法名获得的是 username,实际对应到项目中是用户编号
-     *
-     * @param token JmReport 前端传递的 token
-     * @return 用户编号
-     */
-    @Override
-    public String getUsername(String token) {
-        Long userId = SecurityFrameworkUtils.getLoginUserId();
-        return userId != null ? String.valueOf(userId) : null;
+        return user;
     }
 
 }

+ 1 - 1
yudao-ui-admin-vue3/README.md

@@ -34,7 +34,7 @@
 | [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 4.9.4  |
 | [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.0.28 |
 | [vueuse](https://vueuse.org/) | 常用工具集 | 9.10.0  |
-| [vxe-table](https://vxetable.cn/) | vue 最强表单 | 4.3.7  |
+| [vxe-table](https://vxetable.cn/) | vue 最强表单 | 4.3.9  |
 | [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.2.2  |
 | [vue-router](https://router.vuejs.org/) | vue 路由 | 4.1.6  |
 | [windicss](https://cn.windicss.org/) | 下一代工具优先的 CSS 框架 | 3.5.6  |

+ 11 - 11
yudao-ui-admin-vue3/package.json

@@ -1,6 +1,6 @@
 {
   "name": "yudao-ui-admin-vue3",
-  "version": "1.6.6-snapshot.1901",
+  "version": "1.6.6-snapshot.1911",
   "description": "基于vue3、vite4、element-plus、typesScript",
   "author": "xingyu",
   "private": false,
@@ -50,14 +50,14 @@
     "vue-i18n": "9.2.2",
     "vue-router": "^4.1.6",
     "vue-types": "^5.0.2",
-    "vxe-table": "^4.3.7",
+    "vxe-table": "^4.3.9",
     "web-storage-cache": "^1.1.1",
     "xe-utils": "^3.5.7"
   },
   "devDependencies": {
-    "@commitlint/cli": "^17.4.0",
+    "@commitlint/cli": "^17.4.1",
     "@commitlint/config-conventional": "^17.4.0",
-    "@iconify/json": "^2.2.2",
+    "@iconify/json": "^2.2.5",
     "@intlify/unplugin-vue-i18n": "^0.8.1",
     "@purge-icons/generated": "^0.9.0",
     "@types/intro.js": "^5.1.0",
@@ -66,8 +66,8 @@
     "@types/nprogress": "^0.2.0",
     "@types/qrcode": "^1.5.0",
     "@types/qs": "^6.9.7",
-    "@typescript-eslint/eslint-plugin": "^5.48.0",
-    "@typescript-eslint/parser": "^5.48.0",
+    "@typescript-eslint/eslint-plugin": "^5.48.1",
+    "@typescript-eslint/parser": "^5.48.1",
     "@vitejs/plugin-legacy": "^3.0.1",
     "@vitejs/plugin-vue": "^4.0.0",
     "@vitejs/plugin-vue-jsx": "^3.0.0",
@@ -75,14 +75,14 @@
     "consola": "^2.15.3",
     "eslint": "^8.31.0",
     "eslint-config-prettier": "^8.6.0",
-    "eslint-define-config": "^1.13.0",
+    "eslint-define-config": "^1.14.0",
     "eslint-plugin-prettier": "^4.2.1",
     "eslint-plugin-vue": "^9.8.0",
     "lint-staged": "^13.1.0",
-    "postcss": "^8.4.20",
+    "postcss": "^8.4.21",
     "postcss-html": "^1.5.0",
     "postcss-scss": "^4.0.6",
-    "prettier": "^2.8.1",
+    "prettier": "^2.8.2",
     "rimraf": "^3.0.2",
     "rollup": "^3.9.1",
     "sass": "^1.57.1",
@@ -91,7 +91,7 @@
     "stylelint-config-prettier": "^9.0.4",
     "stylelint-config-recommended": "^9.0.0",
     "stylelint-config-standard": "^29.0.0",
-    "stylelint-order": "^5.0.0",
+    "stylelint-order": "^6.0.1",
     "terser": "^5.16.1",
     "typescript": "4.9.4",
     "vite": "4.0.4",
@@ -104,7 +104,7 @@
     "vite-plugin-svg-icons": "^2.0.1",
     "vite-plugin-vue-setup-extend": "^0.4.0",
     "vite-plugin-windicss": "^1.8.10",
-    "vue-tsc": "^1.0.22",
+    "vue-tsc": "^1.0.24",
     "windicss": "^3.5.6"
   },
   "engines": {

+ 127 - 133
yudao-ui-admin-vue3/pnpm-lock.yaml

@@ -1,10 +1,10 @@
 lockfileVersion: 5.4
 
 specifiers:
-  '@commitlint/cli': ^17.4.0
+  '@commitlint/cli': ^17.4.1
   '@commitlint/config-conventional': ^17.4.0
   '@iconify/iconify': ^3.0.1
-  '@iconify/json': ^2.2.2
+  '@iconify/json': ^2.2.5
   '@intlify/unplugin-vue-i18n': ^0.8.1
   '@purge-icons/generated': ^0.9.0
   '@types/intro.js': ^5.1.0
@@ -13,8 +13,8 @@ specifiers:
   '@types/nprogress': ^0.2.0
   '@types/qrcode': ^1.5.0
   '@types/qs': ^6.9.7
-  '@typescript-eslint/eslint-plugin': ^5.48.0
-  '@typescript-eslint/parser': ^5.48.0
+  '@typescript-eslint/eslint-plugin': ^5.48.1
+  '@typescript-eslint/parser': ^5.48.1
   '@vitejs/plugin-legacy': ^3.0.1
   '@vitejs/plugin-vue': ^4.0.0
   '@vitejs/plugin-vue-jsx': ^3.0.0
@@ -34,7 +34,7 @@ specifiers:
   element-plus: 2.2.28
   eslint: ^8.31.0
   eslint-config-prettier: ^8.6.0
-  eslint-define-config: ^1.13.0
+  eslint-define-config: ^1.14.0
   eslint-plugin-prettier: ^4.2.1
   eslint-plugin-vue: ^9.8.0
   intro.js: ^6.0.0
@@ -44,10 +44,10 @@ specifiers:
   mitt: ^3.0.0
   nprogress: ^0.2.0
   pinia: ^2.0.28
-  postcss: ^8.4.20
+  postcss: ^8.4.21
   postcss-html: ^1.5.0
   postcss-scss: ^4.0.6
-  prettier: ^2.8.1
+  prettier: ^2.8.2
   qrcode: ^1.5.1
   qs: ^6.11.0
   rimraf: ^3.0.2
@@ -58,7 +58,7 @@ specifiers:
   stylelint-config-prettier: ^9.0.4
   stylelint-config-recommended: ^9.0.0
   stylelint-config-standard: ^29.0.0
-  stylelint-order: ^5.0.0
+  stylelint-order: ^6.0.1
   terser: ^5.16.1
   typescript: 4.9.4
   url: ^0.11.0
@@ -75,9 +75,9 @@ specifiers:
   vue: 3.2.45
   vue-i18n: 9.2.2
   vue-router: ^4.1.6
-  vue-tsc: ^1.0.22
+  vue-tsc: ^1.0.24
   vue-types: ^5.0.2
-  vxe-table: ^4.3.7
+  vxe-table: ^4.3.9
   web-storage-cache: ^1.1.1
   windicss: ^3.5.6
   xe-utils: ^3.5.7
@@ -109,14 +109,14 @@ dependencies:
   vue-i18n: 9.2.2_vue@3.2.45
   vue-router: 4.1.6_vue@3.2.45
   vue-types: 5.0.2_vue@3.2.45
-  vxe-table: 4.3.7_vue@3.2.45+xe-utils@3.5.7
+  vxe-table: 4.3.9_vue@3.2.45+xe-utils@3.5.7
   web-storage-cache: 1.1.1
   xe-utils: 3.5.7
 
 devDependencies:
-  '@commitlint/cli': 17.4.0_@types+node@18.11.18
+  '@commitlint/cli': 17.4.1
   '@commitlint/config-conventional': 17.4.0
-  '@iconify/json': 2.2.2
+  '@iconify/json': 2.2.5
   '@intlify/unplugin-vue-i18n': 0.8.1_vue-i18n@9.2.2
   '@purge-icons/generated': 0.9.0
   '@types/intro.js': 5.1.0
@@ -125,23 +125,23 @@ devDependencies:
   '@types/nprogress': 0.2.0
   '@types/qrcode': 1.5.0
   '@types/qs': 6.9.7
-  '@typescript-eslint/eslint-plugin': 5.48.0_k73wpmdolxikpyqun3p36akaaq
-  '@typescript-eslint/parser': 5.48.0_iukboom6ndih5an6iafl45j2fe
+  '@typescript-eslint/eslint-plugin': 5.48.1_3jon24igvnqaqexgwtxk6nkpse
+  '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe
   '@vitejs/plugin-legacy': 3.0.1_terser@5.16.1+vite@4.0.4
   '@vitejs/plugin-vue': 4.0.0_vite@4.0.4+vue@3.2.45
   '@vitejs/plugin-vue-jsx': 3.0.0_vite@4.0.4+vue@3.2.45
-  autoprefixer: 10.4.13_postcss@8.4.20
+  autoprefixer: 10.4.13_postcss@8.4.21
   consola: 2.15.3
   eslint: 8.31.0
   eslint-config-prettier: 8.6.0_eslint@8.31.0
-  eslint-define-config: 1.13.0
-  eslint-plugin-prettier: 4.2.1_32m5uc2milwdw3tnkcq5del26y
+  eslint-define-config: 1.14.0
+  eslint-plugin-prettier: 4.2.1_iu5s7nk6dw7o3tajefwfiqfmge
   eslint-plugin-vue: 9.8.0_eslint@8.31.0
   lint-staged: 13.1.0
-  postcss: 8.4.20
+  postcss: 8.4.21
   postcss-html: 1.5.0
-  postcss-scss: 4.0.6_postcss@8.4.20
-  prettier: 2.8.1
+  postcss-scss: 4.0.6_postcss@8.4.21
+  prettier: 2.8.2
   rimraf: 3.0.2
   rollup: 3.9.1
   sass: 1.57.1
@@ -150,7 +150,7 @@ devDependencies:
   stylelint-config-prettier: 9.0.4_stylelint@14.16.1
   stylelint-config-recommended: 9.0.0_stylelint@14.16.1
   stylelint-config-standard: 29.0.0_stylelint@14.16.1
-  stylelint-order: 5.0.0_stylelint@14.16.1
+  stylelint-order: 6.0.1_stylelint@14.16.1
   terser: 5.16.1
   typescript: 4.9.4
   vite: 4.0.4_zxbrnrc4iyldik6mikh3pswz4i
@@ -163,7 +163,7 @@ devDependencies:
   vite-plugin-svg-icons: 2.0.1_vite@4.0.4
   vite-plugin-vue-setup-extend: 0.4.0_vite@4.0.4
   vite-plugin-windicss: 1.8.10_vite@4.0.4
-  vue-tsc: 1.0.22_typescript@4.9.4
+  vue-tsc: 1.0.24_typescript@4.9.4
   windicss: 3.5.6
 
 packages:
@@ -506,14 +506,14 @@ packages:
       '@babel/helper-validator-identifier': 7.19.1
       to-fast-properties: 2.0.0
 
-  /@commitlint/cli/17.4.0_@types+node@18.11.18:
-    resolution: {integrity: sha512-SEY4sYe8yVlgxPP7X0wJb96DBAGBPsCsy6QbqJt/UECbIAjDeDV5xXBV4jnS7T/qMC10sk6Ub9kDhEX0VWvblw==}
+  /@commitlint/cli/17.4.1:
+    resolution: {integrity: sha512-W8OJwz+izY+fVwyUt1HveCDmABMZNRVZHSVPw/Bh9Y62tp11SmmQaycgbsYLMiMy7JGn4mAJqEGlSHS9Uti9ZQ==}
     engines: {node: '>=v14'}
     hasBin: true
     dependencies:
       '@commitlint/format': 17.4.0
       '@commitlint/lint': 17.4.0
-      '@commitlint/load': 17.4.0_@types+node@18.11.18
+      '@commitlint/load': 17.4.1
       '@commitlint/read': 17.4.0
       '@commitlint/types': 17.4.0
       execa: 5.1.1
@@ -524,7 +524,6 @@ packages:
     transitivePeerDependencies:
       - '@swc/core'
       - '@swc/wasm'
-      - '@types/node'
     dev: true
 
   /@commitlint/config-conventional/17.4.0:
@@ -585,14 +584,15 @@ packages:
       '@commitlint/types': 17.4.0
     dev: true
 
-  /@commitlint/load/17.4.0_@types+node@18.11.18:
-    resolution: {integrity: sha512-wDKNvAJqukqZqKmhRlf3KNo/12QGo1AQcd80EbV01SxtGvyHOsJ/g+/IbrZpopZv8rvzmEVktcpfDYH6ITepFA==}
+  /@commitlint/load/17.4.1:
+    resolution: {integrity: sha512-6A7/LhIaQpL4ieciIDcVvK2d5z/UI1GBrtDaHm6sQSCL0265clB2/F7XKQNTJHXv9yG4LByT2r+QCpM4GugIfw==}
     engines: {node: '>=v14'}
     dependencies:
       '@commitlint/config-validator': 17.4.0
       '@commitlint/execute-rule': 17.4.0
       '@commitlint/resolve-extends': 17.4.0
       '@commitlint/types': 17.4.0
+      '@types/node': 18.11.18
       chalk: 4.1.2
       cosmiconfig: 8.0.0
       cosmiconfig-typescript-loader: 4.2.0_bxtyj3et3xbsdyxhh3oblnfbj4
@@ -605,7 +605,6 @@ packages:
     transitivePeerDependencies:
       - '@swc/core'
       - '@swc/wasm'
-      - '@types/node'
     dev: true
 
   /@commitlint/message/17.4.0:
@@ -682,14 +681,14 @@ packages:
       '@jridgewell/trace-mapping': 0.3.9
     dev: true
 
-  /@csstools/selector-specificity/2.0.2_2xshye3abirqjlplmebvmaxyna:
+  /@csstools/selector-specificity/2.0.2_wajs5nedgkikc5pcuwett7legi:
     resolution: {integrity: sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==}
     engines: {node: ^12 || ^14 || >=16}
     peerDependencies:
       postcss: ^8.2
       postcss-selector-parser: ^6.0.10
     dependencies:
-      postcss: 8.4.20
+      postcss: 8.4.21
       postcss-selector-parser: 6.0.11
     dev: true
 
@@ -964,8 +963,8 @@ packages:
     dependencies:
       '@iconify/types': 2.0.0
 
-  /@iconify/json/2.2.2:
-    resolution: {integrity: sha512-G9HVJz3uvQGNEirk9oI7xYnWb7ygEfTUZ+PVp81qgNp8bu5UOtXaxjTGw78NyNAC2OlryH5tSEp95Dqbt4LLQQ==}
+  /@iconify/json/2.2.5:
+    resolution: {integrity: sha512-AIbJTRF9HJz7FJ8t7058huwDXHaFEY4a4f6uuPtctEQ8/I3ybrX66iZMgoLD1kLaamU4tzZPlZ6tSpA3pM8LZg==}
     dependencies:
       '@iconify/types': 2.0.0
       pathe: 1.0.0
@@ -986,8 +985,8 @@ packages:
       vue-i18n:
         optional: true
     dependencies:
-      '@intlify/message-compiler': 9.3.0-beta.12
-      '@intlify/shared': 9.3.0-beta.12
+      '@intlify/message-compiler': 9.3.0-beta.14
+      '@intlify/shared': 9.3.0-beta.14
       jsonc-eslint-parser: 1.4.1
       source-map: 0.6.1
       vue-i18n: 9.2.2_vue@3.2.45
@@ -1016,11 +1015,11 @@ packages:
       '@intlify/shared': 9.2.2
       source-map: 0.6.1
 
-  /@intlify/message-compiler/9.3.0-beta.12:
-    resolution: {integrity: sha512-A8/s7pb3v8nf6HG77qFPJntxgQKI9GXxGnkn7aO+b03/X/GkF/4WceDSAIk3i+yLeIgszeBn9GZ23tSg4sTEHA==}
+  /@intlify/message-compiler/9.3.0-beta.14:
+    resolution: {integrity: sha512-PlZ3pl+YYuql54Nq+26wv6ohIa8Ig6ALrvQI+f2zZKUtkupb49M4wyVN3bDQbFlgYVE7/u3n19BJSY8lEuX5Eg==}
     engines: {node: '>= 14'}
     dependencies:
-      '@intlify/shared': 9.3.0-beta.11
+      '@intlify/shared': 9.3.0-beta.14
       source-map: 0.6.1
     dev: true
 
@@ -1028,13 +1027,8 @@ packages:
     resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==}
     engines: {node: '>= 14'}
 
-  /@intlify/shared/9.3.0-beta.11:
-    resolution: {integrity: sha512-CtbotesxTRiC3bRyXyv1NG39fkqJ790f8z8xFaeIXSZpOdiyxoh5BIyypCzSFQZDGLwz0Q9gyWbW1XpxQJm68Q==}
-    engines: {node: '>= 14'}
-    dev: true
-
-  /@intlify/shared/9.3.0-beta.12:
-    resolution: {integrity: sha512-WsmaS54sA8xuwezPKpa/OMoaX1v2VF2fCgAmYS6prDr2ir0CkUFWPm9A8ilmxzv4nkS61/v8+vf4lGGkn5uBdA==}
+  /@intlify/shared/9.3.0-beta.14:
+    resolution: {integrity: sha512-mJ/rFan+4uVsBAQSCAJnpQaPvSjQ49mJMNmGelTUbTDAmgf0oexYxwqtKOlFFyY3hmQ8lUDYaGQKuYrFgRuHnA==}
     engines: {node: '>= 14'}
     dev: true
 
@@ -1054,7 +1048,7 @@ packages:
         optional: true
     dependencies:
       '@intlify/bundle-utils': 3.4.0_vue-i18n@9.2.2
-      '@intlify/shared': 9.3.0-beta.12
+      '@intlify/shared': 9.3.0-beta.14
       '@rollup/pluginutils': 4.2.1
       '@vue/compiler-sfc': 3.2.45
       debug: 4.3.4
@@ -1285,8 +1279,8 @@ packages:
     resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==}
     dev: false
 
-  /@typescript-eslint/eslint-plugin/5.48.0_k73wpmdolxikpyqun3p36akaaq:
-    resolution: {integrity: sha512-SVLafp0NXpoJY7ut6VFVUU9I+YeFsDzeQwtK0WZ+xbRN3mtxJ08je+6Oi2N89qDn087COdO0u3blKZNv9VetRQ==}
+  /@typescript-eslint/eslint-plugin/5.48.1_3jon24igvnqaqexgwtxk6nkpse:
+    resolution: {integrity: sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
       '@typescript-eslint/parser': ^5.0.0
@@ -1296,10 +1290,10 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/parser': 5.48.0_iukboom6ndih5an6iafl45j2fe
-      '@typescript-eslint/scope-manager': 5.48.0
-      '@typescript-eslint/type-utils': 5.48.0_iukboom6ndih5an6iafl45j2fe
-      '@typescript-eslint/utils': 5.48.0_iukboom6ndih5an6iafl45j2fe
+      '@typescript-eslint/parser': 5.48.1_iukboom6ndih5an6iafl45j2fe
+      '@typescript-eslint/scope-manager': 5.48.1
+      '@typescript-eslint/type-utils': 5.48.1_iukboom6ndih5an6iafl45j2fe
+      '@typescript-eslint/utils': 5.48.1_iukboom6ndih5an6iafl45j2fe
       debug: 4.3.4
       eslint: 8.31.0
       ignore: 5.2.1
@@ -1312,8 +1306,8 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/parser/5.48.0_iukboom6ndih5an6iafl45j2fe:
-    resolution: {integrity: sha512-1mxNA8qfgxX8kBvRDIHEzrRGrKHQfQlbW6iHyfHYS0Q4X1af+S6mkLNtgCOsGVl8+/LUPrqdHMssAemkrQ01qg==}
+  /@typescript-eslint/parser/5.48.1_iukboom6ndih5an6iafl45j2fe:
+    resolution: {integrity: sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -1322,9 +1316,9 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/scope-manager': 5.48.0
-      '@typescript-eslint/types': 5.48.0
-      '@typescript-eslint/typescript-estree': 5.48.0_typescript@4.9.4
+      '@typescript-eslint/scope-manager': 5.48.1
+      '@typescript-eslint/types': 5.48.1
+      '@typescript-eslint/typescript-estree': 5.48.1_typescript@4.9.4
       debug: 4.3.4
       eslint: 8.31.0
       typescript: 4.9.4
@@ -1332,16 +1326,16 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/scope-manager/5.48.0:
-    resolution: {integrity: sha512-0AA4LviDtVtZqlyUQnZMVHydDATpD9SAX/RC5qh6cBd3xmyWvmXYF+WT1oOmxkeMnWDlUVTwdODeucUnjz3gow==}
+  /@typescript-eslint/scope-manager/5.48.1:
+    resolution: {integrity: sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dependencies:
-      '@typescript-eslint/types': 5.48.0
-      '@typescript-eslint/visitor-keys': 5.48.0
+      '@typescript-eslint/types': 5.48.1
+      '@typescript-eslint/visitor-keys': 5.48.1
     dev: true
 
-  /@typescript-eslint/type-utils/5.48.0_iukboom6ndih5an6iafl45j2fe:
-    resolution: {integrity: sha512-vbtPO5sJyFjtHkGlGK4Sthmta0Bbls4Onv0bEqOGm7hP9h8UpRsHJwsrCiWtCUndTRNQO/qe6Ijz9rnT/DB+7g==}
+  /@typescript-eslint/type-utils/5.48.1_iukboom6ndih5an6iafl45j2fe:
+    resolution: {integrity: sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: '*'
@@ -1350,8 +1344,8 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/typescript-estree': 5.48.0_typescript@4.9.4
-      '@typescript-eslint/utils': 5.48.0_iukboom6ndih5an6iafl45j2fe
+      '@typescript-eslint/typescript-estree': 5.48.1_typescript@4.9.4
+      '@typescript-eslint/utils': 5.48.1_iukboom6ndih5an6iafl45j2fe
       debug: 4.3.4
       eslint: 8.31.0
       tsutils: 3.21.0_typescript@4.9.4
@@ -1360,13 +1354,13 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/types/5.48.0:
-    resolution: {integrity: sha512-UTe67B0Ypius0fnEE518NB2N8gGutIlTojeTg4nt0GQvikReVkurqxd2LvYa9q9M5MQ6rtpNyWTBxdscw40Xhw==}
+  /@typescript-eslint/types/5.48.1:
+    resolution: {integrity: sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dev: true
 
-  /@typescript-eslint/typescript-estree/5.48.0_typescript@4.9.4:
-    resolution: {integrity: sha512-7pjd94vvIjI1zTz6aq/5wwE/YrfIyEPLtGJmRfyNR9NYIW+rOvzzUv3Cmq2hRKpvt6e9vpvPUQ7puzX7VSmsEw==}
+  /@typescript-eslint/typescript-estree/5.48.1_typescript@4.9.4:
+    resolution: {integrity: sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
       typescript: '*'
@@ -1374,8 +1368,8 @@ packages:
       typescript:
         optional: true
     dependencies:
-      '@typescript-eslint/types': 5.48.0
-      '@typescript-eslint/visitor-keys': 5.48.0
+      '@typescript-eslint/types': 5.48.1
+      '@typescript-eslint/visitor-keys': 5.48.1
       debug: 4.3.4
       globby: 11.1.0
       is-glob: 4.0.3
@@ -1386,17 +1380,17 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/utils/5.48.0_iukboom6ndih5an6iafl45j2fe:
-    resolution: {integrity: sha512-x2jrMcPaMfsHRRIkL+x96++xdzvrdBCnYRd5QiW5Wgo1OB4kDYPbC1XjWP/TNqlfK93K/lUL92erq5zPLgFScQ==}
+  /@typescript-eslint/utils/5.48.1_iukboom6ndih5an6iafl45j2fe:
+    resolution: {integrity: sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     peerDependencies:
       eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
     dependencies:
       '@types/json-schema': 7.0.11
       '@types/semver': 7.3.13
-      '@typescript-eslint/scope-manager': 5.48.0
-      '@typescript-eslint/types': 5.48.0
-      '@typescript-eslint/typescript-estree': 5.48.0_typescript@4.9.4
+      '@typescript-eslint/scope-manager': 5.48.1
+      '@typescript-eslint/types': 5.48.1
+      '@typescript-eslint/typescript-estree': 5.48.1_typescript@4.9.4
       eslint: 8.31.0
       eslint-scope: 5.1.1
       eslint-utils: 3.0.0_eslint@8.31.0
@@ -1406,11 +1400,11 @@ packages:
       - typescript
     dev: true
 
-  /@typescript-eslint/visitor-keys/5.48.0:
-    resolution: {integrity: sha512-5motVPz5EgxQ0bHjut3chzBkJ3Z3sheYVcSwS5BpHZpLqSptSmELNtGixmgj65+rIfhvtQTz5i9OP2vtzdDH7Q==}
+  /@typescript-eslint/visitor-keys/5.48.1:
+    resolution: {integrity: sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
     dependencies:
-      '@typescript-eslint/types': 5.48.0
+      '@typescript-eslint/types': 5.48.1
       eslint-visitor-keys: 3.3.0
     dev: true
 
@@ -1498,30 +1492,30 @@ packages:
       vue: 3.2.45
     dev: true
 
-  /@volar/language-core/1.0.22:
-    resolution: {integrity: sha512-hiJeCOqxNdtG/04FRGLGI9H9DVz2l6cTqPDBzwqplHXAWfMxjzUaGUrn9sfTG7YMFNZUgK4EYxJnRfhqdtbSFQ==}
+  /@volar/language-core/1.0.24:
+    resolution: {integrity: sha512-vTN+alJiWwK0Pax6POqrmevbtFW2dXhjwWiW/MW4f48eDYPLdyURWcr8TixO7EN/nHsUBj2udT7igFKPtjyAKg==}
     dependencies:
-      '@volar/source-map': 1.0.22
+      '@volar/source-map': 1.0.24
       muggle-string: 0.1.0
     dev: true
 
-  /@volar/source-map/1.0.22:
-    resolution: {integrity: sha512-cv4gypHSP4MWVR82ed/+1IpI6794qAl0Q0+KJ+VGMVF8rVugsiF9QbyMCgjel9wNRsssQsazzsf6txOR9vHQiw==}
+  /@volar/source-map/1.0.24:
+    resolution: {integrity: sha512-Qsv/tkplx18pgBr8lKAbM1vcDqgkGKQzbChg6NW+v0CZc3G7FLmK+WrqEPzKlN7Cwdc6XVL559Nod8WKAfKr4A==}
     dependencies:
       muggle-string: 0.1.0
     dev: true
 
-  /@volar/typescript/1.0.22:
-    resolution: {integrity: sha512-VPyEicealSD4gqlE5/UQ1j3ietsO6Hfat40KtUEh/K+XEZ7h02b1KgFV64YEuBkBOaZ5hgvRW/WXKtQgXCl7Iw==}
+  /@volar/typescript/1.0.24:
+    resolution: {integrity: sha512-f8hCSk+PfKR1/RQHxZ79V1NpDImHoivqoizK+mstphm25tn/YJ/JnKNjZHB+o21fuW0yKlI26NV3jkVb2Cc/7A==}
     dependencies:
-      '@volar/language-core': 1.0.22
+      '@volar/language-core': 1.0.24
     dev: true
 
-  /@volar/vue-language-core/1.0.22:
-    resolution: {integrity: sha512-Ki0G/ZdBj2/GLw+/VVH3n9XR/JL6krMIth02EekFn6JV4PGN3mNxbvoh6lOPSDZLR6biOU5nJPnnjpKy8nuXhw==}
+  /@volar/vue-language-core/1.0.24:
+    resolution: {integrity: sha512-2NTJzSgrwKu6uYwPqLiTMuAzi7fAY3yFy5PJ255bGJc82If0Xr+cW8pC80vpjG0D/aVLmlwAdO4+Ya2BI8GdDg==}
     dependencies:
-      '@volar/language-core': 1.0.22
-      '@volar/source-map': 1.0.22
+      '@volar/language-core': 1.0.24
+      '@volar/source-map': 1.0.24
       '@vue/compiler-dom': 3.2.45
       '@vue/compiler-sfc': 3.2.45
       '@vue/reactivity': 3.2.45
@@ -1530,11 +1524,11 @@ packages:
       vue-template-compiler: 2.7.14
     dev: true
 
-  /@volar/vue-typescript/1.0.22:
-    resolution: {integrity: sha512-2T1o5z86PAev31OMtVOv/qp4P3ZVl9ln/2KTmykQE8Fh4A5F+868MW4nf5J7XQ6RNyx7RH9LhzgjvbqJpAfiYw==}
+  /@volar/vue-typescript/1.0.24:
+    resolution: {integrity: sha512-9a25oHDvGaNC0okRS47uqJI6FxY4hUQZUsxeOUFHcqVxZEv8s17LPuP/pMMXyz7jPygrZubB/qXqHY5jEu/akA==}
     dependencies:
-      '@volar/typescript': 1.0.22
-      '@volar/vue-language-core': 1.0.22
+      '@volar/typescript': 1.0.24
+      '@volar/vue-language-core': 1.0.24
     dev: true
 
   /@vue/babel-helper-vue-transform-on/1.0.2:
@@ -1583,7 +1577,7 @@ packages:
       '@vue/shared': 3.2.45
       estree-walker: 2.0.2
       magic-string: 0.25.9
-      postcss: 8.4.20
+      postcss: 8.4.21
       source-map: 0.6.1
 
   /@vue/compiler-ssr/3.2.45:
@@ -2066,7 +2060,7 @@ packages:
     hasBin: true
     dev: true
 
-  /autoprefixer/10.4.13_postcss@8.4.20:
+  /autoprefixer/10.4.13_postcss@8.4.21:
     resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==}
     engines: {node: ^10 || ^12 || >=14}
     hasBin: true
@@ -2078,7 +2072,7 @@ packages:
       fraction.js: 4.2.0
       normalize-range: 0.1.2
       picocolors: 1.0.0
-      postcss: 8.4.20
+      postcss: 8.4.21
       postcss-value-parser: 4.2.0
     dev: true
 
@@ -3013,12 +3007,12 @@ packages:
       eslint: 8.31.0
     dev: true
 
-  /eslint-define-config/1.13.0:
-    resolution: {integrity: sha512-d0BfmPGBcMusfiz6QY/piAhWaEyJriJtvk9SHfuJzI7am9k4ce07SfmPkpcR0ckXNyu4FBons10akOO2Tx+X+Q==}
+  /eslint-define-config/1.14.0:
+    resolution: {integrity: sha512-NREt5SzMwKmLAY28YdaqIiTSJxfPpuZ+1ZLJxY2Wbj02dYF4QX81z0q9MPMjZB8C+SlCu66qAhcPpFJyhXOiuA==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13', pnpm: '>= 7.0.0'}
     dev: true
 
-  /eslint-plugin-prettier/4.2.1_32m5uc2milwdw3tnkcq5del26y:
+  /eslint-plugin-prettier/4.2.1_iu5s7nk6dw7o3tajefwfiqfmge:
     resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
     engines: {node: '>=12.0.0'}
     peerDependencies:
@@ -3031,7 +3025,7 @@ packages:
     dependencies:
       eslint: 8.31.0
       eslint-config-prettier: 8.6.0_eslint@8.31.0
-      prettier: 2.8.1
+      prettier: 2.8.2
       prettier-linter-helpers: 1.0.0
     dev: true
 
@@ -4506,7 +4500,7 @@ packages:
     dev: false
 
   /nanoid/3.3.4:
-    resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npm.taobao.org/nanoid/-/nanoid-3.3.4.tgz}
+    resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
     hasBin: true
 
@@ -4848,8 +4842,8 @@ packages:
     dependencies:
       htmlparser2: 8.0.1
       js-tokens: 8.0.0
-      postcss: 8.4.20
-      postcss-safe-parser: 6.0.0_postcss@8.4.20
+      postcss: 8.4.21
+      postcss-safe-parser: 6.0.0_postcss@8.4.21
     dev: true
 
   /postcss-media-query-parser/0.2.3:
@@ -4868,22 +4862,22 @@ packages:
     resolution: {integrity: sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==}
     dev: true
 
-  /postcss-safe-parser/6.0.0_postcss@8.4.20:
+  /postcss-safe-parser/6.0.0_postcss@8.4.21:
     resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==}
     engines: {node: '>=12.0'}
     peerDependencies:
       postcss: ^8.3.3
     dependencies:
-      postcss: 8.4.20
+      postcss: 8.4.21
     dev: true
 
-  /postcss-scss/4.0.6_postcss@8.4.20:
+  /postcss-scss/4.0.6_postcss@8.4.21:
     resolution: {integrity: sha512-rLDPhJY4z/i4nVFZ27j9GqLxj1pwxE80eAzUNRMXtcpipFYIeowerzBgG3yJhMtObGEXidtIgbUpQ3eLDsf5OQ==}
     engines: {node: '>=12.0'}
     peerDependencies:
       postcss: ^8.4.19
     dependencies:
-      postcss: 8.4.20
+      postcss: 8.4.21
     dev: true
 
   /postcss-selector-parser/6.0.10:
@@ -4902,12 +4896,12 @@ packages:
       util-deprecate: 1.0.2
     dev: true
 
-  /postcss-sorting/7.0.1_postcss@8.4.20:
-    resolution: {integrity: sha512-iLBFYz6VRYyLJEJsBJ8M3TCqNcckVzz4wFounSc5Oez35ogE/X+aoC5fFu103Ot7NyvjU3/xqIXn93Gp3kJk4g==}
+  /postcss-sorting/8.0.1_postcss@8.4.21:
+    resolution: {integrity: sha512-go9Zoxx7KQH+uLrJ9xa5wRErFeXu01ydA6O8m7koPXkmAN7Ts//eRcIqjo0stBR4+Nir2gMYDOWAOx7O5EPUZA==}
     peerDependencies:
-      postcss: ^8.3.9
+      postcss: ^8.4.20
     dependencies:
-      postcss: 8.4.20
+      postcss: 8.4.21
     dev: true
 
   /postcss-value-parser/4.2.0:
@@ -4924,8 +4918,8 @@ packages:
       supports-color: 3.2.3
     dev: true
 
-  /postcss/8.4.20:
-    resolution: {integrity: sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npm.taobao.org/postcss/-/postcss-8.4.20.tgz}
+  /postcss/8.4.21:
+    resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==}
     engines: {node: ^10 || ^12 || >=14}
     dependencies:
       nanoid: 3.3.4
@@ -4983,8 +4977,8 @@ packages:
       fast-diff: 1.2.0
     dev: true
 
-  /prettier/2.8.1:
-    resolution: {integrity: sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==}
+  /prettier/2.8.2:
+    resolution: {integrity: sha512-BtRV9BcncDyI2tsuS19zzhzoxD8Dh8LiCx7j7tHzrkz8GFXAexeWFdi22mjE1d16dftH2qNaytVxqiRTGlMfpw==}
     engines: {node: '>=10.13.0'}
     hasBin: true
     dev: true
@@ -5428,7 +5422,7 @@ packages:
     dev: true
 
   /source-map-js/1.0.2:
-    resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npm.taobao.org/source-map-js/-/source-map-js-1.0.2.tgz}
+    resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
     engines: {node: '>=0.10.0'}
 
   /source-map-resolve/0.5.3:
@@ -5636,13 +5630,13 @@ packages:
       stylelint-config-recommended: 9.0.0_stylelint@14.16.1
     dev: true
 
-  /stylelint-order/5.0.0_stylelint@14.16.1:
-    resolution: {integrity: sha512-OWQ7pmicXufDw5BlRqzdz3fkGKJPgLyDwD1rFY3AIEfIH/LQY38Vu/85v8/up0I+VPiuGRwbc2Hg3zLAsJaiyw==}
+  /stylelint-order/6.0.1_stylelint@14.16.1:
+    resolution: {integrity: sha512-C9gJDZArRBZvn+4MPgggwYTp7dK49WPnYa5+6tBEkZnW/YWj4xBVNJdQjIik14w5orlF9RqFpYDHN0FPWIFOSQ==}
     peerDependencies:
       stylelint: ^14.0.0
     dependencies:
-      postcss: 8.4.20
-      postcss-sorting: 7.0.1_postcss@8.4.20
+      postcss: 8.4.21
+      postcss-sorting: 8.0.1_postcss@8.4.21
       stylelint: 14.16.1
     dev: true
 
@@ -5651,7 +5645,7 @@ packages:
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
     hasBin: true
     dependencies:
-      '@csstools/selector-specificity': 2.0.2_2xshye3abirqjlplmebvmaxyna
+      '@csstools/selector-specificity': 2.0.2_wajs5nedgkikc5pcuwett7legi
       balanced-match: 2.0.0
       colord: 2.9.3
       cosmiconfig: 7.1.0
@@ -5674,10 +5668,10 @@ packages:
       micromatch: 4.0.5
       normalize-path: 3.0.0
       picocolors: 1.0.0
-      postcss: 8.4.20
+      postcss: 8.4.21
       postcss-media-query-parser: 0.2.3
       postcss-resolve-nested-selector: 0.1.1
-      postcss-safe-parser: 6.0.0_postcss@8.4.20
+      postcss-safe-parser: 6.0.0_postcss@8.4.21
       postcss-selector-parser: 6.0.11
       postcss-value-parser: 4.2.0
       resolve-from: 5.0.0
@@ -6211,7 +6205,7 @@ packages:
     dependencies:
       '@types/node': 18.11.18
       esbuild: 0.16.5
-      postcss: 8.4.20
+      postcss: 8.4.21
       resolve: 1.22.1
       rollup: 3.9.1
       sass: 1.57.1
@@ -6281,14 +6275,14 @@ packages:
       he: 1.2.0
     dev: true
 
-  /vue-tsc/1.0.22_typescript@4.9.4:
-    resolution: {integrity: sha512-xSxwgWR3czhv7sLKHWu6lzj9Xq6AtsCURVL45AY4TLGFszv2L2YlMgygXvqslyCM5bz9cyoIKSaZnzHqHTHjzA==}
+  /vue-tsc/1.0.24_typescript@4.9.4:
+    resolution: {integrity: sha512-mmU1s5SAqE1nByQAiQnao9oU4vX+mSdsgI8H57SfKH6UVzq/jP9+Dbi2GaV+0b4Cn361d2ln8m6xeU60ApiEXg==}
     hasBin: true
     peerDependencies:
       typescript: '*'
     dependencies:
-      '@volar/vue-language-core': 1.0.22
-      '@volar/vue-typescript': 1.0.22
+      '@volar/vue-language-core': 1.0.24
+      '@volar/vue-typescript': 1.0.24
       typescript: 4.9.4
     dev: true
 
@@ -6314,8 +6308,8 @@ packages:
       '@vue/server-renderer': 3.2.45_vue@3.2.45
       '@vue/shared': 3.2.45
 
-  /vxe-table/4.3.7_vue@3.2.45+xe-utils@3.5.7:
-    resolution: {integrity: sha512-v+d7eEQ5uqtVTQCts4xkW0S15LZcIuEukYHGXI53SdoUj2gLFggPYAxQr1y659CM/ESRWPz9LNVHpd97KkjGHw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npm.taobao.org/vxe-table/-/vxe-table-4.3.7.tgz}
+  /vxe-table/4.3.9_vue@3.2.45+xe-utils@3.5.7:
+    resolution: {integrity: sha512-Ns7Ooa7lOHBpks90i0k0BMNyxfMpUo39ryxTgKE41X3xVnI9tGQs2U6+klfDlsuqYfmG3ibyzHN3OCrWbbKo4Q==}
     peerDependencies:
       vue: ^3.2.28
       xe-utils: ^3.5.0

+ 1 - 1
yudao-ui-admin/src/styles/index.scss

@@ -129,7 +129,7 @@ input, textarea{
 }
 
 .el-scrollbar__view{
-  overflow-x: hidden;
+//   overflow-x: hidden;
 }
 
 .el-rate{

+ 2 - 2
yudao-ui-admin/src/views/infra/redis/index.vue

@@ -136,8 +136,8 @@
 
 <script>
 import {getCache, getKeyDefineList, getKeyList, getKeyValue, deleteKey, deleteKeys} from "@/api/infra/redis";
-import echarts from "echarts";
-
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
 export default {
   name: "Server",
   data () {

+ 1 - 1
yudao-ui-app/api/auth.js

@@ -10,6 +10,6 @@ export const smsLogin = data => http.post('/member/auth/sms-login', data)
 //微信小程序的一键登录
 export const weixinMiniAppLogin = data => http.post('/member/auth/weixin-mini-app-login', data)
 //刷新令牌
-export const  refreshToken = data => http.post('/member/auth/refresh-token', data)
+export const  refreshToken = data => http.post('/member/auth/refresh-token', {data})
 //退出登录
 export const logout = data => http.post('/member/auth/logout', data)

+ 1 - 0
yudao-ui-app/store/getters.js

@@ -1,5 +1,6 @@
 const getters = {
   accessToken: state => state.user.accessToken,
+  refreshToken: state => state.user.refreshToken,
   userInfo: state => state.user.userInfo,
   hasLogin: state => !!state.user.accessToken
 }

+ 5 - 2
yudao-ui-app/utils/request/responseInterceptors.js

@@ -30,13 +30,16 @@ module.exports = vm => {
         if (!isRefreshToken) {
           isRefreshToken = true
           // 1. 如果获取不到刷新令牌,则只能执行登出操作
-          if (!vm.$store.getters.refreshToken()) {
+          if (!vm.$store.getters.refreshToken) {
             vm.$store.commit('CLEAR_LOGIN_INFO')
             return Promise.reject(res)
           }
           // 2. 进行刷新访问令牌
           try {
-            const refreshTokenRes = await refreshToken()
+            let param = {}
+            let refreshToken =  uni.getStorageSync('REFRESH_TOKEN');
+            param.refreshToken = refreshToken;
+            const refreshTokenRes = await refreshToken(param)
             // 2.1 刷新成功,则回放队列的请求 + 当前请求
             vm.$store.commit('SET_TOKEN', refreshTokenRes.data)
             requestList.forEach(cb => cb())