Преглед изворни кода

Merge remote-tracking branch 'upstream/master'

“zyj” пре 4 година
родитељ
комит
f1bba76b11
71 измењених фајлова са 1495 додато и 1244 уклоњено
  1. 6 6
      pom.xml
  2. 1 1
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
  3. 6 6
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java
  4. 12 7
      ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml
  5. 12 1
      ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
  6. 5 0
      ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
  7. 8 0
      ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
  8. 6 6
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
  9. 1 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
  10. 1 1
      ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java
  11. 2 1
      ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
  12. 19 0
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java
  13. 196 60
      ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
  14. 4 36
      ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
  15. 28 53
      ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
  16. 4 29
      ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
  17. 2 2
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
  18. 10 5
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
  19. 0 2
      ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
  20. 6 6
      ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
  21. 6 17
      ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
  22. 9 5
      ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
  23. 1 1
      ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
  24. 22 0
      ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
  25. 1 1
      ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
  26. 29 46
      ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
  27. 37 58
      ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
  28. 1 0
      ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
  29. 4 4
      ruoyi-ui/package.json
  30. 21 0
      ruoyi-ui/src/components/DictData/index.js
  31. 51 50
      ruoyi-ui/src/components/DictTag/index.vue
  32. 5 17
      ruoyi-ui/src/layout/components/Settings/index.vue
  33. 7 14
      ruoyi-ui/src/main.js
  34. 77 0
      ruoyi-ui/src/plugins/cache.js
  35. 48 0
      ruoyi-ui/src/plugins/download.js
  36. 14 0
      ruoyi-ui/src/plugins/index.js
  37. 75 0
      ruoyi-ui/src/plugins/modal.js
  38. 82 0
      ruoyi-ui/src/utils/dict/Dict.js
  39. 17 0
      ruoyi-ui/src/utils/dict/DictConverter.js
  40. 13 0
      ruoyi-ui/src/utils/dict/DictData.js
  41. 38 0
      ruoyi-ui/src/utils/dict/DictMeta.js
  42. 51 0
      ruoyi-ui/src/utils/dict/DictOptions.js
  43. 33 0
      ruoyi-ui/src/utils/dict/index.js
  44. 18 9
      ruoyi-ui/src/utils/ruoyi.js
  45. 0 42
      ruoyi-ui/src/utils/zipdownload.js
  46. 26 33
      ruoyi-ui/src/views/monitor/cache/index.vue
  47. 47 72
      ruoyi-ui/src/views/monitor/job/index.vue
  48. 30 51
      ruoyi-ui/src/views/monitor/job/log.vue
  49. 25 41
      ruoyi-ui/src/views/monitor/logininfor/index.vue
  50. 6 10
      ruoyi-ui/src/views/monitor/online/index.vue
  51. 31 52
      ruoyi-ui/src/views/monitor/operlog/index.vue
  52. 62 69
      ruoyi-ui/src/views/monitor/server/index.vue
  53. 22 34
      ruoyi-ui/src/views/system/config/index.vue
  54. 18 26
      ruoyi-ui/src/views/system/dept/index.vue
  55. 25 37
      ruoyi-ui/src/views/system/dict/data.vue
  56. 26 38
      ruoyi-ui/src/views/system/dict/index.vue
  57. 22 35
      ruoyi-ui/src/views/system/menu/index.vue
  58. 23 36
      ruoyi-ui/src/views/system/notice/index.vue
  59. 25 37
      ruoyi-ui/src/views/system/post/index.vue
  60. 7 19
      ruoyi-ui/src/views/system/role/authUser.vue
  61. 32 48
      ruoyi-ui/src/views/system/role/index.vue
  62. 3 9
      ruoyi-ui/src/views/system/role/selectUser.vue
  63. 1 1
      ruoyi-ui/src/views/system/user/authRole.vue
  64. 37 58
      ruoyi-ui/src/views/system/user/index.vue
  65. 1 1
      ruoyi-ui/src/views/system/user/profile/resetPwd.vue
  66. 2 2
      ruoyi-ui/src/views/system/user/profile/userAvatar.vue
  67. 1 1
      ruoyi-ui/src/views/system/user/profile/userInfo.vue
  68. 4 15
      ruoyi-ui/src/views/tool/build/index.vue
  69. 12 12
      ruoyi-ui/src/views/tool/gen/editTable.vue
  70. 7 2
      ruoyi-ui/src/views/tool/gen/importTable.vue
  71. 11 19
      ruoyi-ui/src/views/tool/gen/index.vue

+ 6 - 6
pom.xml

@@ -18,13 +18,13 @@
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.8</java.version>
         <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
-        <druid.version>1.2.6</druid.version>
+        <druid.version>1.2.8</druid.version>
         <bitwalker.version>1.21</bitwalker.version>
         <swagger.version>3.0.0</swagger.version>
-		<kaptcha.version>2.3.2</kaptcha.version>
-		<mybatis-spring-boot.version>2.1.4</mybatis-spring-boot.version>
-        <pagehelper.boot.version>1.3.1</pagehelper.boot.version>
-        <fastjson.version>1.2.76</fastjson.version>
+        <kaptcha.version>2.3.2</kaptcha.version>
+        <mybatis-spring-boot.version>2.2.0</mybatis-spring-boot.version>
+        <pagehelper.boot.version>1.4.0</pagehelper.boot.version>
+        <fastjson.version>1.2.78</fastjson.version>
         <oshi.version>5.8.0</oshi.version>
         <jna.version>5.8.0</jna.version>
         <commons.io.version>2.11.0</commons.io.version>
@@ -43,7 +43,7 @@
             <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-dependencies</artifactId>
-                <version>2.2.13.RELEASE</version>
+                <version>2.5.5</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>

+ 1 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java

@@ -1,13 +1,13 @@
 package com.ruoyi.web.controller.system;
 
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 import com.ruoyi.common.core.controller.BaseController;
 import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.model.RegisterBody;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.web.service.SysRegisterService;
 import com.ruoyi.system.service.ISysConfigService;
 

+ 6 - 6
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java

@@ -47,7 +47,7 @@ public class TestController extends BaseController
     }
 
     @ApiOperation("获取用户详细")
-    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path")
+    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
     @GetMapping("/{userId}")
     public AjaxResult getUser(@PathVariable Integer userId)
     {
@@ -63,10 +63,10 @@ public class TestController extends BaseController
 
     @ApiOperation("新增用户")
     @ApiImplicitParams({
-        @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer"),
-        @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String"),
-        @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String"),
-        @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String")
+        @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
+        @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
+        @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
+        @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
     })
     @PostMapping("/save")
     public AjaxResult save(UserEntity user)
@@ -95,7 +95,7 @@ public class TestController extends BaseController
     }
 
     @ApiOperation("删除用户信息")
-    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path")
+    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
     @DeleteMapping("/{userId}")
     public AjaxResult delete(@PathVariable Integer userId)
     {

+ 12 - 7
ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml

@@ -3,13 +3,18 @@
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
 <configuration>
-	
-	<settings>
-		<setting name="cacheEnabled"             value="true" />  <!-- 全局映射器启用缓存 -->
-		<setting name="useGeneratedKeys"         value="true" />  <!-- 允许 JDBC 支持自动生成主键 -->
-		<setting name="defaultExecutorType"      value="REUSE" /> <!-- 配置默认的执行器 -->
-		<setting name="logImpl"                  value="SLF4J" /> <!-- 指定 MyBatis 所用日志的具体实现 -->
-		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/>  驼峰式命名 -->
+    <!-- 全局参数 -->
+    <settings>
+        <!-- 使全局的映射器启用或禁用缓存 -->
+        <setting name="cacheEnabled"             value="true"   />
+        <!-- 允许JDBC 支持自动生成主键 -->
+        <setting name="useGeneratedKeys"         value="true"   />
+        <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
+        <setting name="defaultExecutorType"      value="SIMPLE" />
+		<!-- 指定 MyBatis 所用日志的具体实现 -->
+        <setting name="logImpl"                  value="SLF4J"  />
+        <!-- 使用驼峰命名法转换字段 -->
+		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
 	</settings>
 	
 </configuration>

+ 12 - 1
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java

@@ -5,6 +5,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.math.BigDecimal;
+import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
 
 /**
  * 自定义导出Excel数据注解
@@ -108,7 +109,17 @@ public @interface Excel
     /**
      * 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右)
      */
-    Align align() default Align.AUTO;
+    public Align align() default Align.AUTO;
+
+    /**
+     * 自定义数据处理器
+     */
+    public Class<?> handler() default ExcelHandlerAdapter.class;
+
+    /**
+     * 自定义数据处理器参数
+     */
+    public String[] args() default {};
 
     public enum Align
     {

+ 5 - 0
ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java

@@ -38,4 +38,9 @@ public @interface Log
      * 是否保存请求的参数
      */
     public boolean isSaveRequestData() default true;
+
+    /**
+     * 是否保存响应的参数
+     */
+    public boolean isSaveResponseData() default true;
 }

+ 8 - 0
ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java

@@ -19,5 +19,13 @@ import java.lang.annotation.Target;
 @Documented
 public @interface RepeatSubmit
 {
+    /**
+     * 间隔时间(ms),小于此时间视为重复提交
+     */
+    public int interval() default 5000;
 
+    /**
+     * 提示消息
+     */
+    public String message() default "不允许重复提交,请稍后再试";
 }

+ 6 - 6
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java

@@ -4,7 +4,7 @@ import java.util.Collection;
 import java.util.Set;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.userdetails.UserDetails;
-import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.alibaba.fastjson.annotation.JSONField;
 import com.ruoyi.common.core.domain.entity.SysUser;
 
 /**
@@ -119,7 +119,7 @@ public class LoginUser implements UserDetails
         this.permissions = permissions;
     }
 
-    @JsonIgnore
+    @JSONField(serialize = false)
     @Override
     public String getPassword()
     {
@@ -135,7 +135,7 @@ public class LoginUser implements UserDetails
     /**
      * 账户是否未过期,过期无法验证
      */
-    @JsonIgnore
+    @JSONField(serialize = false)
     @Override
     public boolean isAccountNonExpired()
     {
@@ -147,7 +147,7 @@ public class LoginUser implements UserDetails
      * 
      * @return
      */
-    @JsonIgnore
+    @JSONField(serialize = false)
     @Override
     public boolean isAccountNonLocked()
     {
@@ -159,7 +159,7 @@ public class LoginUser implements UserDetails
      * 
      * @return
      */
-    @JsonIgnore
+    @JSONField(serialize = false)
     @Override
     public boolean isCredentialsNonExpired()
     {
@@ -171,7 +171,7 @@ public class LoginUser implements UserDetails
      * 
      * @return
      */
-    @JsonIgnore
+    @JSONField(serialize = false)
     @Override
     public boolean isEnabled()
     {

+ 1 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java

@@ -211,6 +211,7 @@ public class FileUtils
                 .append(percentEncodedFileName);
 
         response.setHeader("Content-disposition", contentDispositionValue.toString());
+        response.setHeader("download-filename", percentEncodedFileName);
     }
 
     /**

+ 1 - 1
ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java

@@ -387,7 +387,7 @@ public final class HTMLFilter
                         {
                             paramValue = processParamProtocol(paramValue);
                         }
-                        params.append(' ').append(paramName).append("=\"").append(paramValue).append("\"");
+                        params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\"");
                     }
                 }
 

+ 2 - 1
ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java

@@ -19,6 +19,7 @@ import javax.net.ssl.X509TrustManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.StringUtils;
 
 /**
  * 通用http发送方法
@@ -55,7 +56,7 @@ public class HttpUtils
         BufferedReader in = null;
         try
         {
-            String urlNameString = url + "?" + param;
+            String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
             log.info("sendGet - {}", urlNameString);
             URL realUrl = new URL(urlNameString);
             URLConnection connection = realUrl.openConnection();

+ 19 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java

@@ -0,0 +1,19 @@
+package com.ruoyi.common.utils.poi;
+
+/**
+ * Excel数据格式处理适配器
+ * 
+ * @author ruoyi
+ */
+public interface ExcelHandlerAdapter
+{
+    /**
+     * 格式化
+     * 
+     * @param value 单元格数据值
+     * @param args excel注解args参数组
+     *
+     * @return 处理后的值
+     */
+    Object format(Object value, String[] args);
+}

+ 196 - 60
ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java

@@ -6,6 +6,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
@@ -46,6 +47,7 @@ import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.VerticalAlignment;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.util.CellRangeAddress;
 import org.apache.poi.ss.util.CellRangeAddressList;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.xssf.streaming.SXSSFWorkbook;
@@ -124,6 +126,16 @@ public class ExcelUtil<T>
      */
     private List<Object[]> fields;
 
+    /**
+     * 当前行号
+     */
+    private int rownum;
+    
+    /**
+     * 标题
+     */
+    private String title;
+
     /**
      * 最大高度
      */
@@ -149,7 +161,7 @@ public class ExcelUtil<T>
         this.clazz = clazz;
     }
 
-    public void init(List<T> list, String sheetName, Type type)
+    public void init(List<T> list, String sheetName, String title, Type type)
     {
         if (list == null)
         {
@@ -158,8 +170,27 @@ public class ExcelUtil<T>
         this.list = list;
         this.sheetName = sheetName;
         this.type = type;
+        this.title = title;
         createExcelField();
         createWorkbook();
+        createTitle();
+    }
+
+    /**
+     * 创建excel第一行标题
+     */
+    public void createTitle()
+    {
+        if (StringUtils.isNotEmpty(title))
+        {
+            Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);
+            titleRow.setHeightInPoints(30);
+            Cell titleCell = titleRow.createCell(0);
+            titleCell.setCellStyle(styles.get("title"));
+            titleCell.setCellValue(title);
+            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), titleRow.getRowNum(),
+                    this.fields.size() - 1));
+        }
     }
 
     /**
@@ -170,17 +201,30 @@ public class ExcelUtil<T>
      */
     public List<T> importExcel(InputStream is) throws Exception
     {
-        return importExcel(StringUtils.EMPTY, is);
+        return importExcel(is, 0);
+    }
+
+    /**
+     * 对excel表单默认第一个索引名转换成list
+     * 
+     * @param is 输入流
+     * @param titleNum 标题占用行数
+     * @return 转换后集合
+     */
+    public List<T> importExcel(InputStream is, int titleNum) throws Exception
+    {
+        return importExcel(StringUtils.EMPTY, is, titleNum);
     }
 
     /**
      * 对excel表单指定表格索引名转换成list
      * 
      * @param sheetName 表格索引名
+     * @param titleNum 标题占用行数
      * @param is 输入流
      * @return 转换后集合
      */
-    public List<T> importExcel(String sheetName, InputStream is) throws Exception
+    public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception
     {
         this.type = Type.IMPORT;
         this.wb = WorkbookFactory.create(is);
@@ -209,7 +253,7 @@ public class ExcelUtil<T>
             // 定义一个map用于存放excel列的序号和field.
             Map<String, Integer> cellMap = new HashMap<String, Integer>();
             // 获取表头
-            Row heard = sheet.getRow(0);
+            Row heard = sheet.getRow(titleNum);
             for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
             {
                 Cell cell = heard.getCell(i);
@@ -224,25 +268,18 @@ public class ExcelUtil<T>
                 }
             }
             // 有数据时才处理 得到类的所有field.
-            Field[] allFields = clazz.getDeclaredFields();
-            // 定义一个map用于存放列的序号和field.
-            Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
-            for (int col = 0; col < allFields.length; col++)
+            List<Object[]> fields = this.getFields();
+            Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
+            for (Object[] objects : fields)
             {
-                Field field = allFields[col];
-                Excel attr = field.getAnnotation(Excel.class);
-                if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
+                Excel attr = (Excel) objects[1];
+                Integer column = cellMap.get(attr.name());
+                if (column != null)
                 {
-                    // 设置类的私有字段属性可访问.
-                    field.setAccessible(true);
-                    Integer column = cellMap.get(attr.name());
-                    if (column != null)
-                    {
-                        fieldsMap.put(column, field);
-                    }
+                    fieldsMap.put(column, objects);
                 }
             }
-            for (int i = 1; i <= rows; i++)
+            for (int i = titleNum + 1; i <= rows; i++)
             {
                 // 从第2行开始取数据,默认第一行是表头.
                 Row row = sheet.getRow(i);
@@ -252,14 +289,15 @@ public class ExcelUtil<T>
                     continue;
                 }
                 T entity = null;
-                for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet())
+                for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())
                 {
                     Object val = this.getCellValue(row, entry.getKey());
 
                     // 如果不存在实例则新建.
                     entity = (entity == null ? clazz.newInstance() : entity);
                     // 从map中得到对应列的field.
-                    Field field = fieldsMap.get(entry.getKey());
+                    Field field = (Field) entry.getValue()[0];
+                    Excel attr = (Excel) entry.getValue()[1];
                     // 取得类型,并根据对象类型设置值.
                     Class<?> fieldType = field.getType();
                     if (String.class == fieldType)
@@ -319,7 +357,6 @@ public class ExcelUtil<T>
                     }
                     if (StringUtils.isNotNull(fieldType))
                     {
-                        Excel attr = field.getAnnotation(Excel.class);
                         String propertyName = field.getName();
                         if (StringUtils.isNotEmpty(attr.targetAttr()))
                         {
@@ -333,6 +370,10 @@ public class ExcelUtil<T>
                         {
                             val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
                         }
+                        else if (!attr.handler().equals(ExcelHandlerAdapter.class))
+                        {
+                            val = dataFormatHandlerAdapter(val, attr);
+                        }
                         else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
                         {
                             PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());
@@ -340,8 +381,11 @@ public class ExcelUtil<T>
                             {
                                 val = "";
                             }
-                            byte[] data = image.getData();
-                            val = FileUtils.writeImportBytes(data);
+                            else
+                            {
+                                byte[] data = image.getData();
+                                val = FileUtils.writeImportBytes(data);
+                            }
                         }
                         ReflectUtils.invokeSetter(entity, propertyName, val);
                     }
@@ -361,7 +405,20 @@ public class ExcelUtil<T>
      */
     public AjaxResult exportExcel(List<T> list, String sheetName)
     {
-        this.init(list, sheetName, Type.EXPORT);
+        return exportExcel(list, sheetName, StringUtils.EMPTY);
+    }
+    
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @param title 标题
+     * @return 结果
+     */
+    public AjaxResult exportExcel(List<T> list, String sheetName, String title)
+    {
+        this.init(list, sheetName, title, Type.EXPORT);
         return exportExcel();
     }
 
@@ -374,11 +431,26 @@ public class ExcelUtil<T>
      * @return 结果
      * @throws IOException
      */
-    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName) throws IOException
+    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)throws IOException
+    {
+        exportExcel(response, list, sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param response 返回数据
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @param title 标题
+     * @return 结果
+     * @throws IOException
+     */
+    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title) throws IOException
     {
         response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
         response.setCharacterEncoding("utf-8");
-        this.init(list, sheetName, Type.EXPORT);
+        this.init(list, sheetName, title, Type.EXPORT);
         exportExcel(response.getOutputStream());
     }
 
@@ -390,7 +462,19 @@ public class ExcelUtil<T>
      */
     public AjaxResult importTemplateExcel(String sheetName)
     {
-        this.init(null, sheetName, Type.IMPORT);
+        return importTemplateExcel(sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param sheetName 工作表的名称
+     * @param title 标题
+     * @return 结果
+     */
+    public AjaxResult importTemplateExcel(String sheetName, String title)
+    {
+        this.init(null, sheetName, title, Type.IMPORT);
         return exportExcel();
     }
 
@@ -401,10 +485,22 @@ public class ExcelUtil<T>
      * @return 结果
      */
     public void importTemplateExcel(HttpServletResponse response, String sheetName) throws IOException
+    {
+        importTemplateExcel(response, sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param sheetName 工作表的名称
+     * @param title 标题
+     * @return 结果
+     */
+    public void importTemplateExcel(HttpServletResponse response, String sheetName, String title) throws IOException
     {
         response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
         response.setCharacterEncoding("utf-8");
-        this.init(null, sheetName, Type.IMPORT);
+        this.init(null, sheetName, title, Type.IMPORT);
         exportExcel(response.getOutputStream());
     }
 
@@ -465,13 +561,13 @@ public class ExcelUtil<T>
     public void writeSheet()
     {
         // 取出一共有多少个sheet.
-        double sheetNo = Math.ceil(list.size() / sheetSize);
-        for (int index = 0; index <= sheetNo; index++)
+        int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));
+        for (int index = 0; index < sheetNo; index++)
         {
             createSheet(sheetNo, index);
 
             // 产生一行
-            Row row = sheet.createRow(0);
+            Row row = sheet.createRow(rownum);
             int column = 0;
             // 写入各个字段的列头名称
             for (Object[] os : fields)
@@ -499,7 +595,7 @@ public class ExcelUtil<T>
         int endNo = Math.min(startNo + sheetSize, list.size());
         for (int i = startNo; i < endNo; i++)
         {
-            row = sheet.createRow(i + 1 - startNo);
+            row = sheet.createRow(i + 1 + rownum - startNo);
             // 得到导出对象.
             T vo = (T) list.get(i);
             int column = 0;
@@ -507,8 +603,6 @@ public class ExcelUtil<T>
             {
                 Field field = (Field) os[0];
                 Excel excel = (Excel) os[1];
-                // 设置实体类私有属性可访问
-                field.setAccessible(true);
                 this.addCell(excel, row, vo, field, column++);
             }
         }
@@ -527,6 +621,16 @@ public class ExcelUtil<T>
         CellStyle style = wb.createCellStyle();
         style.setAlignment(HorizontalAlignment.CENTER);
         style.setVerticalAlignment(VerticalAlignment.CENTER);
+        Font titleFont = wb.createFont();
+        titleFont.setFontName("Arial");
+        titleFont.setFontHeightInPoints((short) 16);
+        titleFont.setBold(true);
+        style.setFont(titleFont);
+        styles.put("title", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
         style.setBorderRight(BorderStyle.THIN);
         style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
         style.setBorderLeft(BorderStyle.THIN);
@@ -726,6 +830,10 @@ public class ExcelUtil<T>
                 {
                     cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString());
                 }
+                else if (!attr.handler().equals(ExcelHandlerAdapter.class))
+                {
+                    cell.setCellValue(dataFormatHandlerAdapter(value, attr));
+                }
                 else
                 {
                     // 设置列类型
@@ -898,6 +1006,28 @@ public class ExcelUtil<T>
         return DictUtils.getDictValue(dictType, dictLabel, separator);
     }
 
+    /**
+     * 数据处理器
+     * 
+     * @param value 数据值
+     * @param excel 数据注解
+     * @return
+     */
+    public String dataFormatHandlerAdapter(Object value, Excel excel)
+    {
+        try
+        {
+            Object instance = excel.handler().newInstance();
+            Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class });
+            value = formatMethod.invoke(instance, value, excel.args());
+        }
+        catch (Exception e)
+        {
+            log.error("不能格式化数据 " + excel.handler(), e.getMessage());
+        }
+        return Convert.toStr(value);
+    }
+
     /**
      * 合计统计信息
      */
@@ -1025,7 +1155,17 @@ public class ExcelUtil<T>
      */
     private void createExcelField()
     {
-        this.fields = new ArrayList<Object[]>();
+        this.fields = getFields();
+        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
+        this.maxHeight = getRowHeight();
+    }
+
+    /**
+     * 获取字段注解信息
+     */
+    public List<Object[]> getFields()
+    {
+        List<Object[]> fields = new ArrayList<Object[]>();
         List<Field> tempFields = new ArrayList<>();
         tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
         tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
@@ -1034,7 +1174,12 @@ public class ExcelUtil<T>
             // 单注解
             if (field.isAnnotationPresent(Excel.class))
             {
-                putToField(field, field.getAnnotation(Excel.class));
+                Excel attr = field.getAnnotation(Excel.class);
+                if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
+                {
+                    field.setAccessible(true);
+                    fields.add(new Object[] { field, attr });
+                }
             }
 
             // 多注解
@@ -1042,14 +1187,17 @@ public class ExcelUtil<T>
             {
                 Excels attrs = field.getAnnotation(Excels.class);
                 Excel[] excels = attrs.value();
-                for (Excel excel : excels)
+                for (Excel attr : excels)
                 {
-                    putToField(field, excel);
+                    if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
+                    {
+                        field.setAccessible(true);
+                        fields.add(new Object[] { field, attr });
+                    }
                 }
             }
         }
-        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
-        this.maxHeight = getRowHeight();
+        return fields;
     }
 
     /**
@@ -1066,23 +1214,15 @@ public class ExcelUtil<T>
         return (short) (maxHeight * 20);
     }
 
-    /**
-     * 放到字段集合中
-     */
-    private void putToField(Field field, Excel attr)
-    {
-        if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
-        {
-            this.fields.add(new Object[] { field, attr });
-        }
-    }
-
     /**
      * 创建一个工作簿
      */
     public void createWorkbook()
     {
         this.wb = new SXSSFWorkbook(500);
+        this.sheet = wb.createSheet();
+        wb.setSheetName(0, sheetName);
+        this.styles = createStyles(wb);
     }
 
     /**
@@ -1091,17 +1231,13 @@ public class ExcelUtil<T>
      * @param sheetNo sheet数量
      * @param index 序号
      */
-    public void createSheet(double sheetNo, int index)
+    public void createSheet(int sheetNo, int index)
     {
-        this.sheet = wb.createSheet();
-        this.styles = createStyles(wb);
         // 设置工作表的名称.
-        if (sheetNo == 0)
-        {
-            wb.setSheetName(index, sheetName);
-        }
-        else
+        if (sheetNo > 1 && index > 0)
         {
+            this.sheet = wb.createSheet();
+            this.createTitle();
             wb.setSheetName(index, sheetName + index);
         }
     }

+ 4 - 36
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java

@@ -1,12 +1,8 @@
 package com.ruoyi.framework.aspectj;
 
-import java.lang.reflect.Method;
 import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.Signature;
 import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Before;
-import org.aspectj.lang.annotation.Pointcut;
-import org.aspectj.lang.reflect.MethodSignature;
 import org.springframework.stereotype.Component;
 import com.ruoyi.common.annotation.DataScope;
 import com.ruoyi.common.core.domain.BaseEntity;
@@ -55,27 +51,15 @@ public class DataScopeAspect
      */
     public static final String DATA_SCOPE = "dataScope";
 
-    // 配置织入点
-    @Pointcut("@annotation(com.ruoyi.common.annotation.DataScope)")
-    public void dataScopePointCut()
-    {
-    }
-
-    @Before("dataScopePointCut()")
-    public void doBefore(JoinPoint point) throws Throwable
+    @Before("@annotation(controllerDataScope)")
+    public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
     {
         clearDataScope(point);
-        handleDataScope(point);
+        handleDataScope(point, controllerDataScope);
     }
 
-    protected void handleDataScope(final JoinPoint joinPoint)
+    protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
     {
-        // 获得注解
-        DataScope controllerDataScope = getAnnotationLog(joinPoint);
-        if (controllerDataScope == null)
-        {
-            return;
-        }
         // 获取当前的用户
         LoginUser loginUser = SecurityUtils.getLoginUser();
         if (StringUtils.isNotNull(loginUser))
@@ -150,22 +134,6 @@ public class DataScopeAspect
         }
     }
 
-    /**
-     * 是否存在注解,如果存在就获取
-     */
-    private DataScope getAnnotationLog(JoinPoint joinPoint)
-    {
-        Signature signature = joinPoint.getSignature();
-        MethodSignature methodSignature = (MethodSignature) signature;
-        Method method = methodSignature.getMethod();
-
-        if (method != null)
-        {
-            return method.getAnnotation(DataScope.class);
-        }
-        return null;
-    }
-
     /**
      * 拼接权限sql前先清空params.dataScope参数防止注入
      */

+ 28 - 53
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java

@@ -1,18 +1,13 @@
 package com.ruoyi.framework.aspectj;
 
-import java.lang.reflect.Method;
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.Map;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.Signature;
 import org.aspectj.lang.annotation.AfterReturning;
 import org.aspectj.lang.annotation.AfterThrowing;
 import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Pointcut;
-import org.aspectj.lang.reflect.MethodSignature;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
@@ -43,21 +38,15 @@ public class LogAspect
 {
     private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
 
-    // 配置织入点
-    @Pointcut("@annotation(com.ruoyi.common.annotation.Log)")
-    public void logPointCut()
-    {
-    }
-
     /**
      * 处理完请求后执行
      *
      * @param joinPoint 切点
      */
-    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
-    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
+    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
     {
-        handleLog(joinPoint, null, jsonResult);
+        handleLog(joinPoint, controllerLog, null, jsonResult);
     }
 
     /**
@@ -66,22 +55,16 @@ public class LogAspect
      * @param joinPoint 切点
      * @param e 异常
      */
-    @AfterThrowing(value = "logPointCut()", throwing = "e")
-    public void doAfterThrowing(JoinPoint joinPoint, Exception e)
+    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
     {
-        handleLog(joinPoint, e, null);
+        handleLog(joinPoint, controllerLog, e, null);
     }
 
-    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
+    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
     {
         try
         {
-            // 获得注解
-            Log controllerLog = getAnnotationLog(joinPoint);
-            if (controllerLog == null)
-            {
-                return;
-            }
 
             // 获取当前的用户
             LoginUser loginUser = SecurityUtils.getLoginUser();
@@ -92,9 +75,6 @@ public class LogAspect
             // 请求的地址
             String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
             operLog.setOperIp(ip);
-            // 返回参数
-            operLog.setJsonResult(JSON.toJSONString(jsonResult));
-
             operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
             if (loginUser != null)
             {
@@ -113,7 +93,7 @@ public class LogAspect
             // 设置请求方式
             operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
             // 处理设置注解上的参数
-            getControllerMethodDescription(joinPoint, controllerLog, operLog);
+            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
             // 保存数据库
             AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
         }
@@ -133,7 +113,7 @@ public class LogAspect
      * @param operLog 操作日志
      * @throws Exception
      */
-    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception
+    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
     {
         // 设置action动作
         operLog.setBusinessType(log.businessType().ordinal());
@@ -147,6 +127,11 @@ public class LogAspect
             // 获取参数的信息,传入到数据库中。
             setRequestValue(joinPoint, operLog);
         }
+        // 是否需要保存response,参数和值
+        if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
+        {
+            operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
+        }
     }
 
     /**
@@ -170,22 +155,6 @@ public class LogAspect
         }
     }
 
-    /**
-     * 是否存在注解,如果存在就获取
-     */
-    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
-    {
-        Signature signature = joinPoint.getSignature();
-        MethodSignature methodSignature = (MethodSignature) signature;
-        Method method = methodSignature.getMethod();
-
-        if (method != null)
-        {
-            return method.getAnnotation(Log.class);
-        }
-        return null;
-    }
-
     /**
      * 参数拼装
      */
@@ -194,12 +163,18 @@ public class LogAspect
         String params = "";
         if (paramsArray != null && paramsArray.length > 0)
         {
-            for (int i = 0; i < paramsArray.length; i++)
+            for (Object o : paramsArray)
             {
-                if (StringUtils.isNotNull(paramsArray[i]) && !isFilterObject(paramsArray[i]))
+                if (StringUtils.isNotNull(o) && !isFilterObject(o))
                 {
-                    Object jsonObj = JSON.toJSON(paramsArray[i]);
-                    params += jsonObj.toString() + " ";
+                    try
+                    {
+                        Object jsonObj = JSON.toJSON(o);
+                        params += jsonObj.toString() + " ";
+                    }
+                    catch (Exception e)
+                    {
+                    }
                 }
             }
         }
@@ -223,17 +198,17 @@ public class LogAspect
         else if (Collection.class.isAssignableFrom(clazz))
         {
             Collection collection = (Collection) o;
-            for (Iterator iter = collection.iterator(); iter.hasNext();)
+            for (Object value : collection)
             {
-                return iter.next() instanceof MultipartFile;
+                return value instanceof MultipartFile;
             }
         }
         else if (Map.class.isAssignableFrom(clazz))
         {
             Map map = (Map) o;
-            for (Iterator iter = map.entrySet().iterator(); iter.hasNext();)
+            for (Object value : map.entrySet())
             {
-                Map.Entry entry = (Map.Entry) iter.next();
+                Map.Entry entry = (Map.Entry) value;
                 return entry.getValue() instanceof MultipartFile;
             }
         }

+ 4 - 29
ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java

@@ -4,10 +4,8 @@ import java.lang.reflect.Method;
 import java.util.Collections;
 import java.util.List;
 import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.Signature;
 import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Before;
-import org.aspectj.lang.annotation.Pointcut;
 import org.aspectj.lang.reflect.MethodSignature;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -49,16 +47,9 @@ public class RateLimiterAspect
         this.limitScript = limitScript;
     }
 
-    // 配置织入点
-    @Pointcut("@annotation(com.ruoyi.common.annotation.RateLimiter)")
-    public void rateLimiterPointCut()
+    @Before("@annotation(rateLimiter)")
+    public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
     {
-    }
-
-    @Before("rateLimiterPointCut()")
-    public void doBefore(JoinPoint point) throws Throwable
-    {
-        RateLimiter rateLimiter = getAnnotationRateLimiter(point);
         String key = rateLimiter.key();
         int time = rateLimiter.time();
         int count = rateLimiter.count();
@@ -84,33 +75,17 @@ public class RateLimiterAspect
         }
     }
 
-    /**
-     * 是否存在注解,如果存在就获取
-     */
-    private RateLimiter getAnnotationRateLimiter(JoinPoint joinPoint)
-    {
-        Signature signature = joinPoint.getSignature();
-        MethodSignature methodSignature = (MethodSignature) signature;
-        Method method = methodSignature.getMethod();
-
-        if (method != null)
-        {
-            return method.getAnnotation(RateLimiter.class);
-        }
-        return null;
-    }
-
     public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
     {
         StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
         if (rateLimiter.limitType() == LimitType.IP)
         {
-            stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest()));
+            stringBuffer.append(IpUtils.getIpAddr(ServletUtils.getRequest())).append("-");
         }
         MethodSignature signature = (MethodSignature) point.getSignature();
         Method method = signature.getMethod();
         Class<?> targetClass = method.getDeclaringClass();
-        stringBuffer.append("-").append(targetClass.getName()).append("- ").append(method.getName());
+        stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
         return stringBuffer.toString();
     }
 }

+ 2 - 2
ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java

@@ -68,12 +68,12 @@ public class RedisConfig extends CachingConfigurerSupport
                 "local time = tonumber(ARGV[2])\n" +
                 "local current = redis.call('get', key);\n" +
                 "if current and tonumber(current) > count then\n" +
-                "    return current;\n" +
+                "    return tonumber(current);\n" +
                 "end\n" +
                 "current = redis.call('incr', key)\n" +
                 "if tonumber(current) == 1 then\n" +
                 "    redis.call('expire', key, time)\n" +
                 "end\n" +
-                "return current;";
+                "return tonumber(current);";
     }
 }

+ 10 - 5
ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java

@@ -28,10 +28,12 @@ public class ResourcesConfig implements WebMvcConfigurer
     public void addResourceHandlers(ResourceHandlerRegistry registry)
     {
         /** 本地文件上传路径 */
-        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
+        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
+                .addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
 
         /** swagger配置 */
-        registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
+        registry.addResourceHandler("/swagger-ui/**")
+                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
     }
 
     /**
@@ -49,17 +51,20 @@ public class ResourcesConfig implements WebMvcConfigurer
     @Bean
     public CorsFilter corsFilter()
     {
-        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
         CorsConfiguration config = new CorsConfiguration();
         config.setAllowCredentials(true);
         // 设置访问源地址
-        config.addAllowedOrigin("*");
+        config.addAllowedOriginPattern("*");
         // 设置访问源请求头
         config.addAllowedHeader("*");
         // 设置访问源请求方法
         config.addAllowedMethod("*");
-        // 对接口配置跨域设置
+        // 有效期 1800秒
+        config.setMaxAge(1800L);
+        // 添加映射路径,拦截一切请求
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
         source.registerCorsConfiguration("/**", config);
+        // 返回新的CorsFilter
         return new CorsFilter(source);
     }
 }

+ 0 - 2
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -107,8 +107,6 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                         "/**/*.js",
                         "/profile/**"
                 ).permitAll()
-                .antMatchers("/common/download**").anonymous()
-                .antMatchers("/common/download/resource**").anonymous()
                 .antMatchers("/swagger-ui.html").anonymous()
                 .antMatchers("/swagger-resources/**").anonymous()
                 .antMatchers("/webjars/**").anonymous()

+ 6 - 6
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java

@@ -5,7 +5,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.springframework.stereotype.Component;
 import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+import org.springframework.web.servlet.HandlerInterceptor;
 import com.alibaba.fastjson.JSONObject;
 import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.core.domain.AjaxResult;
@@ -17,7 +17,7 @@ import com.ruoyi.common.utils.ServletUtils;
  * @author ruoyi
  */
 @Component
-public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
+public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
 {
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
@@ -29,9 +29,9 @@ public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
             RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
             if (annotation != null)
             {
-                if (this.isRepeatSubmit(request))
+                if (this.isRepeatSubmit(request, annotation))
                 {
-                    AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
+                    AjaxResult ajaxResult = AjaxResult.error(annotation.message());
                     ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
                     return false;
                 }
@@ -40,7 +40,7 @@ public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
         }
         else
         {
-            return super.preHandle(request, response, handler);
+            return true;
         }
     }
 
@@ -51,5 +51,5 @@ public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
      * @return
      * @throws Exception
      */
-    public abstract boolean isRepeatSubmit(HttpServletRequest request);
+    public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);
 }

+ 6 - 17
ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java

@@ -8,6 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import com.alibaba.fastjson.JSONObject;
+import com.ruoyi.common.annotation.RepeatSubmit;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
@@ -35,21 +36,9 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
     @Autowired
     private RedisCache redisCache;
 
-    /**
-     * 间隔时间,单位:秒 默认10秒
-     * 
-     * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
-     */
-    private int intervalTime = 10;
-
-    public void setIntervalTime(int intervalTime)
-    {
-        this.intervalTime = intervalTime;
-    }
-
     @SuppressWarnings("unchecked")
     @Override
-    public boolean isRepeatSubmit(HttpServletRequest request)
+    public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
     {
         String nowParams = "";
         if (request instanceof RepeatedlyRequestWrapper)
@@ -87,7 +76,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
             if (sessionMap.containsKey(url))
             {
                 Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
-                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap))
+                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))
                 {
                     return true;
                 }
@@ -95,7 +84,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
         }
         Map<String, Object> cacheMap = new HashMap<String, Object>();
         cacheMap.put(url, nowDataMap);
-        redisCache.setCacheObject(cacheRepeatKey, cacheMap, intervalTime, TimeUnit.SECONDS);
+        redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
         return false;
     }
 
@@ -112,11 +101,11 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
     /**
      * 判断两次间隔时间
      */
-    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
+    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval)
     {
         long time1 = (Long) nowMap.get(REPEAT_TIME);
         long time2 = (Long) preMap.get(REPEAT_TIME);
-        if ((time1 - time2) < (this.intervalTime * 1000))
+        if ((time1 - time2) < interval)
         {
             return true;
         }

+ 9 - 5
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java

@@ -87,7 +87,7 @@ public class SysLoginService
         }
         AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
         LoginUser loginUser = (LoginUser) authentication.getPrincipal();
-        recordLoginInfo(loginUser.getUser());
+        recordLoginInfo(loginUser.getUserId());
         // 生成token
         return tokenService.createToken(loginUser);
     }
@@ -119,11 +119,15 @@ public class SysLoginService
 
     /**
      * 记录登录信息
+     *
+     * @param userId 用户ID
      */
-    public void recordLoginInfo(SysUser user)
+    public void recordLoginInfo(Long userId)
     {
-        user.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
-        user.setLoginDate(DateUtils.getNowDate());
-        userService.updateUserProfile(user);
+        SysUser sysUser = new SysUser();
+        sysUser.setUserId(userId);
+        sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+        sysUser.setLoginDate(DateUtils.getNowDate());
+        userService.updateUserProfile(sysUser);
     }
 }

+ 1 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java

@@ -2,7 +2,6 @@ package com.ruoyi.framework.web.service;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
-import org.springframework.util.StringUtils;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.constant.UserConstants;
 import com.ruoyi.common.core.domain.entity.SysUser;
@@ -12,6 +11,7 @@ import com.ruoyi.common.exception.user.CaptchaException;
 import com.ruoyi.common.exception.user.CaptchaExpireException;
 import com.ruoyi.common.utils.MessageUtils;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.manager.AsyncManager;
 import com.ruoyi.framework.manager.factory.AsyncFactory;
 import com.ruoyi.system.service.ISysConfigService;

+ 22 - 0
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java

@@ -58,6 +58,7 @@ public class VelocityUtils
         velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
         velocityContext.put("columns", genTable.getColumns());
         velocityContext.put("table", genTable);
+        velocityContext.put("dicts", getDicts(genTable));
         setMenuVelocityContext(velocityContext, genTable);
         if (GenConstants.TPL_TREE.equals(tplCategory))
         {
@@ -260,6 +261,27 @@ public class VelocityUtils
         return importList;
     }
 
+    /**
+     * 根据列类型获取字典组
+     * 
+     * @param genTable 业务表对象
+     * @return 返回字典组
+     */
+    public static String getDicts(GenTable genTable)
+    {
+        List<GenTableColumn> columns = genTable.getColumns();
+        List<String> dicts = new ArrayList<String>();
+        for (GenTableColumn column : columns)
+        {
+            if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
+                    column.getHtmlType(), new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO }))
+            {
+                dicts.add("'" + column.getDictType() + "'");
+            }
+        }
+        return StringUtils.join(dicts, ", ");
+    }
+
     /**
      * 获取权限前缀
      *

+ 1 - 1
ruoyi-generator/src/main/resources/vm/java/mapper.java.vm

@@ -69,7 +69,7 @@ public interface ${ClassName}Mapper
      * @param ${pkColumn.javaField}s 需要删除的数据主键集合
      * @return 结果
      */
-    public int delete${subClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+    public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
     
     /**
      * 批量新增${subTable.functionName}

+ 29 - 46
ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm

@@ -25,10 +25,10 @@
       <el-form-item label="${comment}" prop="${column.javaField}">
         <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
           <el-option
-            v-for="dict in ${column.javaField}Options"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -108,7 +108,7 @@
 #elseif($column.list && "" != $column.dictType)
       <el-table-column label="${comment}" align="center" prop="${javaField}">
         <template slot-scope="scope">
-          <dict-tag :options="${javaField}Options" :value="scope.row.${javaField}"/>
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
         </template>
       </el-table-column>
 #elseif($column.list && "" != $javaField)
@@ -184,10 +184,10 @@
         <el-form-item label="${comment}" prop="${field}">
           <el-select v-model="form.${field}" placeholder="请选择${comment}">
             <el-option
-              v-for="dict in ${field}Options"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              #if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.dictValue)"#else:value="dict.dictValue"#end
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+              #if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end
 
             ></el-option>
           </el-select>
@@ -202,10 +202,10 @@
         <el-form-item label="${comment}">
           <el-checkbox-group v-model="form.${field}">
             <el-checkbox
-              v-for="dict in ${field}Options"
-              :key="dict.dictValue"
-              :label="dict.dictValue">
-              {{dict.dictLabel}}
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
             </el-checkbox>
           </el-checkbox-group>
         </el-form-item>
@@ -219,11 +219,11 @@
         <el-form-item label="${comment}">
           <el-radio-group v-model="form.${field}">
             <el-radio
-              v-for="dict in ${field}Options"
-              :key="dict.dictValue"
-              #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.dictValue)"#else:label="dict.dictValue"#end
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end
 
-            >{{dict.dictLabel}}</el-radio>
+            >{{dict.label}}</el-radio>
           </el-radio-group>
         </el-form-item>
 #elseif($column.htmlType == "radio" && $dictType)
@@ -265,6 +265,9 @@ import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
 export default {
   name: "${BusinessName}",
+#if(${dicts} != '')
+  dicts: [${dicts}],
+#end
   components: {
     Treeselect
   },
@@ -283,16 +286,7 @@ export default {
       // 是否显示弹出层
       open: false,
 #foreach ($column in $columns)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if(${column.dictType} != '')
-      // $comment字典
-      ${column.javaField}Options: [],
-#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
 #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
       // $comment时间范围
       daterange${AttrName}: [],
@@ -330,13 +324,6 @@ export default {
   },
   created() {
     this.getList();
-#foreach ($column in $columns)
-#if(${column.dictType} != '')
-    this.getDicts("${column.dictType}").then(response => {
-      this.${column.javaField}Options = response.data;
-    });
-#end
-#end
   },
   methods: {
     /** 查询${functionName}列表 */
@@ -461,13 +448,13 @@ export default {
 #end
           if (this.form.${pkColumn.javaField} != null) {
             update${BusinessName}(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.#[[$modal]]#.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             add${BusinessName}(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.#[[$modal]]#.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -477,16 +464,12 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return del${BusinessName}(row.${pkColumn.javaField});
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
+        return del${BusinessName}(row.${pkColumn.javaField});
+      }).then(() => {
+        this.getList();
+        this.#[[$modal]]#.msgSuccess("删除成功");
+      }).catch(() => {});
     }
   }
 };

+ 37 - 58
ruoyi-generator/src/main/resources/vm/vue/index.vue.vm

@@ -25,10 +25,10 @@
       <el-form-item label="${comment}" prop="${column.javaField}">
         <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable size="small">
           <el-option
-            v-for="dict in ${column.javaField}Options"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -137,7 +137,7 @@
 #elseif($column.list && "" != $column.dictType)
       <el-table-column label="${comment}" align="center" prop="${javaField}">
         <template slot-scope="scope">
-          <dict-tag :options="${javaField}Options" :value="scope.row.${javaField}"/>
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
         </template>
       </el-table-column>
 #elseif($column.list && "" != $javaField)
@@ -206,10 +206,10 @@
         <el-form-item label="${comment}" prop="${field}">
           <el-select v-model="form.${field}" placeholder="请选择${comment}">
             <el-option
-              v-for="dict in ${field}Options"
-              :key="dict.dictValue"
-              :label="dict.dictLabel"
-              #if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.dictValue)"#else:value="dict.dictValue"#end
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+              #if($column.javaType == "Integer" || $column.javaType == "Long"):value="parseInt(dict.value)"#else:value="dict.value"#end
 
             ></el-option>
           </el-select>
@@ -224,10 +224,10 @@
         <el-form-item label="${comment}">
           <el-checkbox-group v-model="form.${field}">
             <el-checkbox
-              v-for="dict in ${field}Options"
-              :key="dict.dictValue"
-              :label="dict.dictValue">
-              {{dict.dictLabel}}
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
             </el-checkbox>
           </el-checkbox-group>
         </el-form-item>
@@ -241,11 +241,11 @@
         <el-form-item label="${comment}">
           <el-radio-group v-model="form.${field}">
             <el-radio
-              v-for="dict in ${field}Options"
-              :key="dict.dictValue"
-              #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.dictValue)"#else:label="dict.dictValue"#end
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              #if($column.javaType == "Integer" || $column.javaType == "Long"):label="parseInt(dict.value)"#else:label="dict.value"#end
 
-            >{{dict.dictLabel}}</el-radio>
+            >{{dict.label}}</el-radio>
           </el-radio-group>
         </el-form-item>
 #elseif($column.htmlType == "radio" && $dictType)
@@ -317,6 +317,9 @@ import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${Busin
 
 export default {
   name: "${BusinessName}",
+#if(${dicts} != '')
+  dicts: [${dicts}],
+#end
   data() {
     return {
       // 遮罩层
@@ -348,16 +351,7 @@ export default {
       // 是否显示弹出层
       open: false,
 #foreach ($column in $columns)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if(${column.dictType} != '')
-      // $comment字典
-      ${column.javaField}Options: [],
-#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
 #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
       // $comment时间范围
       daterange${AttrName}: [],
@@ -397,13 +391,6 @@ export default {
   },
   created() {
     this.getList();
-#foreach ($column in $columns)
-#if(${column.dictType} != '')
-    this.getDicts("${column.dictType}").then(response => {
-      this.${column.javaField}Options = response.data;
-    });
-#end
-#end
   },
   methods: {
     /** 查询${functionName}列表 */
@@ -516,13 +503,13 @@ export default {
 #end
           if (this.form.${pkColumn.javaField} != null) {
             update${BusinessName}(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.#[[$modal]]#.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             add${BusinessName}(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.#[[$modal]]#.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -533,16 +520,12 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids;
-      this.$confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return del${BusinessName}(${pkColumn.javaField}s);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
+        return del${BusinessName}(${pkColumn.javaField}s);
+      }).then(() => {
+        this.getList();
+        this.#[[$modal]]#.msgSuccess("删除成功");
+      }).catch(() => {});
     },
 #if($table.sub)
 	/** ${subTable.functionName}序号 */
@@ -563,7 +546,7 @@ export default {
     /** ${subTable.functionName}删除按钮操作 */
     handleDelete${subClassName}() {
       if (this.checked${subClassName}.length == 0) {
-        this.msgError("请先选择要删除的${subTable.functionName}数据");
+        this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
       } else {
         const ${subclassName}List = this.${subclassName}List;
         const checked${subClassName} = this.checked${subClassName};
@@ -580,17 +563,13 @@ export default {
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有${functionName}数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return export${BusinessName}(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.#[[$modal]]#.confirm('是否确认导出所有${functionName}数据项?').then(() => {
+        this.exportLoading = true;
+        return export${BusinessName}(queryParams);
+      }).then(response => {
+        this.#[[$download]]#.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 1 - 0
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java

@@ -169,6 +169,7 @@ public class SysMenuServiceImpl implements ISysMenuService
                 children.setComponent(menu.getComponent());
                 children.setName(StringUtils.capitalize(menu.getPath()));
                 children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
+                children.setQuery(menu.getQuery());
                 childrenList.add(children);
                 router.setChildren(childrenList);
             }

+ 4 - 4
ruoyi-ui/package.json

@@ -41,8 +41,8 @@
     "clipboard": "2.0.6",
     "core-js": "3.8.1",
     "echarts": "4.9.0",
-    "element-ui": "2.15.5",
-    "file-saver": "2.0.4",
+    "element-ui": "2.15.6",
+    "file-saver": "2.0.5",
     "fuse.js": "6.4.3",
     "highlight.js": "9.18.5",
     "js-beautify": "1.13.0",
@@ -71,8 +71,8 @@
     "eslint-plugin-vue": "7.2.0",
     "lint-staged": "10.5.3",
     "runjs": "4.4.2",
-    "sass": "1.32.0",
-    "sass-loader": "10.1.0",
+    "sass": "1.32.13",
+    "sass-loader": "10.1.1",
     "script-ext-html-webpack-plugin": "2.1.5",
     "svg-sprite-loader": "5.1.1",
     "vue-template-compiler": "2.6.12"

+ 21 - 0
ruoyi-ui/src/components/DictData/index.js

@@ -0,0 +1,21 @@
+import Vue from 'vue'
+import DataDict from '@/utils/dict'
+import { getDicts as getDicts } from '@/api/system/dict/data'
+
+function install() {
+  Vue.use(DataDict, {
+    metas: {
+      '*': {
+        labelField: 'dictLabel',
+        valueField: 'dictValue',
+        request(dictMeta) {
+          return getDicts(dictMeta.type).then(res => res.data)
+        },
+      },
+    },
+  })
+}
+
+export default {
+  install,
+}

+ 51 - 50
ruoyi-ui/src/components/DictTag/index.vue

@@ -1,51 +1,52 @@
-<template>
-  <div>
-    <template v-for="(item, index) in options">
-      <template v-if="values.includes(item.dictValue)">
-        <span
-          v-if="item.listClass == 'default' || item.listClass == ''"
-          :key="item.dictValue"
-          :index="index"
-          :class="item.cssClass"
-          >{{ item.dictLabel }}</span
-        >
-        <el-tag
-          v-else
-          :key="item.dictValue"
-          :index="index"
-          :type="item.listClass == 'primary' ? '' : item.listClass"
-          :class="item.cssClass"
-        >
-          {{ item.dictLabel }}
-        </el-tag>
-      </template>
-    </template>
-  </div>
-</template>
-
-<script>
-export default {
-  name: "DictTag",
-  props: {
-    options: {
-      type: Array,
-      default: null,
-    },
-    value: [Number, String, Array],
-  },
-  computed: {
-    values() {
-      if (this.value !== null && typeof this.value !== 'undefined') {
-        return Array.isArray(this.value) ? this.value : [String(this.value)];
-      } else {
-        return [];
-      }
-    },
-  },
-};
-</script>
-<style scoped>
-.el-tag + .el-tag {
-  margin-left: 10px;
-}
+<template>
+  <div>
+    <template v-for="(item, index) in options">
+      <template v-if="values.includes(item.value)">
+        <span
+          v-if="item.raw.listClass == 'default' || item.raw.listClass == ''"
+          :key="item.value"
+          :index="index"
+          :class="item.raw.cssClass"
+          >{{ item.label }}</span
+        >
+        <el-tag
+          v-else
+          :disable-transitions="true"
+          :key="item.value"
+          :index="index"
+          :type="item.raw.listClass == 'primary' ? '' : item.raw.listClass"
+          :class="item.raw.cssClass"
+        >
+          {{ item.label }}
+        </el-tag>
+      </template>
+    </template>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "DictTag",
+  props: {
+    options: {
+      type: Array,
+      default: null,
+    },
+    value: [Number, String, Array],
+  },
+  computed: {
+    values() {
+      if (this.value !== null && typeof this.value !== 'undefined') {
+        return Array.isArray(this.value) ? this.value : [String(this.value)];
+      } else {
+        return [];
+      }
+    },
+  },
+};
+</script>
+<style scoped>
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
 </style>

+ 5 - 17
ruoyi-ui/src/layout/components/Settings/index.vue

@@ -162,14 +162,8 @@ export default {
       this.sideTheme = val;
     },
     saveSetting() {
-      const loading = this.$loading({
-        lock: true,
-        fullscreen: false,
-        text: "正在保存到本地,请稍后...",
-        spinner: "el-icon-loading",
-        background: "rgba(0, 0, 0, 0.7)"
-      });
-      localStorage.setItem(
+      this.$modal.loading("正在保存到本地,请稍后...");
+      this.$cache.local.set(
         "layout-setting",
         `{
             "topNav":${this.topNav},
@@ -181,17 +175,11 @@ export default {
             "theme":"${this.theme}"
           }`
       );
-      setTimeout(loading.close(), 1000)
+      setTimeout(this.$modal.closeLoading(), 1000)
     },
     resetSetting() {
-      this.$loading({
-        lock: true,
-        fullscreen: false,
-        text: "正在清除设置缓存并刷新,请稍后...",
-        spinner: "el-icon-loading",
-        background: "rgba(0, 0, 0, 0.7)"
-      });
-      localStorage.removeItem("layout-setting")
+      this.$modal.loading("正在清除设置缓存并刷新,请稍后...");
+      this.$cache.local.remove("layout-setting")
       setTimeout("window.location.reload()", 1000)
     }
   }

+ 7 - 14
ruoyi-ui/src/main.js

@@ -11,12 +11,14 @@ import App from './App'
 import store from './store'
 import router from './router'
 import directive from './directive' //directive
+import plugins from './plugins' // plugins
 
 import './assets/icons' // icon
 import './permission' // permission control
 import { getDicts } from "@/api/system/dict/data";
 import { getConfigKey } from "@/api/system/config";
-import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree } from "@/utils/ruoyi";
+import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
+// 分页组件
 import Pagination from "@/components/Pagination";
 // 自定义表格工具组件
 import RightToolbar from "@/components/RightToolbar"
@@ -30,6 +32,8 @@ import ImageUpload from "@/components/ImageUpload"
 import DictTag from '@/components/DictTag'
 // 头部标签组件
 import VueMeta from 'vue-meta'
+// 字典数据组件
+import DictData from '@/components/DictData'
 
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts
@@ -39,21 +43,8 @@ Vue.prototype.resetForm = resetForm
 Vue.prototype.addDateRange = addDateRange
 Vue.prototype.selectDictLabel = selectDictLabel
 Vue.prototype.selectDictLabels = selectDictLabels
-Vue.prototype.download = download
 Vue.prototype.handleTree = handleTree
 
-Vue.prototype.msgSuccess = function (msg) {
-  this.$message({ showClose: true, message: msg, type: "success" });
-}
-
-Vue.prototype.msgError = function (msg) {
-  this.$message({ showClose: true, message: msg, type: "error" });
-}
-
-Vue.prototype.msgInfo = function (msg) {
-  this.$message.info(msg);
-}
-
 // 全局组件挂载
 Vue.component('DictTag', DictTag)
 Vue.component('Pagination', Pagination)
@@ -63,7 +54,9 @@ Vue.component('FileUpload', FileUpload)
 Vue.component('ImageUpload', ImageUpload)
 
 Vue.use(directive)
+Vue.use(plugins)
 Vue.use(VueMeta)
+DictData.install()
 
 /**
  * If you don't want to use mock-server

+ 77 - 0
ruoyi-ui/src/plugins/cache.js

@@ -0,0 +1,77 @@
+const sessionCache = {
+  set (key, value) {
+    if (!sessionStorage) {
+      return
+    }
+    if (key != null && value != null) {
+      sessionStorage.setItem(key, value)
+    }
+  },
+  get (key) {
+    if (!sessionStorage) {
+      return null
+    }
+    if (key == null) {
+      return null
+    }
+    return sessionStorage.getItem(key)
+  },
+  setJSON (key, jsonValue) {
+    if (jsonValue != null) {
+      this.set(key, JSON.stringify(jsonValue))
+    }
+  },
+  getJSON (key) {
+    const value = this.get(key)
+    if (value != null) {
+      return JSON.parse(value)
+    }
+  },
+  remove (key) {
+    sessionStorage.removeItem(key);
+  }
+}
+const localCache = {
+  set (key, value) {
+    if (!localStorage) {
+      return
+    }
+    if (key != null && value != null) {
+      localStorage.setItem(key, value)
+    }
+  },
+  get (key) {
+    if (!localStorage) {
+      return null
+    }
+    if (key == null) {
+      return null
+    }
+    return localStorage.getItem(key)
+  },
+  setJSON (key, jsonValue) {
+    if (jsonValue != null) {
+      this.set(key, JSON.stringify(jsonValue))
+    }
+  },
+  getJSON (key) {
+    const value = this.get(key)
+    if (value != null) {
+      return JSON.parse(value)
+    }
+  },
+  remove (key) {
+    localStorage.removeItem(key);
+  }
+}
+
+export default {
+  /**
+   * 会话级缓存
+   */
+  session: sessionCache,
+  /**
+   * 本地缓存
+   */
+  local: localCache
+}

+ 48 - 0
ruoyi-ui/src/plugins/download.js

@@ -0,0 +1,48 @@
+import { saveAs } from 'file-saver'
+import axios from 'axios'
+import { getToken } from '@/utils/auth'
+
+const baseURL = process.env.VUE_APP_BASE_API
+
+export default {
+  name(name, isDelete = true) {
+    var url = baseURL + "/common/download?fileName=" + encodeURI(name) + "&delete=" + isDelete
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: { 'Authorization': 'Bearer ' + getToken() }
+    }).then(res => {
+      const blob = new Blob([res.data])
+      this.saveAs(blob, decodeURI(res.headers['download-filename']))
+    })
+  },
+  resource(resource) {
+    var url = baseURL + "/common/download/resource?resource=" + encodeURI(resource);
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: { 'Authorization': 'Bearer ' + getToken() }
+    }).then(res => {
+      const blob = new Blob([res.data])
+      this.saveAs(blob, decodeURI(res.headers['download-filename']))
+    })
+  },
+  zip(url, name) {
+    var url = baseURL + url
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: { 'Authorization': 'Bearer ' + getToken() }
+    }).then(res => {
+      const blob = new Blob([res.data], { type: 'application/zip' })
+      this.saveAs(blob, name)
+    })
+  },
+  saveAs(text, name, opts) {
+    saveAs(text, name, opts);
+  }
+}
+

+ 14 - 0
ruoyi-ui/src/plugins/index.js

@@ -0,0 +1,14 @@
+import cache from './cache'
+import modal from './modal'
+import download from './download'
+
+export default {
+  install(Vue) {
+    // 缓存对象
+    Vue.prototype.$cache = cache
+    // 模态框对象
+    Vue.prototype.$modal = modal
+    // 下载文件
+    Vue.prototype.$download = download
+  }
+}

+ 75 - 0
ruoyi-ui/src/plugins/modal.js

@@ -0,0 +1,75 @@
+import { Message, MessageBox, Notification, Loading } from 'element-ui'
+
+let loadingInstance;
+
+export default {
+  // 消息提示
+  msg(content) {
+    Message.info(content)
+  },
+  // 错误消息
+  msgError(content) {
+    Message.error(content)
+  },
+  // 成功消息
+  msgSuccess(content) {
+    Message.success(content)
+  },
+  // 警告消息
+  msgWarning(content) {
+    Message.warning(content)
+  },
+  // 弹出提示
+  alert(content) {
+    MessageBox.alert(content, "系统提示")
+  },
+  // 错误提示
+  alertError(content) {
+    MessageBox.alert(content, "系统提示", { type: 'error' })
+  },
+  // 成功提示
+  alertSuccess(content) {
+    MessageBox.alert(content, "系统提示", { type: 'success' })
+  },
+  // 警告提示
+  alertWarning(content) {
+    MessageBox.alert(content, "系统提示", { type: 'warning' })
+  },
+  // 通知提示
+  notify(content) {
+    Notification.info(content)
+  },
+  // 错误通知
+  notifyError(content) {
+    Notification.error(content);
+  },
+  // 成功通知
+  notifySuccess(content) {
+    Notification.success(content)
+  },
+  // 警告通知
+  notifyWarning(content) {
+    Notification.warning(content)
+  },
+  // 确认窗体
+  confirm(content) {
+    return MessageBox.confirm(content, "系统提示", {
+      confirmButtonText: '确定',
+      cancelButtonText: '取消',
+      type: "warning",
+    })
+  },
+  // 打开遮罩层
+  loading(content) {
+    loadingInstance = Loading.service({
+      lock: true,
+      text: content,
+      spinner: "el-icon-loading",
+      background: "rgba(0, 0, 0, 0.7)",
+    })
+  },
+  // 关闭遮罩层
+  closeLoading() {
+    loadingInstance.close();
+  }
+}

+ 82 - 0
ruoyi-ui/src/utils/dict/Dict.js

@@ -0,0 +1,82 @@
+import Vue from 'vue'
+import { mergeRecursive } from "@/utils/ruoyi";
+import DictMeta from './DictMeta'
+import DictData from './DictData'
+
+const DEFAULT_DICT_OPTIONS = {
+  types: [],
+}
+
+/**
+ * @classdesc 字典
+ * @property {Object} label 标签对象,内部属性名为字典类型名称
+ * @property {Object} dict 字段数组,内部属性名为字典类型名称
+ * @property {Array.<DictMeta>} _dictMetas 字典元数据数组
+ */
+export default class Dict {
+  constructor() {
+    this.owner = null
+    this.label = {}
+    this.type = {}
+  }
+
+  init(options) {
+    if (options instanceof Array) {
+      options = { types: options }
+    }
+    const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
+    if (opts.types === undefined) {
+      throw new Error('need dict types')
+    }
+    const ps = []
+    this._dictMetas = opts.types.map(t => DictMeta.parse(t))
+    this._dictMetas.forEach(dictMeta => {
+      const type = dictMeta.type
+      Vue.set(this.label, type, {})
+      Vue.set(this.type, type, [])
+      if (dictMeta.lazy) {
+        return
+      }
+      ps.push(loadDict(this, dictMeta))
+    })
+    return Promise.all(ps)
+  }
+
+  /**
+   * 重新加载字典
+   * @param {String} type 字典类型
+   */
+  reloadDict(type) {
+    const dictMeta = this._dictMetas.find(e => e.type === type)
+    if (dictMeta === undefined) {
+      return Promise.reject(`the dict meta of ${type} was not found`)
+    }
+    return loadDict(this, dictMeta)
+  }
+}
+
+/**
+ * 加载字典
+ * @param {Dict} dict 字典
+ * @param {DictMeta} dictMeta 字典元数据
+ * @returns {Promise}
+ */
+function loadDict(dict, dictMeta) {
+  return dictMeta.request(dictMeta)
+    .then(response => {
+      const type = dictMeta.type
+      let dicts = dictMeta.responseConverter(response, dictMeta)
+      if (!(dicts instanceof Array)) {
+        console.error('the return of responseConverter must be Array.<DictData>')
+        dicts = []
+      } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) {
+        console.error('the type of elements in dicts must be DictData')
+        dicts = []
+      }
+      dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
+      dicts.forEach(d => {
+        Vue.set(dict.label[type], d.value, d.label)
+      })
+      return dicts
+    })
+}

+ 17 - 0
ruoyi-ui/src/utils/dict/DictConverter.js

@@ -0,0 +1,17 @@
+import DictOptions from './DictOptions'
+import DictData from './DictData'
+
+export default function(dict, dictMeta) {
+  const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS)
+  const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS)
+  return new DictData(dict[label], dict[value], dict)
+}
+
+/**
+ * 确定字典字段
+ * @param {DictData} dict
+ * @param  {...String} fields
+ */
+function determineDictField(dict, ...fields) {
+  return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f))
+}

+ 13 - 0
ruoyi-ui/src/utils/dict/DictData.js

@@ -0,0 +1,13 @@
+/**
+ * @classdesc 字典数据
+ * @property {String} label 标签
+ * @property {*} value 标签
+ * @property {Object} raw 原始数据
+ */
+export default class DictData {
+  constructor(label, value, raw) {
+    this.label = label
+    this.value = value
+    this.raw = raw
+  }
+}

+ 38 - 0
ruoyi-ui/src/utils/dict/DictMeta.js

@@ -0,0 +1,38 @@
+import { mergeRecursive } from "@/utils/ruoyi";
+import DictOptions from './DictOptions'
+
+/**
+ * @classdesc 字典元数据
+ * @property {String} type 类型
+ * @property {Function} request 请求
+ * @property {String} label 标签字段
+ * @property {String} value 值字段
+ */
+export default class DictMeta {
+  constructor(options) {
+    this.type = options.type
+    this.request = options.request,
+    this.responseConverter = options.responseConverter
+    this.labelField = options.labelField
+    this.valueField = options.valueField
+    this.lazy = options.lazy === true
+  }
+}
+
+
+/**
+ * 解析字典元数据
+ * @param {Object} options
+ * @returns {DictMeta}
+ */
+DictMeta.parse= function(options) {
+  let opts = null
+  if (typeof options === 'string') {
+    opts = DictOptions.metas[options] || {}
+    opts.type = options
+  } else if (typeof options === 'object') {
+    opts = options
+  }
+  opts = mergeRecursive(DictOptions.metas['*'], opts)
+  return new DictMeta(opts)
+}

+ 51 - 0
ruoyi-ui/src/utils/dict/DictOptions.js

@@ -0,0 +1,51 @@
+import { mergeRecursive } from "@/utils/ruoyi";
+import dictConverter from './DictConverter'
+
+export const options = {
+  metas: {
+    '*': {
+      /**
+       * 字典请求,方法签名为function(dictMeta: DictMeta): Promise
+       */
+      request: (dictMeta) => {
+        console.log(`load dict ${dictMeta.type}`)
+        return Promise.resolve([])
+      },
+      /**
+       * 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData
+       */
+      responseConverter,
+      labelField: 'label',
+      valueField: 'value',
+    },
+  },
+  /**
+   * 默认标签字段
+   */
+  DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
+  /**
+   * 默认值字段
+   */
+  DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
+}
+
+/**
+ * 映射字典
+ * @param {Object} response 字典数据
+ * @param {DictMeta} dictMeta 字典元数据
+ * @returns {DictData}
+ */
+function responseConverter(response, dictMeta) {
+  const dicts = response.content instanceof Array ? response.content : response
+  if (dicts === undefined) {
+    console.warn(`no dict data of "${dictMeta.type}" found in the response`)
+    return []
+  }
+  return dicts.map(d => dictConverter(d, dictMeta))
+}
+
+export function mergeOptions(src) {
+  mergeRecursive(options, src)
+}
+
+export default options

+ 33 - 0
ruoyi-ui/src/utils/dict/index.js

@@ -0,0 +1,33 @@
+import Dict from './Dict'
+import { mergeOptions } from './DictOptions'
+
+export default function(Vue, options) {
+  mergeOptions(options)
+  Vue.mixin({
+    data() {
+      if (this.$options.dicts === undefined || this.$options.dicts === null) {
+        return {}
+      }
+      const dict = new Dict()
+      dict.owner = this
+      return {
+        dict
+      }
+    },
+    created() {
+      if (!(this.dict instanceof Dict)) {
+        return
+      }
+      options.onCreated && options.onCreated(this.dict)
+      this.dict.init(this.$options.dicts).then(() => {
+        options.onReady && options.onReady(this.dict)
+        this.$nextTick(() => {
+          this.$emit('dictReady', this.dict)
+          if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
+            this.$options.methods.onDictReady.call(this, this.dict)
+          }
+        })
+      })
+    },
+  })
+}

+ 18 - 9
ruoyi-ui/src/utils/ruoyi.js

@@ -3,8 +3,6 @@
  * Copyright (c) 2019 ruoyi
  */
 
-const baseURL = process.env.VUE_APP_BASE_API
-
 // 日期格式化
 export function parseTime(time, pattern) {
 	if (arguments.length === 0 || !time) {
@@ -72,8 +70,8 @@ export function addDateRange(params, dateRange, propName) {
 export function selectDictLabel(datas, value) {
 	var actions = [];
 	Object.keys(datas).some((key) => {
-		if (datas[key].dictValue == ('' + value)) {
-			actions.push(datas[key].dictLabel);
+		if (datas[key].value == ('' + value)) {
+			actions.push(datas[key].label);
 			return true;
 		}
 	})
@@ -95,11 +93,6 @@ export function selectDictLabels(datas, value, separator) {
 	return actions.join('').substring(0, actions.join('').length - 1);
 }
 
-// 通用下载方法
-export function download(fileName) {
-	window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
-}
-
 // 字符串格式化(%s )
 export function sprintf(str) {
 	var args = arguments, flag = true, i = 1;
@@ -122,6 +115,22 @@ export function praseStrEmpty(str) {
 	return str;
 }
 
+// 数据合并
+export function mergeRecursive(source, target) {
+    for (var p in target) {
+        try {
+            if (target[p].constructor == Object) {
+                source[p] = mergeRecursive(source[p], target[p]);
+            } else {
+                source[p] = target[p];
+            }
+        } catch(e) {
+            source[p] = target[p];
+        }
+    }
+    return source;
+};
+
 /**
  * 构造树型结构数据
  * @param {*} data 数据源

+ 0 - 42
ruoyi-ui/src/utils/zipdownload.js

@@ -1,42 +0,0 @@
-import axios from 'axios'
-import { getToken } from '@/utils/auth'
-
-const mimeMap = {
-  xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
-  zip: 'application/zip'
-}
-
-const baseUrl = process.env.VUE_APP_BASE_API
-export function downLoadZip(str, filename) {
-  var url = baseUrl + str
-  axios({
-    method: 'get',
-    url: url,
-    responseType: 'blob',
-    headers: { 'Authorization': 'Bearer ' + getToken() }
-  }).then(res => {
-    resolveBlob(res, mimeMap.zip)
-  })
-}
-/**
- * 解析blob响应内容并下载
- * @param {*} res blob响应内容
- * @param {String} mimeType MIME类型
- */
-export function resolveBlob(res, mimeType) {
-  const aLink = document.createElement('a')
-  var blob = new Blob([res.data], { type: mimeType })
-  // //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
-  var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
-  var contentDisposition = decodeURI(res.headers['content-disposition'])
-  var result = patt.exec(contentDisposition)
-  var fileName = result[1]
-  fileName = fileName.replace(/\"/g, '')
-  aLink.style.display = 'none'
-  aLink.href = URL.createObjectURL(blob)
-  aLink.setAttribute('download', fileName) // 设置下载文件名称
-  document.body.appendChild(aLink)
-  aLink.click()
-  URL.revokeObjectURL(aLink.href);//清除引用
-  document.body.removeChild(aLink);
-}

+ 26 - 33
ruoyi-ui/src/views/monitor/cache/index.vue

@@ -8,34 +8,34 @@
             <table cellspacing="0" style="width: 100%">
               <tbody>
                 <tr>
-                  <td><div class="cell">Redis版本</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
-                  <td><div class="cell">运行模式</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td>
-                  <td><div class="cell">端口</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
-                  <td><div class="cell">客户端数</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">Redis版本</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">运行模式</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "单机" : "集群" }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">端口</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">客户端数</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">运行时间(天)</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
-                  <td><div class="cell">使用内存</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
-                  <td><div class="cell">使用CPU</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
-                  <td><div class="cell">内存配置</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">运行时间(天)</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">使用内存</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">使用CPU</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">内存配置</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">AOF是否开启</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
-                  <td><div class="cell">RDB是否成功</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
-                  <td><div class="cell">Key数量</div></td>
-                  <td><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
-                  <td><div class="cell">网络入口/出口</div></td>
-                  <td><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">AOF是否开启</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "否" : "是" }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">RDB是否成功</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">Key数量</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">网络入口/出口</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
                 </tr>
               </tbody>
             </table>
@@ -74,8 +74,6 @@ export default {
   name: "Server",
   data() {
     return {
-      // 加载层信息
-      loading: [],
       // 统计命令信息
       commandstats: null,
       // 使用内存
@@ -93,7 +91,7 @@ export default {
     getList() {
       getCache().then((response) => {
         this.cache = response.data;
-        this.loading.close();
+        this.$modal.closeLoading();
 
         this.commandstats = echarts.init(this.$refs.commandstats, "macarons");
         this.commandstats.setOption({
@@ -141,12 +139,7 @@ export default {
     },
     // 打开加载层
     openLoading() {
-      this.loading = this.$loading({
-        lock: true,
-        text: "拼命读取中",
-        spinner: "el-icon-loading",
-        background: "rgba(0, 0, 0, 0.7)",
-      });
+      this.$modal.loading("正在加载缓存监控数据,请稍后!");
     },
   },
 };

+ 47 - 72
ruoyi-ui/src/views/monitor/job/index.vue

@@ -13,20 +13,20 @@
       <el-form-item label="任务组名" prop="jobGroup">
         <el-select v-model="queryParams.jobGroup" placeholder="请选择任务组名" clearable size="small">
           <el-option
-            v-for="dict in jobGroupOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_job_group"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
       <el-form-item label="任务状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable size="small">
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_job_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -99,7 +99,7 @@
       <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
       <el-table-column label="任务组名" align="center" prop="jobGroup">
         <template slot-scope="scope">
-          <dict-tag :options="jobGroupOptions" :value="scope.row.jobGroup"/>
+          <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
         </template>
       </el-table-column>
       <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
@@ -168,10 +168,10 @@
             <el-form-item label="任务分组" prop="jobGroup">
               <el-select v-model="form.jobGroup" placeholder="请选择">
                 <el-option
-                  v-for="dict in jobGroupOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictLabel"
-                  :value="dict.dictValue"
+                  v-for="dict in dict.type.sys_job_group"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
                 ></el-option>
               </el-select>
             </el-form-item>
@@ -225,10 +225,10 @@
             <el-form-item label="状态">
               <el-radio-group v-model="form.status">
                 <el-radio
-                  v-for="dict in statusOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictValue"
-                >{{dict.dictLabel}}</el-radio>
+                  v-for="dict in dict.type.sys_job_status"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -240,7 +240,7 @@
       </div>
     </el-dialog>
 
-    <el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body class="scrollbar">
+    <el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar">
       <crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
     </el-dialog>
 
@@ -301,6 +301,7 @@ import Crontab from '@/components/Crontab'
 export default {
   components: { Crontab },
   name: "Job",
+  dicts: ['sys_job_group', 'sys_job_status'],
   data() {
     return {
       // 遮罩层
@@ -329,10 +330,6 @@ export default {
       openCron: false,
       // 传入的表达式
       expression: "",
-      // 任务组名字典
-      jobGroupOptions: [],
-      // 状态字典
-      statusOptions: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -359,12 +356,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_job_group").then(response => {
-      this.jobGroupOptions = response.data;
-    });
-    this.getDicts("sys_job_status").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     /** 查询定时任务列表 */
@@ -378,7 +369,7 @@ export default {
     },
     // 任务组名字典翻译
     jobGroupFormat(row, column) {
-      return this.selectDictLabel(this.jobGroupOptions, row.jobGroup);
+      return this.selectDictLabel(this.dict.type.sys_job_group, row.jobGroup);
     },
     // 取消按钮
     cancel() {
@@ -434,29 +425,21 @@ export default {
     // 任务状态修改
     handleStatusChange(row) {
       let text = row.status === "0" ? "启用" : "停用";
-      this.$confirm('确认要"' + text + '""' + row.jobName + '"任务吗?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return changeJobStatus(row.jobId, row.status);
-        }).then(() => {
-          this.msgSuccess(text + "成功");
-        }).catch(function() {
-          row.status = row.status === "0" ? "1" : "0";
-        });
+      this.$modal.confirm('确认要"' + text + '""' + row.jobName + '"任务吗?').then(function() {
+        return changeJobStatus(row.jobId, row.status);
+      }).then(() => {
+        this.$modal.msgSuccess(text + "成功");
+      }).catch(function() {
+        row.status = row.status === "0" ? "1" : "0";
+      });
     },
     /* 立即执行一次 */
     handleRun(row) {
-      this.$confirm('确认要立即执行一次"' + row.jobName + '"任务吗?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return runJob(row.jobId, row.jobGroup);
-        }).then(() => {
-          this.msgSuccess("执行成功");
-        }).catch(() => {});
+      this.$modal.confirm('确认要立即执行一次"' + row.jobName + '"任务吗?').then(function() {
+        return runJob(row.jobId, row.jobGroup);
+      }).then(() => {
+        this.$modal.msgSuccess("执行成功");
+      }).catch(() => {});
     },
     /** 任务详细信息 */
     handleView(row) {
@@ -501,13 +484,13 @@ export default {
         if (valid) {
           if (this.form.jobId != undefined) {
             updateJob(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addJob(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -518,31 +501,23 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const jobIds = row.jobId || this.ids;
-      this.$confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delJob(jobIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?').then(function() {
+        return delJob(jobIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm("是否确认导出所有定时任务数据项?", "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportJob(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有定时任务数据项?').then(() => {
+        this.exportLoading = true;
+        return exportJob(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 30 - 51
ruoyi-ui/src/views/monitor/job/log.vue

@@ -20,10 +20,10 @@
           style="width: 240px"
         >
           <el-option
-            v-for="dict in jobGroupOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_job_group"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -36,10 +36,10 @@
           style="width: 240px"
         >
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_common_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -112,14 +112,14 @@
       <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
       <el-table-column label="任务组名" align="center" prop="jobGroup" :show-overflow-tooltip="true">
         <template slot-scope="scope">
-          <dict-tag :options="jobGroupOptions" :value="scope.row.jobGroup"/>
+          <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
         </template>
       </el-table-column>
       <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
       <el-table-column label="日志信息" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
       <el-table-column label="执行状态" align="center" prop="status">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="执行时间" align="center" prop="createTime" width="180">
@@ -190,6 +190,7 @@ import { listJobLog, delJobLog, exportJobLog, cleanJobLog } from "@/api/monitor/
 
 export default {
   name: "JobLog",
+  dicts: ['sys_common_status', 'sys_job_group'],
   data() {
     return {
       // 遮罩层
@@ -212,10 +213,6 @@ export default {
       dateRange: [],
       // 表单参数
       form: {},
-      // 执行状态字典
-      statusOptions: [],
-      // 任务组名字典
-      jobGroupOptions: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -237,12 +234,6 @@ export default {
     } else {
       this.getList();
     }
-    this.getDicts("sys_common_status").then(response => {
-      this.statusOptions = response.data;
-    });
-    this.getDicts("sys_job_group").then(response => {
-      this.jobGroupOptions = response.data;
-    });
   },
   methods: {
     /** 查询调度日志列表 */
@@ -284,44 +275,32 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const jobLogIds = this.ids;
-      this.$confirm('是否确认删除调度日志编号为"' + jobLogIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delJobLog(jobLogIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除调度日志编号为"' + jobLogIds + '"的数据项?').then(function() {
+        return delJobLog(jobLogIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 清空按钮操作 */
     handleClean() {
-      this.$confirm("是否确认清空所有调度日志数据项?", "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return cleanJobLog();
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("清空成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认清空所有调度日志数据项?').then(function() {
+        return cleanJobLog();
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("清空成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm("是否确认导出所有调度日志数据项?", "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportJobLog(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有调度日志数据项?').then(() => {
+        this.exportLoading = true;
+        return exportJobLog(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 25 - 41
ruoyi-ui/src/views/monitor/logininfor/index.vue

@@ -30,10 +30,10 @@
           style="width: 240px"
         >
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_common_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -101,7 +101,7 @@
       <el-table-column label="操作系统" align="center" prop="os" />
       <el-table-column label="登录状态" align="center" prop="status">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="操作信息" align="center" prop="msg" />
@@ -127,6 +127,7 @@ import { list, delLogininfor, cleanLogininfor, exportLogininfor } from "@/api/mo
 
 export default {
   name: "Logininfor",
+  dicts: ['sys_common_status'],
   data() {
     return {
       // 遮罩层
@@ -143,8 +144,6 @@ export default {
       total: 0,
       // 表格数据
       list: [],
-      // 状态数据字典
-      statusOptions: [],
       // 日期范围
       dateRange: [],
       // 默认排序
@@ -161,9 +160,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_common_status").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     /** 查询登录日志列表 */
@@ -202,44 +198,32 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const infoIds = row.infoId || this.ids;
-      this.$confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delLogininfor(infoIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除访问编号为"' + infoIds + '"的数据项?').then(function() {
+        return delLogininfor(infoIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 清空按钮操作 */
     handleClean() {
-        this.$confirm('是否确认清空所有登录日志数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return cleanLogininfor();
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("清空成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认清空所有登录日志数据项?').then(function() {
+        return cleanLogininfor();
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("清空成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportLogininfor(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有操作日志数据项?').then(() => {
+        this.exportLoading = true;
+        return exportLogininfor(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 6 - 10
ruoyi-ui/src/views/monitor/online/index.vue

@@ -111,16 +111,12 @@ export default {
     },
     /** 强退按钮操作 */
     handleForceLogout(row) {
-      this.$confirm('是否确认强退名称为"' + row.userName + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return forceLogout(row.tokenId);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("强退成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认强退名称为"' + row.userName + '"的数据项?').then(function() {
+        return forceLogout(row.tokenId);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("强退成功");
+      }).catch(() => {});
     }
   }
 };

+ 31 - 52
ruoyi-ui/src/views/monitor/operlog/index.vue

@@ -30,10 +30,10 @@
           style="width: 240px"
         >
           <el-option
-            v-for="dict in typeOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_oper_type"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -46,10 +46,10 @@
           style="width: 240px"
         >
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_common_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -113,7 +113,7 @@
       <el-table-column label="系统模块" align="center" prop="title" />
       <el-table-column label="操作类型" align="center" prop="businessType">
         <template slot-scope="scope">
-          <dict-tag :options="typeOptions" :value="scope.row.businessType"/>
+          <dict-tag :options="dict.type.sys_oper_type" :value="scope.row.businessType"/>
         </template>
       </el-table-column>
       <el-table-column label="请求方式" align="center" prop="requestMethod" />
@@ -122,7 +122,7 @@
       <el-table-column label="操作地点" align="center" prop="operLocation" :show-overflow-tooltip="true" />
       <el-table-column label="操作状态" align="center" prop="status">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="操作日期" align="center" prop="operTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
@@ -200,6 +200,7 @@ import { list, delOperlog, cleanOperlog, exportOperlog } from "@/api/monitor/ope
 
 export default {
   name: "Operlog",
+  dicts: ['sys_oper_type', 'sys_common_status'],
   data() {
     return {
       // 遮罩层
@@ -218,10 +219,6 @@ export default {
       list: [],
       // 是否显示弹出层
       open: false,
-      // 类型数据字典
-      typeOptions: [],
-      // 类型数据字典
-      statusOptions: [],
       // 日期范围
       dateRange: [],
       // 默认排序
@@ -241,12 +238,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_oper_type").then(response => {
-      this.typeOptions = response.data;
-    });
-    this.getDicts("sys_common_status").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     /** 查询登录日志 */
@@ -261,7 +252,7 @@ export default {
     },
     // 操作日志类型字典翻译
     typeFormat(row, column) {
-      return this.selectDictLabel(this.typeOptions, row.businessType);
+      return this.selectDictLabel(this.dict.type.sys_oper_type, row.businessType);
     },
     /** 搜索按钮操作 */
     handleQuery() {
@@ -294,44 +285,32 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const operIds = row.operId || this.ids;
-      this.$confirm('是否确认删除日志编号为"' + operIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delOperlog(operIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除日志编号为"' + operIds + '"的数据项?').then(function() {
+        return delOperlog(operIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 清空按钮操作 */
     handleClean() {
-        this.$confirm('是否确认清空所有操作日志数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return cleanOperlog();
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("清空成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认清空所有操作日志数据项?').then(function() {
+        return cleanOperlog();
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("清空成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportOperlog(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有操作日志数据项?').then(() => {
+        this.exportLoading = true;
+        return exportOperlog(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 62 - 69
ruoyi-ui/src/views/monitor/server/index.vue

@@ -8,26 +8,26 @@
             <table cellspacing="0" style="width: 100%;">
               <thead>
                 <tr>
-                  <th class="is-leaf"><div class="cell">属性</div></th>
-                  <th class="is-leaf"><div class="cell">值</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">属性</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">值</div></th>
                 </tr>
               </thead>
               <tbody>
                 <tr>
-                  <td><div class="cell">核心数</div></td>
-                  <td><div class="cell" v-if="server.cpu">{{ server.cpu.cpuNum }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">核心数</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.cpu">{{ server.cpu.cpuNum }}</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">用户使用率</div></td>
-                  <td><div class="cell" v-if="server.cpu">{{ server.cpu.used }}%</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">用户使用率</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.cpu">{{ server.cpu.used }}%</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">系统使用率</div></td>
-                  <td><div class="cell" v-if="server.cpu">{{ server.cpu.sys }}%</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">系统使用率</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.cpu">{{ server.cpu.sys }}%</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">当前空闲率</div></td>
-                  <td><div class="cell" v-if="server.cpu">{{ server.cpu.free }}%</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">当前空闲率</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.cpu">{{ server.cpu.free }}%</div></td>
                 </tr>
               </tbody>
             </table>
@@ -42,31 +42,31 @@
             <table cellspacing="0" style="width: 100%;">
               <thead>
                 <tr>
-                  <th class="is-leaf"><div class="cell">属性</div></th>
-                  <th class="is-leaf"><div class="cell">内存</div></th>
-                  <th class="is-leaf"><div class="cell">JVM</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">属性</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">内存</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">JVM</div></th>
                 </tr>
               </thead>
               <tbody>
                 <tr>
-                  <td><div class="cell">总内存</div></td>
-                  <td><div class="cell" v-if="server.mem">{{ server.mem.total }}G</div></td>
-                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.total }}M</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">总内存</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.mem">{{ server.mem.total }}G</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.total }}M</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">已用内存</div></td>
-                  <td><div class="cell" v-if="server.mem">{{ server.mem.used}}G</div></td>
-                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.used}}M</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">已用内存</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.mem">{{ server.mem.used}}G</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.used}}M</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">剩余内存</div></td>
-                  <td><div class="cell" v-if="server.mem">{{ server.mem.free }}G</div></td>
-                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.free }}M</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">剩余内存</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.mem">{{ server.mem.free }}G</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.free }}M</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">使用率</div></td>
-                  <td><div class="cell" v-if="server.mem" :class="{'text-danger': server.mem.usage > 80}">{{ server.mem.usage }}%</div></td>
-                  <td><div class="cell" v-if="server.jvm" :class="{'text-danger': server.jvm.usage > 80}">{{ server.jvm.usage }}%</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">使用率</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.mem" :class="{'text-danger': server.mem.usage > 80}">{{ server.mem.usage }}%</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm" :class="{'text-danger': server.jvm.usage > 80}">{{ server.jvm.usage }}%</div></td>
                 </tr>
               </tbody>
             </table>
@@ -83,16 +83,16 @@
             <table cellspacing="0" style="width: 100%;">
               <tbody>
                 <tr>
-                  <td><div class="cell">服务器名称</div></td>
-                  <td><div class="cell" v-if="server.sys">{{ server.sys.computerName }}</div></td>
-                  <td><div class="cell">操作系统</div></td>
-                  <td><div class="cell" v-if="server.sys">{{ server.sys.osName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">服务器名称</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.computerName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">操作系统</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.osName }}</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">服务器IP</div></td>
-                  <td><div class="cell" v-if="server.sys">{{ server.sys.computerIp }}</div></td>
-                  <td><div class="cell">系统架构</div></td>
-                  <td><div class="cell" v-if="server.sys">{{ server.sys.osArch }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">服务器IP</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.computerIp }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">系统架构</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.osArch }}</div></td>
                 </tr>
               </tbody>
             </table>
@@ -109,24 +109,24 @@
             <table cellspacing="0" style="width: 100%;">
               <tbody>
                 <tr>
-                  <td><div class="cell">Java名称</div></td>
-                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.name }}</div></td>
-                  <td><div class="cell">Java版本</div></td>
-                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.version }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">Java名称</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.name }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">Java版本</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.version }}</div></td>
                 </tr>
                 <tr>
-                  <td><div class="cell">启动时间</div></td>
-                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.startTime }}</div></td>
-                  <td><div class="cell">运行时长</div></td>
-                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.runTime }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">启动时间</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.startTime }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">运行时长</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.runTime }}</div></td>
                 </tr>
                 <tr>
-                  <td colspan="1"><div class="cell">安装路径</div></td>
-                  <td colspan="3"><div class="cell" v-if="server.jvm">{{ server.jvm.home }}</div></td>
+                  <td colspan="1" class="el-table__cell is-leaf"><div class="cell">安装路径</div></td>
+                  <td colspan="3" class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.home }}</div></td>
                 </tr>
                 <tr>
-                  <td colspan="1"><div class="cell">项目路径</div></td>
-                  <td colspan="3"><div class="cell" v-if="server.sys">{{ server.sys.userDir }}</div></td>
+                  <td colspan="1" class="el-table__cell is-leaf"><div class="cell">项目路径</div></td>
+                  <td colspan="3" class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.userDir }}</div></td>
                 </tr>
               </tbody>
             </table>
@@ -143,24 +143,24 @@
             <table cellspacing="0" style="width: 100%;">
               <thead>
                 <tr>
-                  <th class="is-leaf"><div class="cell">盘符路径</div></th>
-                  <th class="is-leaf"><div class="cell">文件系统</div></th>
-                  <th class="is-leaf"><div class="cell">盘符类型</div></th>
-                  <th class="is-leaf"><div class="cell">总大小</div></th>
-                  <th class="is-leaf"><div class="cell">可用大小</div></th>
-                  <th class="is-leaf"><div class="cell">已用大小</div></th>
-                  <th class="is-leaf"><div class="cell">已用百分比</div></th>
+                  <th class="el-table__cell el-table__cell is-leaf"><div class="cell">盘符路径</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">文件系统</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">盘符类型</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">总大小</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">可用大小</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">已用大小</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">已用百分比</div></th>
                 </tr>
               </thead>
               <tbody v-if="server.sysFiles">
-                <tr v-for="sysFile in server.sysFiles">
-                  <td><div class="cell">{{ sysFile.dirName }}</div></td>
-                  <td><div class="cell">{{ sysFile.sysTypeName }}</div></td>
-                  <td><div class="cell">{{ sysFile.typeName }}</div></td>
-                  <td><div class="cell">{{ sysFile.total }}</div></td>
-                  <td><div class="cell">{{ sysFile.free }}</div></td>
-                  <td><div class="cell">{{ sysFile.used }}</div></td>
-                  <td><div class="cell" :class="{'text-danger': sysFile.usage > 80}">{{ sysFile.usage }}%</div></td>
+                <tr v-for="(sysFile, index) in server.sysFiles" :key="index">
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.dirName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.sysTypeName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.typeName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.total }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.free }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.used }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" :class="{'text-danger': sysFile.usage > 80}">{{ sysFile.usage }}%</div></td>
                 </tr>
               </tbody>
             </table>
@@ -178,8 +178,6 @@ export default {
   name: "Server",
   data() {
     return {
-      // 加载层信息
-      loading: [],
       // 服务器信息
       server: []
     };
@@ -193,17 +191,12 @@ export default {
     getList() {
       getServer().then(response => {
         this.server = response.data;
-        this.loading.close();
+        this.$modal.closeLoading();
       });
     },
     // 打开加载层
     openLoading() {
-      this.loading = this.$loading({
-        lock: true,
-        text: "拼命读取中",
-        spinner: "el-icon-loading",
-        background: "rgba(0, 0, 0, 0.7)"
-      });
+      this.$modal.loading("正在加载服务监控数据,请稍后!");
     }
   }
 };

+ 22 - 34
ruoyi-ui/src/views/system/config/index.vue

@@ -24,10 +24,10 @@
       <el-form-item label="系统内置" prop="configType">
         <el-select v-model="queryParams.configType" placeholder="系统内置" clearable size="small">
           <el-option
-            v-for="dict in typeOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_yes_no"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -114,7 +114,7 @@
       <el-table-column label="参数键值" align="center" prop="configValue" />
       <el-table-column label="系统内置" align="center" prop="configType">
         <template slot-scope="scope">
-          <dict-tag :options="typeOptions" :value="scope.row.configType"/>
+          <dict-tag :options="dict.type.sys_yes_no" :value="scope.row.configType"/>
         </template>
       </el-table-column>
       <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
@@ -166,10 +166,10 @@
         <el-form-item label="系统内置" prop="configType">
           <el-radio-group v-model="form.configType">
             <el-radio
-              v-for="dict in typeOptions"
-              :key="dict.dictValue"
-              :label="dict.dictValue"
-            >{{dict.dictLabel}}</el-radio>
+              v-for="dict in dict.type.sys_yes_no"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="备注" prop="remark">
@@ -189,6 +189,7 @@ import { listConfig, getConfig, delConfig, addConfig, updateConfig, exportConfig
 
 export default {
   name: "Config",
+  dicts: ['sys_yes_no'],
   data() {
     return {
       // 遮罩层
@@ -211,8 +212,6 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
-      // 类型数据字典
-      typeOptions: [],
       // 日期范围
       dateRange: [],
       // 查询参数
@@ -241,9 +240,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_yes_no").then(response => {
-      this.typeOptions = response.data;
-    });
   },
   methods: {
     /** 查询参数列表 */
@@ -312,13 +308,13 @@ export default {
         if (valid) {
           if (this.form.configId != undefined) {
             updateConfig(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addConfig(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -329,36 +325,28 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const configIds = row.configId || this.ids;
-      this.$confirm('是否确认删除参数编号为"' + configIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
+      this.$modal.confirm('是否确认删除参数编号为"' + configIds + '"的数据项?').then(function() {
           return delConfig(configIds);
         }).then(() => {
           this.getList();
-          this.msgSuccess("删除成功");
+          this.$modal.msgSuccess("删除成功");
         }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有参数数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportConfig(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有参数数据项?').then(() => {
+        this.exportLoading = true;
+        return exportConfig(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     },
     /** 刷新缓存按钮操作 */
     handleRefreshCache() {
       refreshCache().then(() => {
-        this.msgSuccess("刷新成功");
+        this.$modal.msgSuccess("刷新成功");
       });
     }
   }

+ 18 - 26
ruoyi-ui/src/views/system/dept/index.vue

@@ -13,10 +13,10 @@
       <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="部门状态" clearable size="small">
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -61,7 +61,7 @@
       <el-table-column prop="orderNum" label="排序" width="200"></el-table-column>
       <el-table-column prop="status" label="状态" width="100">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="200">
@@ -135,10 +135,10 @@
             <el-form-item label="部门状态">
               <el-radio-group v-model="form.status">
                 <el-radio
-                  v-for="dict in statusOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictValue"
-                >{{dict.dictLabel}}</el-radio>
+                  v-for="dict in dict.type.sys_normal_disable"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -159,6 +159,7 @@ import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
 export default {
   name: "Dept",
+  dicts: ['sys_normal_disable'],
   components: { Treeselect },
   data() {
     return {
@@ -180,8 +181,6 @@ export default {
       refreshTable: true,
       // 是否展开
       expand: false,
-      // 状态数据字典
-      statusOptions: [],
       // 查询参数
       queryParams: {
         deptName: undefined,
@@ -219,9 +218,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     /** 查询部门列表 */
@@ -309,13 +305,13 @@ export default {
         if (valid) {
           if (this.form.deptId != undefined) {
             updateDept(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addDept(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -325,16 +321,12 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除名称为"' + row.deptName + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delDept(row.deptId);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除名称为"' + row.deptName + '"的数据项?').then(function() {
+        return delDept(row.deptId);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     }
   }
 };

+ 25 - 37
ruoyi-ui/src/views/system/dict/data.vue

@@ -23,10 +23,10 @@
       <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="数据状态" clearable size="small">
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -96,7 +96,7 @@
       <el-table-column label="字典排序" align="center" prop="dictSort" />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
@@ -164,10 +164,10 @@
         <el-form-item label="状态" prop="status">
           <el-radio-group v-model="form.status">
             <el-radio
-              v-for="dict in statusOptions"
-              :key="dict.dictValue"
-              :label="dict.dictValue"
-            >{{dict.dictLabel}}</el-radio>
+              v-for="dict in dict.type.sys_normal_disable"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="备注" prop="remark">
@@ -188,6 +188,7 @@ import { listType, getType } from "@/api/system/dict/type";
 
 export default {
   name: "Data",
+  dicts: ['sys_normal_disable'],
   data() {
     return {
       // 遮罩层
@@ -239,8 +240,6 @@ export default {
           label: "危险"
         }
       ],
-      // 状态数据字典
-      statusOptions: [],
       // 类型数据字典
       typeOptions: [],
       // 查询参数
@@ -271,9 +270,6 @@ export default {
     const dictId = this.$route.params && this.$route.params.dictId;
     this.getType(dictId);
     this.getTypeList();
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     /** 查询字典类型详细 */
@@ -358,13 +354,13 @@ export default {
         if (valid) {
           if (this.form.dictCode != undefined) {
             updateData(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addData(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -375,31 +371,23 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const dictCodes = row.dictCode || this.ids;
-      this.$confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delData(dictCodes);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?').then(function() {
+        return delData(dictCodes);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportData(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有数据项?').then(() => {
+        this.exportLoading = true;
+        return exportData(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 26 - 38
ruoyi-ui/src/views/system/dict/index.vue

@@ -30,10 +30,10 @@
           style="width: 240px"
         >
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -125,7 +125,7 @@
       </el-table-column>
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
@@ -174,10 +174,10 @@
         <el-form-item label="状态" prop="status">
           <el-radio-group v-model="form.status">
             <el-radio
-              v-for="dict in statusOptions"
-              :key="dict.dictValue"
-              :label="dict.dictValue"
-            >{{dict.dictLabel}}</el-radio>
+              v-for="dict in dict.type.sys_normal_disable"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="备注" prop="remark">
@@ -197,6 +197,7 @@ import { listType, getType, delType, addType, updateType, exportType, refreshCac
 
 export default {
   name: "Dict",
+  dicts: ['sys_normal_disable'],
   data() {
     return {
       // 遮罩层
@@ -219,8 +220,6 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
-      // 状态数据字典
-      statusOptions: [],
       // 日期范围
       dateRange: [],
       // 查询参数
@@ -246,9 +245,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     /** 查询字典类型列表 */
@@ -316,13 +312,13 @@ export default {
         if (valid) {
           if (this.form.dictId != undefined) {
             updateType(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addType(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -333,36 +329,28 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const dictIds = row.dictId || this.ids;
-      this.$confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delType(dictIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?').then(function() {
+        return delType(dictIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有类型数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportType(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有类型数据项?').then(() => {
+        this.exportLoading = true;
+        return exportType(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     },
     /** 刷新缓存按钮操作 */
     handleRefreshCache() {
       refreshCache().then(() => {
-        this.msgSuccess("刷新成功");
+        this.$modal.msgSuccess("刷新成功");
       });
     }
   }

+ 22 - 35
ruoyi-ui/src/views/system/menu/index.vue

@@ -13,10 +13,10 @@
       <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="菜单状态" clearable size="small">
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -68,7 +68,7 @@
       <el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
       <el-table-column prop="status" label="状态" width="80">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime">
@@ -240,10 +240,10 @@
               </span>
               <el-radio-group v-model="form.visible">
                 <el-radio
-                  v-for="dict in visibleOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictValue"
-                >{{dict.dictLabel}}</el-radio>
+                  v-for="dict in dict.type.sys_show_hide"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -257,10 +257,10 @@
               </span>
               <el-radio-group v-model="form.status">
                 <el-radio
-                  v-for="dict in statusOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictValue"
-                >{{dict.dictLabel}}</el-radio>
+                  v-for="dict in dict.type.sys_normal_disable"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -282,6 +282,7 @@ import IconSelect from "@/components/IconSelect";
 
 export default {
   name: "Menu",
+  dicts: ['sys_show_hide', 'sys_normal_disable'],
   components: { Treeselect, IconSelect },
   data() {
     return {
@@ -301,10 +302,6 @@ export default {
       isExpandAll: false,
       // 重新渲染表格状态
       refreshTable: true,
-      // 显示状态数据字典
-      visibleOptions: [],
-      // 菜单状态数据字典
-      statusOptions: [],
       // 查询参数
       queryParams: {
         menuName: undefined,
@@ -328,12 +325,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_show_hide").then(response => {
-      this.visibleOptions = response.data;
-    });
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     // 选择图标
@@ -434,13 +425,13 @@ export default {
         if (valid) {
           if (this.form.menuId != undefined) {
             updateMenu(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addMenu(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -450,16 +441,12 @@ export default {
     },
     /** 删除按钮操作 */
     handleDelete(row) {
-      this.$confirm('是否确认删除名称为"' + row.menuName + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delMenu(row.menuId);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项?').then(function() {
+        return delMenu(row.menuId);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     }
   }
 };

+ 23 - 36
ruoyi-ui/src/views/system/notice/index.vue

@@ -22,10 +22,10 @@
       <el-form-item label="类型" prop="noticeType">
         <el-select v-model="queryParams.noticeType" placeholder="公告类型" clearable size="small">
           <el-option
-            v-for="dict in typeOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_notice_type"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -82,12 +82,12 @@
       />
       <el-table-column label="公告类型" align="center" prop="noticeType" width="100">
         <template slot-scope="scope">
-          <dict-tag :options="typeOptions" :value="scope.row.noticeType"/>
+          <dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType"/>
         </template>
       </el-table-column>
       <el-table-column label="状态" align="center" prop="status" width="100">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_notice_status" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="创建者" align="center" prop="createBy" width="100" />
@@ -137,10 +137,10 @@
             <el-form-item label="公告类型" prop="noticeType">
               <el-select v-model="form.noticeType" placeholder="请选择">
                 <el-option
-                  v-for="dict in typeOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictLabel"
-                  :value="dict.dictValue"
+                  v-for="dict in dict.type.sys_notice_type"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
                 ></el-option>
               </el-select>
             </el-form-item>
@@ -149,10 +149,10 @@
             <el-form-item label="状态">
               <el-radio-group v-model="form.status">
                 <el-radio
-                  v-for="dict in statusOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictValue"
-                >{{dict.dictLabel}}</el-radio>
+                  v-for="dict in dict.type.sys_notice_status"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -176,6 +176,7 @@ import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api
 
 export default {
   name: "Notice",
+  dicts: ['sys_notice_status', 'sys_notice_type'],
   data() {
     return {
       // 遮罩层
@@ -196,10 +197,6 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
-      // 类型数据字典
-      statusOptions: [],
-      // 状态数据字典
-      typeOptions: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -223,12 +220,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_notice_status").then(response => {
-      this.statusOptions = response.data;
-    });
-    this.getDicts("sys_notice_type").then(response => {
-      this.typeOptions = response.data;
-    });
   },
   methods: {
     /** 查询公告列表 */
@@ -294,13 +285,13 @@ export default {
         if (valid) {
           if (this.form.noticeId != undefined) {
             updateNotice(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addNotice(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -311,16 +302,12 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const noticeIds = row.noticeId || this.ids
-      this.$confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delNotice(noticeIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除公告编号为"' + noticeIds + '"的数据项?').then(function() {
+        return delNotice(noticeIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     }
   }
 };

+ 25 - 37
ruoyi-ui/src/views/system/post/index.vue

@@ -22,10 +22,10 @@
       <el-form-item label="状态" prop="status">
         <el-select v-model="queryParams.status" placeholder="岗位状态" clearable size="small">
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -90,7 +90,7 @@
       <el-table-column label="岗位排序" align="center" prop="postSort" />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180">
@@ -141,10 +141,10 @@
         <el-form-item label="岗位状态" prop="status">
           <el-radio-group v-model="form.status">
             <el-radio
-              v-for="dict in statusOptions"
-              :key="dict.dictValue"
-              :label="dict.dictValue"
-            >{{dict.dictLabel}}</el-radio>
+              v-for="dict in dict.type.sys_normal_disable"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="备注" prop="remark">
@@ -164,6 +164,7 @@ import { listPost, getPost, delPost, addPost, updatePost, exportPost } from "@/a
 
 export default {
   name: "Post",
+  dicts: ['sys_normal_disable'],
   data() {
     return {
       // 遮罩层
@@ -186,8 +187,6 @@ export default {
       title: "",
       // 是否显示弹出层
       open: false,
-      // 状态数据字典
-      statusOptions: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -214,9 +213,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     /** 查询岗位列表 */
@@ -283,13 +279,13 @@ export default {
         if (valid) {
           if (this.form.postId != undefined) {
             updatePost(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addPost(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -300,31 +296,23 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const postIds = row.postId || this.ids;
-      this.$confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delPost(postIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除岗位编号为"' + postIds + '"的数据项?').then(function() {
+        return delPost(postIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有岗位数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportPost(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有岗位数据项?').then(() => {
+        this.exportLoading = true;
+        return exportPost(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 7 - 19
ruoyi-ui/src/views/system/role/authUser.vue

@@ -69,7 +69,7 @@
       <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
-          <dict-tag :options="statusOptions" :value="scope.row.status"/>
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
         </template>
       </el-table-column>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180">
@@ -107,6 +107,7 @@ import selectUser from "./selectUser";
 
 export default {
   name: "AuthUser",
+  dicts: ['sys_normal_disable'],
   components: { selectUser },
   data() {
     return {
@@ -122,8 +123,6 @@ export default {
       total: 0,
       // 用户表格数据
       userList: [],
-      // 状态数据字典
-      statusOptions: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -139,9 +138,6 @@ export default {
     if (roleId) {
       this.queryParams.roleId = roleId;
       this.getList();
-      this.getDicts("sys_normal_disable").then(response => {
-        this.statusOptions = response.data;
-      });
     }
   },
   methods: {
@@ -182,30 +178,22 @@ export default {
     /** 取消授权按钮操作 */
     cancelAuthUser(row) {
       const roleId = this.queryParams.roleId;
-      this.$confirm('确认要取消该用户"' + row.userName + '"角色吗?', "警告", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      }).then(function() {
+      this.$modal.confirm('确认要取消该用户"' + row.userName + '"角色吗?').then(function() {
         return authUserCancel({ userId: row.userId, roleId: roleId });
       }).then(() => {
         this.getList();
-        this.msgSuccess("取消授权成功");
+        this.$modal.msgSuccess("取消授权成功");
       }).catch(() => {});
     },
     /** 批量取消授权按钮操作 */
     cancelAuthUserAll(row) {
       const roleId = this.queryParams.roleId;
       const userIds = this.userIds.join(",");
-      this.$confirm('是否取消选中用户授权数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-      }).then(() => {
-          return authUserCancelAll({ roleId: roleId, userIds: userIds });
+      this.$modal.confirm('是否取消选中用户授权数据项?').then(function() {
+        return authUserCancelAll({ roleId: roleId, userIds: userIds });
       }).then(() => {
         this.getList();
-        this.msgSuccess("取消授权成功");
+        this.$modal.msgSuccess("取消授权成功");
       }).catch(() => {});
     }
   }

+ 32 - 48
ruoyi-ui/src/views/system/role/index.vue

@@ -30,10 +30,10 @@
           style="width: 240px"
         >
           <el-option
-            v-for="dict in statusOptions"
-            :key="dict.dictValue"
-            :label="dict.dictLabel"
-            :value="dict.dictValue"
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
           />
         </el-select>
       </el-form-item>
@@ -183,10 +183,10 @@
         <el-form-item label="状态">
           <el-radio-group v-model="form.status">
             <el-radio
-              v-for="dict in statusOptions"
-              :key="dict.dictValue"
-              :label="dict.dictValue"
-            >{{dict.dictLabel}}</el-radio>
+              v-for="dict in dict.type.sys_normal_disable"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="菜单权限">
@@ -265,6 +265,7 @@ import { treeselect as deptTreeselect, roleDeptTreeselect } from "@/api/system/d
 
 export default {
   name: "Role",
+  dicts: ['sys_normal_disable'],
   data() {
     return {
       // 遮罩层
@@ -295,8 +296,6 @@ export default {
       deptNodeAll: false,
       // 日期范围
       dateRange: [],
-      // 状态数据字典
-      statusOptions: [],
       // 数据范围选项
       dataScopeOptions: [
         {
@@ -354,9 +353,6 @@ export default {
   },
   created() {
     this.getList();
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
   },
   methods: {
     /** 查询角色列表 */
@@ -417,17 +413,13 @@ export default {
     // 角色状态修改
     handleStatusChange(row) {
       let text = row.status === "0" ? "启用" : "停用";
-      this.$confirm('确认要"' + text + '""' + row.roleName + '"角色吗?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return changeRoleStatus(row.roleId, row.status);
-        }).then(() => {
-          this.msgSuccess(text + "成功");
-        }).catch(function() {
-          row.status = row.status === "0" ? "1" : "0";
-        });
+      this.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?').then(function() {
+        return changeRoleStatus(row.roleId, row.status);
+      }).then(() => {
+        this.$modal.msgSuccess(text + "成功");
+      }).catch(function() {
+        row.status = row.status === "0" ? "1" : "0";
+      });
     },
     // 取消按钮
     cancel() {
@@ -583,14 +575,14 @@ export default {
           if (this.form.roleId != undefined) {
             this.form.menuIds = this.getMenuAllCheckedKeys();
             updateRole(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             this.form.menuIds = this.getMenuAllCheckedKeys();
             addRole(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -603,7 +595,7 @@ export default {
       if (this.form.roleId != undefined) {
         this.form.deptIds = this.getDeptAllCheckedKeys();
         dataScope(this.form).then(response => {
-          this.msgSuccess("修改成功");
+          this.$modal.msgSuccess("修改成功");
           this.openDataScope = false;
           this.getList();
         });
@@ -612,31 +604,23 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const roleIds = row.roleId || this.ids;
-      this.$confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delRole(roleIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除角色编号为"' + roleIds + '"的数据项?').then(function() {
+        return delRole(roleIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有角色数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportRole(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有用户数据项?').then(() => {
+        this.exportLoading = true;
+        return exportRole(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     }
   }
 };

+ 3 - 9
ruoyi-ui/src/views/system/role/selectUser.vue

@@ -34,7 +34,7 @@
         <el-table-column label="手机" prop="phonenumber" :show-overflow-tooltip="true" />
         <el-table-column label="状态" align="center" prop="status">
           <template slot-scope="scope">
-            <dict-tag :options="statusOptions" :value="scope.row.status"/>
+            <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
           </template>
         </el-table-column>
         <el-table-column label="创建时间" align="center" prop="createTime" width="180">
@@ -61,6 +61,7 @@
 <script>
 import { unallocatedUserList, authUserSelectAll } from "@/api/system/role";
 export default {
+  dicts: ['sys_normal_disable'],
   props: {
     // 角色编号
     roleId: {
@@ -77,8 +78,6 @@ export default {
       total: 0,
       // 未授权用户数据
       userList: [],
-      // 状态数据字典
-      statusOptions: [],
       // 查询参数
       queryParams: {
         pageNum: 1,
@@ -89,11 +88,6 @@ export default {
       }
     };
   },
-  created() {
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
-  },
   methods: {
     // 显示弹框
     show() {
@@ -130,7 +124,7 @@ export default {
       const roleId = this.queryParams.roleId;
       const userIds = this.userIds.join(",");
       authUserSelectAll({ roleId: roleId, userIds: userIds }).then(res => {
-        this.msgSuccess(res.msg);
+        this.$modal.msgSuccess(res.msg);
         if (res.code === 200) {
           this.visible = false;
           this.$emit("ok");

+ 1 - 1
ruoyi-ui/src/views/system/user/authRole.vue

@@ -103,7 +103,7 @@ export default {
       const userId = this.form.userId;
       const roleIds = this.roleIds.join(",");
       updateAuthRole({ userId: userId, roleIds: roleIds }).then((response) => {
-        this.msgSuccess("授权成功");
+        this.$modal.msgSuccess("授权成功");
         this.close();
       });
     },

+ 37 - 58
ruoyi-ui/src/views/system/user/index.vue

@@ -57,10 +57,10 @@
               style="width: 240px"
             >
               <el-option
-                v-for="dict in statusOptions"
-                :key="dict.dictValue"
-                :label="dict.dictLabel"
-                :value="dict.dictValue"
+                v-for="dict in dict.type.sys_normal_disable"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
               />
             </el-select>
           </el-form-item>
@@ -251,10 +251,10 @@
             <el-form-item label="用户性别">
               <el-select v-model="form.sex" placeholder="请选择">
                 <el-option
-                  v-for="dict in sexOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictLabel"
-                  :value="dict.dictValue"
+                  v-for="dict in dict.type.sys_user_sex"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
                 ></el-option>
               </el-select>
             </el-form-item>
@@ -263,10 +263,10 @@
             <el-form-item label="状态">
               <el-radio-group v-model="form.status">
                 <el-radio
-                  v-for="dict in statusOptions"
-                  :key="dict.dictValue"
-                  :label="dict.dictValue"
-                >{{dict.dictLabel}}</el-radio>
+                  v-for="dict in dict.type.sys_normal_disable"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
               </el-radio-group>
             </el-form-item>
           </el-col>
@@ -354,6 +354,7 @@ import "@riophae/vue-treeselect/dist/vue-treeselect.css";
 
 export default {
   name: "User",
+  dicts: ['sys_normal_disable', 'sys_user_sex'],
   components: { Treeselect },
   data() {
     return {
@@ -385,10 +386,6 @@ export default {
       initPassword: undefined,
       // 日期范围
       dateRange: [],
-      // 状态数据字典
-      statusOptions: [],
-      // 性别状态字典
-      sexOptions: [],
       // 岗位选项
       postOptions: [],
       // 角色选项
@@ -472,12 +469,6 @@ export default {
   created() {
     this.getList();
     this.getTreeselect();
-    this.getDicts("sys_normal_disable").then(response => {
-      this.statusOptions = response.data;
-    });
-    this.getDicts("sys_user_sex").then(response => {
-      this.sexOptions = response.data;
-    });
     this.getConfigKey("sys.user.initPassword").then(response => {
       this.initPassword = response.msg;
     });
@@ -512,17 +503,13 @@ export default {
     // 用户状态修改
     handleStatusChange(row) {
       let text = row.status === "0" ? "启用" : "停用";
-      this.$confirm('确认要"' + text + '""' + row.userName + '"用户吗?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return changeUserStatus(row.userId, row.status);
-        }).then(() => {
-          this.msgSuccess(text + "成功");
-        }).catch(function() {
-          row.status = row.status === "0" ? "1" : "0";
-        });
+      this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() {
+        return changeUserStatus(row.userId, row.status);
+      }).then(() => {
+        this.$modal.msgSuccess(text + "成功");
+      }).catch(function() {
+        row.status = row.status === "0" ? "1" : "0";
+      });
     },
     // 取消按钮
     cancel() {
@@ -615,7 +602,7 @@ export default {
         inputErrorMessage: "用户密码长度必须介于 5 和 20 之间",
       }).then(({ value }) => {
           resetUserPwd(row.userId, value).then(response => {
-            this.msgSuccess("修改成功,新密码是:" + value);
+            this.$modal.msgSuccess("修改成功,新密码是:" + value);
           });
         }).catch(() => {});
     },
@@ -630,13 +617,13 @@ export default {
         if (valid) {
           if (this.form.userId != undefined) {
             updateUser(this.form).then(response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
               this.open = false;
               this.getList();
             });
           } else {
             addUser(this.form).then(response => {
-              this.msgSuccess("新增成功");
+              this.$modal.msgSuccess("新增成功");
               this.open = false;
               this.getList();
             });
@@ -647,31 +634,23 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const userIds = row.userId || this.ids;
-      this.$confirm('是否确认删除用户编号为"' + userIds + '"的数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(function() {
-          return delUser(userIds);
-        }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
-        }).catch(() => {});
+      this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() {
+        return delUser(userIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
-      this.$confirm('是否确认导出所有用户数据项?', "警告", {
-          confirmButtonText: "确定",
-          cancelButtonText: "取消",
-          type: "warning"
-        }).then(() => {
-          this.exportLoading = true;
-          return exportUser(queryParams);
-        }).then(response => {
-          this.download(response.msg);
-          this.exportLoading = false;
-        }).catch(() => {});
+      this.$modal.confirm('是否确认导出所有用户数据项?').then(() => {
+        this.exportLoading = true;
+        return exportUser(queryParams);
+      }).then(response => {
+        this.$download.name(response.msg);
+        this.exportLoading = false;
+      }).catch(() => {});
     },
     /** 导入按钮操作 */
     handleImport() {
@@ -681,7 +660,7 @@ export default {
     /** 下载模板操作 */
     importTemplate() {
       importTemplate().then(response => {
-        this.download(response.msg);
+        this.$download.name(response.msg);
       });
     },
     // 文件上传中处理

+ 1 - 1
ruoyi-ui/src/views/system/user/profile/resetPwd.vue

@@ -57,7 +57,7 @@ export default {
         if (valid) {
           updateUserPwd(this.user.oldPassword, this.user.newPassword).then(
             response => {
-              this.msgSuccess("修改成功");
+              this.$modal.msgSuccess("修改成功");
             }
           );
         }

+ 2 - 2
ruoyi-ui/src/views/system/user/profile/userAvatar.vue

@@ -110,7 +110,7 @@ export default {
     // 上传预处理
     beforeUpload(file) {
       if (file.type.indexOf("image/") == -1) {
-        this.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
+        this.$modal.msgError("文件格式错误,请上传图片类型,如:JPG,PNG后缀的文件。");
       } else {
         const reader = new FileReader();
         reader.readAsDataURL(file);
@@ -128,7 +128,7 @@ export default {
           this.open = false;
           this.options.img = process.env.VUE_APP_BASE_API + response.imgUrl;
           store.commit('SET_AVATAR', this.options.img);
-          this.msgSuccess("修改成功");
+          this.$modal.msgSuccess("修改成功");
           this.visible = false;
         });
       });

+ 1 - 1
ruoyi-ui/src/views/system/user/profile/userInfo.vue

@@ -62,7 +62,7 @@ export default {
       this.$refs["form"].validate(valid => {
         if (valid) {
           updateUserProfile(this.user).then(response => {
-            this.msgSuccess("修改成功");
+            this.$modal.msgSuccess("修改成功");
           });
         }
       });

+ 4 - 15
ruoyi-ui/src/views/tool/build/index.vue

@@ -137,23 +137,13 @@
 
 <script>
 import draggable from 'vuedraggable'
-import { saveAs } from 'file-saver'
 import beautifier from 'js-beautify'
 import ClipboardJS from 'clipboard'
 import render from '@/utils/generator/render'
 import RightPanel from './RightPanel'
-import {
-  inputComponents,
-  selectComponents,
-  layoutComponents,
-  formConf
-} from '@/utils/generator/config'
-import {
-  exportDefault, beautifierConf, isNumberStr, titleCase
-} from '@/utils/index'
-import {
-  makeUpHtml, vueTemplate, vueScript, cssStyle
-} from '@/utils/generator/html'
+import { inputComponents, selectComponents, layoutComponents, formConf } from '@/utils/generator/config'
+import { beautifierConf, titleCase } from '@/utils/index'
+import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html'
 import { makeUpJs } from '@/utils/generator/js'
 import { makeUpCss } from '@/utils/generator/css'
 import drawingDefalut from '@/utils/generator/drawingDefalut'
@@ -161,7 +151,6 @@ import logo from '@/assets/logo/logo.png'
 import CodeTypeDialog from './CodeTypeDialog'
 import DraggableItem from './DraggableItem'
 
-const emptyActiveData = { style: {}, autosize: {} }
 let oldActiveId
 let tempActiveData
 
@@ -287,7 +276,7 @@ export default {
     execDownload(data) {
       const codeStr = this.generateCode()
       const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
-      saveAs(blob, data.fileName)
+      this.$download.saveAs(blob, data.fileName)
     },
     execCopy(data) {
       document.getElementById('copyNode').click()

+ 12 - 12
ruoyi-ui/src/views/tool/gen/editTable.vue

@@ -4,8 +4,8 @@
       <el-tab-pane label="基本信息" name="basic">
         <basic-info-form ref="basicInfo" :info="info" />
       </el-tab-pane>
-      <el-tab-pane label="字段信息" name="cloum">
-        <el-table ref="dragTable" :data="cloumns" row-key="columnId" :max-height="tableHeight">
+      <el-tab-pane label="字段信息" name="columnInfo">
+        <el-table ref="dragTable" :data="columns" row-key="columnId" :max-height="tableHeight">
           <el-table-column label="序号" type="index" min-width="5%" class-name="allowDrag" />
           <el-table-column
             label="字段列名"
@@ -141,13 +141,13 @@ export default {
   data() {
     return {
       // 选中选项卡的 name
-      activeName: "cloum",
+      activeName: "columnInfo",
       // 表格的高度
       tableHeight: document.documentElement.scrollHeight - 245 + "px",
       // 表信息
       tables: [],
       // 表列信息
-      cloumns: [],
+      columns: [],
       // 字典信息
       dictOptions: [],
       // 菜单信息
@@ -161,7 +161,7 @@ export default {
     if (tableId) {
       // 获取表详细信息
       getGenTable(tableId).then(res => {
-        this.cloumns = res.data.rows;
+        this.columns = res.data.rows;
         this.info = res.data.info;
         this.tables = res.data.tables;
       });
@@ -184,7 +184,7 @@ export default {
         const validateResult = res.every(item => !!item);
         if (validateResult) {
           const genTable = Object.assign({}, basicForm.model, genForm.model);
-          genTable.columns = this.cloumns;
+          genTable.columns = this.columns;
           genTable.params = {
             treeCode: genTable.treeCode,
             treeName: genTable.treeName,
@@ -192,13 +192,13 @@ export default {
             parentMenuId: genTable.parentMenuId
           };
           updateGenTable(genTable).then(res => {
-            this.msgSuccess(res.msg);
+            this.$modal.msgSuccess(res.msg);
             if (res.code === 200) {
               this.close();
             }
           });
         } else {
-          this.msgError("表单校验未通过,请重新检查提交内容");
+          this.$modal.msgError("表单校验未通过,请重新检查提交内容");
         }
       });
     },
@@ -220,10 +220,10 @@ export default {
     const sortable = Sortable.create(el, {
       handle: ".allowDrag",
       onEnd: evt => {
-        const targetRow = this.cloumns.splice(evt.oldIndex, 1)[0];
-        this.cloumns.splice(evt.newIndex, 0, targetRow);
-        for (let index in this.cloumns) {
-          this.cloumns[index].sort = parseInt(index) + 1;
+        const targetRow = this.columns.splice(evt.oldIndex, 1)[0];
+        this.columns.splice(evt.newIndex, 0, targetRow);
+        for (let index in this.columns) {
+          this.columns[index].sort = parseInt(index) + 1;
         }
       }
     });

+ 7 - 2
ruoyi-ui/src/views/tool/gen/importTable.vue

@@ -104,8 +104,13 @@ export default {
     },
     /** 导入按钮操作 */
     handleImportTable() {
-      importTable({ tables: this.tables.join(",") }).then(res => {
-        this.msgSuccess(res.msg);
+      const tableNames = this.tables.join(",");
+      if (tableNames == "") {
+        this.$modal.msgError("请选择要导入的表");
+        return;
+      }
+      importTable({ tables: tableNames }).then(res => {
+        this.$modal.msgSuccess(res.msg);
         if (res.code === 200) {
           this.visible = false;
           this.$emit("ok");

+ 11 - 19
ruoyi-ui/src/views/tool/gen/index.vue

@@ -180,7 +180,6 @@
 <script>
 import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen";
 import importTable from "./importTable";
-import { downLoadZip } from "@/utils/zipdownload";
 import hljs from "highlight.js/lib/highlight";
 import "highlight.js/styles/github-gist.css";
 hljs.registerLanguage("java", require("highlight.js/lib/languages/java"));
@@ -262,28 +261,24 @@ export default {
     handleGenTable(row) {
       const tableNames = row.tableName || this.tableNames;
       if (tableNames == "") {
-        this.msgError("请选择要生成的数据");
+        this.$modal.msgError("请选择要生成的数据");
         return;
       }
       if(row.genType === "1") {
         genCode(row.tableName).then(response => {
-          this.msgSuccess("成功生成到自定义路径:" + row.genPath);
+          this.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath);
         });
       } else {
-        downLoadZip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi");
+        this.$download.zip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi");
       }
     },
     /** 同步数据库操作 */
     handleSynchDb(row) {
       const tableName = row.tableName;
-      this.$confirm('确认要强制同步"' + tableName + '"表结构吗?', "警告", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      }).then(function() {
-          return synchDb(tableName);
+      this.$modal.confirm('确认要强制同步"' + tableName + '"表结构吗?').then(function() {
+        return synchDb(tableName);
       }).then(() => {
-          this.msgSuccess("同步成功");
+        this.$modal.msgSuccess("同步成功");
       }).catch(() => {});
     },
     /** 打开导入表弹窗 */
@@ -301,6 +296,7 @@ export default {
       previewTable(row.tableId).then(response => {
         this.preview.data = response.data;
         this.preview.open = true;
+        this.preview.activeName = "domain.java";
       });
     },
     /** 高亮显示 */
@@ -325,15 +321,11 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const tableIds = row.tableId || this.ids;
-      this.$confirm('是否确认删除表编号为"' + tableIds + '"的数据项?', "警告", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning"
-      }).then(function() {
-          return delTable(tableIds);
+      this.$modal.confirm('是否确认删除表编号为"' + tableIds + '"的数据项?').then(function() {
+        return delTable(tableIds);
       }).then(() => {
-          this.getList();
-          this.msgSuccess("删除成功");
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
       }).catch(() => {});
     }
   }