diff --git a/README.md b/README.md index 117604113..0535be600 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,9 @@ 性别男,若依是给还没有出生女儿取的名字(寓意:你若不离不弃,我必生死相依) -> 阿里云服务器89元/年,双12年末特惠,爆款产品限时1折 :[点我进入](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link) - -> 如需前后端分离版本,请移步 [RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) - -> 如需单应用,请移步 [RuoYi-fast](https://gitee.com/y_project/RuoYi-fast) `(保持同步更新)`,如需其他版本,请移步 [项目扩展](http://doc.ruoyi.vip/ruoyi/document/xmkz.html) `(不定时更新)` - -> 阿里云通用云产品1888优惠券 :[点我领取](https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=brki8iof)    腾讯云通用云产品2860优惠券 :[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)  `(仅限新用户)` - -> 阿里云Hi拼购 限量爆款 低至199元/年 [点我进入](https://www.aliyun.com/acts/hi-group-buying?userCode=brki8iof)  `(仅限新用户)` +* 感谢 [hplus](https://gitee.com/hplus_admin/hplus) 后台主题 UI 框架。 +* 前后端分离版本,请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud) +* 阿里云优惠券:[点我进入](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link),腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)   ## 内置功能 @@ -33,12 +27,13 @@ 15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 16. 在线构建器:拖动表单元素生成相应的HTML代码。 17. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 + ## 在线体验 -> admin/admin123 -> 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。 + +- admin/admin123 +- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。 演示地址:http://ruoyi.vip - 文档地址:http://doc.ruoyi.vip ## 演示图 @@ -82,11 +77,11 @@ - + ## 若依交流群 -QQ群: [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) \ No newline at end of file +QQ群: [![加入QQ群](https://img.shields.io/badge/已满-1389287-blue.svg)](https://jq.qq.com/?_wv=1027&k=5HBAaYN) [![加入QQ群](https://img.shields.io/badge/已满-1679294-blue.svg)](https://jq.qq.com/?_wv=1027&k=5cHeRVW) [![加入QQ群](https://img.shields.io/badge/已满-1529866-blue.svg)](https://jq.qq.com/?_wv=1027&k=53R0L5Z) [![加入QQ群](https://img.shields.io/badge/已满-1772718-blue.svg)](https://jq.qq.com/?_wv=1027&k=5g75dCU) [![加入QQ群](https://img.shields.io/badge/已满-1366522-blue.svg)](https://jq.qq.com/?_wv=1027&k=58cPoHA) [![加入QQ群](https://img.shields.io/badge/已满-1382251-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Ofd4Pb) [![加入QQ群](https://img.shields.io/badge/已满-1145125-blue.svg)](https://jq.qq.com/?_wv=1027&k=5yugASz) [![加入QQ群](https://img.shields.io/badge/已满-86752435-blue.svg)](https://jq.qq.com/?_wv=1027&k=5Rf3d2P) [![加入QQ群](https://img.shields.io/badge/已满-134072510-blue.svg)](https://jq.qq.com/?_wv=1027&k=5ZIjaeP) [![加入QQ群](https://img.shields.io/badge/已满-210336300-blue.svg)](https://jq.qq.com/?_wv=1027&k=5CJw1jY) [![加入QQ群](https://img.shields.io/badge/已满-339522636-blue.svg)](https://jq.qq.com/?_wv=1027&k=5omzbKc) [![加入QQ群](https://img.shields.io/badge/130035985-blue.svg)](https://jq.qq.com/?_wv=1027&k=qPIKBb7s) \ No newline at end of file diff --git a/doc/若依环境使用手册.docx b/doc/若依环境使用手册.docx index c0edbcc48..fa5b62d7d 100644 --- a/doc/若依环境使用手册.docx +++ b/doc/若依环境使用手册.docx @@ -18,8 +18,12 @@ 2.2 导入工程 通过Eclipse导入工程,步骤如下: (1)点击左侧项目区域 -- >Import... -(2)选择RuoYi -(3)点击Finish(4)RuoYi的代码就被导出到Eclipse中了,此时可以在工程视图中看到。 + +(2)选择RuoYi + +(3)点击Finish + +(4)RuoYi的代码就被导出到Eclipse中了,此时可以在工程视图中看到。 3. 运行若依系统 3.1 必要的配置 @@ -33,18 +37,24 @@ 3.1.3 代码生成配置 编辑src/main/ resources目录下的application.yml 文件, -默认为module,根据实际情况修改即可。生成的表要有注释注:如对模板有特殊需求,可自行修改。编辑src/main/ resources/templates/vm目录下 +默认为module,根据实际情况修改即可。生成的表要有注释 + +注:如对模板有特殊需求,可自行修改。编辑src/main/ resources/templates/vm目录下 + 3.1.4 日志配置 编辑src/main/ resources目录下的logback.yml 文件 改为自己需要的路径 - + 3.2 启动及验证 启动RuoYiApplication.java 出现如下图表示启动成功 -打开浏览器,输入:http://localhost:80/若能正确展示登录页面,并能成功登录,登录后菜单及页面展示正常,则表明环境搭建成功。默认密码为 admin/admin123 -演示地址:http://www.ruoyi.club +打开浏览器,输入:http://localhost:80/ +若能正确展示登录页面,并能成功登录,登录后菜单及页面展示正常,则表明环境搭建成功。 +默认密码为 admin/admin123 + +演示地址:http://ruoyi.vip @@ -69,6 +79,7 @@ 4.1.4 启动及验证 运行startup.bat 出现如下图即部署成功 + 4.2 Jar方式部署 执行命令:java - jar RuoYi.jar 脚本执行:ry.sh start 启动stop 停止 diff --git a/pom.xml b/pom.xml index 2493c9fa2..a664b5332 100644 --- a/pom.xml +++ b/pom.xml @@ -1,39 +1,37 @@ - - 4.0.0 - + + 4.0.0 + com.ruoyi ruoyi - 4.1.0 + 4.4.0 ruoyi - http://www.ruoyi.vip + http://www.ruoyi.vip 若依管理系统 - 4.1.0 - UTF-8 - UTF-8 - 1.8 - 1.4.2 - 2.0.0 - 1.3.2 - 1.1.14 - 1.19 - 2.3.2 - 2.9.2 - 1.2.5 - 1.2.60 - 3.9.1 - 2.5 - 1.3.3 - 3.17 - 1.7 - 4.2.1 - - + 4.4.0 + UTF-8 + UTF-8 + 1.8 + 1.6.0 + 2.0.0 + 1.3.2 + 1.1.22 + 1.19 + 2.3.2 + 2.9.2 + 1.2.5 + 1.2.73 + 3.9.1 + 2.5 + 1.3.3 + 3.17 + 1.7 + + @@ -48,211 +46,182 @@ - - com.alibaba - druid-spring-boot-starter - ${druid.version} - - - - - com.github.penggle - kaptcha - ${kaptcha.version} - - - - - org.apache.shiro - shiro-core - ${shiro.version} - - - - - org.apache.shiro - shiro-spring - ${shiro.version} - - - - - org.apache.shiro - shiro-ehcache - ${shiro.version} - - - - - com.github.theborakompanioni - thymeleaf-extras-shiro - ${thymeleaf.extras.shiro.version} - - - - - eu.bitwalker - UserAgentUtils - ${bitwalker.version} - - - - - com.github.pagehelper - pagehelper-spring-boot-starter - ${pagehelper.boot.version} - - - - - com.github.oshi - oshi-core - ${oshi.version} - - - - - io.springfox - springfox-swagger2 - ${swagger.version} - - - io.swagger - swagger-annotations - - - io.swagger - swagger-models - - - - - - - io.springfox - springfox-swagger-ui - ${swagger.version} - + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + + + com.github.penggle + kaptcha + ${kaptcha.version} + + + + + org.apache.shiro + shiro-core + ${shiro.version} + + + + + org.apache.shiro + shiro-spring + ${shiro.version} + + + + + org.apache.shiro + shiro-ehcache + ${shiro.version} + + + + + com.github.theborakompanioni + thymeleaf-extras-shiro + ${thymeleaf.extras.shiro.version} + + + + + eu.bitwalker + UserAgentUtils + ${bitwalker.version} + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.boot.version} + + + + + com.github.oshi + oshi-core + ${oshi.version} + + + + + io.springfox + springfox-swagger2 + ${swagger.version} + + + io.swagger + swagger-annotations + + + io.swagger + swagger-models + + + + + + + io.springfox + springfox-swagger-ui + ${swagger.version} + - - commons-io - commons-io - ${commons.io.version} - - - - - commons-fileupload - commons-fileupload - ${commons.fileupload.version} - - - - - org.apache.poi - poi-ooxml - ${poi.version} - - - - - org.apache.velocity - velocity - ${velocity.version} - - - - - com.alibaba - fastjson - ${fastjson.version} - + + commons-io + commons-io + ${commons.io.version} + + + + + commons-fileupload + commons-fileupload + ${commons.fileupload.version} + + + + + org.apache.poi + poi-ooxml + ${poi.version} + + + + + org.apache.velocity + velocity + ${velocity.version} + + + + + com.alibaba + fastjson + ${fastjson.version} + - - com.ruoyi - ruoyi-quartz - ${ruoyi.version} - - - - - com.ruoyi - ruoyi-generator - ${ruoyi.version} - - - - - com.ruoyi - ruoyi-framework - ${ruoyi.version} - - - - - com.ruoyi - ruoyi-system - ${ruoyi.version} - - - - - com.ruoyi - ruoyi-common - ${ruoyi.version} - + + com.ruoyi + ruoyi-quartz + ${ruoyi.version} + + + + + com.ruoyi + ruoyi-generator + ${ruoyi.version} + + + + + com.ruoyi + ruoyi-framework + ${ruoyi.version} + + + + + com.ruoyi + ruoyi-system + ${ruoyi.version} + + + + + com.ruoyi + ruoyi-common + ${ruoyi.version} + - ruoyi-admin - ruoyi-framework - ruoyi-system - ruoyi-quartz - ruoyi-generator + ruoyi-admin + ruoyi-framework + ruoyi-system + ruoyi-quartz + ruoyi-generator ruoyi-common pom - + - - com.querydsl - querydsl-jpa - ${querydsl.version} - + - - - + - - com.mysema.maven - apt-maven-plugin - 1.1.3 - - - - process - - - target/generated-sources/java - com.querydsl.apt.jpa.JPAAnnotationProcessor - - - - - - com.querydsl - querydsl-apt - ${querydsl.version} - - - org.apache.maven.plugins maven-compiler-plugin @@ -266,29 +235,29 @@ - - - public - aliyun nexus - http://maven.aliyun.com/nexus/content/groups/public/ - - true - - - + + + public + aliyun nexus + http://maven.aliyun.com/nexus/content/groups/public/ + + true + + + - - - public - aliyun nexus - http://maven.aliyun.com/nexus/content/groups/public/ - - true - - - false - - - + + + public + aliyun nexus + http://maven.aliyun.com/nexus/content/groups/public/ + + true + + + false + + + \ No newline at end of file diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index ad7345a68..06a6028ce 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -5,18 +5,18 @@ ruoyi com.ruoyi - 4.1.0 + 4.4.0 4.0.0 - jar + jar ruoyi-admin - - - web服务入口 - + + + web服务入口 + - + org.springframework.boot @@ -24,42 +24,47 @@ - - org.springframework.boot - spring-boot-devtools - true - + + org.springframework.boot + spring-boot-devtools + true + - - - io.springfox - springfox-swagger2 - - - + + + io.springfox + springfox-swagger2 + + + io.swagger swagger-annotations 1.5.21 - + io.swagger swagger-models 1.5.21 - - - - io.springfox - springfox-swagger-ui - + + + + io.springfox + springfox-swagger-ui + + + + + mysql + mysql-connector-java + com.ruoyi ruoyi-framework - ${ruoyi.version} @@ -67,25 +72,13 @@ com.ruoyi ruoyi-quartz - + com.ruoyi ruoyi-generator - - - org.flywaydb - flyway-core - - - - - com.fasterxml.jackson.datatype - jackson-datatype-hibernate5 - 2.10.1 - @@ -93,10 +86,10 @@ org.springframework.boot spring-boot-maven-plugin - 2.1.1.RELEASE + 2.1.1.RELEASE - true - + true + @@ -113,9 +106,9 @@ false ${project.artifactId} - + ${project.artifactId} - + \ No newline at end of file diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java index 69b8034de..ebfb8c120 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java @@ -6,6 +6,7 @@ import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -46,10 +47,9 @@ public class CommonController { String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); String filePath = Global.getDownloadPath() + fileName; - response.setCharacterEncoding("utf-8"); - response.setContentType("multipart/form-data"); - response.setHeader("Content-Disposition", - "attachment;fileName=" + FileUtils.setFileDownloadHeader(request, realFileName)); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, realFileName); + FileUtils.writeBytes(filePath, response.getOutputStream()); if (delete) { FileUtils.deleteFile(filePath); @@ -92,10 +92,10 @@ public class CommonController { String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX); // 下载名称 String downloadName = StringUtils.substringAfterLast(downloadPath, "/"); - response.setCharacterEncoding("utf-8"); - response.setContentType("multipart/form-data"); - response.setHeader("Content-Disposition", - "attachment;fileName=" + FileUtils.setFileDownloadHeader(request, downloadName)); + + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, downloadName); + FileUtils.writeBytes(downloadPath, response.getOutputStream()); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoFormController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoFormController.java index 5b3e402f9..102d9372a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoFormController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoFormController.java @@ -2,25 +2,31 @@ package com.ruoyi.web.controller.demo.controller; import java.util.ArrayList; import java.util.List; - import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; +import com.alibaba.fastjson.JSON; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.CxSelect; +import com.ruoyi.common.json.JSONObject; +import com.ruoyi.common.json.JSONObject.JSONArray; +import com.ruoyi.common.utils.StringUtils; /** * 表单相关 - * + * * @author ruoyi */ @Controller @RequestMapping("/demo/form") -public class DemoFormController { +public class DemoFormController +{ private String prefix = "demo/form"; private final static List users = new ArrayList(); - { users.add(new UserFormModel(1, "1000001", "测试1", "15888888888")); users.add(new UserFormModel(2, "1000002", "测试2", "15666666666")); @@ -33,7 +39,8 @@ public class DemoFormController { * 按钮页 */ @GetMapping("/button") - public String button() { + public String button() + { return prefix + "/button"; } @@ -41,7 +48,8 @@ public class DemoFormController { * 下拉框 */ @GetMapping("/select") - public String select() { + public String select() + { return prefix + "/select"; } @@ -49,7 +57,8 @@ public class DemoFormController { * 时间轴 */ @GetMapping("/timeline") - public String timeline() { + public String timeline() + { return prefix + "/timeline"; } @@ -57,7 +66,8 @@ public class DemoFormController { * 表单校验 */ @GetMapping("/validate") - public String validate() { + public String validate() + { return prefix + "/validate"; } @@ -65,7 +75,8 @@ public class DemoFormController { * 功能扩展(包含文件上传) */ @GetMapping("/jasny") - public String jasny() { + public String jasny() + { return prefix + "/jasny"; } @@ -73,7 +84,8 @@ public class DemoFormController { * 拖动排序 */ @GetMapping("/sortable") - public String sortable() { + public String sortable() + { return prefix + "/sortable"; } @@ -81,7 +93,8 @@ public class DemoFormController { * 选项卡 & 面板 */ @GetMapping("/tabs_panels") - public String tabs_panels() { + public String tabs_panels() + { return prefix + "/tabs_panels"; } @@ -89,7 +102,8 @@ public class DemoFormController { * 栅格 */ @GetMapping("/grid") - public String grid() { + public String grid() + { return prefix + "/grid"; } @@ -97,7 +111,8 @@ public class DemoFormController { * 表单向导 */ @GetMapping("/wizard") - public String wizard() { + public String wizard() + { return prefix + "/wizard"; } @@ -105,7 +120,8 @@ public class DemoFormController { * 文件上传 */ @GetMapping("/upload") - public String upload() { + public String upload() + { return prefix + "/upload"; } @@ -113,7 +129,8 @@ public class DemoFormController { * 日期和时间页 */ @GetMapping("/datetime") - public String datetime() { + public String datetime() + { return prefix + "/datetime"; } @@ -121,7 +138,8 @@ public class DemoFormController { * 左右互选组件 */ @GetMapping("/duallistbox") - public String duallistbox() { + public String duallistbox() + { return prefix + "/duallistbox"; } @@ -129,7 +147,8 @@ public class DemoFormController { * 基本表单 */ @GetMapping("/basic") - public String basic() { + public String basic() + { return prefix + "/basic"; } @@ -137,7 +156,8 @@ public class DemoFormController { * 卡片列表 */ @GetMapping("/cards") - public String cards() { + public String cards() + { return prefix + "/cards"; } @@ -145,7 +165,8 @@ public class DemoFormController { * summernote 富文本编辑器 */ @GetMapping("/summernote") - public String summernote() { + public String summernote() + { return prefix + "/summernote"; } @@ -153,16 +174,112 @@ public class DemoFormController { * 搜索自动补全 */ @GetMapping("/autocomplete") - public String autocomplete() { + public String autocomplete() + { return prefix + "/autocomplete"; } + /** + * 多级联动下拉 + */ + @GetMapping("/cxselect") + public String cxselect(ModelMap mmap) + { + CxSelect cxSelectTB = new CxSelect(); + cxSelectTB.setN("淘宝"); + cxSelectTB.setV("taobao"); + CxSelect cxSelectTm = new CxSelect(); + cxSelectTm.setN("天猫"); + cxSelectTm.setV("tm"); + CxSelect cxSelectJhs = new CxSelect(); + cxSelectJhs.setN("聚划算"); + cxSelectJhs.setV("jhs"); + List tmList = new ArrayList(); + tmList.add(cxSelectTm); + tmList.add(cxSelectJhs); + cxSelectTB.setS(tmList); + + CxSelect cxSelectJD = new CxSelect(); + cxSelectJD.setN("京东"); + cxSelectJD.setV("jd"); + CxSelect cxSelectCs = new CxSelect(); + cxSelectCs.setN("京东超市"); + cxSelectCs.setV("jdcs"); + CxSelect cxSelectSx = new CxSelect(); + cxSelectSx.setN("京东生鲜"); + cxSelectSx.setV("jdsx"); + List jdList = new ArrayList(); + jdList.add(cxSelectCs); + jdList.add(cxSelectSx); + cxSelectJD.setS(jdList); + + List cxList = new ArrayList(); + cxList.add(cxSelectTB); + cxList.add(cxSelectJD); + + mmap.put("data", JSON.toJSON(cxList)); + return prefix + "/cxselect"; + } + + /** + * 局部刷新 + */ + @GetMapping("/localrefresh") + public String localRefresh(ModelMap mmap) + { + JSONArray list = new JSONArray(); + JSONObject item = new JSONObject(); + item.put("name", "这条任务数据是由ModelMap传递到页面的,点击添加按钮后会将这条数据替换为新数据"); + item.put("type", "默认"); + item.put("date", "2020.06.10"); + list.add(item); + mmap.put("tasks",list); + mmap.put("min",2); + mmap.put("max",10); + return prefix + "/localrefresh"; + } + + /** + * 局部刷新-添加任务 + * @param fragment 页面中的模板名称 + * @param taskName 任务名称 + */ + @PostMapping("/localrefresh/task") + public String localRefreshTask(String fragment,String taskName,ModelMap mmap) + { + JSONArray list = new JSONArray(); + JSONObject item = new JSONObject(); + item.put("name", StringUtils.defaultIfBlank(taskName, "通过电话销售过程中了解各盛市的设备仪器使用、采购情况及相关重要追踪人")); + item.put("type", "新增"); + item.put("date", "2018.06.10"); + list.add(item); + item = new JSONObject(); + item.put("name", "提高自己电话营销技巧,灵活专业地与客户进行电话交流"); + item.put("type", "新增"); + item.put("date", "2018.06.12"); + list.add(item); + mmap.put("tasks",list); + return prefix + "/localrefresh::" + fragment; + } + + /** + * 模拟数据 + */ + @GetMapping("/cityData") + @ResponseBody + public String cityData() + { + String data = "[{\"n\":\"湖南省\",\"s\":[{\"n\":\"长沙市\",\"s\":[{\"n\":\"芙蓉区\"},{\"n\":\"天心区\"},{\"n\":\"岳麓区\"},{\"n\":\"开福区\"},{\"n\":\"雨花区\"},{\"n\":\"望城区\"},{\"n\":\"长沙县\"},{\"n\":\"宁乡县\"},{\"n\":\"浏阳市\"}]},{\"n\":\"株洲市\",\"s\":[{\"n\":\"荷塘区\"},{\"n\":\"芦淞区\"},{\"n\":\"石峰区\"},{\"n\":\"天元区\"},{\"n\":\"株洲县\"},{\"n\":\"攸县\"},{\"n\":\"茶陵县\"},{\"n\":\"炎陵县\"},{\"n\":\"醴陵市\"}]},{\"n\":\"湘潭市\",\"s\":[{\"n\":\"雨湖区\"},{\"n\":\"岳塘区\"},{\"n\":\"湘潭县\"},{\"n\":\"湘乡市\"},{\"n\":\"韶山市\"}]},{\"n\":\"衡阳市\",\"s\":[{\"n\":\"珠晖区\"},{\"n\":\"雁峰区\"},{\"n\":\"石鼓区\"},{\"n\":\"蒸湘区\"},{\"n\":\"南岳区\"},{\"n\":\"衡阳县\"},{\"n\":\"衡南县\"},{\"n\":\"衡山县\"},{\"n\":\"衡东县\"},{\"n\":\"祁东县\"},{\"n\":\"耒阳市\"},{\"n\":\"常宁市\"}]},{\"n\":\"邵阳市\",\"s\":[{\"n\":\"双清区\"},{\"n\":\"大祥区\"},{\"n\":\"北塔区\"},{\"n\":\"邵东县\"},{\"n\":\"新邵县\"},{\"n\":\"邵阳县\"},{\"n\":\"隆回县\"},{\"n\":\"洞口县\"},{\"n\":\"绥宁县\"},{\"n\":\"新宁县\"},{\"n\":\"城步苗族自治县\"},{\"n\":\"武冈市\"}]},{\"n\":\"岳阳市\",\"s\":[{\"n\":\"岳阳楼区\"},{\"n\":\"云溪区\"},{\"n\":\"君山区\"},{\"n\":\"岳阳县\"},{\"n\":\"华容县\"},{\"n\":\"湘阴县\"},{\"n\":\"平江县\"},{\"n\":\"汨罗市\"},{\"n\":\"临湘市\"}]},{\"n\":\"常德市\",\"s\":[{\"n\":\"武陵区\"},{\"n\":\"鼎城区\"},{\"n\":\"安乡县\"},{\"n\":\"汉寿县\"},{\"n\":\"澧县\"},{\"n\":\"临澧县\"},{\"n\":\"桃源县\"},{\"n\":\"石门县\"},{\"n\":\"津市市\"}]},{\"n\":\"张家界市\",\"s\":[{\"n\":\"永定区\"},{\"n\":\"武陵源区\"},{\"n\":\"慈利县\"},{\"n\":\"桑植县\"}]},{\"n\":\"益阳市\",\"s\":[{\"n\":\"资阳区\"},{\"n\":\"赫山区\"},{\"n\":\"南县\"},{\"n\":\"桃江县\"},{\"n\":\"安化县\"},{\"n\":\"沅江市\"}]},{\"n\":\"郴州市\",\"s\":[{\"n\":\"北湖区\"},{\"n\":\"苏仙区\"},{\"n\":\"桂阳县\"},{\"n\":\"宜章县\"},{\"n\":\"永兴县\"},{\"n\":\"嘉禾县\"},{\"n\":\"临武县\"},{\"n\":\"汝城县\"},{\"n\":\"桂东县\"},{\"n\":\"安仁县\"},{\"n\":\"资兴市\"}]},{\"n\":\"永州市\",\"s\":[{\"n\":\"零陵区\"},{\"n\":\"冷水滩区\"},{\"n\":\"祁阳县\"},{\"n\":\"东安县\"},{\"n\":\"双牌县\"},{\"n\":\"道县\"},{\"n\":\"江永县\"},{\"n\":\"宁远县\"},{\"n\":\"蓝山县\"},{\"n\":\"新田县\"},{\"n\":\"江华瑶族自治县\"}]},{\"n\":\"怀化市\",\"s\":[{\"n\":\"鹤城区\"},{\"n\":\"中方县\"},{\"n\":\"沅陵县\"},{\"n\":\"辰溪县\"},{\"n\":\"溆浦县\"},{\"n\":\"会同县\"},{\"n\":\"麻阳苗族自治县\"},{\"n\":\"新晃侗族自治县\"},{\"n\":\"芷江侗族自治县\"},{\"n\":\"靖州苗族侗族自治县\"},{\"n\":\"通道侗族自治县\"},{\"n\":\"洪江市\"}]},{\"n\":\"娄底市\",\"s\":[{\"n\":\"娄星区\"},{\"n\":\"双峰县\"},{\"n\":\"新化县\"},{\"n\":\"冷水江市\"},{\"n\":\"涟源市\"}]},{\"n\":\"湘西土家族苗族自治州\",\"s\":[{\"n\":\"吉首市\"},{\"n\":\"泸溪县\"},{\"n\":\"凤凰县\"},{\"n\":\"花垣县\"},{\"n\":\"保靖县\"},{\"n\":\"古丈县\"},{\"n\":\"永顺县\"},{\"n\":\"龙山县\"}]}]},{\"n\":\"广东省\",\"s\":[{\"n\":\"广州市\",\"s\":[{\"n\":\"荔湾区\"},{\"n\":\"越秀区\"},{\"n\":\"海珠区\"},{\"n\":\"天河区\"},{\"n\":\"白云区\"},{\"n\":\"黄埔区\"},{\"n\":\"番禺区\"},{\"n\":\"花都区\"},{\"n\":\"南沙区\"},{\"n\":\"萝岗区\"},{\"n\":\"增城市\"},{\"n\":\"从化市\"}]},{\"n\":\"韶关市\",\"s\":[{\"n\":\"武江区\"},{\"n\":\"浈江区\"},{\"n\":\"曲江区\"},{\"n\":\"始兴县\"},{\"n\":\"仁化县\"},{\"n\":\"翁源县\"},{\"n\":\"乳源瑶族自治县\"},{\"n\":\"新丰县\"},{\"n\":\"乐昌市\"},{\"n\":\"南雄市\"}]},{\"n\":\"深圳市\",\"s\":[{\"n\":\"罗湖区\"},{\"n\":\"福田区\"},{\"n\":\"南山区\"},{\"n\":\"宝安区\"},{\"n\":\"龙岗区\"},{\"n\":\"盐田区\"}]},{\"n\":\"珠海市\",\"s\":[{\"n\":\"香洲区\"},{\"n\":\"斗门区\"},{\"n\":\"金湾区\"}]},{\"n\":\"汕头市\",\"s\":[{\"n\":\"龙湖区\"},{\"n\":\"金平区\"},{\"n\":\"濠江区\"},{\"n\":\"潮阳区\"},{\"n\":\"潮南区\"},{\"n\":\"澄海区\"},{\"n\":\"南澳县\"}]},{\"n\":\"佛山市\",\"s\":[{\"n\":\"禅城区\"},{\"n\":\"南海区\"},{\"n\":\"顺德区\"},{\"n\":\"三水区\"},{\"n\":\"高明区\"}]},{\"n\":\"江门市\",\"s\":[{\"n\":\"蓬江区\"},{\"n\":\"江海区\"},{\"n\":\"新会区\"},{\"n\":\"台山市\"},{\"n\":\"开平市\"},{\"n\":\"鹤山市\"},{\"n\":\"恩平市\"}]},{\"n\":\"湛江市\",\"s\":[{\"n\":\"赤坎区\"},{\"n\":\"霞山区\"},{\"n\":\"坡头区\"},{\"n\":\"麻章区\"},{\"n\":\"遂溪县\"},{\"n\":\"徐闻县\"},{\"n\":\"廉江市\"},{\"n\":\"雷州市\"},{\"n\":\"吴川市\"}]},{\"n\":\"茂名市\",\"s\":[{\"n\":\"茂南区\"},{\"n\":\"茂港区\"},{\"n\":\"电白县\"},{\"n\":\"高州市\"},{\"n\":\"化州市\"},{\"n\":\"信宜市\"}]},{\"n\":\"肇庆市\",\"s\":[{\"n\":\"端州区\"},{\"n\":\"鼎湖区\"},{\"n\":\"广宁县\"},{\"n\":\"怀集县\"},{\"n\":\"封开县\"},{\"n\":\"德庆县\"},{\"n\":\"高要市\"},{\"n\":\"四会市\"}]},{\"n\":\"惠州市\",\"s\":[{\"n\":\"惠城区\"},{\"n\":\"惠阳区\"},{\"n\":\"博罗县\"},{\"n\":\"惠东县\"},{\"n\":\"龙门县\"}]},{\"n\":\"梅州市\",\"s\":[{\"n\":\"梅江区\"},{\"n\":\"梅县\"},{\"n\":\"大埔县\"},{\"n\":\"丰顺县\"},{\"n\":\"五华县\"},{\"n\":\"平远县\"},{\"n\":\"蕉岭县\"},{\"n\":\"兴宁市\"}]},{\"n\":\"汕尾市\",\"s\":[{\"n\":\"城区\"},{\"n\":\"海丰县\"},{\"n\":\"陆河县\"},{\"n\":\"陆丰市\"}]},{\"n\":\"河源市\",\"s\":[{\"n\":\"源城区\"},{\"n\":\"紫金县\"},{\"n\":\"龙川县\"},{\"n\":\"连平县\"},{\"n\":\"和平县\"},{\"n\":\"东源县\"}]},{\"n\":\"阳江市\",\"s\":[{\"n\":\"江城区\"},{\"n\":\"阳西县\"},{\"n\":\"阳东县\"},{\"n\":\"阳春市\"}]},{\"n\":\"清远市\",\"s\":[{\"n\":\"清城区\"},{\"n\":\"清新区\"},{\"n\":\"佛冈县\"},{\"n\":\"阳山县\"},{\"n\":\"连山壮族瑶族自治县\"},{\"n\":\"连南瑶族自治县\"},{\"n\":\"英德市\"},{\"n\":\"连州市\"}]},{\"n\":\"东莞市\"},{\"n\":\"中山市\"},{\"n\":\"潮州市\",\"s\":[{\"n\":\"湘桥区\"},{\"n\":\"潮安区\"},{\"n\":\"饶平县\"}]},{\"n\":\"揭阳市\",\"s\":[{\"n\":\"榕城区\"},{\"n\":\"揭东区\"},{\"n\":\"揭西县\"},{\"n\":\"惠来县\"},{\"n\":\"普宁市\"}]},{\"n\":\"云浮市\",\"s\":[{\"n\":\"云城区\"},{\"n\":\"新兴县\"},{\"n\":\"郁南县\"},{\"n\":\"云安县\"},{\"n\":\"罗定市\"}]}]}]"; + return data; + } + /** * 获取用户数据 */ @GetMapping("/userModel") @ResponseBody - public AjaxResult userModel() { + public AjaxResult userModel() + { AjaxResult ajax = new AjaxResult(); ajax.put("code", 200); @@ -175,75 +292,79 @@ public class DemoFormController { */ @GetMapping("/collection") @ResponseBody - public AjaxResult collection() { - String[] array = {"ruoyi 1", "ruoyi 2", "ruoyi 3", "ruoyi 4", "ruoyi 5"}; + public AjaxResult collection() + { + String[] array = { "ruoyi 1", "ruoyi 2", "ruoyi 3", "ruoyi 4", "ruoyi 5" }; AjaxResult ajax = new AjaxResult(); ajax.put("value", array); return ajax; } } -class UserFormModel { - /** - * 用户ID - */ +class UserFormModel +{ + /** 用户ID */ private int userId; - /** - * 用户编号 - */ + /** 用户编号 */ private String userCode; - /** - * 用户姓名 - */ + /** 用户姓名 */ private String userName; - /** - * 用户手机 - */ + /** 用户手机 */ private String userPhone; - public UserFormModel() { + public UserFormModel() + { } - public UserFormModel(int userId, String userCode, String userName, String userPhone) { + public UserFormModel(int userId, String userCode, String userName, String userPhone) + { this.userId = userId; this.userCode = userCode; this.userName = userName; this.userPhone = userPhone; } - public int getUserId() { + public int getUserId() + { return userId; } - public void setUserId(int userId) { + public void setUserId(int userId) + { this.userId = userId; } - public String getUserCode() { + public String getUserCode() + { return userCode; } - public void setUserCode(String userCode) { + public void setUserCode(String userCode) + { this.userCode = userCode; } - public String getUserName() { + public String getUserName() + { return userName; } - public void setUserName(String userName) { + public void setUserName(String userName) + { this.userName = userName; } - public String getUserPhone() { + public String getUserPhone() + { return userPhone; } - public void setUserPhone(String userPhone) { + public void setUserPhone(String userPhone) + { this.userPhone = userPhone; } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoOperateController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoOperateController.java index 23b2a5d6e..10b9df688 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoOperateController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoOperateController.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; @@ -22,20 +21,21 @@ import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.exception.BusinessException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.web.controller.demo.domain.CustomerModel; import com.ruoyi.web.controller.demo.domain.UserOperateModel; /** * 操作控制 - * + * * @author ruoyi */ @Controller @RequestMapping("/demo/operate") -public class DemoOperateController extends BaseController { +public class DemoOperateController extends BaseController +{ private String prefix = "demo/operate"; private final static Map users = new LinkedHashMap(); - { users.put(1, new UserOperateModel(1, "1000001", "测试1", "0", "15888888888", "ry@qq.com", 150.0, "0")); users.put(2, new UserOperateModel(2, "1000002", "测试2", "1", "15666666666", "ry@qq.com", 180.0, "1")); @@ -69,7 +69,8 @@ public class DemoOperateController extends BaseController { * 表格 */ @GetMapping("/table") - public String table() { + public String table() + { return prefix + "/table"; } @@ -77,7 +78,8 @@ public class DemoOperateController extends BaseController { * 其他 */ @GetMapping("/other") - public String other() { + public String other() + { return prefix + "/other"; } @@ -86,34 +88,44 @@ public class DemoOperateController extends BaseController { */ @PostMapping("/list") @ResponseBody - public TableDataInfo list(UserOperateModel userModel) { + public TableDataInfo list(UserOperateModel userModel) + { TableDataInfo rspData = new TableDataInfo(); List userList = new ArrayList(users.values()); // 查询条件过滤 - if (StringUtils.isNotEmpty(userModel.getSearchValue())) { + if (StringUtils.isNotEmpty(userModel.getSearchValue())) + { userList.clear(); - for (Map.Entry entry : users.entrySet()) { - if (entry.getValue().getUserName().equals(userModel.getSearchValue())) { + for (Map.Entry entry : users.entrySet()) + { + if (entry.getValue().getUserName().equals(userModel.getSearchValue())) + { userList.add(entry.getValue()); } } - } else if (StringUtils.isNotEmpty(userModel.getUserName())) { + } + else if (StringUtils.isNotEmpty(userModel.getUserName())) + { userList.clear(); - for (Map.Entry entry : users.entrySet()) { - if (entry.getValue().getUserName().equals(userModel.getUserName())) { + for (Map.Entry entry : users.entrySet()) + { + if (entry.getValue().getUserName().equals(userModel.getUserName())) + { userList.add(entry.getValue()); } } } PageDomain pageDomain = TableSupport.buildPageRequest(); - if (null == pageDomain.getPageNum() || null == pageDomain.getPageSize()) { + if (null == pageDomain.getPageNum() || null == pageDomain.getPageSize()) + { rspData.setRows(userList); rspData.setTotal(userList.size()); return rspData; } Integer pageNum = (pageDomain.getPageNum() - 1) * 10; Integer pageSize = pageDomain.getPageNum() * 10; - if (pageSize > userList.size()) { + if (pageSize > userList.size()) + { pageSize = userList.size(); } rspData.setRows(userList.subList(pageNum, pageSize)); @@ -125,7 +137,8 @@ public class DemoOperateController extends BaseController { * 新增用户 */ @GetMapping("/add") - public String add(ModelMap mmap) { + public String add(ModelMap mmap) + { return prefix + "/add"; } @@ -134,17 +147,30 @@ public class DemoOperateController extends BaseController { */ @PostMapping("/add") @ResponseBody - public AjaxResult addSave(UserOperateModel user) { + public AjaxResult addSave(UserOperateModel user) + { Integer userId = users.size() + 1; user.setUserId(userId); return AjaxResult.success(users.put(userId, user)); } + /** + * 新增保存主子表信息 + */ + @PostMapping("/customer/add") + @ResponseBody + public AjaxResult addSave(CustomerModel customerModel) + { + System.out.println(customerModel.toString()); + return AjaxResult.success(); + } + /** * 修改用户 */ @GetMapping("/edit/{userId}") - public String edit(@PathVariable("userId") Integer userId, ModelMap mmap) { + public String edit(@PathVariable("userId") Integer userId, ModelMap mmap) + { mmap.put("user", users.get(userId)); return prefix + "/edit"; } @@ -154,7 +180,8 @@ public class DemoOperateController extends BaseController { */ @PostMapping("/edit") @ResponseBody - public AjaxResult editSave(UserOperateModel user) { + public AjaxResult editSave(UserOperateModel user) + { return AjaxResult.success(users.put(user.getUserId(), user)); } @@ -163,7 +190,8 @@ public class DemoOperateController extends BaseController { */ @PostMapping("/export") @ResponseBody - public AjaxResult export(UserOperateModel user) { + public AjaxResult export(UserOperateModel user) + { List list = new ArrayList(users.values()); ExcelUtil util = new ExcelUtil(UserOperateModel.class); return util.exportExcel(list, "用户数据"); @@ -174,7 +202,8 @@ public class DemoOperateController extends BaseController { */ @GetMapping("/importTemplate") @ResponseBody - public AjaxResult importTemplate() { + public AjaxResult importTemplate() + { ExcelUtil util = new ExcelUtil(UserOperateModel.class); return util.importTemplateExcel("用户数据"); } @@ -184,7 +213,8 @@ public class DemoOperateController extends BaseController { */ @PostMapping("/importData") @ResponseBody - public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + { ExcelUtil util = new ExcelUtil(UserOperateModel.class); List userList = util.importExcel(file.getInputStream()); String message = importUser(userList, updateSupport); @@ -196,9 +226,11 @@ public class DemoOperateController extends BaseController { */ @PostMapping("/remove") @ResponseBody - public AjaxResult remove(String ids) { + public AjaxResult remove(String ids) + { Integer[] userIds = Convert.toIntArray(ids); - for (Integer userId : userIds) { + for (Integer userId : userIds) + { users.remove(userId); } return AjaxResult.success(); @@ -208,67 +240,85 @@ public class DemoOperateController extends BaseController { * 查看详细 */ @GetMapping("/detail/{userId}") - public String detail(@PathVariable("userId") Integer userId, ModelMap mmap) { + public String detail(@PathVariable("userId") Integer userId, ModelMap mmap) + { mmap.put("user", users.get(userId)); return prefix + "/detail"; } @PostMapping("/clean") @ResponseBody - public AjaxResult clean() { + public AjaxResult clean() + { users.clear(); return success(); } /** * 导入用户数据 - * - * @param userList 用户数据列表 + * + * @param userList 用户数据列表 * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据 * @return 结果 */ - public String importUser(List userList, Boolean isUpdateSupport) { - if (StringUtils.isNull(userList) || userList.size() == 0) { + public String importUser(List userList, Boolean isUpdateSupport) + { + if (StringUtils.isNull(userList) || userList.size() == 0) + { throw new BusinessException("导入用户数据不能为空!"); } int successNum = 0; int failureNum = 0; StringBuilder successMsg = new StringBuilder(); StringBuilder failureMsg = new StringBuilder(); - for (UserOperateModel user : userList) { - try { + for (UserOperateModel user : userList) + { + try + { // 验证是否存在这个用户 boolean userFlag = false; - for (Map.Entry entry : users.entrySet()) { - if (entry.getValue().getUserName().equals(user.getUserName())) { + for (Map.Entry entry : users.entrySet()) + { + if (entry.getValue().getUserName().equals(user.getUserName())) + { userFlag = true; break; } } - if (!userFlag) { + if (!userFlag) + { Integer userId = users.size() + 1; user.setUserId(userId); users.put(userId, user); successNum++; successMsg.append("
" + successNum + "、用户 " + user.getUserName() + " 导入成功"); - } else if (isUpdateSupport) { + } + else if (isUpdateSupport) + { users.put(user.getUserId(), user); successNum++; successMsg.append("
" + successNum + "、用户 " + user.getUserName() + " 更新成功"); - } else { + } + else + { failureNum++; failureMsg.append("
" + failureNum + "、用户 " + user.getUserName() + " 已存在"); } - } catch (Exception e) { + } + catch (Exception e) + { failureNum++; String msg = "
" + failureNum + "、账号 " + user.getUserName() + " 导入失败:"; failureMsg.append(msg + e.getMessage()); } } - if (failureNum > 0) { + if (failureNum > 0) + { failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:"); throw new BusinessException(failureMsg.toString()); - } else { + } + else + { successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:"); } return successMsg.toString(); diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoTableController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoTableController.java index 8ba3bd0b9..8c9f29b19 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoTableController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/controller/DemoTableController.java @@ -5,8 +5,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; - import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,16 +21,16 @@ import com.ruoyi.common.utils.StringUtils; /** * 表格相关 - * + * * @author ruoyi */ @Controller @RequestMapping("/demo/table") -public class DemoTableController extends BaseController { +public class DemoTableController extends BaseController +{ private String prefix = "demo/table"; private final static List users = new ArrayList(); - { users.add(new UserTableModel(1, "1000001", "测试1", "0", "15888888888", "ry@qq.com", 150.0, "0")); users.add(new UserTableModel(2, "1000002", "测试2", "1", "15666666666", "ry@qq.com", 180.0, "1")); @@ -64,7 +64,8 @@ public class DemoTableController extends BaseController { * 搜索相关 */ @GetMapping("/search") - public String search() { + public String search() + { return prefix + "/search"; } @@ -72,7 +73,8 @@ public class DemoTableController extends BaseController { * 数据汇总 */ @GetMapping("/footer") - public String footer() { + public String footer() + { return prefix + "/footer"; } @@ -80,7 +82,8 @@ public class DemoTableController extends BaseController { * 组合表头 */ @GetMapping("/groupHeader") - public String groupHeader() { + public String groupHeader() + { return prefix + "/groupHeader"; } @@ -88,7 +91,8 @@ public class DemoTableController extends BaseController { * 表格导出 */ @GetMapping("/export") - public String export() { + public String export() + { return prefix + "/export"; } @@ -96,7 +100,8 @@ public class DemoTableController extends BaseController { * 翻页记住选择 */ @GetMapping("/remember") - public String remember() { + public String remember() + { return prefix + "/remember"; } @@ -104,7 +109,8 @@ public class DemoTableController extends BaseController { * 跳转至指定页 */ @GetMapping("/pageGo") - public String pageGo() { + public String pageGo() + { return prefix + "/pageGo"; } @@ -112,7 +118,8 @@ public class DemoTableController extends BaseController { * 自定义查询参数 */ @GetMapping("/params") - public String params() { + public String params() + { return prefix + "/params"; } @@ -120,7 +127,8 @@ public class DemoTableController extends BaseController { * 多表格 */ @GetMapping("/multi") - public String multi() { + public String multi() + { return prefix + "/multi"; } @@ -128,15 +136,27 @@ public class DemoTableController extends BaseController { * 点击按钮加载表格 */ @GetMapping("/button") - public String button() { + public String button() + { return prefix + "/button"; } + /** + * 直接加载表格数据 + */ + @GetMapping("/data") + public String data(ModelMap mmap) + { + mmap.put("users", users); + return prefix + "/data"; + } + /** * 表格冻结列 */ @GetMapping("/fixedColumns") - public String fixedColumns() { + public String fixedColumns() + { return prefix + "/fixedColumns"; } @@ -144,7 +164,8 @@ public class DemoTableController extends BaseController { * 自定义触发事件 */ @GetMapping("/event") - public String event() { + public String event() + { return prefix + "/event"; } @@ -152,7 +173,8 @@ public class DemoTableController extends BaseController { * 表格细节视图 */ @GetMapping("/detail") - public String detail() { + public String detail() + { return prefix + "/detail"; } @@ -160,7 +182,8 @@ public class DemoTableController extends BaseController { * 表格父子视图 */ @GetMapping("/child") - public String child() { + public String child() + { return prefix + "/child"; } @@ -168,7 +191,8 @@ public class DemoTableController extends BaseController { * 表格图片预览 */ @GetMapping("/image") - public String image() { + public String image() + { return prefix + "/image"; } @@ -176,7 +200,8 @@ public class DemoTableController extends BaseController { * 动态增删改查 */ @GetMapping("/curd") - public String curd() { + public String curd() + { return prefix + "/curd"; } @@ -184,7 +209,8 @@ public class DemoTableController extends BaseController { * 表格拖拽操作 */ @GetMapping("/reorder") - public String reorder() { + public String reorder() + { return prefix + "/reorder"; } @@ -192,15 +218,53 @@ public class DemoTableController extends BaseController { * 表格行内编辑操作 */ @GetMapping("/editable") - public String editable() { + public String editable() + { return prefix + "/editable"; } + /** + * 主子表提交 + */ + @GetMapping("/subdata") + public String subdata() + { + return prefix + "/subdata"; + } + + /** + * 表格自动刷新 + */ + @GetMapping("/refresh") + public String refresh() + { + return prefix + "/refresh"; + } + + /** + * 表格打印配置 + */ + @GetMapping("/print") + public String print() + { + return prefix + "/print"; + } + + /** + * 表格标题格式化 + */ + @GetMapping("/headerStyle") + public String headerStyle() + { + return prefix + "/headerStyle"; + } + /** * 表格其他操作 */ @GetMapping("/other") - public String other() { + public String other() + { return prefix + "/other"; } @@ -209,28 +273,34 @@ public class DemoTableController extends BaseController { */ @PostMapping("/list") @ResponseBody - public TableDataInfo list(UserTableModel userModel) { + public TableDataInfo list(UserTableModel userModel) + { TableDataInfo rspData = new TableDataInfo(); List userList = new ArrayList(Arrays.asList(new UserTableModel[users.size()])); Collections.copy(userList, users); // 查询条件过滤 - if (StringUtils.isNotEmpty(userModel.getUserName())) { + if (StringUtils.isNotEmpty(userModel.getUserName())) + { userList.clear(); - for (UserTableModel user : users) { - if (user.getUserName().equals(userModel.getUserName())) { + for (UserTableModel user : users) + { + if (user.getUserName().equals(userModel.getUserName())) + { userList.add(user); } } } PageDomain pageDomain = TableSupport.buildPageRequest(); - if (null == pageDomain.getPageNum() || null == pageDomain.getPageSize()) { + if (null == pageDomain.getPageNum() || null == pageDomain.getPageSize()) + { rspData.setRows(userList); rspData.setTotal(userList.size()); return rspData; } Integer pageNum = (pageDomain.getPageNum() - 1) * 10; Integer pageSize = pageDomain.getPageNum() * 10; - if (pageSize > userList.size()) { + if (pageSize > userList.size()) + { pageSize = userList.size(); } rspData.setRows(userList.subList(pageNum, pageSize)); @@ -239,59 +309,44 @@ public class DemoTableController extends BaseController { } } -class UserTableModel { - /** - * 用户ID - */ +class UserTableModel +{ + /** 用户ID */ private int userId; - /** - * 用户编号 - */ + /** 用户编号 */ private String userCode; - /** - * 用户姓名 - */ + /** 用户姓名 */ private String userName; - /** - * 用户性别 - */ + /** 用户性别 */ private String userSex; - /** - * 用户手机 - */ + /** 用户手机 */ private String userPhone; - /** - * 用户邮箱 - */ + /** 用户邮箱 */ private String userEmail; - /** - * 用户余额 - */ + /** 用户余额 */ private double userBalance; - /** - * 用户状态(0正常 1停用) - */ + /** 用户状态(0正常 1停用) */ private String status; - /** - * 创建时间 - */ + /** 创建时间 */ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; - public UserTableModel() { + public UserTableModel() + { } public UserTableModel(int userId, String userCode, String userName, String userSex, String userPhone, - String userEmail, double userBalance, String status) { + String userEmail, double userBalance, String status) + { this.userId = userId; this.userCode = userCode; this.userName = userName; @@ -303,75 +358,93 @@ class UserTableModel { this.createTime = DateUtils.getNowDate(); } - public int getUserId() { + public int getUserId() + { return userId; } - public void setUserId(int userId) { + public void setUserId(int userId) + { this.userId = userId; } - public String getUserCode() { + public String getUserCode() + { return userCode; } - public void setUserCode(String userCode) { + public void setUserCode(String userCode) + { this.userCode = userCode; } - public String getUserName() { + public String getUserName() + { return userName; } - public void setUserName(String userName) { + public void setUserName(String userName) + { this.userName = userName; } - public String getUserSex() { + public String getUserSex() + { return userSex; } - public void setUserSex(String userSex) { + public void setUserSex(String userSex) + { this.userSex = userSex; } - public String getUserPhone() { + public String getUserPhone() + { return userPhone; } - public void setUserPhone(String userPhone) { + public void setUserPhone(String userPhone) + { this.userPhone = userPhone; } - public String getUserEmail() { + public String getUserEmail() + { return userEmail; } - public void setUserEmail(String userEmail) { + public void setUserEmail(String userEmail) + { this.userEmail = userEmail; } - public double getUserBalance() { + public double getUserBalance() + { return userBalance; } - public void setUserBalance(double userBalance) { + public void setUserBalance(double userBalance) + { this.userBalance = userBalance; } - public String getStatus() { + public String getStatus() + { return status; } - public void setStatus(String status) { + public void setStatus(String status) + { this.status = status; } - public Date getCreateTime() { + public Date getCreateTime() + { return createTime; } - public void setCreateTime(Date createTime) { + public void setCreateTime(Date createTime) + { this.createTime = createTime; } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/CustomerModel.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/CustomerModel.java new file mode 100644 index 000000000..d1aebf2ba --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/CustomerModel.java @@ -0,0 +1,116 @@ +package com.ruoyi.web.controller.demo.domain; + +import java.util.List; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 客户测试信息 + * + * @author ruoyi + */ +public class CustomerModel +{ + /** + * 客户姓名 + */ + private String name; + + /** + * 客户手机 + */ + private String phonenumber; + + /** + * 客户性别 + */ + private String sex; + + /** + * 客户生日 + */ + private String birthday; + + /** + * 客户描述 + */ + private String remark; + + /** + * 商品信息 + */ + private List goods; + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public String getPhonenumber() + { + return phonenumber; + } + + public void setPhonenumber(String phonenumber) + { + this.phonenumber = phonenumber; + } + + + public String getSex() + { + return sex; + } + + public void setSex(String sex) + { + this.sex = sex; + } + + public String getBirthday() + { + return birthday; + } + + public void setBirthday(String birthday) + { + this.birthday = birthday; + } + + public String getRemark() + { + return remark; + } + + public void setRemark(String remark) + { + this.remark = remark; + } + + public List getGoods() + { + return goods; + } + + public void setGoods(List goods) + { + this.goods = goods; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("name", getName()) + .append("phonenumber", getPhonenumber()) + .append("sex", getSex()) + .append("birthday", getBirthday()) + .append("goods", getGoods()) + .append("remark", getRemark()) + .toString(); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/GoodsModel.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/GoodsModel.java new file mode 100644 index 000000000..897a010e6 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/GoodsModel.java @@ -0,0 +1,99 @@ +package com.ruoyi.web.controller.demo.domain; + +import java.util.Date; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +/** + * 商品测试信息 + * + * @author ruoyi + */ +public class GoodsModel +{ + /** + * 商品名称 + */ + private String name; + + /** + * 商品重量 + */ + private Integer weight; + + /** + * 商品价格 + */ + private Double price; + + /** + * 商品日期 + */ + private Date date; + + /** + * 商品种类 + */ + private String type; + + public String getName() + { + return name; + } + + public void setName(String name) + { + this.name = name; + } + + public Integer getWeight() + { + return weight; + } + + public void setWeight(Integer weight) + { + this.weight = weight; + } + + public Double getPrice() + { + return price; + } + + public void setPrice(Double price) + { + this.price = price; + } + + public Date getDate() + { + return date; + } + + public void setDate(Date date) + { + this.date = date; + } + + public String getType() + { + return type; + } + + public void setType(String type) + { + this.type = type; + } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("name", getName()) + .append("weight", getWeight()) + .append("price", getPrice()) + .append("date", getDate()) + .append("type", getType()) + .toString(); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/UserOperateModel.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/UserOperateModel.java index 5cfef057c..8b158aa10 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/UserOperateModel.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/demo/domain/UserOperateModel.java @@ -1,13 +1,13 @@ package com.ruoyi.web.controller.demo.domain; import java.util.Date; - import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.annotation.Excel.Type; import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.utils.DateUtils; -public class UserOperateModel extends BaseEntity { +public class UserOperateModel extends BaseEntity +{ private static final long serialVersionUID = 1L; private int userId; @@ -36,12 +36,14 @@ public class UserOperateModel extends BaseEntity { @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) private Date createTime; - public UserOperateModel() { + public UserOperateModel() + { } public UserOperateModel(int userId, String userCode, String userName, String userSex, String userPhone, - String userEmail, double userBalance, String status) { + String userEmail, double userBalance, String status) + { this.userId = userId; this.userCode = userCode; this.userName = userName; @@ -53,75 +55,95 @@ public class UserOperateModel extends BaseEntity { this.createTime = DateUtils.getNowDate(); } - public int getUserId() { + public int getUserId() + { return userId; } - public void setUserId(int userId) { + public void setUserId(int userId) + { this.userId = userId; } - public String getUserCode() { + public String getUserCode() + { return userCode; } - public void setUserCode(String userCode) { + public void setUserCode(String userCode) + { this.userCode = userCode; } - public String getUserName() { + public String getUserName() + { return userName; } - public void setUserName(String userName) { + public void setUserName(String userName) + { this.userName = userName; } - public String getUserSex() { + public String getUserSex() + { return userSex; } - public void setUserSex(String userSex) { + public void setUserSex(String userSex) + { this.userSex = userSex; } - public String getUserPhone() { + public String getUserPhone() + { return userPhone; } - public void setUserPhone(String userPhone) { + public void setUserPhone(String userPhone) + { this.userPhone = userPhone; } - public String getUserEmail() { + public String getUserEmail() + { return userEmail; } - public void setUserEmail(String userEmail) { + public void setUserEmail(String userEmail) + { this.userEmail = userEmail; } - public double getUserBalance() { + public double getUserBalance() + { return userBalance; } - public void setUserBalance(double userBalance) { + public void setUserBalance(double userBalance) + { this.userBalance = userBalance; } - public String getStatus() { + public String getStatus() + { return status; } - public void setStatus(String status) { + public void setStatus(String status) + { this.status = status; } - public Date getCreateTime() { + @Override + public Date getCreateTime() + { return createTime; } - public void setCreateTime(Date createTime) { + @Override + public void setCreateTime(Date createTime) + { this.createTime = createTime; } } \ No newline at end of file diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java index d1b82f6d8..d9a09f0f2 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java @@ -1,9 +1,19 @@ package com.ruoyi.web.controller.monitor; +import java.util.List; +import org.apache.shiro.authz.annotation.Logical; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.text.Convert; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.OnlineStatus; import com.ruoyi.framework.shiro.session.OnlineSession; @@ -11,19 +21,16 @@ import com.ruoyi.framework.shiro.session.OnlineSessionDAO; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysUserOnline; import com.ruoyi.system.service.ISysUserOnlineService; -import org.apache.shiro.authz.annotation.RequiresPermissions; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; /** * 在线用户监控 - * + * * @author ruoyi */ @Controller @RequestMapping("/monitor/online") -public class SysUserOnlineController extends BaseController { +public class SysUserOnlineController extends BaseController +{ private String prefix = "monitor/online"; @Autowired @@ -34,62 +41,48 @@ public class SysUserOnlineController extends BaseController { @RequiresPermissions("monitor:online:view") @GetMapping() - public String online() { + public String online() + { return prefix + "/online"; } @RequiresPermissions("monitor:online:list") @PostMapping("/list") @ResponseBody - public TableDataInfo list(SysUserOnline userOnline) { - return getDataTable(userOnlineService.selectUserOnlineList(userOnline, getPageRequest())); + public TableDataInfo list(SysUserOnline userOnline) + { + startPage(); + List list = userOnlineService.selectUserOnlineList(userOnline); + return getDataTable(list); } - @RequiresPermissions("monitor:online:batchForceLogout") + @RequiresPermissions(value = { "monitor:online:batchForceLogout", "monitor:online:forceLogout" }, logical = Logical.OR) @Log(title = "在线用户", businessType = BusinessType.FORCE) @PostMapping("/batchForceLogout") @ResponseBody - public AjaxResult batchForceLogout(@RequestParam("ids[]") String[] ids) { - for (String sessionId : ids) { + public AjaxResult batchForceLogout(String ids) + { + for (String sessionId : Convert.toStrArray(ids)) + { SysUserOnline online = userOnlineService.selectOnlineById(sessionId); - if (online == null) { + if (online == null) + { return error("用户已下线"); } OnlineSession onlineSession = (OnlineSession) onlineSessionDAO.readSession(online.getSessionId()); - if (onlineSession == null) { + if (onlineSession == null) + { return error("用户已下线"); } - if (sessionId.equals(ShiroUtils.getSessionId())) { + if (sessionId.equals(ShiroUtils.getSessionId())) + { return error("当前登陆用户无法强退"); } - onlineSession.setStatus(OnlineStatus.off_line); - onlineSessionDAO.update(onlineSession); + onlineSessionDAO.delete(onlineSession); online.setStatus(OnlineStatus.off_line); userOnlineService.saveOnline(online); + userOnlineService.removeUserCache(online.getLoginName(), sessionId); } return success(); } - - @RequiresPermissions("monitor:online:forceLogout") - @Log(title = "在线用户", businessType = BusinessType.FORCE) - @PostMapping("/forceLogout") - @ResponseBody - public AjaxResult forceLogout(String sessionId) { - SysUserOnline online = userOnlineService.selectOnlineById(sessionId); - if (sessionId.equals(ShiroUtils.getSessionId())) { - return error("当前登陆用户无法强退"); - } - if (online == null) { - return error("用户已下线"); - } - OnlineSession onlineSession = (OnlineSession) onlineSessionDAO.readSession(online.getSessionId()); - if (onlineSession == null) { - return error("用户已下线"); - } - onlineSession.setStatus(OnlineStatus.off_line); - onlineSessionDAO.update(onlineSession); - online.setStatus(OnlineStatus.off_line); - userOnlineService.saveOnline(online); - return success(); - } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java index e3069f838..086b764bc 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java @@ -1,5 +1,16 @@ package com.ruoyi.web.controller.system; +import java.util.List; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; @@ -10,24 +21,16 @@ import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysConfig; import com.ruoyi.system.service.ISysConfigService; -import org.apache.shiro.authz.annotation.RequiresPermissions; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; /** * 参数配置 信息操作处理 - * + * * @author ruoyi */ @Controller @RequestMapping("/system/config") -public class SysConfigController extends BaseController { +public class SysConfigController extends BaseController +{ private String prefix = "system/config"; @Autowired @@ -35,7 +38,8 @@ public class SysConfigController extends BaseController { @RequiresPermissions("system:config:view") @GetMapping() - public String config() { + public String config() + { return prefix + "/config"; } @@ -45,16 +49,20 @@ public class SysConfigController extends BaseController { @RequiresPermissions("system:config:list") @PostMapping("/list") @ResponseBody - public TableDataInfo list(SysConfig config) { - return getDataTable(configService.selectConfigList(config, getPageRequest())); + public TableDataInfo list(SysConfig config) + { + startPage(); + List list = configService.selectConfigList(config); + return getDataTable(list); } @Log(title = "参数管理", businessType = BusinessType.EXPORT) @RequiresPermissions("system:config:export") @PostMapping("/export") @ResponseBody - public AjaxResult export(SysConfig config) { - List list = configService.selectConfigList(config, Pageable.unpaged()).getContent(); + public AjaxResult export(SysConfig config) + { + List list = configService.selectConfigList(config); ExcelUtil util = new ExcelUtil(SysConfig.class); return util.exportExcel(list, "参数数据"); } @@ -63,7 +71,8 @@ public class SysConfigController extends BaseController { * 新增参数配置 */ @GetMapping("/add") - public String add() { + public String add() + { return prefix + "/add"; } @@ -74,8 +83,10 @@ public class SysConfigController extends BaseController { @Log(title = "参数管理", businessType = BusinessType.INSERT) @PostMapping("/add") @ResponseBody - public AjaxResult addSave(@Validated SysConfig config) { - if (UserConstants.CONFIG_KEY_NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) { + public AjaxResult addSave(@Validated SysConfig config) + { + if (UserConstants.CONFIG_KEY_NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) + { return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在"); } config.setCreateBy(ShiroUtils.getLoginName()); @@ -86,7 +97,8 @@ public class SysConfigController extends BaseController { * 修改参数配置 */ @GetMapping("/edit/{configId}") - public String edit(@PathVariable("configId") Long configId, ModelMap mmap) { + public String edit(@PathVariable("configId") Long configId, ModelMap mmap) + { mmap.put("config", configService.selectConfigById(configId)); return prefix + "/edit"; } @@ -98,8 +110,10 @@ public class SysConfigController extends BaseController { @Log(title = "参数管理", businessType = BusinessType.UPDATE) @PostMapping("/edit") @ResponseBody - public AjaxResult editSave(@Validated SysConfig config) { - if (UserConstants.CONFIG_KEY_NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) { + public AjaxResult editSave(@Validated SysConfig config) + { + if (UserConstants.CONFIG_KEY_NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) + { return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在"); } config.setUpdateBy(ShiroUtils.getLoginName()); @@ -113,16 +127,31 @@ public class SysConfigController extends BaseController { @Log(title = "参数管理", businessType = BusinessType.DELETE) @PostMapping("/remove") @ResponseBody - public AjaxResult remove(String ids) { + public AjaxResult remove(String ids) + { return toAjax(configService.deleteConfigByIds(ids)); } + /** + * 清空缓存 + */ + @RequiresPermissions("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @GetMapping("/clearCache") + @ResponseBody + public AjaxResult clearCache() + { + configService.clearCache(); + return success(); + } + /** * 校验参数键名 */ @PostMapping("/checkConfigKeyUnique") @ResponseBody - public String checkConfigKeyUnique(SysConfig config) { + public String checkConfigKeyUnique(SysConfig config) + { return configService.checkConfigKeyUnique(config); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java index c92644841..55362e6e6 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java @@ -1,33 +1,37 @@ package com.ruoyi.web.controller.system; +import java.util.List; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.Ztree; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysDept; import com.ruoyi.system.domain.SysRole; import com.ruoyi.system.service.ISysDeptService; -import org.apache.shiro.authz.annotation.RequiresPermissions; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; /** * 部门信息 - * + * * @author ruoyi */ @Controller @RequestMapping("/system/dept") -public class SysDeptController extends BaseController { +public class SysDeptController extends BaseController +{ private String prefix = "system/dept"; @Autowired @@ -35,22 +39,26 @@ public class SysDeptController extends BaseController { @RequiresPermissions("system:dept:view") @GetMapping() - public String dept() { + public String dept() + { return prefix + "/dept"; } @RequiresPermissions("system:dept:list") @PostMapping("/list") @ResponseBody - public List list(SysDept dept) { - return deptService.selectDeptList(dept, Pageable.unpaged()).getContent(); + public List list(SysDept dept) + { + List deptList = deptService.selectDeptList(dept); + return deptList; } /** * 新增部门 */ @GetMapping("/add/{parentId}") - public String add(@PathVariable("parentId") Long parentId, ModelMap mmap) { + public String add(@PathVariable("parentId") Long parentId, ModelMap mmap) + { mmap.put("dept", deptService.selectDeptById(parentId)); return prefix + "/add"; } @@ -62,20 +70,27 @@ public class SysDeptController extends BaseController { @RequiresPermissions("system:dept:add") @PostMapping("/add") @ResponseBody - public AjaxResult addSave(@Validated SysDept dept) { - if (UserConstants.DEPT_NAME_NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) { + public AjaxResult addSave(@Validated SysDept dept) + { + if (UserConstants.DEPT_NAME_NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) + { return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在"); } dept.setCreateBy(ShiroUtils.getLoginName()); - return success(deptService.insertDept(dept)); + return toAjax(deptService.insertDept(dept)); } /** * 修改 */ @GetMapping("/edit/{deptId}") - public String edit(@PathVariable("deptId") Long deptId, ModelMap mmap) { + public String edit(@PathVariable("deptId") Long deptId, ModelMap mmap) + { SysDept dept = deptService.selectDeptById(deptId); + if (StringUtils.isNotNull(dept) && 100L == deptId) + { + dept.setParentName("无"); + } mmap.put("dept", dept); return prefix + "/edit"; } @@ -87,15 +102,23 @@ public class SysDeptController extends BaseController { @RequiresPermissions("system:dept:edit") @PostMapping("/edit") @ResponseBody - public AjaxResult editSave(@Validated SysDept dept) { - if (UserConstants.DEPT_NAME_NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) { + public AjaxResult editSave(@Validated SysDept dept) + { + if (UserConstants.DEPT_NAME_NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) + { return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在"); - } else if (dept.getParentId().equals(dept.getDeptId())) { + } + else if (dept.getParentId().equals(dept.getDeptId())) + { return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己"); } + else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) + && deptService.selectNormalChildrenDeptById(dept.getDeptId()) > 0) + { + return AjaxResult.error("该部门包含未停用的子部门!"); + } dept.setUpdateBy(ShiroUtils.getLoginName()); - deptService.updateDept(dept); - return success(); + return toAjax(deptService.updateDept(dept)); } /** @@ -105,15 +128,17 @@ public class SysDeptController extends BaseController { @RequiresPermissions("system:dept:remove") @GetMapping("/remove/{deptId}") @ResponseBody - public AjaxResult remove(@PathVariable("deptId") Long deptId) { - if (deptService.countChildren(deptId) > 0) { + public AjaxResult remove(@PathVariable("deptId") Long deptId) + { + if (deptService.selectDeptCount(deptId) > 0) + { return AjaxResult.warn("存在下级部门,不允许删除"); } - if (deptService.checkDeptExistUser(deptId)) { + if (deptService.checkDeptExistUser(deptId)) + { return AjaxResult.warn("部门存在用户,不允许删除"); } - deptService.deleteDeptById(deptId); - return success(); + return toAjax(deptService.deleteDeptById(deptId)); } /** @@ -121,16 +146,23 @@ public class SysDeptController extends BaseController { */ @PostMapping("/checkDeptNameUnique") @ResponseBody - public String checkDeptNameUnique(SysDept dept) { + public String checkDeptNameUnique(SysDept dept) + { return deptService.checkDeptNameUnique(dept); } /** * 选择部门树 + * + * @param deptId 部门ID + * @param excludeId 排除ID */ - @GetMapping("/selectDeptTree/{deptId}") - public String selectDeptTree(@PathVariable("deptId") Long deptId, ModelMap mmap) { + @GetMapping(value = { "/selectDeptTree/{deptId}", "/selectDeptTree/{deptId}/{excludeId}" }) + public String selectDeptTree(@PathVariable("deptId") Long deptId, + @PathVariable(value = "excludeId", required = false) String excludeId, ModelMap mmap) + { mmap.put("dept", deptService.selectDeptById(deptId)); + mmap.put("excludeId", excludeId); return prefix + "/tree"; } @@ -139,17 +171,32 @@ public class SysDeptController extends BaseController { */ @GetMapping("/treeData") @ResponseBody - public List treeData() { + public List treeData() + { List ztrees = deptService.selectDeptTree(new SysDept()); return ztrees; } + /** + * 加载部门列表树(排除下级) + */ + @GetMapping("/treeData/{excludeId}") + @ResponseBody + public List treeDataExcludeChild(@PathVariable(value = "excludeId", required = false) Long excludeId) + { + SysDept dept = new SysDept(); + dept.setDeptId(excludeId); + List ztrees = deptService.selectDeptTreeExcludeChild(dept); + return ztrees; + } + /** * 加载角色部门(数据权限)列表树 */ @GetMapping("/roleDeptTreeData") @ResponseBody - public List deptTreeData(SysRole role) { + public List deptTreeData(SysRole role) + { List ztrees = deptService.roleDeptTreeData(role); return ztrees; } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java index f853418e1..4769dc74e 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java @@ -1,5 +1,16 @@ package com.ruoyi.web.controller.system; +import java.util.List; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; @@ -11,24 +22,16 @@ import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysDictType; import com.ruoyi.system.service.ISysDictTypeService; -import org.apache.shiro.authz.annotation.RequiresPermissions; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import java.util.List; /** * 数据字典信息 - * + * * @author ruoyi */ @Controller @RequestMapping("/system/dict") -public class SysDictTypeController extends BaseController { +public class SysDictTypeController extends BaseController +{ private String prefix = "system/dict/type"; @Autowired @@ -36,23 +39,29 @@ public class SysDictTypeController extends BaseController { @RequiresPermissions("system:dict:view") @GetMapping() - public String dictType() { + public String dictType() + { return prefix + "/type"; } @PostMapping("/list") @RequiresPermissions("system:dict:list") @ResponseBody - public TableDataInfo list(SysDictType dictType) { - return getDataTable(dictTypeService.selectDictTypeList(dictType, getPageRequest())); + public TableDataInfo list(SysDictType dictType) + { + startPage(); + List list = dictTypeService.selectDictTypeList(dictType); + return getDataTable(list); } @Log(title = "字典类型", businessType = BusinessType.EXPORT) @RequiresPermissions("system:dict:export") @PostMapping("/export") @ResponseBody - public AjaxResult export(SysDictType dictType) { - List list = dictTypeService.selectDictTypeList(dictType, Pageable.unpaged()).getContent(); + public AjaxResult export(SysDictType dictType) + { + + List list = dictTypeService.selectDictTypeList(dictType); ExcelUtil util = new ExcelUtil(SysDictType.class); return util.exportExcel(list, "字典类型"); } @@ -61,7 +70,8 @@ public class SysDictTypeController extends BaseController { * 新增字典类型 */ @GetMapping("/add") - public String add() { + public String add() + { return prefix + "/add"; } @@ -72,8 +82,10 @@ public class SysDictTypeController extends BaseController { @RequiresPermissions("system:dict:add") @PostMapping("/add") @ResponseBody - public AjaxResult addSave(@Validated SysDictType dict) { - if (UserConstants.DICT_TYPE_NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) { + public AjaxResult addSave(@Validated SysDictType dict) + { + if (UserConstants.DICT_TYPE_NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) + { return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在"); } dict.setCreateBy(ShiroUtils.getLoginName()); @@ -84,7 +96,8 @@ public class SysDictTypeController extends BaseController { * 修改字典类型 */ @GetMapping("/edit/{dictId}") - public String edit(@PathVariable("dictId") Long dictId, ModelMap mmap) { + public String edit(@PathVariable("dictId") Long dictId, ModelMap mmap) + { mmap.put("dict", dictTypeService.selectDictTypeById(dictId)); return prefix + "/edit"; } @@ -96,8 +109,10 @@ public class SysDictTypeController extends BaseController { @RequiresPermissions("system:dict:edit") @PostMapping("/edit") @ResponseBody - public AjaxResult editSave(@Validated SysDictType dict) { - if (UserConstants.DICT_TYPE_NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) { + public AjaxResult editSave(@Validated SysDictType dict) + { + if (UserConstants.DICT_TYPE_NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) + { return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在"); } dict.setUpdateBy(ShiroUtils.getLoginName()); @@ -108,12 +123,22 @@ public class SysDictTypeController extends BaseController { @RequiresPermissions("system:dict:remove") @PostMapping("/remove") @ResponseBody - public AjaxResult remove(String ids) { - try { - return toAjax(dictTypeService.deleteDictTypeByIds(ids)); - } catch (Exception e) { - return error(e.getMessage()); - } + public AjaxResult remove(String ids) + { + return toAjax(dictTypeService.deleteDictTypeByIds(ids)); + } + + /** + * 清空缓存 + */ + @RequiresPermissions("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @GetMapping("/clearCache") + @ResponseBody + public AjaxResult clearCache() + { + dictTypeService.clearCache(); + return success(); } /** @@ -121,7 +146,8 @@ public class SysDictTypeController extends BaseController { */ @RequiresPermissions("system:dict:list") @GetMapping("/detail/{dictId}") - public String detail(@PathVariable("dictId") Long dictId, ModelMap mmap) { + public String detail(@PathVariable("dictId") Long dictId, ModelMap mmap) + { mmap.put("dict", dictTypeService.selectDictTypeById(dictId)); mmap.put("dictList", dictTypeService.selectDictTypeAll()); return "system/dict/data/data"; @@ -132,7 +158,8 @@ public class SysDictTypeController extends BaseController { */ @PostMapping("/checkDictTypeUnique") @ResponseBody - public String checkDictTypeUnique(SysDictType dictType) { + public String checkDictTypeUnique(SysDictType dictType) + { return dictTypeService.checkDictTypeUnique(dictType); } @@ -141,7 +168,8 @@ public class SysDictTypeController extends BaseController { */ @GetMapping("/selectDictTree/{columnId}/{dictType}") public String selectDeptTree(@PathVariable("columnId") Long columnId, @PathVariable("dictType") String dictType, - ModelMap mmap) { + ModelMap mmap) + { mmap.put("columnId", columnId); mmap.put("dict", dictTypeService.selectDictTypeByType(dictType)); return prefix + "/tree"; @@ -152,7 +180,8 @@ public class SysDictTypeController extends BaseController { */ @GetMapping("/treeData") @ResponseBody - public List treeData() { + public List treeData() + { List ztrees = dictTypeService.selectDictTree(new SysDictType()); return ztrees; } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java index b0e575bc4..7c592363f 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java @@ -2,50 +2,91 @@ package com.ruoyi.web.controller.system; import java.util.List; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import com.ruoyi.common.config.Global; import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.utils.CookieUtils; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysMenu; import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.system.service.ISysMenuService; /** * 首页 业务处理 - * + * * @author ruoyi */ @Controller -public class SysIndexController extends BaseController { +public class SysIndexController extends BaseController +{ @Autowired private ISysMenuService menuService; + @Autowired + private ISysConfigService configService; + // 系统首页 @GetMapping("/index") - public String index(ModelMap mmap) { + public String index(ModelMap mmap) + { // 取身份信息 SysUser user = ShiroUtils.getSysUser(); // 根据用户id取出菜单 List menus = menuService.selectMenusByUser(user); mmap.put("menus", menus); mmap.put("user", user); + mmap.put("sideTheme", configService.selectConfigByKey("sys.index.sideTheme")); + mmap.put("skinName", configService.selectConfigByKey("sys.index.skinName")); + mmap.put("ignoreFooter", configService.selectConfigByKey("sys.index.ignoreFooter")); mmap.put("copyrightYear", Global.getCopyrightYear()); mmap.put("demoEnabled", Global.isDemoEnabled()); - return "index"; + + // 菜单导航显示风格 + String menuStyle = configService.selectConfigByKey("sys.index.menuStyle"); + // 移动端,默认使左侧导航菜单,否则取默认配置 + String indexStyle = ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent")) ? "index" : menuStyle; + + // 优先Cookie配置导航菜单 + Cookie[] cookies = ServletUtils.getRequest().getCookies(); + for (Cookie cookie : cookies) + { + if (StringUtils.isNotEmpty(cookie.getName()) && "nav-style".equalsIgnoreCase(cookie.getName())) + { + indexStyle = cookie.getValue(); + break; + } + } + String webIndex = "topnav".equalsIgnoreCase(indexStyle) ? "index-topnav" : "index"; + return webIndex; } // 切换主题 @GetMapping("/system/switchSkin") - public String switchSkin(ModelMap mmap) { + public String switchSkin() + { return "skin"; } + // 切换菜单 + @GetMapping("/system/menuStyle/{style}") + public void menuStyle(@PathVariable String style, HttpServletResponse response) + { + CookieUtils.setCookie(response, "nav-style", style); + } + // 系统介绍 @GetMapping("/system/main") - public String main(ModelMap mmap) { + public String main(ModelMap mmap) + { mmap.put("version", Global.getVersion()); return "main"; } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java new file mode 100644 index 000000000..a0f0a4848 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java @@ -0,0 +1,46 @@ +package com.ruoyi.web.controller.system; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.framework.shiro.service.SysRegisterService; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.service.ISysConfigService; + +/** + * 注册验证 + * + * @author ruoyi + */ +@Controller +public class SysRegisterController extends BaseController +{ + @Autowired + private SysRegisterService registerService; + + @Autowired + private ISysConfigService configService; + + @GetMapping("/register") + public String register() + { + return "register"; + } + + @PostMapping("/register") + @ResponseBody + public AjaxResult ajaxRegister(SysUser user) + { + if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) + { + return error("当前系统没有开启注册功能!"); + } + String msg = registerService.register(user); + return StringUtils.isEmpty(msg) ? success() : error(msg); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java index 2661a3dc6..fc768b49a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java @@ -1,39 +1,42 @@ package com.ruoyi.web.controller.system; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.shiro.service.SysPasswordService; import com.ruoyi.framework.util.ShiroUtils; +import com.ruoyi.system.domain.SysRole; import com.ruoyi.system.domain.SysUser; import com.ruoyi.system.service.ISysPostService; import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysUserService; -import org.apache.shiro.authz.annotation.RequiresPermissions; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.util.List; /** * 用户信息 - * + * * @author ruoyi */ @Controller @RequestMapping("/system/user") -public class SysUserController extends BaseController { +public class SysUserController extends BaseController +{ private String prefix = "system/user"; @Autowired @@ -50,32 +53,38 @@ public class SysUserController extends BaseController { @RequiresPermissions("system:user:view") @GetMapping() - public String user() { + public String user() + { return prefix + "/user"; } @RequiresPermissions("system:user:list") @PostMapping("/list") @ResponseBody - public TableDataInfo list(SysUser user) { - return getDataTable(userService.selectUserList(user, getPageRequest())); + public TableDataInfo list(SysUser user) + { + startPage(); + List list = userService.selectUserList(user); + return getDataTable(list); } @Log(title = "用户管理", businessType = BusinessType.EXPORT) @RequiresPermissions("system:user:export") @PostMapping("/export") @ResponseBody - public AjaxResult export(SysUser user) { - Page page = userService.selectUserList(user, Pageable.unpaged()); + public AjaxResult export(SysUser user) + { + List list = userService.selectUserList(user); ExcelUtil util = new ExcelUtil(SysUser.class); - return util.exportExcel(page.getContent(), "用户数据"); + return util.exportExcel(list, "用户数据"); } @Log(title = "用户管理", businessType = BusinessType.IMPORT) @RequiresPermissions("system:user:import") @PostMapping("/importData") @ResponseBody - public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { + public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception + { ExcelUtil util = new ExcelUtil(SysUser.class); List userList = util.importExcel(file.getInputStream()); String operName = ShiroUtils.getSysUser().getLoginName(); @@ -86,7 +95,8 @@ public class SysUserController extends BaseController { @RequiresPermissions("system:user:view") @GetMapping("/importTemplate") @ResponseBody - public AjaxResult importTemplate() { + public AjaxResult importTemplate() + { ExcelUtil util = new ExcelUtil(SysUser.class); return util.importTemplateExcel("用户数据"); } @@ -95,8 +105,9 @@ public class SysUserController extends BaseController { * 新增用户 */ @GetMapping("/add") - public String add(ModelMap mmap) { - mmap.put("roles", roleService.selectRoleAll()); + public String add(ModelMap mmap) + { + mmap.put("roles", roleService.selectRoleAll().stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); mmap.put("posts", postService.selectPostAll()); return prefix + "/add"; } @@ -108,28 +119,36 @@ public class SysUserController extends BaseController { @Log(title = "用户管理", businessType = BusinessType.INSERT) @PostMapping("/add") @ResponseBody - public AjaxResult addSave(@Validated SysUser user) { - if (UserConstants.USER_NAME_NOT_UNIQUE.equals(userService.checkLoginNameUnique(user.getLoginName()))) { + public AjaxResult addSave(@Validated SysUser user) + { + if (UserConstants.USER_NAME_NOT_UNIQUE.equals(userService.checkLoginNameUnique(user.getLoginName()))) + { return error("新增用户'" + user.getLoginName() + "'失败,登录账号已存在"); - } else if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { + } + else if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) + { return error("新增用户'" + user.getLoginName() + "'失败,手机号码已存在"); - } else if (UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { + } + else if (UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(user))) + { return error("新增用户'" + user.getLoginName() + "'失败,邮箱账号已存在"); } user.setSalt(ShiroUtils.randomSalt()); user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt())); user.setCreateBy(ShiroUtils.getLoginName()); - return success(userService.insertUser(user)); + return toAjax(userService.insertUser(user)); } /** * 修改用户 */ @GetMapping("/edit/{userId}") - public String edit(@PathVariable("userId") Long userId, ModelMap mmap) { - mmap.put("user", userService.selectUserWithRolesAndPostsById(userId)); - mmap.put("roles", roleService.selectRoleAll()); - mmap.put("posts", postService.selectPostAll()); + public String edit(@PathVariable("userId") Long userId, ModelMap mmap) + { + List roles = roleService.selectRolesByUserId(userId); + mmap.put("user", userService.selectUserById(userId)); + mmap.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + mmap.put("posts", postService.selectPostsByUserId(userId)); return prefix + "/edit"; } @@ -140,22 +159,25 @@ public class SysUserController extends BaseController { @Log(title = "用户管理", businessType = BusinessType.UPDATE) @PostMapping("/edit") @ResponseBody - public AjaxResult editSave(@Validated SysUser user) { + public AjaxResult editSave(@Validated SysUser user) + { userService.checkUserAllowed(user); - if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) { + if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) + { return error("修改用户'" + user.getLoginName() + "'失败,手机号码已存在"); - } else if (UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { + } + else if (UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(user))) + { return error("修改用户'" + user.getLoginName() + "'失败,邮箱账号已存在"); } user.setUpdateBy(ShiroUtils.getLoginName()); - userService.updateUser(user); - return success(); + return toAjax(userService.updateUser(user)); } @RequiresPermissions("system:user:resetPwd") - @Log(title = "重置密码", businessType = BusinessType.UPDATE) @GetMapping("/resetPwd/{userId}") - public String resetPwd(@PathVariable("userId") Long userId, ModelMap mmap) { + public String resetPwd(@PathVariable("userId") Long userId, ModelMap mmap) + { mmap.put("user", userService.selectUserById(userId)); return prefix + "/resetPwd"; } @@ -164,14 +186,46 @@ public class SysUserController extends BaseController { @Log(title = "重置密码", businessType = BusinessType.UPDATE) @PostMapping("/resetPwd") @ResponseBody - public AjaxResult resetPwdSave(SysUser user) { + public AjaxResult resetPwdSave(SysUser user) + { userService.checkUserAllowed(user); user.setSalt(ShiroUtils.randomSalt()); user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt())); - userService.resetUserPwd(user); - if (ShiroUtils.getUserId() == user.getUserId()) { - ShiroUtils.setSysUser(userService.selectUserById(user.getUserId())); + if (userService.resetUserPwd(user) > 0) + { + if (ShiroUtils.getUserId().longValue() == user.getUserId().longValue()) + { + ShiroUtils.setSysUser(userService.selectUserById(user.getUserId())); + } + return success(); } + return error(); + } + + /** + * 进入授权角色页 + */ + @GetMapping("/authRole/{userId}") + public String authRole(@PathVariable("userId") Long userId, ModelMap mmap) + { + SysUser user = userService.selectUserById(userId); + // 获取用户所属的角色列表 + List roles = roleService.selectRolesByUserId(userId); + mmap.put("user", user); + mmap.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); + return prefix + "/authRole"; + } + + /** + * 用户授权角色 + */ + @RequiresPermissions("system:user:add") + @Log(title = "用户管理", businessType = BusinessType.GRANT) + @PostMapping("/authRole/insertAuthRole") + @ResponseBody + public AjaxResult insertAuthRole(Long userId, Long[] roleIds) + { + userService.insertUserAuth(userId, roleIds); return success(); } @@ -179,10 +233,14 @@ public class SysUserController extends BaseController { @Log(title = "用户管理", businessType = BusinessType.DELETE) @PostMapping("/remove") @ResponseBody - public AjaxResult remove(String ids) { - try { + public AjaxResult remove(String ids) + { + try + { return toAjax(userService.deleteUserByIds(ids)); - } catch (Exception e) { + } + catch (Exception e) + { return error(e.getMessage()); } } @@ -192,7 +250,8 @@ public class SysUserController extends BaseController { */ @PostMapping("/checkLoginNameUnique") @ResponseBody - public String checkLoginNameUnique(SysUser user) { + public String checkLoginNameUnique(SysUser user) + { return userService.checkLoginNameUnique(user.getLoginName()); } @@ -201,7 +260,8 @@ public class SysUserController extends BaseController { */ @PostMapping("/checkPhoneUnique") @ResponseBody - public String checkPhoneUnique(SysUser user) { + public String checkPhoneUnique(SysUser user) + { return userService.checkPhoneUnique(user); } @@ -210,7 +270,8 @@ public class SysUserController extends BaseController { */ @PostMapping("/checkEmailUnique") @ResponseBody - public String checkEmailUnique(SysUser user) { + public String checkEmailUnique(SysUser user) + { return userService.checkEmailUnique(user); } @@ -221,9 +282,9 @@ public class SysUserController extends BaseController { @RequiresPermissions("system:user:edit") @PostMapping("/changeStatus") @ResponseBody - public AjaxResult changeStatus(SysUser user) { + public AjaxResult changeStatus(SysUser user) + { userService.checkUserAllowed(user); - userService.changeStatus(user); - return success(); + return toAjax(userService.changeStatus(user)); } } \ No newline at end of file diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java index 36a30811c..1105c2749 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java @@ -1,5 +1,6 @@ package com.ruoyi.web.core.config; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.ruoyi.common.config.Global; @@ -15,18 +16,26 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2; /** * Swagger2的接口配置 - * + * * @author ruoyi */ @Configuration @EnableSwagger2 -public class SwaggerConfig { +public class SwaggerConfig +{ + /** 是否开启swagger */ + @Value("${swagger.enabled}") + private boolean enabled; + /** * 创建API */ @Bean - public Docket createRestApi() { + public Docket createRestApi() + { return new Docket(DocumentationType.SWAGGER_2) + // 是否启用Swagger + .enable(enabled) // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) .apiInfo(apiInfo()) // 设置哪些接口暴露给Swagger展示 @@ -43,7 +52,8 @@ public class SwaggerConfig { /** * 添加摘要信息 */ - private ApiInfo apiInfo() { + private ApiInfo apiInfo() + { // 用ApiInfoBuilder进行定制 return new ApiInfoBuilder() // 设置标题 diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index deb1852ed..93486cf4c 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -3,7 +3,7 @@ ruoyi: # 名称 name: RuoYi # 版本 - version: 4.1.0 + version: 4.4.0 # 版权年份 copyrightYear: 2019 # 实例演示开关 @@ -11,7 +11,7 @@ ruoyi: # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath) profile: D:/ruoyi/uploadPath # 获取ip地址开关 - addressEnabled: true + addressEnabled: false # 开发环境配置 server: @@ -124,6 +124,8 @@ shiro: httpOnly: true # 设置Cookie的过期时间,天为单位 maxAge: 30 + # 设置密钥,务必保持唯一性(生成方式,直接拷贝到main运行即可)KeyGenerator keygen = KeyGenerator.getInstance("AES"); SecretKey deskey = keygen.generateKey(); System.out.println(Base64.encodeToString(deskey.getEncoded())); + cipherKey: zSyK5Kp6PZAAjlT+eeNMlg== session: # Session超时时间,-1代表永不过期(默认30分钟) expireTime: 30 @@ -144,3 +146,8 @@ xss: excludes: /system/notice/* # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* + +# Swagger配置 +swagger: + # 是否开启swagger + enabled: true diff --git a/ruoyi-admin/src/main/resources/db/migration/mysql/v001__init_sys_tables.sql b/ruoyi-admin/src/main/resources/db/migration/mysql/v001__init_sys_tables.sql index b05ec4360..c6b0b3865 100644 --- a/ruoyi-admin/src/main/resources/db/migration/mysql/v001__init_sys_tables.sql +++ b/ruoyi-admin/src/main/resources/db/migration/mysql/v001__init_sys_tables.sql @@ -5,7 +5,6 @@ drop table if exists sys_dept; create table sys_dept ( dept_id bigint(20) not null auto_increment comment '部门id', parent_id bigint(20) default 0 comment '父部门id', - code varchar(128) not null comment '部门编码', ancestors varchar(50) default '' comment '祖级列表', dept_name varchar(30) default '' comment '部门名称', order_num int(4) default 0 comment '显示顺序', @@ -24,7 +23,17 @@ create table sys_dept ( -- ---------------------------- -- 初始化-部门表数据 -- ---------------------------- -insert into sys_dept values(1, NULL, '001', NULL, '根', 0, 'Admin', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); +insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00'); + -- ---------------------------- -- 2、用户信息表 @@ -34,8 +43,8 @@ create table sys_user ( user_id bigint(20) not null auto_increment comment '用户ID', dept_id bigint(20) default null comment '部门ID', login_name varchar(30) not null comment '登录账号', - user_name varchar(30) not null comment '用户昵称', - user_type varchar(2) default '00' comment '用户类型(00系统用户)', + user_name varchar(30) default '' comment '用户昵称', + user_type varchar(2) default '00' comment '用户类型(00系统用户 01注册用户)', email varchar(50) default '' comment '用户邮箱', phonenumber varchar(11) default '' comment '手机号码', sex char(1) default '0' comment '用户性别(0男 1女 2未知)', @@ -57,8 +66,8 @@ create table sys_user ( -- ---------------------------- -- 初始化-用户信息表数据 -- ---------------------------- -insert into sys_user values(1, 1, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '29c67a30398638269fe600f73a054934', '111111', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员'); -insert into sys_user values(2, 1, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '8e6d98b90472783cc73c17047ddccf36', '222222', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '测试员'); +insert into sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '29c67a30398638269fe600f73a054934', '111111', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员'); +insert into sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '8e6d98b90472783cc73c17047ddccf36', '222222', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '测试员'); -- ---------------------------- @@ -112,8 +121,8 @@ create table sys_role ( -- ---------------------------- -- 初始化-角色信息表数据 -- ---------------------------- -insert into sys_role values('1', '管理员', 'admin', 1, 1, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员'); -insert into sys_role values('2', '普通角色', 'common', 2, 2, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '普通角色'); +insert into sys_role values('1', '超级管理员', 'admin', 1, 1, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '超级管理员'); +insert into sys_role values('2', '普通角色', 'common', 2, 2, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '普通角色'); -- ---------------------------- @@ -143,29 +152,30 @@ create table sys_menu ( -- 初始化-菜单信息表数据 -- ---------------------------- -- 一级菜单 -insert into sys_menu values('1', '系统管理', '0', '1', '#', '', 'M', '0', '', 'fa fa-gear', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统管理目录'); -insert into sys_menu values('2', '系统监控', '0', '2', '#', '', 'M', '0', '', 'fa fa-video-camera', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统监控目录'); -insert into sys_menu values('3', '系统工具', '0', '3', '#', '', 'M', '0', '', 'fa fa-bars', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统工具目录'); +insert into sys_menu values('1', '系统管理', '0', '1', '#', '', 'M', '0', '', 'fa fa-gear', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统管理目录'); +insert into sys_menu values('2', '系统监控', '0', '2', '#', '', 'M', '0', '', 'fa fa-video-camera', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统监控目录'); +insert into sys_menu values('3', '系统工具', '0', '3', '#', '', 'M', '0', '', 'fa fa-bars', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统工具目录'); +insert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', 'menuBlank', 'C', '0', '', 'fa fa-location-arrow', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '若依官网地址'); -- 二级菜单 -insert into sys_menu values('100', '用户管理', '1', '1', '/system/user', '', 'C', '0', 'system:user:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '用户管理菜单'); -insert into sys_menu values('101', '角色管理', '1', '2', '/system/role', '', 'C', '0', 'system:role:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '角色管理菜单'); -insert into sys_menu values('102', '菜单管理', '1', '3', '/system/menu', '', 'C', '0', 'system:menu:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '菜单管理菜单'); -insert into sys_menu values('103', '部门管理', '1', '4', '/system/dept', '', 'C', '0', 'system:dept:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '部门管理菜单'); -insert into sys_menu values('104', '岗位管理', '1', '5', '/system/post', '', 'C', '0', 'system:post:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '岗位管理菜单'); -insert into sys_menu values('105', '字典管理', '1', '6', '/system/dict', '', 'C', '0', 'system:dict:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '字典管理菜单'); -insert into sys_menu values('106', '参数设置', '1', '7', '/system/config', '', 'C', '0', 'system:config:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '参数设置菜单'); -insert into sys_menu values('107', '通知公告', '1', '8', '/system/notice', '', 'C', '0', 'system:notice:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '通知公告菜单'); -insert into sys_menu values('108', '日志管理', '1', '9', '#', '', 'M', '0', '', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '日志管理菜单'); -insert into sys_menu values('109', '在线用户', '2', '1', '/monitor/online', '', 'C', '0', 'monitor:online:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '在线用户菜单'); -insert into sys_menu values('110', '定时任务', '2', '2', '/monitor/job', '', 'C', '0', 'monitor:job:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '定时任务菜单'); -insert into sys_menu values('111', '数据监控', '2', '3', '/monitor/data', '', 'C', '0', 'monitor:data:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '数据监控菜单'); -insert into sys_menu values('112', '服务监控', '2', '3', '/monitor/server', '', 'C', '0', 'monitor:server:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '服务监控菜单'); -insert into sys_menu values('113', '表单构建', '3', '1', '/tool/build', '', 'C', '0', 'tool:build:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '表单构建菜单'); -insert into sys_menu values('114', '代码生成', '3', '2', '/tool/gen', '', 'C', '0', 'tool:gen:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '代码生成菜单'); -insert into sys_menu values('115', '系统接口', '3', '3', '/tool/swagger', '', 'C', '0', 'tool:swagger:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统接口菜单'); +insert into sys_menu values('100', '用户管理', '1', '1', '/system/user', '', 'C', '0', 'system:user:view', 'fa fa-user-o', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '用户管理菜单'); +insert into sys_menu values('101', '角色管理', '1', '2', '/system/role', '', 'C', '0', 'system:role:view', 'fa fa-user-secret', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '角色管理菜单'); +insert into sys_menu values('102', '菜单管理', '1', '3', '/system/menu', '', 'C', '0', 'system:menu:view', 'fa fa-th-list', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '菜单管理菜单'); +insert into sys_menu values('103', '部门管理', '1', '4', '/system/dept', '', 'C', '0', 'system:dept:view', 'fa fa-outdent', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '部门管理菜单'); +insert into sys_menu values('104', '岗位管理', '1', '5', '/system/post', '', 'C', '0', 'system:post:view', 'fa fa-address-card-o', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '岗位管理菜单'); +insert into sys_menu values('105', '字典管理', '1', '6', '/system/dict', '', 'C', '0', 'system:dict:view', 'fa fa-bookmark-o', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '字典管理菜单'); +insert into sys_menu values('106', '参数设置', '1', '7', '/system/config', '', 'C', '0', 'system:config:view', 'fa fa-sun-o', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '参数设置菜单'); +insert into sys_menu values('107', '通知公告', '1', '8', '/system/notice', '', 'C', '0', 'system:notice:view', 'fa fa-bullhorn', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '通知公告菜单'); +insert into sys_menu values('108', '日志管理', '1', '9', '#', '', 'M', '0', '', 'fa fa-pencil-square-o', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '日志管理菜单'); +insert into sys_menu values('109', '在线用户', '2', '1', '/monitor/online', '', 'C', '0', 'monitor:online:view', 'fa fa-user-circle', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '在线用户菜单'); +insert into sys_menu values('110', '定时任务', '2', '2', '/monitor/job', '', 'C', '0', 'monitor:job:view', 'fa fa-tasks', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '定时任务菜单'); +insert into sys_menu values('111', '数据监控', '2', '3', '/monitor/data', '', 'C', '0', 'monitor:data:view', 'fa fa-bug', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '数据监控菜单'); +insert into sys_menu values('112', '服务监控', '2', '3', '/monitor/server', '', 'C', '0', 'monitor:server:view', 'fa fa-server', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '服务监控菜单'); +insert into sys_menu values('113', '表单构建', '3', '1', '/tool/build', '', 'C', '0', 'tool:build:view', 'fa fa-wpforms', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '表单构建菜单'); +insert into sys_menu values('114', '代码生成', '3', '2', '/tool/gen', '', 'C', '0', 'tool:gen:view', 'fa fa-code', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '代码生成菜单'); +insert into sys_menu values('115', '系统接口', '3', '3', '/tool/swagger', '', 'C', '0', 'tool:swagger:view', 'fa fa-gg', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统接口菜单'); -- 三级菜单 -insert into sys_menu values('500', '操作日志', '108', '1', '/monitor/operlog', '', 'C', '0', 'monitor:operlog:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '操作日志菜单'); -insert into sys_menu values('501', '登录日志', '108', '2', '/monitor/logininfor', '', 'C', '0', 'monitor:logininfor:view', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '登录日志菜单'); +insert into sys_menu values('500', '操作日志', '108', '1', '/monitor/operlog', '', 'C', '0', 'monitor:operlog:view', 'fa fa-address-book', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '操作日志菜单'); +insert into sys_menu values('501', '登录日志', '108', '2', '/monitor/logininfor', '', 'C', '0', 'monitor:logininfor:view', 'fa fa-file-image-o', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '登录日志菜单'); -- 用户管理按钮 insert into sys_menu values('1000', '用户查询', '100', '1', '#', '', 'F', '0', 'system:user:list', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); insert into sys_menu values('1001', '用户新增', '100', '2', '#', '', 'F', '0', 'system:user:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', ''); @@ -276,6 +286,7 @@ create table sys_role_menu ( insert into sys_role_menu values ('2', '1'); insert into sys_role_menu values ('2', '2'); insert into sys_role_menu values ('2', '3'); +insert into sys_role_menu values ('2', '4'); insert into sys_role_menu values ('2', '100'); insert into sys_role_menu values ('2', '101'); insert into sys_role_menu values ('2', '102'); @@ -488,17 +499,18 @@ insert into sys_dict_data values(14, 1, '通知', '1', 'sys_notice_ty insert into sys_dict_data values(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '公告'); insert into sys_dict_data values(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '正常状态'); insert into sys_dict_data values(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '关闭状态'); -insert into sys_dict_data values(18, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '新增操作'); -insert into sys_dict_data values(19, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '修改操作'); -insert into sys_dict_data values(20, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '删除操作'); -insert into sys_dict_data values(21, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '授权操作'); -insert into sys_dict_data values(22, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '导出操作'); -insert into sys_dict_data values(23, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '导入操作'); -insert into sys_dict_data values(24, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '强退操作'); -insert into sys_dict_data values(25, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '生成操作'); -insert into sys_dict_data values(26, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '清空操作'); -insert into sys_dict_data values(27, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '正常状态'); -insert into sys_dict_data values(28, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '停用状态'); +insert into sys_dict_data values(18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '其他操作'); +insert into sys_dict_data values(19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '新增操作'); +insert into sys_dict_data values(20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '修改操作'); +insert into sys_dict_data values(21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '删除操作'); +insert into sys_dict_data values(22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '授权操作'); +insert into sys_dict_data values(23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '导出操作'); +insert into sys_dict_data values(24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '导入操作'); +insert into sys_dict_data values(25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '强退操作'); +insert into sys_dict_data values(26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '生成操作'); +insert into sys_dict_data values(27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '清空操作'); +insert into sys_dict_data values(28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '正常状态'); +insert into sys_dict_data values(29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '停用状态'); -- ---------------------------- @@ -519,9 +531,13 @@ create table sys_config ( primary key (config_id) ) engine=innodb auto_increment=100 comment = '参数配置表'; -insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' ); -insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '初始化密码 123456' ); -insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '深色主题theme-dark,浅色主题theme-light' ); +insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'); +insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '初始化密码 123456'); +insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '深黑主题theme-dark,浅色主题theme-light,深蓝主题theme-blue'); +insert into sys_config values(4, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '是否开启注册用户功能(true开启,false关闭)'); +insert into sys_config values(5, '用户管理-密码字符范围', 'sys.account.chrtype', '0', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '默认任意字符范围,0任意(密码可以输入任意字符),1数字(密码只能为0-9数字),2英文字母(密码只能为a-z和A-Z字母),3字母和数字(密码必须包含字母,数字),4字母数组和特殊字符(密码必须包含字母,数字,特殊字符-_)'); +insert into sys_config values(6, '主框架页-菜单导航显示风格', 'sys.index.menuStyle', 'default', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '菜单导航显示风格(default为左侧导航菜单,topnav为顶部导航菜单)'); +insert into sys_config values(7, '主框架页-是否开启页脚', 'sys.index.ignoreFooter', 'true', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '是否开启底部页脚显示(true显示,false隐藏)'); -- ---------------------------- @@ -547,7 +563,7 @@ create table sys_logininfor ( -- ---------------------------- drop table if exists sys_user_online; create table sys_user_online ( - session_id varchar(50) default '' comment '用户会话id', + sessionId varchar(50) default '' comment '用户会话id', login_name varchar(50) default '' comment '登录账号', dept_name varchar(50) default '' comment '部门名称', ipaddr varchar(50) default '' comment '登录IP地址', @@ -558,7 +574,7 @@ create table sys_user_online ( start_timestamp datetime comment 'session创建时间', last_access_time datetime comment 'session最后访问时间', expire_time int(5) default 0 comment '超时时间,单位为分钟', - primary key (session_id) + primary key (sessionId) ) engine=innodb comment = '在线用户记录'; @@ -635,22 +651,26 @@ insert into sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨 -- ---------------------------- drop table if exists gen_table; create table gen_table ( - table_id bigint(20) not null auto_increment comment '编号', - table_name varchar(200) default '' comment '表名称', - table_comment varchar(500) default '' comment '表描述', - class_name varchar(100) default '' comment '实体类名称', - tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)', - package_name varchar(100) comment '生成包路径', - module_name varchar(30) comment '生成模块名', - business_name varchar(30) comment '生成业务名', - function_name varchar(50) comment '生成功能名', - function_author varchar(50) comment '生成功能作者', - options varchar(1000) comment '其它生成选项', - create_by varchar(64) default '' comment '创建者', - create_time datetime comment '创建时间', - update_by varchar(64) default '' comment '更新者', - update_time datetime comment '更新时间', - remark varchar(500) default null comment '备注', + table_id bigint(20) not null auto_increment comment '编号', + table_name varchar(200) default '' comment '表名称', + table_comment varchar(500) default '' comment '表描述', + sub_table_name varchar(64) default null comment '关联子表的表名', + sub_table_fk_name varchar(64) default null comment '子表关联的外键名', + class_name varchar(100) default '' comment '实体类名称', + tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作 sub主子表操作)', + package_name varchar(100) comment '生成包路径', + module_name varchar(30) comment '生成模块名', + business_name varchar(30) comment '生成业务名', + function_name varchar(50) comment '生成功能名', + function_author varchar(50) comment '生成功能作者', + gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)', + gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)', + options varchar(1000) comment '其它生成选项', + create_by varchar(64) default '' comment '创建者', + create_time datetime comment '创建时间', + update_by varchar(64) default '' comment '更新者', + update_time datetime comment '更新时间', + remark varchar(500) default null comment '备注', primary key (table_id) ) engine=innodb auto_increment=1 comment = '代码生成业务表'; diff --git a/ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml b/ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml index 0ff3c1e23..72469e13a 100644 --- a/ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml +++ b/ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml @@ -41,7 +41,31 @@ timeToIdleSeconds="0" statistics="true"> - + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml b/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml index e8b52be8c..2b1811312 100644 --- a/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml +++ b/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml @@ -5,10 +5,10 @@ PUBLIC "-//mybatis.org//DTD Config 3.0//EN" - - - - + + + + diff --git a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/bootstrap-table.min.css b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/bootstrap-table.min.css index d72d06558..e2dcb51ab 100644 --- a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/bootstrap-table.min.css +++ b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/bootstrap-table.min.css @@ -1 +1 @@ -.fixed-table-container .bs-checkbox,.fixed-table-container .no-records-found{text-align:center}.fixed-table-body thead th .th-inner,.table td,.table th{box-sizing:border-box}.bootstrap-table .table{margin-bottom:0!important;border-bottom:1px solid #ddd;border-collapse:collapse!important;border-radius:1px}.bootstrap-table .table:not(.table-condensed),.bootstrap-table .table:not(.table-condensed)>tbody>tr>td,.bootstrap-table .table:not(.table-condensed)>tbody>tr>th,.bootstrap-table .table:not(.table-condensed)>tfoot>tr>td,.bootstrap-table .table:not(.table-condensed)>tfoot>tr>th,.bootstrap-table .table:not(.table-condensed)>thead>tr>td{padding:8px}.bootstrap-table .table.table-no-bordered>tbody>tr>td,.bootstrap-table .table.table-no-bordered>thead>tr>th{border-right:2px solid transparent}.bootstrap-table .table.table-no-bordered>tbody>tr>td:last-child{border-right:none}.fixed-table-container{position:relative;clear:both;border:1px solid #ddd;border-radius:4px;-webkit-border-radius:4px;-moz-border-radius:4px}.fixed-table-container.table-no-bordered{border:1px solid transparent}.fixed-table-footer,.fixed-table-header{overflow:hidden}.fixed-table-footer{border-top:1px solid #ddd}.fixed-table-body{overflow-x:auto;overflow-y:auto;height:100%}.fixed-table-container table{width:100%}.fixed-table-container thead th{height:0;padding:0;margin:0;border-left:1px solid #ddd}.fixed-table-container thead th:focus{outline:transparent solid 0}.fixed-table-container thead th:first-child{border-left:none;border-top-left-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px}.fixed-table-container tbody td .th-inner,.fixed-table-container thead th .th-inner{padding:8px;line-height:24px;vertical-align:top;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fixed-table-container thead th .sortable{cursor:pointer;background-position:right;background-repeat:no-repeat;padding-right:30px}.fixed-table-container thead th .both{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC')}.fixed-table-container thead th .asc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==)}.fixed-table-container thead th .desc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII=)}.fixed-table-container th.detail{width:30px}.fixed-table-container tbody td{border-left:1px solid #ddd}.fixed-table-container tbody tr:first-child td{border-top:none}.fixed-table-container tbody td:first-child{border-left:none}.fixed-table-container tbody .selected td{background-color:#f5f5f5}.fixed-table-container .bs-checkbox .th-inner{padding:8px 0}.fixed-table-container input[type=radio],.fixed-table-container input[type=checkbox]{margin:0 auto!important}.fixed-table-pagination .pagination-detail,.fixed-table-pagination div.pagination{margin-top:10px;margin-bottom:10px}.fixed-table-pagination div.pagination .pagination{margin:0}.fixed-table-pagination .pagination a{padding:6px 12px;line-height:1.428571429}.fixed-table-pagination .pagination-info{line-height:34px;margin-right:5px}.fixed-table-pagination .btn-group{position:relative;display:inline-block;vertical-align:middle}.fixed-table-pagination .dropup .dropdown-menu{margin-bottom:0}.fixed-table-pagination .page-list{display:inline-block}.fixed-table-toolbar .columns-left{margin-right:5px}.fixed-table-toolbar .columns-right{margin-left:5px}.fixed-table-toolbar .columns label{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429}.fixed-table-toolbar .bs-bars,.fixed-table-toolbar .columns,.fixed-table-toolbar .search{position:relative;margin-top:10px;margin-bottom:10px;line-height:34px}.fixed-table-pagination li.disabled a{pointer-events:none;cursor:default}.fixed-table-loading{display:none;position:absolute;top:42px;right:0;bottom:0;left:0;z-index:99;background-color:#fff;text-align:center}.fixed-table-body .card-view .title{font-weight:700;display:inline-block;min-width:30%;text-align:left!important}.table td,.table th{vertical-align:middle}.fixed-table-toolbar .dropdown-menu{text-align:left;max-height:300px;overflow:auto}.fixed-table-toolbar .btn-group>.btn-group{display:inline-block;margin-left:-1px!important}.fixed-table-toolbar .btn-group>.btn-group>.btn{border-radius:0}.fixed-table-toolbar .btn-group>.btn-group:first-child>.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.fixed-table-toolbar .btn-group>.btn-group:last-child>.btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.bootstrap-table .table>thead>tr>th{vertical-align:bottom;border-bottom:1px solid #ddd}.bootstrap-table .table thead>tr>th{padding:0;margin:0}.bootstrap-table .fixed-table-footer tbody>tr>td{padding:0!important}.bootstrap-table .fixed-table-footer .table{border-bottom:none;border-radius:0;padding:0!important}.pull-right .dropdown-menu{right:0;left:auto}p.fixed-table-scroll-inner{width:100%;height:200px}div.fixed-table-scroll-outer{top:0;left:0;visibility:hidden;width:200px;height:150px;overflow:hidden} \ No newline at end of file +.bootstrap-table .fixed-table-toolbar::after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-toolbar .bs-bars,.bootstrap-table .fixed-table-toolbar .search,.bootstrap-table .fixed-table-toolbar .columns{position:relative;margin-top:10px;margin-bottom:10px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group{display:inline-block;margin-left:-1px!important}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group>.btn{border-radius:0}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group:first-child>.btn{border-top-left-radius:4px;border-bottom-left-radius:4px}.bootstrap-table .fixed-table-toolbar .columns .btn-group>.btn-group:last-child>.btn{border-top-right-radius:4px;border-bottom-right-radius:4px}.bootstrap-table .fixed-table-toolbar .columns .dropdown-menu{text-align:left;max-height:300px;overflow:auto;-ms-overflow-style:scrollbar;z-index:1001}.bootstrap-table .fixed-table-toolbar .columns label{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429}.bootstrap-table .fixed-table-toolbar .columns-left{margin-right:5px}.bootstrap-table .fixed-table-toolbar .columns-right{margin-left:5px}.bootstrap-table .fixed-table-toolbar .pull-right .dropdown-menu{right:0;left:auto}.bootstrap-table .fixed-table-container{position:relative;clear:both}.bootstrap-table .fixed-table-container .table{width:100%;margin-bottom:0!important}.bootstrap-table .fixed-table-container .table th,.bootstrap-table .fixed-table-container .table td{vertical-align:middle;box-sizing:border-box}.bootstrap-table .fixed-table-container .table thead th{vertical-align:bottom;padding:0;margin:0}.bootstrap-table .fixed-table-container .table thead th:focus{outline:0 solid transparent}.bootstrap-table .fixed-table-container .table thead th.detail{width:30px}.bootstrap-table .fixed-table-container .table thead th .th-inner{padding:.75rem;vertical-align:bottom;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.bootstrap-table .fixed-table-container .table thead th .sortable{cursor:pointer;background-position:right;background-repeat:no-repeat;padding-right:30px!important}.bootstrap-table .fixed-table-container .table thead th .both{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7XQMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+Tq/QCM1oNiJidwox0355mXnG/DrEtIQ6azioNZQxI0ykPhTQIwhCR+BmBYtlK7kLJYwWCcJA9M4qdrZrd8pPjZWPtOqdRQy320YSV17OatFC4euts6z39GYMKRPCTKY9UnPQ6P+GtMRfGtPnBCiqhAeJPmkqAAAAAElFTkSuQmCC")}.bootstrap-table .fixed-table-container .table thead th .asc{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZ0lEQVQ4y2NgGLKgquEuFxBPAGI2ahhWCsS/gDibUoO0gPgxEP8H4ttArEyuQYxAPBdqEAxPBImTY5gjEL9DM+wTENuQahAvEO9DMwiGdwAxOymGJQLxTyD+jgWDxCMZRsEoGAVoAADeemwtPcZI2wAAAABJRU5ErkJggg==")}.bootstrap-table .fixed-table-container .table thead th .desc{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAYAAAByUDbMAAAAZUlEQVQ4y2NgGAWjYBSggaqGu5FA/BOIv2PBIPFEUgxjB+IdQPwfC94HxLykus4GiD+hGfQOiB3J8SojEE9EM2wuSJzcsFMG4ttQgx4DsRalkZENxL+AuJQaMcsGxBOAmGvopk8AVz1sLZgg0bsAAAAASUVORK5CYII=")}.bootstrap-table .fixed-table-container .table tbody tr.no-records-found td{text-align:center}.bootstrap-table .fixed-table-container .table tbody tr .card-view{display:flex}.bootstrap-table .fixed-table-container .table tbody tr .card-view .card-view-title{font-weight:bold;display:inline-block;min-width:30%;text-align:left!important}.bootstrap-table .fixed-table-container .table .bs-checkbox{text-align:center}.bootstrap-table .fixed-table-container .table .bs-checkbox label{margin-bottom:0}.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type="radio"],.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type="checkbox"]{margin:0 auto!important}.bootstrap-table .fixed-table-container .table.table-sm .th-inner{padding:.3rem}.bootstrap-table .fixed-table-container.fixed-height:not(.has-footer){border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height.has-card-view{border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .fixed-table-border{border-left:1px solid #dee2e6;border-right:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .table thead th{border-bottom:1px solid #dee2e6}.bootstrap-table .fixed-table-container.fixed-height .table-dark thead th{border-bottom:1px solid #32383e}.bootstrap-table .fixed-table-container .fixed-table-header{overflow:hidden}.bootstrap-table .fixed-table-container .fixed-table-body{overflow-x:auto;overflow-y:auto;height:100%}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading{align-items:center;background:#fff;display:none;justify-content:center;position:absolute;bottom:0;width:100%;z-index:1000}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap{align-items:baseline;display:flex;justify-content:center}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .loading-text{margin-right:6px}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap{align-items:center;display:flex;justify-content:center}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::before{content:"";animation-duration:1.5s;animation-iteration-count:infinite;animation-name:LOADING;background:#212529;border-radius:50%;display:block;height:5px;margin:0 4px;opacity:0;width:5px}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-dot{animation-delay:.3s}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading .loading-wrap .animation-wrap::after{animation-delay:.6s}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark{background:#212529}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-dot,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::after,.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.table-dark .animation-wrap::before{background:#fff}.bootstrap-table .fixed-table-container .fixed-table-footer{overflow:hidden}.bootstrap-table .fixed-table-pagination::after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-pagination>.pagination-detail,.bootstrap-table .fixed-table-pagination>.pagination{margin-top:10px;margin-bottom:10px}.bootstrap-table .fixed-table-pagination>.pagination-detail .pagination-info{line-height:34px;margin-right:5px}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list{display:inline-block}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list .btn-group{position:relative;display:inline-block;vertical-align:middle}.bootstrap-table .fixed-table-pagination>.pagination-detail .page-list .btn-group .dropdown-menu{margin-bottom:0}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination{margin:0}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination a{padding:6px 12px;line-height:1.428571429}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a{color:#c8c8c8}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a::before{content:'\2B05'}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.page-intermediate a::after{content:'\27A1'}.bootstrap-table .fixed-table-pagination>.pagination ul.pagination li.disabled a{pointer-events:none;cursor:default}.bootstrap-table.fullscreen{position:fixed;top:0;left:0;z-index:1050;width:100%!important;background:#fff;height:calc(100vh);overflow-y:scroll}div.fixed-table-scroll-inner{width:100%;height:200px}div.fixed-table-scroll-outer{top:0;left:0;visibility:hidden;width:200px;height:150px;overflow:hidden}@keyframes LOADING{0%{opacity:0}50%{opacity:1}to{opacity:0}} \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/bootstrap-table.min.js b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/bootstrap-table.min.js index 0ea13e57c..25732255d 100644 --- a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/bootstrap-table.min.js +++ b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/bootstrap-table.min.js @@ -1,7 +1,9 @@ /** * @author zhixin wen - * version: 1.11.0 + * version: 1.17.1 * https://github.com/wenzhixin/bootstrap-table/ */ -(function(j){var k=null;var m=function(u){var s=arguments,r=true,t=1;u=u.replace(/%s/g,function(){var v=s[t++];if(typeof v==="undefined"){r=false;return""}return v});return r?u:""};var c=function(t,v,u,s){var r="";j.each(t,function(w,x){if(x[v]===s){r=x[u];return false}return true});return r};var i=function(s,t){var r=-1;j.each(s,function(u,v){if(v.field===t){r=u;return false}return true});return r};var l=function(u){var y,x,w,A=0,B=[];for(y=0;y").addClass("fixed-table-scroll-inner"),u=j("
").addClass("fixed-table-scroll-outer"),s,r;u.append(t);j("body").append(u);s=t[0].offsetWidth;u.css("overflow","scroll");r=t[0].offsetWidth;if(s===r){r=u[0].clientWidth}u.remove();k=s-r}return k};var q=function(s,u,t,r){var v=u;if(typeof u==="string"){var w=u.split(".");if(w.length>1){v=window;j.each(w,function(x,y){v=v[y]})}else{v=window[u]}}if(typeof v==="object"){return v}if(typeof v==="function"){return v.apply(s,t)}if(!v&&typeof u==="string"&&m.apply(this,[u].concat(t))){return m.apply(this,[u].concat(t))}return r};var f=function(s,r,w){var x=Object.getOwnPropertyNames(s),u=Object.getOwnPropertyNames(r),v="";if(w){if(x.length!==u.length){return false}}for(var t=0;t-1){if(s[v]!==r[v]){return false}}}return true};var p=function(r){if(typeof r==="string"){return r.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'").replace(/`/g,"`")}return r};var d=function(s){var r=0;s.children().each(function(){if(r0||!!navigator.userAgent.match(/Trident.*rv\:11\./))};var h=function(){if(!Object.keys){Object.keys=(function(){var t=Object.prototype.hasOwnProperty,u=!({toString:null}).propertyIsEnumerable("toString"),s=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],r=s.length;return function(x){if(typeof x!=="object"&&(typeof x!=="function"||x===null)){throw new TypeError("Object.keys called on non-object")}var v=[],y,w;for(y in x){if(t.call(x,y)){v.push(y)}}if(u){for(w=0;w','
',this.options.paginationVAlign==="top"||this.options.paginationVAlign==="both"?'
':"",'
','
','
','
',this.options.formatLoadingMessage(),"
","
",'',this.options.paginationVAlign==="bottom"||this.options.paginationVAlign==="both"?'
':"","
","
"].join(""));this.$container.insertAfter(this.$el);this.$tableContainer=this.$container.find(".fixed-table-container");this.$tableHeader=this.$container.find(".fixed-table-header");this.$tableBody=this.$container.find(".fixed-table-body");this.$tableLoading=this.$container.find(".fixed-table-loading");this.$tableFooter=this.$container.find(".fixed-table-footer");this.$toolbar=this.$container.find(".fixed-table-toolbar");this.$pagination=this.$container.find(".fixed-table-pagination");this.$tableBody.append(this.$el);this.$container.after('
');this.$el.addClass(this.options.classes);if(this.options.striped){this.$el.addClass("table-striped")}if(j.inArray("table-no-bordered",this.options.classes.split(" "))!==-1){this.$tableContainer.addClass("table-no-bordered")}};e.prototype.initTable=function(){var t=this,s=[],u=[];this.$header=this.$el.find(">thead");if(!this.$header.length){this.$header=j("").appendTo(this.$el)}this.$header.find("tr").each(function(){var v=[];j(this).find("th").each(function(){if(typeof j(this).data("field")!=="undefined"){j(this).data("field",j(this).data("field")+"")}v.push(j.extend({},{title:j(this).html(),"class":j(this).attr("class"),titleTooltip:j(this).attr("title"),rowspan:j(this).attr("rowspan")?+j(this).attr("rowspan"):undefined,colspan:j(this).attr("colspan")?+j(this).attr("colspan"):undefined},j(this).data()))});s.push(v)});if(!j.isArray(this.options.columns[0])){this.options.columns=[this.options.columns]}this.options.columns=j.extend(true,[],s,this.options.columns);this.columns=[];l(this.options.columns);j.each(this.options.columns,function(w,v){j.each(v,function(x,y){y=j.extend({},e.COLUMN_DEFAULTS,y);if(typeof y.fieldIndex!=="undefined"){t.columns[y.fieldIndex]=y}t.options.columns[w][x]=y})});if(this.options.data.length){return}var r=[];this.$el.find(">tbody>tr").each(function(w){var v={};v._id=j(this).attr("id");v._class=j(this).attr("class");v._data=g(j(this).data());j(this).find(">td").each(function(z){var E=j(this),B=+E.attr("colspan")||1,C=+E.attr("rowspan")||1,A,y;for(;r[w]&&r[w][z];z++){}for(A=z;A");if(v===0&&!t.options.cardView&&t.options.detailView){s.push(m('
',t.options.columns.length))}j.each(u,function(B,A){var F="",C="",E="",w="",D=m(' class="%s"',A["class"]),z=t.options.sortOrder||A.order,y="px",x=A.width;if(A.width!==undefined&&(!t.options.cardView)){if(typeof A.width==="string"){if(A.width.indexOf("%")!==-1){y="%"}}}if(A.width&&typeof A.width==="string"){x=A.width.replace("%","").replace("px","")}C=m("text-align: %s; ",A.halign?A.halign:A.align);E=m("text-align: %s; ",A.align);w=m("vertical-align: %s; ",A.valign);w+=m("width: %s; ",(A.checkbox||A.radio)&&!x?"36px":(x?x+y:undefined));if(typeof A.fieldIndex!=="undefined"){t.header.fields[A.fieldIndex]=A.field;t.header.styles[A.fieldIndex]=E+w;t.header.classes[A.fieldIndex]=D;t.header.formatters[A.fieldIndex]=A.formatter;t.header.events[A.fieldIndex]=A.events;t.header.sorters[A.fieldIndex]=A.sorter;t.header.sortNames[A.fieldIndex]=A.sortName;t.header.cellStyles[A.fieldIndex]=A.cellStyle;t.header.searchables[A.fieldIndex]=A.searchable;if(!A.visible){return}if(t.options.cardView&&(!A.cardVisible)){return}r[A.field]=A}s.push("");s.push(m('
',t.options.sortable&&A.sortable?"sortable both":""));F=A.title;if(A.checkbox){if(!t.options.singleSelect&&t.options.checkboxHeader){F=''}t.header.stateField=A.field}if(A.radio){F="";t.header.stateField=A.field;t.options.singleSelect=true}s.push(F);s.push("
");s.push('
');s.push("");s.push("")});s.push("")});this.$header.html(s.join(""));this.$header.find("th[data-field]").each(function(u){j(this).data(r[j(this).data("field")])});this.$container.off("click",".th-inner").on("click",".th-inner",function(u){var v=j(this);if(t.options.detailView){if(v.closest(".bootstrap-table")[0]!==t.$container[0]){return false}}if(t.options.sortable&&v.parent().data().sortable){t.onSort(u)}});this.$header.children().children().off("keypress").on("keypress",function(v){if(t.options.sortable&&j(this).data().sortable){var u=v.keyCode||v.which;if(u==13){t.onSort(v)}}});j(window).off("resize.bootstrap-table");if(!this.options.showHeader||this.options.cardView){this.$header.hide();this.$tableHeader.hide();this.$tableLoading.css("top",0)}else{this.$header.show();this.$tableHeader.show();this.$tableLoading.css("top",this.$header.outerHeight()+1);this.getCaret();j(window).on("resize.bootstrap-table",j.proxy(this.resetWidth,this))}this.$selectAll=this.$header.find('[name="btSelectAll"]');this.$selectAll.off("click").on("click",function(){var u=j(this).prop("checked");t[u?"checkAll":"uncheckAll"]();t.updateSelected()})};e.prototype.initFooter=function(){if(!this.options.showFooter||this.options.cardView){this.$tableFooter.hide()}else{this.$tableFooter.show()}};e.prototype.initData=function(s,r){if(r==="append"){this.data=this.data.concat(s)}else{if(r==="prepend"){this.data=[].concat(s).concat(this.data)}else{this.data=s||this.options.data}}if(r==="append"){this.options.data=this.options.data.concat(s)}else{if(r==="prepend"){this.options.data=[].concat(s).concat(this.options.data)}else{this.options.data=this.data}}if(this.options.sidePagination==="server"){return}this.initSort()};e.prototype.initSort=function(){var u=this,t=this.options.sortName,r=this.options.sortOrder==="desc"?-1:1,s=j.inArray(this.options.sortName,this.header.fields);if(this.options.customSort!==j.noop){this.options.customSort.apply(this,[this.options.sortName,this.options.sortOrder]);return}if(s!==-1){if(this.options.sortStable){j.each(this.data,function(v,w){if(!w.hasOwnProperty("_position")){w._position=v}})}this.data.sort(function(w,v){if(u.header.sortNames[s]){t=u.header.sortNames[s]}var y=o(w,t,u.options.escape),z=o(v,t,u.options.escape),x=q(u.header,u.header.sorters[s],[y,z]);if(x!==undefined){return r*x}if(y===undefined||y===null){y=""}if(z===undefined||z===null){z=""}if(u.options.sortStable&&y===z){y=w._position;z=v._position}if(j.isNumeric(y)&&j.isNumeric(z)){y=parseFloat(y);z=parseFloat(z);if(y',this.options.toolbarAlign)).appendTo(this.$toolbar).append(j(this.options.toolbar))}t=[m('
',this.options.buttonsAlign,this.options.buttonsAlign)];if(typeof this.options.icons==="string"){this.options.icons=q(null,this.options.icons)}if(this.options.showSearch){t.push(m('")}if(this.options.showPaginationSwitch){t.push(m('")}if(this.options.showRefresh){t.push(m('")}if(this.options.showToggle){t.push(m('")}if(this.options.showColumns){t.push(m('
',this.options.formatColumns()),'",'","
")}t.push("
");if(this.showToolbar||t.length>2){this.$toolbar.append(t.join(""))}if(this.options.showPaginationSwitch){this.$toolbar.find('button[name="paginationSwitch"]').off("click").on("click",j.proxy(this.togglePagination,this))}if(this.options.showRefresh){this.$toolbar.find('button[name="refresh"]').off("click").on("click",j.proxy(this.refresh,this))}if(this.options.showToggle){this.$toolbar.find('button[name="toggle"]').off("click").on("click",function(){u.toggleView()})}if(this.options.showSearch){this.$toolbar.find('button[name="showSearch"]').off("click").on("click",function(){j(this).parents(".select-table").siblings().slideToggle()})}if(this.options.showColumns){s=this.$toolbar.find(".keep-open");if(r<=this.options.minimumCountColumns){s.find("input").prop("disabled",true)}s.find("li").off("click").on("click",function(x){x.stopImmediatePropagation()});s.find("input").off("click").on("click",function(){var x=j(this);u.toggleColumn(j(this).val(),x.prop("checked"),false);u.trigger("column-switch",j(this).data("field"),x.prop("checked"))})}if(this.options.search){t=[];t.push('");this.$toolbar.append(t.join(""));v=this.$toolbar.find(".search input");v.off("keyup drop").on("keyup drop",function(x){if(u.options.searchOnEnterKey&&x.keyCode!==13){return}if(j.inArray(x.keyCode,[37,38,39,40])>-1){return}clearTimeout(w);w=setTimeout(function(){u.onSearch(x)},u.options.searchTimeOut)});if(b()){v.off("mouseup").on("mouseup",function(x){clearTimeout(w);w=setTimeout(function(){u.onSearch(x)},u.options.searchTimeOut)})}}};e.prototype.onSearch=function(r){var s=j.trim(j(r.currentTarget).val());if(this.options.trimOnSearch&&j(r.currentTarget).val()!==s){j(r.currentTarget).val(s)}if(s===this.searchText){return}this.searchText=s;this.options.searchText=s;this.options.pageNumber=1;this.initSearch();this.updatePagination();this.trigger("search",s)};e.prototype.initSearch=function(){var t=this;if(this.options.sidePagination!=="server"){if(this.options.customSearch!==j.noop){this.options.customSearch.apply(this,[this.searchText]);return}var r=this.searchText&&(this.options.escape?p(this.searchText):this.searchText).toLowerCase();var u=j.isEmptyObject(this.filterColumns)?null:this.filterColumns;this.data=u?j.grep(this.options.data,function(w,v){for(var s in u){if(j.isArray(u[s])&&j.inArray(w[s],u[s])===-1||w[s]!==u[s]){return false}}return true}):this.options.data;this.data=r?j.grep(this.data,function(A,x){for(var v=0;v-1){r=true}}}this.totalPages=~~((this.options.totalRows-1)/this.options.pageSize)+1;this.options.totalPages=this.totalPages}if(this.totalPages>0&&this.options.pageNumber>this.totalPages){this.options.pageNumber=this.totalPages}this.pageFrom=(this.options.pageNumber-1)*this.options.pageSize+1;this.pageTo=this.options.pageNumber*this.options.pageSize;if(this.pageTo>this.options.totalRows){this.pageTo=this.options.totalRows}x.push('
','',this.options.onlyInfoPagination?this.options.formatDetailPagination(this.options.totalRows):this.options.formatShowingRows(this.pageFrom,this.pageTo,this.options.totalRows),"");if(!this.options.onlyInfoPagination){x.push('');var F=[m('',this.options.paginationVAlign==="top"||this.options.paginationVAlign==="both"?"dropdown":"dropup"),'",'");x.push(this.options.formatRecordsPerPage(F.join("")));x.push("");x.push("
",'")}this.$pagination.html(x.join(""));if(!this.options.onlyInfoPagination){w=this.$pagination.find(".page-list a");G=this.$pagination.find(".page-first");I=this.$pagination.find(".page-pre");E=this.$pagination.find(".page-next");y=this.$pagination.find(".page-last");u=this.$pagination.find(".page-number");if(this.options.smartDisplay){if(this.totalPages<=1){this.$pagination.find("div.pagination").hide()}if(t.length<2||this.options.totalRows<=t[0]){this.$pagination.find("span.page-list").hide()}this.$pagination[this.getData().length?"show":"hide"]()}if(r){this.options.pageSize=this.options.formatAllRows()}w.off("click").on("click",j.proxy(this.onPageListChange,this));G.off("click").on("click",j.proxy(this.onPageFirst,this));I.off("click").on("click",j.proxy(this.onPagePre,this));E.off("click").on("click",j.proxy(this.onPageNext,this));y.off("click").on("click",j.proxy(this.onPageLast,this));u.off("click").on("click",j.proxy(this.onPageNumber,this))}if(this.options.showPageGo){var v=this,C=this.$pagination.find("ul.pagination"),B=C.find("li.pageGo");if(!B.length){B=j(['
  • ',m('',this.options.pageNumber),'","
  • "].join("")).appendTo(C);B.find("button").click(function(){var K=parseInt(B.find("input").val())||1;if(K<1||K>v.options.totalPages){K=1}v.selectPage(K)})}}};e.prototype.updatePagination=function(r){if(r&&j(r.currentTarget).hasClass("disabled")){return}if(!this.options.maintainSelected){this.resetRows()}this.initPagination();if(this.options.sidePagination==="server"){this.initServer()}else{this.initBody()}this.trigger("page-change",this.options.pageNumber,this.options.pageSize)};e.prototype.onPageListChange=function(r){var s=j(r.currentTarget);s.parent().addClass("active").siblings().removeClass("active");this.options.pageSize=s.text().toUpperCase()===this.options.formatAllRows().toUpperCase()?this.options.formatAllRows():+s.text();this.$toolbar.find(".page-size").text(this.options.pageSize);this.updatePagination(r)};e.prototype.onPageFirst=function(r){this.options.pageNumber=1;this.updatePagination(r)};e.prototype.onPagePre=function(r){if((this.options.pageNumber-1)===0){this.options.pageNumber=this.options.totalPages}else{this.options.pageNumber--}this.updatePagination(r)};e.prototype.onPageNext=function(r){if((this.options.pageNumber+1)>this.options.totalPages){this.options.pageNumber=1}else{this.options.pageNumber++}this.updatePagination(r)};e.prototype.onPageLast=function(r){this.options.pageNumber=this.totalPages;this.updatePagination(r)};e.prototype.onPageNumber=function(r){if(this.options.pageNumber===+j(r.currentTarget).text()){return}this.options.pageNumber=+j(r.currentTarget).text();this.updatePagination(r)};e.prototype.initBody=function(x){var z=this,y=[],v=this.getData();this.trigger("pre-body",v);this.$body=this.$el.find(">tbody");if(!this.$body.length){this.$body=j("").appendTo(this.$el)}if(!this.options.pagination||this.options.sidePagination==="server"){this.pageFrom=1;this.pageTo=v.length}for(var w=this.pageFrom-1;w");if(this.options.cardView){y.push(m('
    ',this.header.fields.length))}if(!this.options.cardView&&this.options.detailView){y.push("",'',m('',this.options.iconsPrefix,this.options.icons.detailOpen),"","")}j.each(this.header.fields,function(I,L){var P="",M=o(C,L,z.options.escape),K="",E={},Q="",J=z.header.classes[I],G="",O="",R="",H="",F=z.columns[I];if(z.fromHtml&&typeof M==="undefined"){return}if(!F.visible){return}if(z.options.cardView&&!F.cardVisible){return}r=m('style="%s"',s.concat(z.header.styles[I]).join("; "));if(C["_"+L+"_id"]){Q=m(' id="%s"',C["_"+L+"_id"])}if(C["_"+L+"_class"]){J=m(' class="%s"',C["_"+L+"_class"])}if(C["_"+L+"_rowspan"]){O=m(' rowspan="%s"',C["_"+L+"_rowspan"])}if(C["_"+L+"_colspan"]){R=m(' colspan="%s"',C["_"+L+"_colspan"])}if(C["_"+L+"_title"]){H=m(' title="%s"',C["_"+L+"_title"])}E=q(z.header,z.header.cellStyles[I],[M,C,w,L],E);if(E.classes){J=m(' class="%s"',E.classes)}if(E.css){var D=[];for(var N in E.css){D.push(N+": "+E.css[N])}r=m('style="%s"',D.concat(z.header.styles[I]).join("; "))}M=q(F,z.header.formatters[I],[M,C,w],M);if(C["_"+L+"_data"]&&!j.isEmptyObject(C["_"+L+"_data"])){j.each(C["_"+L+"_data"],function(T,S){if(T==="index"){return}G+=m(' data-%s="%s"',T,S)})}if(F.checkbox||F.radio){K=F.checkbox?"checkbox":K;K=F.radio?"radio":K;P=[m(z.options.cardView?'
    ':'',F["class"]||""),"",z.header.formatters[I]&&typeof M==="string"?M:"",z.options.cardView?"
    ":""].join("");C[z.header.stateField]=M===true||(M&&M.checked)}else{M=typeof M==="undefined"||M===null?z.options.undefinedText:M;P=z.options.cardView?['
    ',z.options.showHeader?m('%s',r,c(z.columns,"field","title",L)):"",m('%s',M),"
    "].join(""):[m("",Q,J,r,G,O,R,H),M,""].join("");if(z.options.cardView&&z.options.smartDisplay&&M===""){P='
    '}}y.push(P)});if(this.options.cardView){y.push("
    ")}y.push("")}if(!y.length){y.push('',m('%s',this.$header.find("th").length,this.options.formatNoMatches()),"")}this.$body.html(y.join(""));if(!x){this.scrollTo(0)}this.$body.find("> tr[data-index] > td").off("click dblclick").on("click dblclick",function(J){var D=j(this),F=D.parent(),M=z.data[F.data("index")],H=D[0].cellIndex,G=z.getVisibleFields(),K=G[z.options.detailView&&!z.options.cardView?H-1:H],E=z.columns[i(z.columns,K)],L=o(M,K,z.options.escape);if(D.find(".detail-icon").length){return}z.trigger(J.type==="click"?"click-cell":"dbl-click-cell",K,L,M,D);z.trigger(J.type==="click"?"click-row":"dbl-click-row",M,F,K);if(J.type==="click"&&z.options.clickToSelect&&E.clickToSelect){var I=F.find(m('[name="%s"]',z.options.selectItemName));if(I.length){I[0].click()}}});this.$body.find("> tr[data-index] > td > .detail-icon").off("click").on("click",function(){var H=j(this),G=H.parent().parent(),E=G.data("index"),I=v[E];if(G.next().is("tr.detail-view")){H.find("i").attr("class",m("%s %s",z.options.iconsPrefix,z.options.icons.detailOpen));G.next().remove();z.trigger("collapse-row",E,I)}else{H.find("i").attr("class",m("%s %s",z.options.iconsPrefix,z.options.icons.detailClose));G.after(m('',G.find("td").length));var D=G.next().find("td");var F=q(z.options,z.options.detailFormatter,[E,I,D],"");if(D.length===1){D.append(F)}z.trigger("expand-row",E,I,D)}z.resetView()});this.$selectItem=this.$body.find(m('[name="%s"]',this.options.selectItemName));this.$selectItem.off("click").on("click",function(E){E.stopImmediatePropagation();var F=j(this),D=F.prop("checked"),G=z.data[F.data("index")];if(z.options.maintainSelected&&j(this).is(":radio")){j.each(z.options.data,function(H,I){I[z.header.stateField]=false})}G[z.header.stateField]=D;if(z.options.singleSelect){z.$selectItem.not(this).each(function(){z.data[j(this).data("index")][z.header.stateField]=false});z.$selectItem.filter(":checked").not(this).prop("checked",false)}z.updateSelected();z.trigger(D?"check":"uncheck",G,F)});j.each(this.header.events,function(G,F){if(!F){return}if(typeof F==="string"){F=q(null,F)}var H=z.header.fields[G],D=j.inArray(H,z.getVisibleFields());if(z.options.detailView&&!z.options.cardView){D+=1}for(var E in F){z.$body.find(">tr:not(.no-records-found)").each(function(){var M=j(this),N=M.find(z.options.cardView?".card-view":"td").eq(D),J=E.indexOf(" "),I=E.substring(0,J),K=E.substring(J+1),L=F[E];N.find(K).off(I).on(I,function(Q){var O=M.data("index"),R=z.data[O],P=R[H];L.apply(this,[Q,P,R,O])})})}});this.updateSelected();this.resetView();this.trigger("post-body",v)};e.prototype.initServer=function(r,w,s){var u=this,v={},x={searchText:this.searchText,sortName:this.options.sortName,sortOrder:this.options.sortOrder},t;if(this.options.pagination){x.pageSize=this.options.pageSize===this.options.formatAllRows()?this.options.totalRows:this.options.pageSize;x.pageNumber=this.options.pageNumber}if(!this.options.firstLoad&&!firstLoadTable.includes(this.options.id)){firstLoadTable.push(this.options.id);return}if(!(s||this.options.url)&&!this.options.ajax){return}if(this.options.queryParamsType==="limit"){x={search:x.searchText,sort:x.sortName,order:x.sortOrder};if(this.options.pagination){x.offset=this.options.pageSize===this.options.formatAllRows()?0:this.options.pageSize*(this.options.pageNumber-1);x.limit=this.options.pageSize===this.options.formatAllRows()?this.options.totalRows:this.options.pageSize}}if(!(j.isEmptyObject(this.filterColumnsPartial))){x.filter=JSON.stringify(this.filterColumnsPartial,null)}v=q(this.options,this.options.queryParams,[x],v);j.extend(v,w||{});if(v===false){return}if(!r){this.$tableLoading.show()}t=j.extend({},q(null,this.options.ajaxOptions),{type:this.options.method,url:s||this.options.url,data:this.options.contentType==="application/json"&&this.options.method==="post"?JSON.stringify(v):v,cache:this.options.cache,contentType:this.options.contentType,dataType:this.options.dataType,success:function(y){y=q(u.options,u.options.responseHandler,[y],y);u.load(y);u.trigger("load-success",y);if(!r){u.$tableLoading.hide()}},error:function(y){u.trigger("load-error",y.status,y);if(!r){u.$tableLoading.hide()}}});if(this.options.ajax){q(this,this.options.ajax,[t],null)}else{if(this._xhr&&this._xhr.readyState!==4){this._xhr.abort()}this._xhr=j.ajax(t)}};e.prototype.initSearchText=function(){if(this.options.search){if(this.options.searchText!==""){var r=this.$toolbar.find(".search input");r.val(this.options.searchText);this.onSearch({currentTarget:r})}}};e.prototype.getCaret=function(){var r=this;j.each(this.$header.find("th"),function(s,t){j(t).find(".sortable").removeClass("desc asc").addClass((j(t).data("field")===r.options.sortName||j(t).data("sortName")===r.options.sortName)?r.options.sortOrder:"both")})};e.prototype.updateSelected=function(){var r=this.$selectItem.filter(":enabled").length&&this.$selectItem.filter(":enabled").length===this.$selectItem.filter(":enabled").filter(":checked").length;var s=j(".left-fixed-table-columns input[name=btSelectItem]");if(s.length>0){r=this.$selectItem.filter(":enabled").length&&this.$selectItem.filter(":enabled").length===s.filter(":enabled").filter(":checked").length}this.$selectAll.add(this.$selectAll_).prop("checked",r);this.$selectItem.each(function(){j(this).closest("tr")[j(this).prop("checked")?"addClass":"removeClass"]("selected")})};e.prototype.updateRows=function(){var r=this;this.$selectItem.each(function(){r.data[j(this).data("index")][r.header.stateField]=j(this).prop("checked")})};e.prototype.resetRows=function(){var r=this;j.each(this.data,function(s,t){r.$selectAll.prop("checked",false);r.$selectItem.prop("checked",false);if(r.header.stateField){t[r.header.stateField]=false}})};e.prototype.trigger=function(s){var r=Array.prototype.slice.call(arguments,1);s+=".bs.table";this.options[e.EVENTS[s]].apply(this.options,r);this.$el.trigger(j.Event(s),r);this.options.onAll(s,r);this.$el.trigger(j.Event("all.bs.table"),[s,r])};e.prototype.resetHeader=function(){clearTimeout(this.timeoutId_);this.timeoutId_=setTimeout(j.proxy(this.fitHeader,this),this.$el.is(":hidden")?100:0)};e.prototype.fitHeader=function(){var t=this,u,r,x,y;if(t.$el.is(":hidden")){t.timeoutId_=setTimeout(j.proxy(t.fitHeader,t),100);return}u=this.$tableBody.get(0);r=u.scrollWidth>u.clientWidth&&u.scrollHeight>u.clientHeight+this.$header.outerHeight()?a():0;this.$el.css("margin-top",-this.$header.outerHeight());x=j(":focus");if(x.length>0){var z=x.parents("th");if(z.length>0){var A=z.attr("data-field");if(A!==undefined){var s=this.$header.find("[data-field='"+A+"']");if(s.length>0){s.find(":input").addClass("focus-temp")}}}}this.$header_=this.$header.clone(true,true);this.$selectAll_=this.$header_.find('[name="btSelectAll"]');this.$tableHeader.css({"margin-right":r}).find("table").css("width",this.$el.outerWidth()).html("").attr("class",this.$el.attr("class")).append(this.$header_);y=j(".focus-temp:visible:eq(0)");if(y.length>0){y.focus();this.$header.find(".focus-temp").removeClass("focus-temp")}this.$header.find("th[data-field]").each(function(B){t.$header_.find(m('th[data-field="%s"]',j(this).data("field"))).data(j(this).data())});var w=this.getVisibleFields(),v=this.$header_.find("th");this.$body.find(">tr:first-child:not(.no-records-found) > *").each(function(C){var E=j(this),B=C;if(t.options.detailView&&!t.options.cardView){if(C===0){t.$header_.find("th.detail").find(".fht-cell").width(E.innerWidth())}B=C-1}var D=t.$header_.find(m('th[data-field="%s"]',w[B]));if(D.length>1){D=j(v[E[0].cellIndex])}D.find(".fht-cell").width(E.innerWidth())});this.$tableBody.off("scroll").on("scroll",function(){t.$tableHeader.scrollLeft(j(this).scrollLeft());if(t.options.showFooter&&!t.options.cardView){t.$tableFooter.scrollLeft(j(this).scrollLeft())}});t.trigger("post-header")};e.prototype.resetFooter=function(){var s=this,t=s.getData(),r=[];if(!this.options.showFooter||this.options.cardView){return}if(!this.options.cardView&&this.options.detailView){r.push('
     
    ')}j.each(this.columns,function(x,z){var w,B="",v="",A=[],y={},u=m(' class="%s"',z["class"]);if(!z.visible){return}if(s.options.cardView&&(!z.cardVisible)){return}B=m("text-align: %s; ",z.falign?z.falign:z.align);v=m("vertical-align: %s; ",z.valign);y=q(null,s.options.footerStyle);if(y&&y.css){for(w in y.css){A.push(w+": "+y.css[w])}}r.push("");r.push('
    ');r.push(q(z,z.footerFormatter,[t]," ")||" ");r.push("
    ");r.push('
    ');r.push("");r.push("")});this.$tableFooter.find("tr").html(r.join(""));this.$tableFooter.show();clearTimeout(this.timeoutFooter_);this.timeoutFooter_=setTimeout(j.proxy(this.fitFooter,this),this.$el.is(":hidden")?100:0)};e.prototype.fitFooter=function(){var u=this,r,t,s;clearTimeout(this.timeoutFooter_);if(this.$el.is(":hidden")){this.timeoutFooter_=setTimeout(j.proxy(this.fitFooter,this),100);return}t=this.$el.css("width");s=t>this.$tableBody.width()?a():0;this.$tableFooter.css({"margin-right":s}).find("table").css("width",t).attr("class",this.$el.attr("class"));r=this.$tableFooter.find("td");this.$body.find(">tr:first-child:not(.no-records-found) > *").each(function(v){var w=j(this);r.eq(v).find(".fht-cell").width(w.innerWidth()+1)})};e.prototype.toggleColumn=function(r,s,u){if(r===-1){return}this.columns[r].visible=s;this.initHeader();this.initSearch();this.initPagination();this.initBody();if(this.options.showColumns){var t=this.$toolbar.find(".keep-open input").prop("disabled",false);if(u){t.filter(m('[value="%s"]',r)).prop("checked",s)}if(t.filter(":checked").length<=this.options.minimumCountColumns){t.filter(":checked").prop("disabled",true)}}};e.prototype.toggleRow=function(r,t,s){if(r===-1){return}this.$body.find(typeof r!=="undefined"?m('tr[data-index="%s"]',r):m('tr[data-uniqueid="%s"]',t))[s?"show":"hide"]()};e.prototype.getVisibleFields=function(){var s=this,r=[];j.each(this.header.fields,function(t,v){var u=s.columns[i(s.columns,v)];if(!u.visible){return}r.push(v)});return r};e.prototype.resetView=function(u){var s=0;if(u&&u.height){this.options.height=u.height}this.$selectAll.prop("checked",this.$selectItem.length>0&&this.$selectItem.length===this.$selectItem.filter(":checked").length);if(this.options.height){var t=d(this.$toolbar),v=d(this.$pagination),r=this.options.height-t-v;this.$tableContainer.css("height",r+"px")}if(this.options.cardView){this.$el.css("margin-top","0");this.$tableContainer.css("padding-bottom","0");this.$tableFooter.hide();return}if(this.options.showHeader&&this.options.height){this.$tableHeader.show();this.resetHeader();s+=this.$header.outerHeight()}else{this.$tableHeader.hide();this.trigger("post-header")}if(this.options.showFooter){this.resetFooter();if(this.options.height){s+=this.$tableFooter.outerHeight()+1}}this.getCaret();this.$tableContainer.css("padding-bottom",s+"px");this.trigger("reset-view")};e.prototype.getData=function(r){return(this.searchText||!j.isEmptyObject(this.filterColumns)||!j.isEmptyObject(this.filterColumnsPartial))?(r?this.data.slice(this.pageFrom-1,this.pageTo):this.data):(r?this.options.data.slice(this.pageFrom-1,this.pageTo):this.options.data)};e.prototype.load=function(s){var r=false;if(this.options.sidePagination==="server"){this.options.totalRows=s.total;r=s.fixedScroll;s=s[this.options.dataField]}else{if(!j.isArray(s)){r=s.fixedScroll;s=s.data}}this.initData(s);this.initSearch();this.initPagination();this.initBody(r)};e.prototype.append=function(r){this.initData(r,"append");this.initSearch();this.initPagination();this.initSort();this.initBody(true)};e.prototype.prepend=function(r){this.initData(r,"prepend");this.initSearch();this.initPagination();this.initSort();this.initBody(true)};e.prototype.remove=function(u){var r=this.options.data.length,s,t;if(!u.hasOwnProperty("field")||!u.hasOwnProperty("values")){return}for(s=r-1;s>=0;s--){t=this.options.data[s];if(!t.hasOwnProperty(u.field)){continue}if(j.inArray(t[u.field],u.values)!==-1){this.options.data.splice(s,1)}}if(r===this.options.data.length){return}this.initSearch();this.initPagination();this.initSort();this.initBody(true)};e.prototype.removeAll=function(){if(this.options.data.length>0){this.options.data.splice(0,this.options.data.length);this.initSearch();this.initPagination();this.initBody(true)}};e.prototype.getRowByUniqueId=function(x){var w=this.options.uniqueId,r=this.options.data.length,s=null,t,v,u;for(t=r-1;t>=0;t--){v=this.options.data[t];if(v.hasOwnProperty(w)){u=v[w]}else{if(v._data.hasOwnProperty(w)){u=v._data[w]}else{continue}}if(typeof u==="string"){x=x.toString()}else{if(typeof u==="number"){if((Number(u)===u)&&(u%1===0)){x=parseInt(x)}else{if((u===Number(u))&&(u!==0)){x=parseFloat(x)}}}}if(u===x){s=v;break}}return s};e.prototype.removeByUniqueId=function(t){var r=this.options.data.length,s=this.getRowByUniqueId(t);if(s){this.options.data.splice(this.options.data.indexOf(s),1)}if(r===this.options.data.length){return}this.initSearch();this.initPagination();this.initBody(true)};e.prototype.updateByUniqueId=function(t){var r=this;var s=j.isArray(t)?t:[t];j.each(s,function(u,w){var v;if(!w.hasOwnProperty("id")||!w.hasOwnProperty("row")){return}v=j.inArray(r.getRowByUniqueId(w.id),r.options.data);if(v===-1){return}j.extend(r.options.data[v],w.row)});this.initSearch();this.initSort();this.initBody(true)};e.prototype.insertRow=function(r){if(!r.hasOwnProperty("index")||!r.hasOwnProperty("row")){return}this.data.splice(r.index,0,r.row);this.initSearch();this.initPagination();this.initSort();this.initBody(true)};e.prototype.updateRow=function(t){var r=this;var s=j.isArray(t)?t:[t];j.each(s,function(u,v){if(!v.hasOwnProperty("index")||!v.hasOwnProperty("row")){return}j.extend(r.options.data[v.index],v.row)});this.initSearch();this.initSort();this.initBody(true)};e.prototype.showRow=function(r){if(!r.hasOwnProperty("index")&&!r.hasOwnProperty("uniqueId")){return}this.toggleRow(r.index,r.uniqueId,true)};e.prototype.hideRow=function(r){if(!r.hasOwnProperty("index")&&!r.hasOwnProperty("uniqueId")){return}this.toggleRow(r.index,r.uniqueId,false)};e.prototype.getRowsHidden=function(r){var t=j(this.$body[0]).children().filter(":hidden"),s=0;if(r){for(;str"),r;if(this.options.detailView&&!this.options.cardView){t+=1}r=x.eq(y).find(">td").eq(t);if(y<0||t<0||y>=this.data.length){return}for(w=y;wtd").eq(v).hide()}}r.attr("rowspan",u).attr("colspan",s).show()};e.prototype.updateCell=function(r){if(!r.hasOwnProperty("index")||!r.hasOwnProperty("field")||!r.hasOwnProperty("value")){return}this.data[r.index][r.field]=r.value;if(r.reinit===false){return}this.initSort();this.initBody(true)};e.prototype.getOptions=function(){return this.options};e.prototype.getSelections=function(){var r=this;return j.grep(this.options.data,function(s){return s[r.header.stateField]})};e.prototype.getAllSelections=function(){var r=this;return j.grep(this.options.data,function(s){return s[r.header.stateField]})};e.prototype.checkAll=function(){this.checkAll_(true)};e.prototype.uncheckAll=function(){this.checkAll_(false)};e.prototype.checkInvert=function(){var s=this;var t=s.$selectItem.filter(":enabled");var r=t.filter(":checked");t.each(function(){j(this).prop("checked",!j(this).prop("checked"))});s.updateRows();s.updateSelected();s.trigger("uncheck-some",r);r=s.getSelections();s.trigger("check-some",r)};e.prototype.checkAll_=function(r){var s;if(!r){s=this.getSelections()}this.$selectAll.add(this.$selectAll_).prop("checked",r);this.$selectItem.filter(":enabled").prop("checked",r);this.updateRows();if(r){s=this.getSelections()}this.trigger(r?"check-all":"uncheck-all",s)};e.prototype.check=function(r){this.check_(true,r) -};e.prototype.uncheck=function(r){this.check_(false,r)};e.prototype.check_=function(t,r){var s=this.$selectItem.filter(m('[data-index="%s"]',r)).prop("checked",t);this.data[r][this.header.stateField]=t;this.updateSelected();this.trigger(t?"check":"uncheck",this.data[r],s)};e.prototype.checkBy=function(r){this.checkBy_(true,r)};e.prototype.uncheckBy=function(r){this.checkBy_(false,r)};e.prototype.checkBy_=function(s,u){if(!u.hasOwnProperty("field")||!u.hasOwnProperty("values")){return}var r=this,t=[];j.each(this.options.data,function(v,x){if(!x.hasOwnProperty(u.field)){return false}if(j.inArray(x[u.field],u.values)!==-1){var w=r.$selectItem.filter(":enabled").filter(m('[data-index="%s"]',v)).prop("checked",s);x[r.header.stateField]=s;t.push(x);r.trigger(s?"check":"uncheck",x,w)}});this.updateSelected();this.trigger(s?"check-some":"uncheck-some",t)};e.prototype.destroy=function(){this.$el.insertBefore(this.$container);j(this.options.toolbar).insertBefore(this.$el);this.$container.next().remove();this.$container.remove();this.$el.html(this.$el_.html()).css("margin-top","0").attr("class",this.$el_.attr("class")||"")};e.prototype.showLoading=function(){this.$tableLoading.show()};e.prototype.hideLoading=function(){this.$tableLoading.hide()};e.prototype.togglePagination=function(){this.options.pagination=!this.options.pagination;var r=this.$toolbar.find('button[name="paginationSwitch"] i');if(this.options.pagination){r.attr("class",this.options.iconsPrefix+" "+this.options.icons.paginationSwitchDown)}else{r.attr("class",this.options.iconsPrefix+" "+this.options.icons.paginationSwitchUp)}this.updatePagination()};e.prototype.refresh=function(r){if(r&&r.url){this.options.pageNumber=1}table.rememberSelecteds={};table.rememberSelectedIds={};this.initServer(r&&r.silent,r&&r.query,r&&r.url);this.trigger("refresh",r)};e.prototype.resetWidth=function(){if(this.options.showHeader&&this.options.height){this.fitHeader()}if(this.options.showFooter){this.fitFooter()}};e.prototype.showColumn=function(r){this.toggleColumn(i(this.columns,r),true,true)};e.prototype.hideColumn=function(r){this.toggleColumn(i(this.columns,r),false,true)};e.prototype.getHiddenColumns=function(){return j.grep(this.columns,function(r){return !r.visible})};e.prototype.getVisibleColumns=function(){return j.grep(this.columns,function(r){return r.visible})};e.prototype.toggleAllColumns=function(r){j.each(this.columns,function(t,u){this.columns[t].visible=r});this.initHeader();this.initSearch();this.initPagination();this.initBody();if(this.options.showColumns){var s=this.$toolbar.find(".keep-open input").prop("disabled",false);if(s.filter(":checked").length<=this.options.minimumCountColumns){s.filter(":checked").prop("disabled",true)}}};e.prototype.showAllColumns=function(){this.toggleAllColumns(true)};e.prototype.hideAllColumns=function(){this.toggleAllColumns(false)};e.prototype.filterBy=function(r){this.filterColumns=j.isEmptyObject(r)?{}:r;this.options.pageNumber=1;this.initSearch();this.updatePagination()};e.prototype.scrollTo=function(r){if(typeof r==="string"){r=r==="bottom"?this.$tableBody[0].scrollHeight:0}if(typeof r==="number"){this.$tableBody.scrollTop(r)}if(typeof r==="undefined"){return this.$tableBody.scrollTop()}};e.prototype.getScrollPosition=function(){return this.scrollTo()};e.prototype.selectPage=function(r){if(r>0&&r<=this.options.totalPages){this.options.pageNumber=r;this.updatePagination()}};e.prototype.prevPage=function(){if(this.options.pageNumber>1){this.options.pageNumber--;this.updatePagination()}};e.prototype.nextPage=function(){if(this.options.pageNumber tr[data-index="%s"]',r));if(t.next().is("tr.detail-view")===(s?false:true)){t.find("> td > .detail-icon").click()}};e.prototype.expandRow=function(r){this.expandRow_(true,r)};e.prototype.collapseRow=function(r){this.expandRow_(false,r)};e.prototype.expandAllRows=function(r){if(r){var w=this.$body.find(m('> tr[data-index="%s"]',0)),x=this,u=null,v=false,s=-1;if(!w.next().is("tr.detail-view")){w.find("> td > .detail-icon").click();v=true}else{if(!w.next().next().is("tr.detail-view")){w.next().find(".detail-icon").click();v=true}}if(v){try{s=setInterval(function(){u=x.$body.find("tr.detail-view").last().find(".detail-icon");if(u.length>0){u.click()}else{clearInterval(s)}},1)}catch(z){clearInterval(s)}}}else{var y=this.$body.children();for(var t=0;t0?Ab:zb)(a)},Cb=Math.min,Db=function(a){return a>0?Cb(Bb(a),9007199254740991):0},Eb=Math.max,Fb=Math.min,Gb=function(a,b){var c=Bb(a);return 0>c?Eb(c+b,0):Fb(c,b)},Hb=function(a){return function(b,c,d){var e,f=F(b),g=Db(f.length),h=Gb(d,g);if(a&&c!=c){for(;g>h;)if(e=f[h++],e!=e)return!0}else for(;g>h;h++)if((a||h in f)&&f[h]===c)return a||h||0;return!a&&-1}},Ib={includes:Hb(!0),indexOf:Hb(!1)},Jb=Ib.indexOf,Kb=function(a,b){var c,d=F(a),e=0,f=[];for(c in d)!J(ib,c)&&J(d,c)&&f.push(c);for(;b.length>e;)J(d,c=b[e++])&&(~Jb(f,c)||f.push(c));return f},Lb=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],Mb=Lb.concat("length","prototype"),Nb=Object.getOwnPropertyNames||function(a){return Kb(a,Mb)},Ob={f:Nb},Pb=Object.getOwnPropertySymbols,Qb={f:Pb},Rb=yb("Reflect","ownKeys")||function(a){var b=Ob.f(R(a)),c=Qb.f;return c?b.concat(c(a)):b},Sb=function(a,b){var c,d,e=Rb(b),f=U.f,g=Q.f;for(c=0;ce;)U.f(a,f=c[e++],b[f]);return a},gc=yb("document","documentElement"),hc=">",ic="<",jc="prototype",kc="script",lc=hb("IE_PROTO"),mc=function(){},nc=function(a){return ic+kc+hc+a+ic+"/"+kc+hc},oc=function(a){a.write(nc("")),a.close();var b=a.parentWindow.Object;return a=null,b},pc=function(){var a,b=M("iframe"),c="java"+kc+":";return b.style.display="none",gc.appendChild(b),b.src=String(c),a=b.contentWindow.document,a.open(),a.write(nc("document.F=Object")),a.close(),a.F},rc=function(){try{qc=document.domain&&new ActiveXObject("htmlfile")}catch(a){}rc=qc?oc(qc):pc();for(var b=Lb.length;b--;)delete rc[jc][Lb[b]];return rc()},ib[lc]=!0,sc=Object.create||function(a,b){var c;return null!==a?(mc[jc]=R(a),c=new mc,mc[jc]=null,c[lc]=a):c=rc(),void 0===b?c:fc(c,b)},tc=Ob.f,uc={}.toString,vc="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],wc=function(a){try{return tc(a)}catch(b){return vc.slice()}},xc=function(a){return vc&&"[object Window]"==uc.call(a)?wc(a):tc(F(a))},yc={f:xc},zc=cb("wks"),Ac=r.Symbol,Bc=bc?Ac:fb,Cc=function(a){return J(zc,a)||(zc[a]=ac&&J(Ac,a)?Ac[a]:Bc("Symbol."+a)),zc[a]},Dc=Cc,Ec={f:Dc},Fc=U.f,Gc=function(a){var b=wb.Symbol||(wb.Symbol={});J(b,a)||Fc(b,a,{value:Ec.f(a)})},Hc=U.f,Ic=Cc("toStringTag"),Jc=function(a,b,c){a&&!J(a=c?a:a.prototype,Ic)&&Hc(a,Ic,{configurable:!0,value:b})},Kc=function(a){if("function"!=typeof a)throw TypeError(String(a)+" is not a function");return a},Lc=function(a,b,c){if(Kc(a),void 0===b)return a;switch(c){case 0:return function(){return a.call(b)};case 1:return function(c){return a.call(b,c)};case 2:return function(c,d){return a.call(b,c,d)};case 3:return function(c,d,e){return a.call(b,c,d,e)}}return function(){return a.apply(b,arguments)}},Mc=Cc("species"),Nc=function(a,b){var c;return cc(a)&&(c=a.constructor,"function"!=typeof c||c!==Array&&!cc(c.prototype)?G(c)&&(c=c[Mc],null===c&&(c=void 0)):c=void 0),new(void 0===c?Array:c)(0===b?0:b)},Oc=[].push,Pc=function(a){var b=1==a,c=2==a,d=3==a,e=4==a,f=6==a,g=5==a||f;return function(h,i,j,k){for(var l,m,n=dc(h),o=D(n),p=Lc(i,j,3),q=Db(o.length),r=0,s=k||Nc,t=b?s(h,q):c?s(h,0):void 0;q>r;r++)if((g||r in o)&&(l=o[r],m=p(l,r,n),a))if(b)t[r]=m;else if(m)switch(a){case 3:return!0;case 5:return l;case 6:return r;case 2:Oc.call(t,l)}else if(e)return!1;return f?-1:d||e?e:t}},Qc={forEach:Pc(0),map:Pc(1),filter:Pc(2),some:Pc(3),every:Pc(4),find:Pc(5),findIndex:Pc(6)},Rc=Qc.forEach,Sc=hb("hidden"),Tc="Symbol",Uc="prototype",Vc=Cc("toPrimitive"),Wc=ub.set,Xc=ub.getterFor(Tc),Yc=Object[Uc],Zc=r.Symbol,$c=yb("JSON","stringify"),_c=Q.f,ad=U.f,bd=yc.f,cd=y.f,dd=cb("symbols"),ed=cb("op-symbols"),fd=cb("string-to-symbol-registry"),gd=cb("symbol-to-string-registry"),hd=cb("wks"),id=r.QObject,jd=!id||!id[Uc]||!id[Uc].findChild,kd=t&&s(function(){return 7!=sc(ad({},"a",{get:function(){return ad(this,"a",{value:7}).a}})).a})?function(a,b,c){var d=_c(Yc,b);d&&delete Yc[b],ad(a,b,c),d&&a!==Yc&&ad(Yc,b,d)}:ad,ld=function(a,b){var c=dd[a]=sc(Zc[Uc]);return Wc(c,{type:Tc,tag:a,description:b}),t||(c.description=b),c},md=ac&&"symbol"==typeof Zc.iterator?function(a){return"symbol"==typeof a}:function(a){return Object(a)instanceof Zc},nd=function(a,b,c){a===Yc&&nd(ed,b,c),R(a);var d=H(b,!0);return R(c),J(dd,d)?(c.enumerable?(J(a,Sc)&&a[Sc][d]&&(a[Sc][d]=!1),c=sc(c,{enumerable:z(0,!1)})):(J(a,Sc)||ad(a,Sc,z(1,{})),a[Sc][d]=!0),kd(a,d,c)):ad(a,d,c)},od=function(a,b){var c,d;return R(a),c=F(b),d=ec(c).concat(td(c)),Rc(d,function(b){(!t||qd.call(c,b))&&nd(a,b,c[b])}),a},pd=function(a,b){return void 0===b?sc(a):od(sc(a),b)},qd=function(a){var b=H(a,!0),c=cd.call(this,b);return this===Yc&&J(dd,b)&&!J(ed,b)?!1:c||!J(this,b)||!J(dd,b)||J(this,Sc)&&this[Sc][b]?c:!0},rd=function(a,b){var c,d=F(a),e=H(b,!0);return d!==Yc||!J(dd,e)||J(ed,e)?(c=_c(d,e),!c||!J(dd,e)||J(d,Sc)&&d[Sc][e]||(c.enumerable=!0),c):void 0},sd=function(a){var b=bd(F(a)),c=[];return Rc(b,function(a){J(dd,a)||J(ib,a)||c.push(a)}),c},td=function(a){var b=a===Yc,c=bd(b?ed:F(a)),d=[];return Rc(c,function(a){!J(dd,a)||b&&!J(Yc,a)||d.push(dd[a])}),d},ac||(Zc=function(){var a,b,c;if(this instanceof Zc)throw TypeError("Symbol is not a constructor");return a=arguments.length&&void 0!==arguments[0]?String(arguments[0]):void 0,b=fb(a),c=function(a){this===Yc&&c.call(ed,a),J(this,Sc)&&J(this[Sc],b)&&(this[Sc][b]=!1),kd(this,b,z(1,a))},t&&jd&&kd(Yc,b,{configurable:!0,set:c}),ld(b,a)},vb(Zc[Uc],"toString",function(){return Xc(this).tag}),y.f=qd,U.f=nd,Q.f=rd,Ob.f=yc.f=sd,Qb.f=td,t&&(ad(Zc[Uc],"description",{configurable:!0,get:function(){return Xc(this).description}}),vb(Yc,"propertyIsEnumerable",qd,{unsafe:!0}))),bc||(Ec.f=function(a){return ld(Cc(a),a)}),_b({global:!0,wrap:!0,forced:!ac,sham:!ac},{Symbol:Zc}),Rc(ec(hd),function(a){Gc(a)}),_b({target:Tc,stat:!0,forced:!ac},{"for":function(a){var b,c=String(a);return J(fd,c)?fd[c]:(b=Zc(c),fd[c]=b,gd[b]=c,b)},keyFor:function(a){if(!md(a))throw TypeError(a+" is not a symbol");return J(gd,a)?gd[a]:void 0},useSetter:function(){jd=!0},useSimple:function(){jd=!1}}),_b({target:"Object",stat:!0,forced:!ac,sham:!t},{create:pd,defineProperty:nd,defineProperties:od,getOwnPropertyDescriptor:rd}),_b({target:"Object",stat:!0,forced:!ac},{getOwnPropertyNames:sd,getOwnPropertySymbols:td}),_b({target:"Object",stat:!0,forced:s(function(){Qb.f(1)})},{getOwnPropertySymbols:function(a){return Qb.f(dc(a))}}),$c&&(ud=!ac||s(function(){var a=Zc();return"[null]"!=$c([a])||"{}"!=$c({a:a})||"{}"!=$c(Object(a))}),_b({target:"JSON",stat:!0,forced:ud},{stringify:function(a,b){for(var c,d=[a],e=1;arguments.length>e;)d.push(arguments[e++]);return c=b,!G(b)&&void 0===a||md(a)?void 0:(cc(b)||(b=function(a,b){return"function"==typeof c&&(b=c.call(this,a,b)),md(b)?void 0:b}),d[1]=b,$c.apply(null,d))}})),Zc[Uc][Vc]||V(Zc[Uc],Vc,Zc[Uc].valueOf),Jc(Zc,Tc),ib[Sc]=!0,vd=U.f,wd=r.Symbol,!t||"function"!=typeof wd||"description"in wd.prototype&&void 0===wd().description||(xd={},yd=function(){var a=arguments.length<1||void 0===arguments[0]?void 0:String(arguments[0]),b=this instanceof yd?new wd(a):void 0===a?wd():wd(a);return""===a&&(xd[b]=!0),b},Sb(yd,wd),zd=yd.prototype=wd.prototype,zd.constructor=yd,Ad=zd.toString,Bd="Symbol(test)"==String(wd("test")),Cd=/^Symbol\((.*)\)[^)]+$/,vd(zd,"description",{configurable:!0,get:function(){var a,b=G(this)?this.valueOf():this,c=Ad.call(b);return J(xd,b)?"":(a=Bd?c.slice(7,-1):c.replace(Cd,"$1"),""===a?void 0:a)}}),_b({global:!0,forced:!0},{Symbol:yd})),Gc("iterator"),Dd=function(a,b,c){var d=H(b);d in a?U.f(a,d,z(0,c)):a[d]=c},Ed=yb("navigator","userAgent")||"",Fd=r.process,Gd=Fd&&Fd.versions,Hd=Gd&&Gd.v8,Hd?(Id=Hd.split("."),Jd=Id[0]+Id[1]):Ed&&(Id=Ed.match(/Edge\/(\d+)/),(!Id||Id[1]>=74)&&(Id=Ed.match(/Chrome\/(\d+)/),Id&&(Jd=Id[1]))),Kd=Jd&&+Jd,Ld=Cc("species"),Md=function(a){return Kd>=51||!s(function(){var b=[],c=b.constructor={};return c[Ld]=function(){return{foo:1}},1!==b[a](Boolean).foo})},Nd=Cc("isConcatSpreadable"),Od=9007199254740991,Pd="Maximum allowed index exceeded",Qd=Kd>=51||!s(function(){var a=[];return a[Nd]=!1,a.concat()[0]!==a}),Rd=Md("concat"),Sd=function(a){if(!G(a))return!1;var b=a[Nd];return void 0!==b?!!b:cc(a)},Td=!Qd||!Rd,_b({target:"Array",proto:!0,forced:Td},{concat:function(){var a,b,c,d,e,f=dc(this),g=Nc(f,0),h=0;for(a=-1,c=arguments.length;c>a;a++)if(e=-1===a?f:arguments[a],Sd(e)){if(d=Db(e.length),h+d>Od)throw TypeError(Pd);for(b=0;d>b;b++,h++)b in e&&Dd(g,h,e[b])}else{if(h>=Od)throw TypeError(Pd);Dd(g,h++,e)}return g.length=h,g}}),Ud=Qc.filter,Vd=Md("filter"),Wd=Vd&&!s(function(){[].filter.call({length:-1,0:1},function(a){throw a})}),_b({target:"Array",proto:!0,forced:!Vd||!Wd},{filter:function(a){return Ud(this,a,arguments.length>1?arguments[1]:void 0)}}),Xd=Cc("unscopables"),Yd=Array.prototype,void 0==Yd[Xd]&&U.f(Yd,Xd,{configurable:!0,value:sc(null)}),Zd=function(a){Yd[Xd][a]=!0},$d=Qc.find,_d="find",ae=!0,_d in[]&&Array(1)[_d](function(){ae=!1}),_b({target:"Array",proto:!0,forced:ae},{find:function(a){return $d(this,a,arguments.length>1?arguments[1]:void 0)}}),Zd(_d),be=Qc.findIndex,ce="findIndex",de=!0,ce in[]&&Array(1)[ce](function(){de=!1}),_b({target:"Array",proto:!0,forced:de},{findIndex:function(a){return be(this,a,arguments.length>1?arguments[1]:void 0)}}),Zd(ce),ee=Ib.includes,_b({target:"Array",proto:!0},{includes:function(a){return ee(this,a,arguments.length>1?arguments[1]:void 0)}}),Zd("includes"),fe=function(a,b){var c=[][a];return!c||!s(function(){c.call(null,b||function(){throw 1},1)})},ge=Ib.indexOf,he=[].indexOf,ie=!!he&&1/[1].indexOf(1,-0)<0,je=fe("indexOf"),_b({target:"Array",proto:!0,forced:ie||je},{indexOf:function(a){return ie?he.apply(this,arguments)||0:ge(this,a,arguments.length>1?arguments[1]:void 0)}}),ke=!s(function(){function a(){}return a.prototype.constructor=null,Object.getPrototypeOf(new a)!==a.prototype}),le=hb("IE_PROTO"),me=Object.prototype,ne=ke?Object.getPrototypeOf:function(a){return a=dc(a),J(a,le)?a[le]:"function"==typeof a.constructor&&a instanceof a.constructor?a.constructor.prototype:a instanceof Object?me:null},oe=Cc("iterator"),pe=!1,qe=function(){return this},[].keys&&(te=[].keys(),"next"in te?(se=ne(ne(te)),se!==Object.prototype&&(re=se)):pe=!0),void 0==re&&(re={}),J(re,oe)||V(re,oe,qe),ue={IteratorPrototype:re,BUGGY_SAFARI_ITERATORS:pe},ve=ue.IteratorPrototype,we=function(a,b,c){var d=b+" Iterator";return a.prototype=sc(ve,{next:z(1,c)}),Jc(a,d,!1),a},xe=function(a){if(!G(a)&&null!==a)throw TypeError("Can't set "+String(a)+" as a prototype");return a},ye=Object.setPrototypeOf||("__proto__"in{}?function(){var a,b=!1,c={};try{a=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set,a.call(c,[]),b=c instanceof Array}catch(d){}return function(c,d){return R(c),xe(d),b?a.call(c,d):c.__proto__=d,c}}():void 0),ze=ue.IteratorPrototype,Ae=ue.BUGGY_SAFARI_ITERATORS,Be=Cc("iterator"),Ce="keys",De="values",Ee="entries",Fe=function(){return this},Ge=function(a,b,c,d,e,f,g){var h,i,j,k,l,m,n,o,p,q;if(we(c,b,d),h=function(a){if(a===e&&m)return m;if(!Ae&&a in k)return k[a];switch(a){case Ce:return function(){return new c(this,a)};case De:return function(){return new c(this,a)};case Ee:return function(){return new c(this,a)}}return function(){return new c(this)}},i=b+" Iterator",j=!1,k=a.prototype,l=k[Be]||k["@@iterator"]||e&&k[e],m=!Ae&&l||h(e),n="Array"==b?k.entries||l:l,n&&(o=ne(n.call(new a)),ze!==Object.prototype&&o.next&&(ne(o)!==ze&&(ye?ye(o,ze):"function"!=typeof o[Be]&&V(o,Be,Fe)),Jc(o,i,!0))),e==De&&l&&l.name!==De&&(j=!0,m=function(){return l.call(this)}),k[Be]!==m&&V(k,Be,m),e)if(p={values:h(De),keys:f?m:h(Ce),entries:h(Ee)},g)for(q in p)!Ae&&!j&&q in k||vb(k,q,p[q]);else _b({target:b,proto:!0,forced:Ae||j},p);return p},He="Array Iterator",Ie=ub.set,Je=ub.getterFor(He),Ke=Ge(Array,"Array",function(a,b){Ie(this,{type:He,target:F(a),index:0,kind:b})},function(){var a=Je(this),b=a.target,c=a.kind,d=a.index++;return!b||d>=b.length?(a.target=void 0,{value:void 0,done:!0}):"keys"==c?{value:d,done:!1}:"values"==c?{value:b[d],done:!1}:{value:[d,b[d]],done:!1}},"values"),Zd("keys"),Zd("values"),Zd("entries"),Le=[].join,Me=D!=Object,Ne=fe("join",","),_b({target:"Array",proto:!0,forced:Me||Ne},{join:function(a){return Le.call(F(this),void 0===a?",":a)}}),Oe=Qc.map,Pe=Md("map"),Qe=Pe&&!s(function(){[].map.call({length:-1,0:1},function(a){throw a})}),_b({target:"Array",proto:!0,forced:!Pe||!Qe},{map:function(a){return Oe(this,a,arguments.length>1?arguments[1]:void 0)}}),Re=[].reverse,Se=[1,2],_b({target:"Array",proto:!0,forced:String(Se)===String(Se.reverse())},{reverse:function(){return cc(this)&&(this.length=this.length),Re.call(this)}}),Te=Cc("species"),Ue=[].slice,Ve=Math.max,_b({target:"Array",proto:!0,forced:!Md("slice")},{slice:function(a,b){var c,d,e,f=F(this),g=Db(f.length),h=Gb(a,g),i=Gb(void 0===b?g:b,g);if(cc(f)&&(c=f.constructor,"function"!=typeof c||c!==Array&&!cc(c.prototype)?G(c)&&(c=c[Te],null===c&&(c=void 0)):c=void 0,c===Array||void 0===c))return Ue.call(f,h,i);for(d=new(void 0===c?Array:c)(Ve(i-h,0)),e=0;i>h;h++,e++)h in f&&Dd(d,e,f[h]);return d.length=e,d}}),We=[],Xe=We.sort,Ye=s(function(){We.sort(void 0)}),Ze=s(function(){We.sort(null)}),$e=fe("sort"),_e=Ye||!Ze||$e,_b({target:"Array",proto:!0,forced:_e},{sort:function(a){return void 0===a?Xe.call(dc(this)):Xe.call(dc(this),Kc(a))}}),af=Math.max,bf=Math.min,cf=9007199254740991,df="Maximum allowed length exceeded",_b({target:"Array",proto:!0,forced:!Md("splice")},{splice:function(a,b){var c,d,e,f,g,h,i=dc(this),j=Db(i.length),k=Gb(a,j),l=arguments.length;if(0===l?c=d=0:1===l?(c=0,d=j-k):(c=l-2,d=bf(af(Bb(b),0),j-k)),j+c-d>cf)throw TypeError(df);for(e=Nc(i,d),f=0;d>f;f++)g=k+f,g in i&&Dd(e,f,i[g]);if(e.length=d,d>c){for(f=k;j-d>f;f++)g=f+d,h=f+c,g in i?i[h]=i[g]:delete i[h];for(f=j;f>j-d+c;f--)delete i[f-1]}else if(c>d)for(f=j-d;f>k;f--)g=f+d-1,h=f+c-1,g in i?i[h]=i[g]:delete i[h];for(f=0;c>f;f++)i[f+k]=arguments[f+2];return i.length=j-d+c,e}}),ef=function(a,b,c){var d,e;return ye&&"function"==typeof(d=b.constructor)&&d!==c&&G(e=d.prototype)&&e!==c.prototype&&ye(a,e),a},ff=" \n \f\r                 \u2028\u2029",gf="["+ff+"]",hf=RegExp("^"+gf+gf+"*"),jf=RegExp(gf+gf+"*$"),kf=function(a){return function(b){var c=String(E(b));return 1&a&&(c=c.replace(hf,"")),2&a&&(c=c.replace(jf,"")),c}},lf={start:kf(1),end:kf(2),trim:kf(3)},mf=Ob.f,nf=Q.f,of=U.f,pf=lf.trim,qf="Number",rf=r[qf],sf=rf.prototype,tf=B(sc(sf))==qf,uf=function(a){var b,c,d,e,f,g,h,i,j=H(a,!1);if("string"==typeof j&&j.length>2)if(j=pf(j),b=j.charCodeAt(0),43===b||45===b){if(c=j.charCodeAt(2),88===c||120===c)return 0/0}else if(48===b){switch(j.charCodeAt(1)){case 66:case 98:d=2,e=49;break;case 79:case 111:d=8,e=55;break;default:return+j}for(f=j.slice(2),g=f.length,h=0;g>h;h++)if(i=f.charCodeAt(h),48>i||i>e)return 0/0;return parseInt(f,d)}return+j},Zb(qf,!rf(" 0o1")||!rf("0b1")||rf("+0x1"))){for(vf=function(a){var b=arguments.length<1?0:a,c=this;return c instanceof vf&&(tf?s(function(){sf.valueOf.call(c)}):B(c)!=qf)?ef(new rf(uf(b)),c,vf):uf(b)},xf=t?mf(rf):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger".split(","),yf=0;xf.length>yf;yf++)J(rf,wf=xf[yf])&&!J(vf,wf)&&of(vf,wf,nf(rf,wf));vf.prototype=sf,sf.constructor=vf,vb(r,qf,vf)}zf=Object.assign,Af=Object.defineProperty,Bf=!zf||s(function(){var a,b,c,d;return t&&1!==zf({b:1},zf(Af({},"a",{enumerable:!0,get:function(){Af(this,"b",{value:3,enumerable:!1})}}),{b:2})).b?!0:(a={},b={},c=Symbol(),d="abcdefghijklmnopqrst",a[c]=7,d.split("").forEach(function(a){b[a]=a}),7!=zf({},a)[c]||ec(zf({},b)).join("")!=d)})?function(a){for(var b,c,d,e,f,g=dc(a),h=arguments.length,i=1,j=Qb.f,k=y.f;h>i;)for(b=D(arguments[i++]),c=j?ec(b).concat(j(b)):ec(b),d=c.length,e=0;d>e;)f=c[e++],(!t||k.call(b,f))&&(g[f]=b[f]);return g}:zf,_b({target:"Object",stat:!0,forced:Object.assign!==Bf},{assign:Bf}),Cf=y.f,Df=function(a){return function(b){for(var c,d=F(b),e=ec(d),f=e.length,g=0,h=[];f>g;)c=e[g++],(!t||Cf.call(d,c))&&h.push(a?[c,d[c]]:d[c]);return h}},Ef={entries:Df(!0),values:Df(!1)},Ff=Ef.entries,_b({target:"Object",stat:!0},{entries:function(a){return Ff(a)}}),Gf=Cc("toStringTag"),Hf={},Hf[Gf]="z",If="[object z]"===String(Hf),Jf=Cc("toStringTag"),Kf="Arguments"==B(function(){return arguments}()),Lf=function(a,b){try{return a[b]}catch(c){}},Mf=If?B:function(a){var b,c,d;return void 0===a?"Undefined":null===a?"Null":"string"==typeof(c=Lf(b=Object(a),Jf))?c:Kf?B(b):"Object"==(d=B(b))&&"function"==typeof b.callee?"Arguments":d},Nf=If?{}.toString:function(){return"[object "+Mf(this)+"]"},If||vb(Object.prototype,"toString",Nf,{unsafe:!0}),Of=lf.trim,Pf=r.parseFloat,Qf=1/Pf(ff+"-0")!==-1/0,Rf=Qf?function(a){var b=Of(String(a)),c=Pf(b);return 0===c&&"-"==b.charAt(0)?-0:c}:Pf,_b({global:!0,forced:parseFloat!=Rf},{parseFloat:Rf}),Sf=lf.trim,Tf=r.parseInt,Uf=/^[+-]?0[Xx]/,Vf=8!==Tf(ff+"08")||22!==Tf(ff+"0x16"),Wf=Vf?function(a,b){var c=Sf(String(a));return Tf(c,b>>>0||(Uf.test(c)?16:10))}:Tf,_b({global:!0,forced:parseInt!=Wf},{parseInt:Wf}),Xf=function(){var a=R(this),b="";return a.global&&(b+="g"),a.ignoreCase&&(b+="i"),a.multiline&&(b+="m"),a.dotAll&&(b+="s"),a.unicode&&(b+="u"),a.sticky&&(b+="y"),b},Yf=s(function(){var a=c("a","y");return a.lastIndex=2,null!=a.exec("abcd")}),Zf=s(function(){var a=c("^r","gy");return a.lastIndex=2,null!=a.exec("str")}),$f={UNSUPPORTED_Y:Yf,BROKEN_CARET:Zf},_f=RegExp.prototype.exec,ag=String.prototype.replace,bg=_f,cg=function(){var a=/a/,b=/b*/g;return _f.call(a,"a"),_f.call(b,"a"),0!==a.lastIndex||0!==b.lastIndex}(),dg=$f.UNSUPPORTED_Y||$f.BROKEN_CARET,eg=void 0!==/()??/.exec("")[1],fg=cg||eg||dg,fg&&(bg=function(a){var b,c,d,e,f=this,g=dg&&f.sticky,h=Xf.call(f),i=f.source,j=0,k=a;return g&&(h=h.replace("y",""),-1===h.indexOf("g")&&(h+="g"),k=String(a).slice(f.lastIndex),f.lastIndex>0&&(!f.multiline||f.multiline&&"\n"!==a[f.lastIndex-1])&&(i="(?: "+i+")",k=" "+k,j++),c=new RegExp("^(?:"+i+")",h)),eg&&(c=new RegExp("^"+i+"$(?!\\s)",h)),cg&&(b=f.lastIndex),d=_f.call(g?c:f,k),g?d?(d.input=d.input.slice(j),d[0]=d[0].slice(j),d.index=f.lastIndex,f.lastIndex+=d[0].length):f.lastIndex=0:cg&&d&&(f.lastIndex=f.global?d.index+d[0].length:b),eg&&d&&d.length>1&&ag.call(d[0],c,function(){for(e=1;e1?arguments[1]:void 0)}}),rg=function(a){return function(b,c){var d,e,f=String(E(b)),g=Bb(c),h=f.length;return 0>g||g>=h?a?"":void 0:(d=f.charCodeAt(g),55296>d||d>56319||g+1===h||(e=f.charCodeAt(g+1))<56320||e>57343?a?f.charAt(g):d:a?f.slice(g,g+2):(d-55296<<10)+(e-56320)+65536)}},sg={codeAt:rg(!1),charAt:rg(!0)},tg=sg.charAt,ug="String Iterator",vg=ub.set,wg=ub.getterFor(ug),Ge(String,"String",function(a){vg(this,{type:ug,string:String(a),index:0})},function(){var a,b=wg(this),c=b.string,d=b.index;return d>=c.length?{value:void 0,done:!0}:(a=tg(c,d),b.index+=a.length,{value:a,done:!1})}),xg=Cc("species"),yg=!s(function(){var a=/./;return a.exec=function(){var a=[];return a.groups={a:"7"},a},"7"!=="".replace(a,"$")}),zg=function(){return"$0"==="a".replace(/./,"$0")}(),Ag=!s(function(){var a,b=/(?:)/,c=b.exec;return b.exec=function(){return c.apply(this,arguments)},a="ab".split(b),2!==a.length||"a"!==a[0]||"b"!==a[1]}),Bg=function(a,b,c,d){var e,f,g,h,i=Cc(a),j=!s(function(){var b={};return b[i]=function(){return 7},7!=""[a](b)}),k=j&&!s(function(){var b=!1,c=/a/;return"split"===a&&(c={},c.constructor={},c.constructor[xg]=function(){return c},c.flags="",c[i]=/./[i]),c.exec=function(){return b=!0,null},c[i](""),!b});j&&k&&("replace"!==a||yg&&zg)&&("split"!==a||Ag)||(e=/./[i],f=c(i,""[a],function(a,b,c,d,f){return b.exec===gg?j&&!f?{done:!0,value:e.call(b,c,d)}:{done:!0,value:a.call(c,b,d)}:{done:!1}},{REPLACE_KEEPS_$0:zg}),g=f[0],h=f[1],vb(String.prototype,a,g),vb(RegExp.prototype,i,2==b?function(a,b){return h.call(a,this,b)}:function(a){return h.call(a,this)})),d&&V(RegExp.prototype[i],"sham",!0)},Cg=sg.charAt,Dg=function(a,b,c){return b+(c?Cg(a,b).length:1)},Eg=function(a,b){var c,d=a.exec;if("function"==typeof d){if(c=d.call(a,b),"object"!=typeof c)throw TypeError("RegExp exec method returned something other than an Object or null");return c}if("RegExp"!==B(a))throw TypeError("RegExp#exec called on incompatible receiver");return gg.call(a,b)},Fg=Math.max,Gg=Math.min,Hg=Math.floor,Ig=/\$([$&'`]|\d\d?|<[^>]*>)/g,Jg=/\$([$&'`]|\d\d?)/g,Kg=function(a){return void 0===a?a:String(a)},Bg("replace",2,function(a,b,c,d){function e(a,c,d,e,f,g){var h=d+a.length,i=e.length,j=Jg;return void 0!==f&&(f=dc(f),j=Ig),b.call(g,j,function(b,g){var j,k,l;switch(g.charAt(0)){case"$":return"$";case"&":return a;case"`":return c.slice(0,d);case"'":return c.slice(h);case"<":j=f[g.slice(1,-1)];break;default:if(k=+g,0===k)return b;if(k>i)return l=Hg(k/10),0===l?b:i>=l?void 0===e[l-1]?g.charAt(1):e[l-1]+g.charAt(1):b;j=e[k-1]}return void 0===j?"":j})}return[function(c,d){var e=E(this),f=void 0==c?void 0:c[a];return void 0!==f?f.call(c,e,d):b.call(String(e),c,d)},function(a,f){var g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y;if((d.REPLACE_KEEPS_$0||"string"==typeof f&&-1===f.indexOf("$0"))&&(g=c(b,a,this,f),g.done))return g.value;for(h=R(a),i=String(this),j="function"==typeof f,j||(f=String(f)),k=h.global,k&&(l=h.unicode,h.lastIndex=0),m=[];(n=Eg(h,i),null!==n)&&(m.push(n),k);)o=String(n[0]),""===o&&(h.lastIndex=Dg(i,Db(h.lastIndex),l));for(p="",q=0,r=0;r=q&&(p+=i.slice(q,t)+y,q=t+s.length)}return p+i.slice(q)}]}),Lg=Object.is||function(a,b){return a===b?0!==a||1/a===1/b:a!=a&&b!=b},Bg("search",1,function(a,b,c){return[function(b){var c=E(this),d=void 0==b?void 0:b[a];return void 0!==d?d.call(b,c):new RegExp(b)[a](String(c))},function(a){var d,e,f,g,h=c(b,a,this);return h.done?h.value:(d=R(a),e=String(this),f=d.lastIndex,Lg(f,0)||(d.lastIndex=0),g=Eg(d,e),Lg(d.lastIndex,f)||(d.lastIndex=f),null===g?-1:g.index)}]}),Mg=Cc("species"),Ng=function(a,b){var c,d=R(a).constructor;return void 0===d||void 0==(c=R(d)[Mg])?b:Kc(c)},Og=[].push,Pg=Math.min,Qg=4294967295,Rg=!s(function(){return!RegExp(Qg,"y")}),Bg("split",2,function(a,b,c){var d;return d="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(a,c){var d,e,f,g,h,i,j,k=String(E(this)),l=void 0===c?Qg:c>>>0;if(0===l)return[];if(void 0===a)return[k];if(!ng(a))return b.call(k,a,l);for(d=[],e=(a.ignoreCase?"i":"")+(a.multiline?"m":"")+(a.unicode?"u":"")+(a.sticky?"y":""),f=0,g=new RegExp(a.source,e+"g");(h=gg.call(g,k))&&(i=g.lastIndex,!(i>f&&(d.push(k.slice(f,h.index)),h.length>1&&h.index=l)));)g.lastIndex===h.index&&g.lastIndex++; +return f===k.length?(j||!g.test(""))&&d.push(""):d.push(k.slice(f)),d.length>l?d.slice(0,l):d}:"0".split(void 0,0).length?function(a,c){return void 0===a&&0===c?[]:b.call(this,a,c)}:b,[function(b,c){var e=E(this),f=void 0==b?void 0:b[a];return void 0!==f?f.call(b,e,c):d.call(String(e),b,c)},function(a,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s=c(d,a,this,e,d!==b);if(s.done)return s.value;if(f=R(a),g=String(this),h=Ng(f,RegExp),i=f.unicode,j=(f.ignoreCase?"i":"")+(f.multiline?"m":"")+(f.unicode?"u":"")+(Rg?"y":"g"),k=new h(Rg?f:"^(?:"+f.source+")",j),l=void 0===e?Qg:e>>>0,0===l)return[];if(0===g.length)return null===Eg(k,g)?[g]:[];for(m=0,n=0,o=[];n1?arguments[1]:void 0)}:[].forEach;for(Yg in Vg)if(Zg=r[Yg],$g=Zg&&Zg.prototype,$g&&$g.forEach!==Xg)try{V($g,"forEach",Xg)}catch(Hh){$g.forEach=Xg}_g=Cc("iterator"),ah=Cc("toStringTag"),bh=Ke.values;for(ch in Vg)if(dh=r[ch],eh=dh&&dh.prototype){if(eh[_g]!==bh)try{V(eh,_g,bh)}catch(Hh){eh[_g]=bh}if(eh[ah]||V(eh,ah,ch),Vg[ch])for(fh in Ke)if(eh[fh]!==Ke[fh])try{V(eh,fh,Ke[fh])}catch(Hh){eh[fh]=Ke[fh]}}gh="1.17.1",hh=4;try{ih=a.fn.dropdown.Constructor.VERSION,void 0!==ih&&(hh=parseInt(ih,10))}catch(Ih){}try{jh=bootstrap.Tooltip.VERSION,void 0!==jh&&(hh=parseInt(jh,10))}catch(Ih){}return kh={3:{iconsPrefix:"glyphicon",icons:{paginationSwitchDown:"glyphicon-collapse-down icon-chevron-down",paginationSwitchUp:"glyphicon-collapse-up icon-chevron-up",refresh:"glyphicon-refresh icon-refresh",toggleOff:"glyphicon-list-alt icon-list-alt",toggleOn:"glyphicon-list-alt icon-list-alt",columns:"glyphicon-th icon-th",detailOpen:"glyphicon-plus icon-plus",detailClose:"glyphicon-minus icon-minus",fullscreen:"glyphicon-fullscreen",search:"glyphicon-search",clearSearch:"glyphicon-trash"},classes:{buttonsPrefix:"btn",buttons:"default",buttonsGroup:"btn-group",buttonsDropdown:"btn-group",pull:"pull",inputGroup:"input-group",inputPrefix:"input-",input:"form-control",paginationDropdown:"btn-group dropdown",dropup:"dropup",dropdownActive:"active",paginationActive:"active",buttonActive:"active"},html:{toolbarDropdown:['"],toolbarDropdownItem:'',toolbarDropdownSeparator:'
  • ',pageDropdown:['"],pageDropdownItem:'
    ',dropdownCaret:'',pagination:['
      ',"
    "],paginationItem:'
  • %s
  • ',icon:'',inputGroup:'
    %s%s
    ',searchInput:'',searchButton:'',searchClearButton:''}},4:{iconsPrefix:"fa",icons:{paginationSwitchDown:"fa-caret-square-down",paginationSwitchUp:"fa-caret-square-up",refresh:"fa-sync",toggleOff:"fa-toggle-off",toggleOn:"fa-toggle-on",columns:"fa-th-list",detailOpen:"fa-plus",detailClose:"fa-minus",fullscreen:"fa-arrows-alt",search:"fa-search",clearSearch:"fa-trash"},classes:{buttonsPrefix:"btn",buttons:"secondary",buttonsGroup:"btn-group",buttonsDropdown:"btn-group",pull:"float",inputGroup:"btn-group",inputPrefix:"form-control-",input:"form-control",paginationDropdown:"btn-group dropdown",dropup:"dropup",dropdownActive:"active",paginationActive:"active",buttonActive:"active"},html:{toolbarDropdown:['"],toolbarDropdownItem:'',pageDropdown:['"],pageDropdownItem:'%s',toolbarDropdownSeparator:'',dropdownCaret:'',pagination:['
      ',"
    "],paginationItem:'
  • %s
  • ',icon:'',inputGroup:'
    %s
    %s
    ',searchInput:'',searchButton:'',searchClearButton:''}},5:{iconsPrefix:"fa",icons:{paginationSwitchDown:"fa-caret-square-down",paginationSwitchUp:"fa-caret-square-up",refresh:"fa-sync",toggleOff:"fa-toggle-off",toggleOn:"fa-toggle-on",columns:"fa-th-list",detailOpen:"fa-plus",detailClose:"fa-minus",fullscreen:"fa-arrows-alt",search:"fa-search",clearSearch:"fa-trash"},classes:{buttonsPrefix:"btn",buttons:"secondary",buttonsGroup:"btn-group",buttonsDropdown:"btn-group",pull:"float",inputGroup:"btn-group",inputPrefix:"form-control-",input:"form-control",paginationDropdown:"btn-group dropdown",dropup:"dropup",dropdownActive:"active",paginationActive:"active",buttonActive:"active"},html:{toolbarDropdown:['"],toolbarDropdownItem:'',pageDropdown:['"],pageDropdownItem:'%s',toolbarDropdownSeparator:'',dropdownCaret:'',pagination:['
      ',"
    "],paginationItem:'
  • %s
  • ',icon:'',inputGroup:'
    %s
    %s
    ',searchInput:'',searchButton:'',searchClearButton:''}}}[hh],lh={id:void 0,firstLoad:!0,height:void 0,classes:"table table-bordered table-hover",theadClasses:"",headerStyle:function(){return{}},rowStyle:function(){return{}},rowAttributes:function(){return{}},undefinedText:"-",locale:void 0,virtualScroll:!1,virtualScrollItemHeight:void 0,sortable:!0,sortClass:void 0,silentSort:!0,sortName:void 0,sortOrder:void 0,sortReset:!1,sortStable:!1,rememberOrder:!1,serverSort:!0,customSort:void 0,columns:[[]],data:[],url:void 0,method:"get",cache:!0,contentType:"application/json",dataType:"json",ajax:void 0,ajaxOptions:{},queryParams:function(a){return a},queryParamsType:"limit",responseHandler:function(a){return a},totalField:"total",totalNotFilteredField:"totalNotFiltered",dataField:"rows",pagination:!1,paginationParts:["pageInfo","pageSize","pageList"],showExtendedPagination:!1,paginationLoop:!0,sidePagination:"client",totalRows:0,totalNotFiltered:0,pageNumber:1,pageSize:10,pageList:[10,25,50,100],paginationHAlign:"right",paginationVAlign:"bottom",paginationDetailHAlign:"left",paginationPreText:"‹",paginationNextText:"›",paginationSuccessivelySize:5,paginationPagesBySide:1,paginationUseIntermediate:!1,search:!1,searchOnEnterKey:!1,strictSearch:!1,visibleSearch:!1,showButtonIcons:!0,showButtonText:!1,showSearchButton:!1,showSearchClearButton:!1,trimOnSearch:!0,searchAlign:"right",searchTimeOut:500,searchText:"",customSearch:void 0,showHeader:!0,showFooter:!1,footerStyle:function(){return{}},searchAccentNeutralise:!1,showColumns:!1,showSearch:!1,showPageGo:!1,showColumnsToggleAll:!1,showColumnsSearch:!1,minimumCountColumns:1,showPaginationSwitch:!1,showRefresh:!1,showToggle:!1,showFullscreen:!1,smartDisplay:!0,escape:!1,filterOptions:{filterAlgorithm:"and"},idField:void 0,selectItemName:"btSelectItem",clickToSelect:!1,ignoreClickToSelectOn:function(a){var b=a.tagName;return["A","BUTTON"].includes(b)},singleSelect:!1,checkboxHeader:!0,maintainMetaData:!1,multipleSelectRow:!1,uniqueId:void 0,cardView:!1,detailView:!1,detailViewIcon:!0,detailViewByClick:!1,detailViewAlign:"left",detailFormatter:function(){return""},detailFilter:function(){return!0},toolbar:void 0,toolbarAlign:"left",buttonsToolbar:void 0,buttonsAlign:"right",buttonsOrder:["search","paginationSwitch","refresh","toggle","fullscreen","columns"],buttonsPrefix:kh.classes.buttonsPrefix,buttonsClass:kh.classes.buttons,icons:kh.icons,iconSize:void 0,iconsPrefix:kh.iconsPrefix,loadingFontSize:"auto",loadingTemplate:function(a){return'\n '.concat(a,'\n \n \n ')},onAll:function(){return!1},onClickCell:function(){return!1},onDblClickCell:function(){return!1},onClickRow:function(){return!1},onDblClickRow:function(){return!1},onSort:function(){return!1},onCheck:function(){return!1},onUncheck:function(){return!1},onCheckAll:function(){return!1},onUncheckAll:function(){return!1},onCheckSome:function(){return!1},onUncheckSome:function(){return!1},onLoadSuccess:function(){return!1},onLoadError:function(){return!1},onColumnSwitch:function(){return!1},onPageChange:function(){return!1},onSearch:function(){return!1},onShowSearch:function(){return!1},onToggle:function(){return!1},onPreBody:function(){return!1},onPostBody:function(){return!1},onPostHeader:function(){return!1},onPostFooter:function(){return!1},onExpandRow:function(){return!1},onCollapseRow:function(){return!1},onRefreshOptions:function(){return!1},onRefresh:function(){return!1},onResetView:function(){return!1},onScrollBody:function(){return!1}},mh={formatLoadingMessage:function(){return"Loading, please wait"},formatRecordsPerPage:function(a){return"".concat(a," rows per page")},formatShowingRows:function(a,b,c,d){return void 0!==d&&d>0&&d>c?"Showing ".concat(a," to ").concat(b," of ").concat(c," rows (filtered from ").concat(d," total rows)"):"Showing ".concat(a," to ").concat(b," of ").concat(c," rows")},formatSRPaginationPreText:function(){return"previous page"},formatSRPaginationPageText:function(a){return"to page ".concat(a)},formatSRPaginationNextText:function(){return"next page"},formatDetailPagination:function(a){return"Showing ".concat(a," rows")},formatSearch:function(){return"Search"},formatPageGo:function(){return"跳转"},formatClearSearch:function(){return"Clear Search"},formatNoMatches:function(){return"No matching records found"},formatPaginationSwitch:function(){return"Hide/Show pagination"},formatPaginationSwitchDown:function(){return"Show pagination"},formatPaginationSwitchUp:function(){return"Hide pagination"},formatRefresh:function(){return"Refresh"},formatToggle:function(){return"Toggle"},formatToggleOn:function(){return"Show card view"},formatToggleOff:function(){return"Hide card view"},formatColumns:function(){return"Columns"},formatColumnsToggleAll:function(){return"Toggle all"},formatFullscreen:function(){return"Fullscreen"},formatAllRows:function(){return"All"}},nh={field:void 0,title:void 0,titleTooltip:void 0,"class":void 0,width:void 0,widthUnit:"px",rowspan:void 0,colspan:void 0,align:void 0,halign:void 0,falign:void 0,valign:void 0,cellStyle:void 0,radio:!1,checkbox:!1,checkboxEnabled:!0,clickToSelect:!0,showSelectTitle:!1,sortable:!1,sortName:void 0,order:"asc",sorter:void 0,visible:!0,ignore:!1,switchable:!0,cardVisible:!0,searchable:!0,formatter:void 0,footerFormatter:void 0,detailFormatter:void 0,searchFormatter:!0,escape:!1,events:void 0},oh=["getOptions","refreshOptions","getData","getSelections","getAllSelections","load","append","prepend","remove","removeAll","insertRow","updateRow","getRowByUniqueId","updateByUniqueId","removeByUniqueId","updateCell","updateCellByUniqueId","showRow","hideRow","getHiddenRows","showColumn","hideColumn","getVisibleColumns","getHiddenColumns","showAllColumns","hideAllColumns","mergeCells","checkAll","uncheckAll","checkInvert","check","uncheck","checkBy","uncheckBy","refresh","destroy","resetView","showLoading","hideLoading","togglePagination","toggleFullscreen","toggleView","resetSearch","filterBy","scrollTo","getScrollPosition","selectPage","prevPage","nextPage","toggleDetailView","expandRow","collapseRow","expandRowByUniqueId","collapseRowByUniqueId","expandAllRows","collapseAllRows","updateColumnTitle","updateFormatText"],ph={"all.bs.table":"onAll","click-row.bs.table":"onClickRow","dbl-click-row.bs.table":"onDblClickRow","click-cell.bs.table":"onClickCell","dbl-click-cell.bs.table":"onDblClickCell","sort.bs.table":"onSort","check.bs.table":"onCheck","uncheck.bs.table":"onUncheck","check-all.bs.table":"onCheckAll","uncheck-all.bs.table":"onUncheckAll","check-some.bs.table":"onCheckSome","uncheck-some.bs.table":"onUncheckSome","load-success.bs.table":"onLoadSuccess","load-error.bs.table":"onLoadError","column-switch.bs.table":"onColumnSwitch","page-change.bs.table":"onPageChange","search.bs.table":"onSearch","toggle.bs.table":"onToggle","pre-body.bs.table":"onPreBody","post-body.bs.table":"onPostBody","post-header.bs.table":"onPostHeader","post-footer.bs.table":"onPostFooter","expand-row.bs.table":"onExpandRow","collapse-row.bs.table":"onCollapseRow","refresh-options.bs.table":"onRefreshOptions","reset-view.bs.table":"onResetView","refresh.bs.table":"onRefresh","scroll-body.bs.table":"onScrollBody"},Object.assign(lh,mh),qh={VERSION:gh,THEME:"bootstrap".concat(hh),CONSTANTS:kh,DEFAULTS:lh,COLUMN_DEFAULTS:nh,METHODS:oh,EVENTS:ph,LOCALES:{en:mh,"en-US":mh}},rh=s(function(){ec(1)}),_b({target:"Object",stat:!0,forced:rh},{keys:function(a){return ec(dc(a))}}),sh=Q.f,th="".endsWith,uh=Math.min,vh=qg("endsWith"),wh=!vh&&!!function(){var a=sh(String.prototype,"endsWith");return a&&!a.writable}(),_b({target:"String",proto:!0,forced:!wh&&!vh},{endsWith:function(a){var b,c,d,e,f=String(E(this));return og(a),b=arguments.length>1?arguments[1]:void 0,c=Db(f.length),d=void 0===b?c:uh(Db(b),c),e=String(a),th?th.call(f,e,d):f.slice(d-e.length,d)===e}}),xh=Q.f,yh="".startsWith,zh=Math.min,Ah=qg("startsWith"),Bh=!Ah&&!!function(){var a=xh(String.prototype,"startsWith");return a&&!a.writable}(),_b({target:"String",proto:!0,forced:!Bh&&!Ah},{startsWith:function(a){var b,c,d=String(E(this));return og(a),b=Db(zh(arguments.length>1?arguments[1]:void 0,d.length)),c=String(a),yh?yh.call(d,c,b):d.slice(b,b+c.length)===c}}),Ch={sprintf:function(a){var b,c,d,e,f,g;for(b=arguments.length,c=new Array(b>1?b-1:0),d=1;b>d;d++)c[d-1]=arguments[d];return e=!0,f=0,g=a.replace(/%s/g,function(){var a=c[f++];return"undefined"==typeof a?(e=!1,""):a}),e?g:""},isEmptyObject:function(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return 0===Object.entries(a).length&&a.constructor===Object},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},getFieldTitle:function(a,b){var c,d,e,f=!0,g=!1,h=void 0;try{for(d=a[Symbol.iterator]();!(f=(c=d.next()).done);f=!0)if(e=c.value,e.field===b)return e.title}catch(i){g=!0,h=i}finally{try{f||null==d.return||d.return()}finally{if(g)throw h}}return""},setFieldIndex:function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s=0,t=[],u=!0,v=!1,w=void 0;try{for(c=a[0][Symbol.iterator]();!(u=(b=c.next()).done);u=!0)d=b.value,s+=d.colspan||1}catch(x){v=!0,w=x}finally{try{u||null==c.return||c.return()}finally{if(v)throw w}}for(e=0;ef;f++)t[e][f]=!1;for(g=0;gq;q++)t[g+q][p]=!0;for(r=0;o>r;r++)t[g][p+r]=!0}}catch(x){i=!0,j=x}finally{try{h||null==l.return||l.return()}finally{if(i)throw j}}}},normalizeAccent:function(a){return a.normalize("NFD").replace(/[\u0300-\u036f]/g,"")},updateFieldGroup:function(a){var b,c,d,e,f,g,h,j,k,l,m,n,o,p=(b=[]).concat.apply(b,i(a)),q=!0,r=!1,s=void 0;try{for(d=a[Symbol.iterator]();!(q=(c=d.next()).done);q=!0){e=c.value,f=!0,g=!1,h=void 0;try{for(k=e[Symbol.iterator]();!(f=(j=k.next()).done);f=!0)if(l=j.value,l.colspanGroup>1){for(m=0,n=function(a){var b=p.find(function(b){return b.fieldIndex===a});b.visible&&m++},o=l.colspanIndex;o0}}catch(t){g=!0,h=t}finally{try{f||null==k.return||k.return()}finally{if(g)throw h}}}}catch(t){r=!0,s=t}finally{try{q||null==d.return||d.return()}finally{if(r)throw s}}},getScrollBarWidth:function(){var b,c,d,e;return void 0===this.cachedWidth&&(b=a("
    ").addClass("fixed-table-scroll-inner"),c=a("
    ").addClass("fixed-table-scroll-outer"),c.append(b),a("body").append(c),d=b[0].offsetWidth,c.css("overflow","scroll"),e=b[0].offsetWidth,d===e&&(e=c[0].clientWidth),c.remove(),this.cachedWidth=d-e),this.cachedWidth},calculateObjectValue:function(a,b,c,e){var f,g,h,j,k,l,m,n=b;if("string"==typeof b)if(f=b.split("."),f.length>1){n=window,g=!0,h=!1,j=void 0;try{for(l=f[Symbol.iterator]();!(g=(k=l.next()).done);g=!0)m=k.value,n=n[m]}catch(o){h=!0,j=o}finally{try{g||null==l.return||l.return()}finally{if(h)throw j}}}else n=window[b];return null!==n&&"object"===d(n)?n:"function"==typeof n?n.apply(a,c||[]):!n&&"string"==typeof b&&this.sprintf.apply(this,[b].concat(i(c)))?this.sprintf.apply(this,[b].concat(i(c))):e},compareObjects:function(a,b,c){var d,e,f,g=Object.keys(a),h=Object.keys(b);if(c&&g.length!==h.length)return!1;for(d=0,e=g;d/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/`/g,"`"):a},unescapeHTML:function(a){return"string"==typeof a?a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/`/g,"`"):a},getRealDataAttr:function(a){var b,c,d,e,f,g;for(b=0,c=Object.entries(a);btd,>th").each(function(e,g){for(var i,j,k,l=+a(g).attr("colspan")||1,m=+a(g).attr("rowspan")||1,n=e;f[c]&&f[c][n];n++);for(i=n;n+l>i;i++)for(j=c;c+m>j;j++)f[j]||(f[j]=[]),f[j][i]=!0;k=b[n].field,h[k]=a(g).html().trim(),h["_".concat(k,"_id")]=a(g).attr("id"),h["_".concat(k,"_class")]=a(g).attr("class"),h["_".concat(k,"_rowspan")]=a(g).attr("rowspan"),h["_".concat(k,"_colspan")]=a(g).attr("colspan"),h["_".concat(k,"_title")]=a(g).attr("title"),h["_".concat(k,"_data")]=d.getRealDataAttr(a(g).data())}),e.push(h)}),e},sort:function(a,b,c,d,e,f){return(void 0===a||null===a)&&(a=""),(void 0===b||null===b)&&(b=""),d&&a===b&&(a=e,b=f),this.isNumeric(a)&&this.isNumeric(b)?(a=parseFloat(a),b=parseFloat(b),b>a?-1*c:a>b?c:0):a===b?0:("string"!=typeof a&&(a=a.toString()),-1===a.localeCompare(b)?-1*c:c)},getResizeEventName:function(){var a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return a=a||"".concat(+new Date).concat(~~(1e6*Math.random())),"resize.bootstrap-table-".concat(a)},hasDetailViewIcon:function(a){return a.detailView&&a.detailViewIcon&&!a.cardView},checkAutoMergeCells:function(a){var b,c,d,e,f,g,h=!0,i=!1,j=void 0;try{for(c=a[Symbol.iterator]();!(h=(b=c.next()).done);h=!0)for(d=b.value,e=0,f=Object.keys(d);ee&&h++,i=c;d>i;i++)a[i]&&g.push(a[i]);return{topOffset:e,bottomOffset:f,rowsAbove:h,rows:g}}},{key:"checkChanges",value:function(a,b){var c=b!==this.cache[a];return this.cache[a]=b,c}},{key:"getExtra",value:function(a,b){var c=document.createElement("tr");return c.className="virtual-scroll-".concat(a),b&&(c.style.height="".concat(b,"px")),c.outerHTML}}]),a}(),Gh=function(){function b(c,d){e(this,b),this.options=d,this.$el=a(c),this.$el_=this.$el.clone(),this.timeoutId_=0,this.timeoutFooter_=0,this.init()}return g(b,[{key:"init",value:function(){this.initConstants(),this.initLocale(),this.initContainer(),this.initTable(),this.initHeader(),this.initData(),this.initHiddenRows(),this.initToolbar(),this.initPagination(),this.initBody(),this.initSearchText(),this.initServer()}},{key:"initConstants",value:function(){var b,c=this.options;this.constants=qh.CONSTANTS,this.constants.theme=a.fn.bootstrapTable.theme,b=c.buttonsPrefix?"".concat(c.buttonsPrefix,"-"):"",this.constants.buttonsClass=[c.buttonsPrefix,b+c.buttonsClass,Ch.sprintf("".concat(b,"%s"),c.iconSize)].join(" ").trim()}},{key:"initLocale",value:function(){var b,c;this.options.locale&&(b=a.fn.bootstrapTable.locales,c=this.options.locale.split(/-|_/),c[0]=c[0].toLowerCase(),c[1]&&(c[1]=c[1].toUpperCase()),b[this.options.locale]?a.extend(this.options,b[this.options.locale]):b[c.join("-")]?a.extend(this.options,b[c.join("-")]):b[c[0]]&&a.extend(this.options,b[c[0]]))}},{key:"initContainer",value:function(){var b=["top","both"].includes(this.options.paginationVAlign)?'
    ':"",c=["bottom","both"].includes(this.options.paginationVAlign)?'
    ':"",d=Ch.calculateObjectValue(this.options,this.options.loadingTemplate,[this.options.formatLoadingMessage()]);this.$container=a('\n
    \n
    \n ').concat(b,'\n
    \n
    \n
    \n
    \n ').concat(d,'\n
    \n
    \n \n
    \n ').concat(c,"\n
    \n ")),this.$container.insertAfter(this.$el),this.$tableContainer=this.$container.find(".fixed-table-container"),this.$tableHeader=this.$container.find(".fixed-table-header"),this.$tableBody=this.$container.find(".fixed-table-body"),this.$tableLoading=this.$container.find(".fixed-table-loading"),this.$tableFooter=this.$el.find("tfoot"),this.$toolbar=this.options.buttonsToolbar?a("body").find(this.options.buttonsToolbar):this.$container.find(".fixed-table-toolbar"),this.$pagination=this.$container.find(".fixed-table-pagination"),this.$tableBody.append(this.$el),this.$container.after('
    '),this.$el.addClass(this.options.classes),this.$tableLoading.addClass(this.options.classes),this.options.height&&(this.$tableContainer.addClass("fixed-height"),this.options.showFooter&&this.$tableContainer.addClass("has-footer"),this.options.classes.split(" ").includes("table-bordered")&&(this.$tableBody.append('
    '),this.$tableBorder=this.$tableBody.find(".fixed-table-border"),this.$tableLoading.addClass("fixed-table-border")),this.$tableFooter=this.$container.find(".fixed-table-footer"))}},{key:"initTable",value:function(){var c,d=this,e=[];this.$header=this.$el.find(">thead"),this.$header.length?this.options.theadClasses&&this.$header.addClass(this.options.theadClasses):this.$header=a('')).appendTo(this.$el),this._headerTrClasses=[],this.$header.find("tr").each(function(b,c){var f=a(c),g=[];f.find("th").each(function(b,c){var d=a(c);"undefined"!=typeof d.data("field")&&d.data("field","".concat(d.data("field"))),g.push(a.extend({},{title:d.html(),"class":d.attr("class"),titleTooltip:d.attr("title"),rowspan:d.attr("rowspan")?+d.attr("rowspan"):void 0,colspan:d.attr("colspan")?+d.attr("colspan"):void 0},d.data()))}),e.push(g),f.attr("class")&&d._headerTrClasses.push(f.attr("class"))}),Array.isArray(this.options.columns[0])||(this.options.columns=[this.options.columns]),this.options.columns=a.extend(!0,[],e,this.options.columns),this.columns=[],this.fieldsColumnsIndex=[],Ch.setFieldIndex(this.options.columns),this.options.columns.forEach(function(c,e){c.forEach(function(c,f){var g=a.extend({},b.COLUMN_DEFAULTS,c);"undefined"!=typeof g.fieldIndex&&(d.columns[g.fieldIndex]=g,d.fieldsColumnsIndex[g.field]=g.fieldIndex),d.options.columns[e][f]=g})}),this.options.data.length||(c=Ch.trToData(this.columns,this.$el.find(">tbody>tr")),c.length&&(this.options.data=c,this.fromHtml=!0)),this.footerData=Ch.trToData(this.columns,this.$el.find(">tfoot>tr")),this.footerData&&this.$el.find("tfoot").html(""),!this.options.showFooter||this.options.cardView?this.$tableFooter.hide():this.$tableFooter.show()}},{key:"initHeader",value:function(){var b,c=this,d={},e=[];this.header={fields:[],styles:[],classes:[],formatters:[],detailFormatters:[],events:[],sorters:[],sortNames:[],cellStyles:[],searchables:[]},Ch.updateFieldGroup(this.options.columns),this.options.columns.forEach(function(a,b){e.push(""));var f="";0===b&&Ch.hasDetailViewIcon(c.options)&&(f='\n
    \n ')),f&&"right"!==c.options.detailViewAlign&&e.push(f),a.forEach(function(a,f){var g,i,j,k,l,m,n,o,p,q,r=Ch.sprintf(' class="%s"',a["class"]),s=a.widthUnit,t=parseFloat(a.width),u=Ch.sprintf("text-align: %s; ",a.halign?a.halign:a.align),v=Ch.sprintf("text-align: %s; ",a.align),w=Ch.sprintf("vertical-align: %s; ",a.valign);if(w+=Ch.sprintf("width: %s; ",!a.checkbox&&!a.radio||t?t?t+s:void 0:a.showSelectTitle?void 0:"36px"),"undefined"!=typeof a.fieldIndex||a.visible){if(g=Ch.calculateObjectValue(null,c.options.headerStyle,[a]),i=[],j="",g&&g.css)for(k=0,l=Object.entries(g.css);k0?" data-not-first-th":"",">"),e.push(Ch.sprintf('
    ',c.options.sortable&&a.sortable?"sortable both":"")),p=c.options.escape?Ch.escapeHTML(a.title):a.title,q=p,a.checkbox&&(p="",!c.options.singleSelect&&c.options.checkboxHeader&&(p=''),c.header.stateField=a.field),a.radio&&(p="",c.header.stateField=a.field),!p&&a.showSelectTitle&&(p+=q),e.push(p),e.push("
    "),e.push('
    '),e.push("
    "),e.push("")}}),f&&"right"===c.options.detailViewAlign&&e.push(f),e.push("")}),this.$header.html(e.join("")),this.$header.find("th[data-field]").each(function(b,c){a(c).data(d[a(c).data("field")])}),this.$container.off("click",".th-inner").on("click",".th-inner",function(b){var d=a(b.currentTarget);return c.options.detailView&&!d.parent().hasClass("bs-checkbox")&&d.closest(".bootstrap-table")[0]!==c.$container[0]?!1:(c.options.sortable&&d.parent().data().sortable&&c.onSort(b),void 0)}),this.$header.children().children().off("keypress").on("keypress",function(b){if(c.options.sortable&&a(b.currentTarget).data().sortable){var d=b.keyCode||b.which;13===d&&c.onSort(b)}}),b=Ch.getResizeEventName(this.$el.attr("id")),a(window).off(b),!this.options.showHeader||this.options.cardView?(this.$header.hide(),this.$tableHeader.hide(),this.$tableLoading.css("top",0)):(this.$header.show(),this.$tableHeader.show(),this.$tableLoading.css("top",this.$header.outerHeight()+1),this.getCaret(),a(window).on(b,function(){return c.resetView() +})),this.$selectAll=this.$header.find('[name="btSelectAll"]'),this.$selectAll.off("click").on("click",function(b){b.stopPropagation();var d=a(b.currentTarget).prop("checked");c[d?"checkAll":"uncheckAll"](),c.updateSelected()})}},{key:"initData",value:function(a,b){"append"===b?this.options.data=this.options.data.concat(a):"prepend"===b?this.options.data=[].concat(a).concat(this.options.data):(a=a||this.options.data,this.options.data=Array.isArray(a)?a:a[this.options.dataField]),this.data=i(this.options.data),this.options.sortReset&&(this.unsortedData=i(this.data)),"server"!==this.options.sidePagination&&this.initSort()}},{key:"initSort",value:function(){var a=this,b=this.options.sortName,c="desc"===this.options.sortOrder?-1:1,d=this.header.fields.indexOf(this.options.sortName),e=0;-1!==d?(this.options.sortStable&&this.data.forEach(function(a,b){a.hasOwnProperty("_position")||(a._position=b)}),this.options.customSort?Ch.calculateObjectValue(this.options,this.options.customSort,[this.options.sortName,this.options.sortOrder,this.data]):this.data.sort(function(e,f){var g,h,i;return a.header.sortNames[d]&&(b=a.header.sortNames[d]),g=Ch.getItemField(e,b,a.options.escape),h=Ch.getItemField(f,b,a.options.escape),i=Ch.calculateObjectValue(a.header,a.header.sorters[d],[g,h,e,f]),void 0!==i?a.options.sortStable&&0===i?c*(e._position-f._position):c*i:Ch.sort(g,h,c,a.options.sortStable,e._position,f._position)}),void 0!==this.options.sortClass&&(clearTimeout(e),e=setTimeout(function(){a.$el.removeClass(a.options.sortClass);var b=a.$header.find('[data-field="'.concat(a.options.sortName,'"]')).index();a.$el.find("tr td:nth-child(".concat(b+1,")")).addClass(a.options.sortClass)},250))):this.options.sortReset&&(this.data=i(this.unsortedData))}},{key:"onSort",value:function(b){var c,d=b.type,e=b.currentTarget,f="keypress"===d?a(e):a(e).parent(),g=this.$header.find("th").eq(f.index());return this.$header.add(this.$header_).find("span.order").remove(),this.options.sortName===f.data("field")?(c=this.options.sortOrder,void 0===c?this.options.sortOrder="asc":"asc"===c?this.options.sortOrder="desc":"desc"===this.options.sortOrder&&(this.options.sortOrder=this.options.sortReset?void 0:"asc"),void 0===this.options.sortOrder&&(this.options.sortName=void 0)):(this.options.sortName=f.data("field"),this.options.sortOrder=this.options.rememberOrder?"asc"===f.data("order")?"desc":"asc":this.columns[this.fieldsColumnsIndex[f.data("field")]].sortOrder||this.columns[this.fieldsColumnsIndex[f.data("field")]].order),this.trigger("sort",this.options.sortName,this.options.sortOrder),f.add(g).data("order",this.options.sortOrder),this.getCaret(),"server"===this.options.sidePagination&&this.options.serverSort?(this.options.pageNumber=1,this.initServer(this.options.silentSort),void 0):(this.initSort(),this.initBody(),void 0)}},{key:"initToolbar",value:function(){var b,c,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=this,w=this.options,x=[],y=0,z=0;this.$toolbar.find(".bs-bars").children().length&&a("body").append(a(w.toolbar)),this.$toolbar.html(""),("string"==typeof w.toolbar||"object"===d(w.toolbar))&&a(Ch.sprintf('
    ',this.constants.classes.pull,w.toolbarAlign)).appendTo(this.$toolbar).append(a(w.toolbar)),x=['
    ')],"string"==typeof w.icons&&(w.icons=Ch.calculateObjectValue(null,w.icons)),c={search:'"),paginationSwitch:'"),refresh:'"),toggle:'"),fullscreen:'"),columns:function(){var a,b,c=[];return c.push('
    \n \n ").concat(v.constants.html.toolbarDropdown[0])),w.showColumnsSearch&&(c.push(Ch.sprintf(v.constants.html.toolbarDropdownItem,Ch.sprintf('',v.constants.classes.input,w.formatSearch()))),c.push(v.constants.html.toolbarDropdownSeparator)),w.showColumnsToggleAll&&(a=v.getVisibleColumns().length===v.columns.filter(function(a){return!v.isSelectionColumn(a)}).length,c.push(Ch.sprintf(v.constants.html.toolbarDropdownItem,Ch.sprintf(' %s',a?'checked="checked"':"",w.formatColumnsToggleAll()))),c.push(v.constants.html.toolbarDropdownSeparator)),b=0,v.columns.forEach(function(a){a.visible&&b++}),v.columns.forEach(function(a,d){var e,f;v.isSelectionColumn(a)||(!w.cardView||a.cardVisible)&&(a.ignore||(e=a.visible?' checked="checked"':"",f=b<=v.options.minimumCountColumns&&e?' disabled="disabled"':"",a.switchable&&(c.push(Ch.sprintf(v.constants.html.toolbarDropdownItem,Ch.sprintf(' %s',a.field,d,e,f,a.title))),z++)))}),c.push(v.constants.html.toolbarDropdown[1],"
    "),c.join("")}()},"string"==typeof w.buttonsOrder&&(w.buttonsOrder=w.buttonsOrder.replace(/\[|\]| |'/g,"").toLowerCase().split(",")),e=!0,f=!1,g=void 0;try{for(i=w.buttonsOrder[Symbol.iterator]();!(e=(h=i.next()).done);e=!0)j=h.value,w["show"+j.charAt(0).toUpperCase()+j.substring(1)]&&x.push(c[j])}catch(A){f=!0,g=A}finally{try{e||null==i.return||i.return()}finally{if(f)throw g}}x.push("
    "),(this.showToolbar||x.length>2)&&this.$toolbar.append(x.join("")),w.showSearch&&this.$toolbar.find('button[name="showSearch"]').off("click").on("click",function(){return v.toggleShowSearch()}),w.showPaginationSwitch&&this.$toolbar.find('button[name="paginationSwitch"]').off("click").on("click",function(){return v.togglePagination()}),w.showFullscreen&&this.$toolbar.find('button[name="fullscreen"]').off("click").on("click",function(){return v.toggleFullscreen()}),w.showRefresh&&this.$toolbar.find('button[name="refresh"]').off("click").on("click",function(){return v.refresh()}),w.showToggle&&this.$toolbar.find('button[name="toggle"]').off("click").on("click",function(){v.toggleView()}),w.showColumns&&(b=this.$toolbar.find(".keep-open"),k=b.find('input[type="checkbox"]:not(".toggle-all")'),l=b.find('input[type="checkbox"].toggle-all'),z<=w.minimumCountColumns&&b.find("input").prop("disabled",!0),b.find("li, label").off("click").on("click",function(a){a.stopImmediatePropagation()}),k.off("click").on("click",function(b){var c=b.currentTarget,d=a(c);v._toggleColumn(d.val(),d.prop("checked"),!1),v.trigger("column-switch",d.data("field"),d.prop("checked")),l.prop("checked",k.filter(":checked").length===v.columns.filter(function(a){return!v.isSelectionColumn(a)}).length)}),l.off("click").on("click",function(b){var c=b.currentTarget;v._toggleAllColumns(a(c).prop("checked"))}),w.showColumnsSearch&&(m=b.find('[name="columnsSearch"]'),n=b.find(".dropdown-item-marker"),m.on("keyup paste change",function(b){var c=b.currentTarget,d=a(c),e=d.val().toLowerCase();n.show(),k.each(function(b,c){var d=a(c),f=d.parents(".dropdown-item-marker"),g=f.text().toLowerCase();g.includes(e)||f.hide()})}))),(w.search||this.showSearchClearButton)&&(x=[],o=Ch.sprintf(this.constants.html.searchButton,this.constants.buttonsClass,w.formatSearch(),w.showButtonIcons?Ch.sprintf(this.constants.html.icon,w.iconsPrefix,w.icons.search):"",w.showButtonText?w.formatSearch():""),p=Ch.sprintf(this.constants.html.searchClearButton,this.constants.buttonsClass,w.formatClearSearch(),w.showButtonIcons?Ch.sprintf(this.constants.html.icon,w.iconsPrefix,w.icons.clearSearch):"",w.showButtonText?w.formatClearSearch():""),q=''),r=q,(w.showSearchButton||w.showSearchClearButton)&&(s=(w.showSearchButton?o:"")+(w.showSearchClearButton?p:""),r=w.search?Ch.sprintf(this.constants.html.inputGroup,q,s):s),x.push(Ch.sprintf('\n
    \n %s\n
    \n '),r)),this.$toolbar.append(x.join("")),t=this.$toolbar.find(".search input"),u=function(){var a="keyup drop blur ".concat(Ch.isIEBrowser()?"mouseup":"");t.off(a).on(a,function(a){w.searchOnEnterKey&&13!==a.keyCode||[37,38,39,40].includes(a.keyCode)||(clearTimeout(y),y=setTimeout(function(){v.onSearch({currentTarget:a.currentTarget})},w.searchTimeOut))})},w.showSearchButton?(this.$toolbar.find(".search button[name=search]").off("click").on("click",function(){clearTimeout(y),y=setTimeout(function(){v.onSearch({currentTarget:t})},w.searchTimeOut)}),w.searchOnEnterKey&&u()):u(),w.showSearchClearButton&&this.$toolbar.find(".search button[name=clearSearch]").click(function(){v.resetSearch()}))}},{key:"onSearch",value:function(){var b,c=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},d=c.currentTarget,e=c.firedByInitSearchText,f=arguments.length>1&&void 0!==arguments[1]?arguments[1]:!0;if(void 0!==d&&a(d).length&&f){if(b=a(d).val().trim(),this.options.trimOnSearch&&a(d).val()!==b&&a(d).val(b),this.searchText===b&&b.length>0)return;a(d).hasClass("search-input")&&(this.searchText=b,this.options.searchText=b)}e||(this.options.pageNumber=1),this.initSearch(),e?"client"===this.options.sidePagination&&this.updatePagination():this.updatePagination(),this.trigger("search",this.searchText)}},{key:"initSearch",value:function(){var a,b,c,d=this;if(this.filterOptions=this.filterOptions||this.options.filterOptions,"server"!==this.options.sidePagination){if(this.options.customSearch)return this.data=Ch.calculateObjectValue(this.options,this.options.customSearch,[this.options.data,this.searchText,this.filterColumns]),void 0;a=this.searchText&&(this.fromHtml?Ch.escapeHTML(this.searchText):this.searchText).toLowerCase(),b=Ch.isEmptyObject(this.filterColumns)?null:this.filterColumns,"function"==typeof this.filterOptions.filterAlgorithm?this.data=this.options.data.filter(function(a){return d.filterOptions.filterAlgorithm.apply(null,[a,b])}):"string"==typeof this.filterOptions.filterAlgorithm&&(this.data=b?this.options.data.filter(function(a){var c,e,f,g=d.filterOptions.filterAlgorithm;if("and"===g){for(c in b)if(Array.isArray(b[c])&&!b[c].includes(a[c])||!Array.isArray(b[c])&&a[c]!==b[c])return!1}else if("or"===g){e=!1;for(f in b)(Array.isArray(b[f])&&b[f].includes(a[f])||!Array.isArray(b[f])&&a[f]===b[f])&&(e=!0);return e}return!0}):i(this.options.data)),c=this.getVisibleFields(),this.data=a?this.data.filter(function(b,e){var f,g,h,i,j,k,l,m,n,o,p,q,r;for(f=0;f|=<|>=|>|<)(?:\s+)?(\d+)?|(\d+)?(\s+)?(<=|=>|=<|>=|>|<))/gm,m=l.exec(a),n=!1,m)switch(o=m[1]||"".concat(m[5],"l"),p=m[2]||m[3],q=parseInt(i,10),r=parseInt(p,10),o){case">":case"r;break;case"<":case">l":n=r>q;break;case"<=":case"=<":case">=l":case"=>l":n=r>=q;break;case">=":case"=>":case"<=l":case"==r}if(n||"".concat(i).toLowerCase().includes(a))return!0}}return!1}):this.data,this.options.sortReset&&(this.unsortedData=i(this.data)),this.initSort()}}},{key:"initPagination",value:function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w=this,x=this.options;if(!x.pagination)return this.$pagination.hide(),void 0;if(this.$pagination.show(),b=[],c=!1,k=this.getData({includeHiddenRows:!1}),l=x.pageList,"string"==typeof l&&(l=l.replace(/\[|\]| /g,"").toLowerCase().split(",")),l=l.map(function(a){return"string"==typeof a?a.toLowerCase()===x.formatAllRows().toLowerCase()||["all","unlimited"].includes(a.toLowerCase())?x.formatAllRows():+a:a}),this.paginationParts=x.paginationParts,"string"==typeof this.paginationParts&&(this.paginationParts=this.paginationParts.replace(/\[|\]| |'/g,"").split(",")),"server"!==x.sidePagination&&(x.totalRows=k.length),this.totalPages=0,x.totalRows&&(x.pageSize===x.formatAllRows()&&(x.pageSize=x.totalRows,c=!0),this.totalPages=~~((x.totalRows-1)/x.pageSize)+1,x.totalPages=this.totalPages),this.totalPages>0&&x.pageNumber>this.totalPages&&(x.pageNumber=this.totalPages),this.pageFrom=(x.pageNumber-1)*x.pageSize+1,this.pageTo=x.pageNumber*x.pageSize,this.pageTo>x.totalRows&&(this.pageTo=x.totalRows),this.options.pagination&&"server"!==this.options.sidePagination&&(this.options.totalNotFiltered=this.options.data.length),this.options.showExtendedPagination||(this.options.totalNotFiltered=void 0),(this.paginationParts.includes("pageInfo")||this.paginationParts.includes("pageInfoShort")||this.paginationParts.includes("pageSize"))&&b.push('
    ')),(this.paginationParts.includes("pageInfo")||this.paginationParts.includes("pageInfoShort"))&&(m=this.paginationParts.includes("pageInfoShort")?x.formatDetailPagination(x.totalRows):x.formatShowingRows(this.pageFrom,this.pageTo,x.totalRows,x.totalNotFiltered),b.push('\n '.concat(m,"\n "))),this.paginationParts.includes("pageSize")&&(b.push(''),n=['\n \n ").concat(this.constants.html.pageDropdown[0])],l.forEach(function(a,b){if(!x.smartDisplay||0===b||l[b-1]")),b.push(x.formatRecordsPerPage(n.join("")))),(this.paginationParts.includes("pageInfo")||this.paginationParts.includes("pageInfoShort")||this.paginationParts.includes("pageSize"))&&b.push("
    "),this.paginationParts.includes("pageList")){if(b.push('
    '),Ch.sprintf(this.constants.html.pagination[0],Ch.sprintf(" pagination-%s",x.iconSize)),Ch.sprintf(this.constants.html.paginationItem," page-pre",x.formatSRPaginationPreText(),x.paginationPreText)),this.totalPagesthis.totalPages-e&&(e=e-(x.paginationSuccessivelySize-(this.totalPages-e))+1),1>e&&(e=1),f>this.totalPages&&(f=this.totalPages),o=Math.round(x.paginationPagesBySide/2),p=function(a){var b=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return Ch.sprintf(w.constants.html.paginationItem,b+(a===x.pageNumber?" ".concat(w.constants.classes.paginationActive):""),x.formatSRPaginationPageText(a),a)},e>1){for(q=x.paginationPagesBySide,q>=e&&(q=e-1),d=1;q>=d;d++)b.push(p(d));e-1===q+1?(d=e-1,b.push(p(d))):e-1>q&&(e-2*x.paginationPagesBySide>x.paginationPagesBySide&&x.paginationUseIntermediate?(d=Math.round((e-o)/2+o),b.push(p(d," page-intermediate"))):b.push(Ch.sprintf(this.constants.html.paginationItem," page-first-separator disabled","","...")))}for(d=e;f>=d;d++)b.push(p(d));if(this.totalPages>f)for(r=this.totalPages-(x.paginationPagesBySide-1),f>=r&&(r=f+1),f+1===r-1?(d=f+1,b.push(p(d))):r>f+1&&(this.totalPages-f>2*x.paginationPagesBySide&&x.paginationUseIntermediate?(d=Math.round((this.totalPages-o-f)/2+f),b.push(p(d," page-intermediate"))):b.push(Ch.sprintf(this.constants.html.paginationItem," page-last-separator disabled","","..."))),d=r;d<=this.totalPages;d++)b.push(p(d));b.push(Ch.sprintf(this.constants.html.paginationItem," page-next",x.formatSRPaginationNextText(),x.paginationNextText)),b.push(this.constants.html.pagination[1],"
    ")}this.$pagination.html(b.join("")),s=["bottom","both"].includes(x.paginationVAlign)?" ".concat(this.constants.classes.dropup):"",this.$pagination.last().find(".page-list > span").addClass(s),x.onlyInfoPagination||(g=this.$pagination.find(".page-list a"),h=this.$pagination.find(".page-pre"),i=this.$pagination.find(".page-next"),j=this.$pagination.find(".page-item").not(".page-next, .page-pre, .page-last-separator, .page-first-separator"),this.totalPages<=1&&this.$pagination.find("div.pagination").hide(),x.smartDisplay&&(l.length<2||x.totalRows<=l[0])&&this.$pagination.find("span.page-list").hide(),this.$pagination[this.getData().length?"show":"hide"](),x.paginationLoop||(1===x.pageNumber&&h.addClass("disabled"),x.pageNumber===this.totalPages&&i.addClass("disabled")),c&&(x.pageSize=x.formatAllRows()),g.off("click").on("click",function(a){return w.onPageListChange(a)}),h.off("click").on("click",function(a){return w.onPagePre(a)}),i.off("click").on("click",function(a){return w.onPageNext(a)}),j.off("click").on("click",function(a){return w.onPageNumber(a)})),this.options.showPageGo&&(t=this,u=this.$pagination.find("ul.pagination"),v=u.find("li.pageGo"),v.length||(v=a(['
  • ',Ch.sprintf('',this.options.pageNumber),'","
  • "].join("")).appendTo(u),v.find("button").click(function(){var a=parseInt(v.find("input").val())||1;(1>a||a>t.options.totalPages)&&(a=1),t.selectPage(a)})))}},{key:"updatePagination",value:function(b){b&&a(b.currentTarget).hasClass("disabled")||(this.options.maintainMetaData||this.resetRows(),this.initPagination(),this.trigger("page-change",this.options.pageNumber,this.options.pageSize),"server"===this.options.sidePagination?this.initServer():this.initBody())}},{key:"onPageListChange",value:function(b){b.preventDefault();var c=a(b.currentTarget);return c.parent().addClass(this.constants.classes.dropdownActive).siblings().removeClass(this.constants.classes.dropdownActive),this.options.pageSize=c.text().toUpperCase()===this.options.formatAllRows().toUpperCase()?this.options.formatAllRows():+c.text(),this.$toolbar.find(".page-size").text(this.options.pageSize),this.updatePagination(b),!1}},{key:"onPagePre",value:function(a){return a.preventDefault(),0===this.options.pageNumber-1?this.options.pageNumber=this.options.totalPages:this.options.pageNumber--,this.updatePagination(a),!1}},{key:"onPageNext",value:function(a){return a.preventDefault(),this.options.pageNumber+1>this.options.totalPages?this.options.pageNumber=1:this.options.pageNumber++,this.updatePagination(a),!1}},{key:"onPageNumber",value:function(b){return b.preventDefault(),this.options.pageNumber!==+a(b.currentTarget).text()?(this.options.pageNumber=+a(b.currentTarget).text(),this.updatePagination(b),!1):void 0}},{key:"initRow",value:function(a,b){var c,e,f,g,i,j,k,l,m,n,o,p,q,r,s,t,u=this,v=[],w={},x=[],y="",z={},A=[];if(!(Ch.findIndex(this.hiddenRows,a)>-1)){if(w=Ch.calculateObjectValue(this.options,this.options.rowStyle,[a,b],w),w&&w.css)for(c=0,e=Object.entries(w.css);c"),this.options.cardView&&v.push('
    ')),t="",Ch.hasDetailViewIcon(this.options)&&(t="",Ch.calculateObjectValue(null,this.options.detailFilter,[b,a])&&(t+='\n \n '.concat(Ch.sprintf(this.constants.html.icon,this.options.iconsPrefix,this.options.icons.detailOpen),"\n \n ")),t+=""),t&&"right"!==this.options.detailViewAlign&&v.push(t),this.header.fields.forEach(function(c,d){var e,f,g,i,j,k,l,m,n,o,p,q,r,s,t,w="",y=Ch.getItemField(a,c,u.options.escape),z="",A="",B={},C="",D=u.header.classes[d],E="",F="",G="",H="",I="",J=u.columns[d];if((!u.fromHtml&&!u.autoMergeCells||"undefined"!=typeof y||J.checkbox||J.radio)&&J.visible&&(!u.options.cardView||J.cardVisible)){if(J.escape&&(y=Ch.escapeHTML(y)),x.concat([u.header.styles[d]]).length&&(E=' style="'.concat(x.concat([u.header.styles[d]]).join("; "),'"')),a["_".concat(c,"_id")]&&(C=Ch.sprintf(' id="%s"',a["_".concat(c,"_id")])),a["_".concat(c,"_class")]&&(D=Ch.sprintf(' class="%s"',a["_".concat(c,"_class")])),a["_".concat(c,"_rowspan")]&&(G=Ch.sprintf(' rowspan="%s"',a["_".concat(c,"_rowspan")])),a["_".concat(c,"_colspan")]&&(H=Ch.sprintf(' colspan="%s"',a["_".concat(c,"_colspan")])),a["_".concat(c,"_title")]&&(I=Ch.sprintf(' title="%s"',a["_".concat(c,"_title")])),B=Ch.calculateObjectValue(u.header,u.header.cellStyles[d],[y,a,b,c],B),B.classes&&(D=' class="'.concat(B.classes,'"')),B.css){for(e=[],f=0,g=Object.entries(B.css);f'):'"),'"),u.header.formatters[d]&&"string"==typeof z?z:"",u.options.cardView?"
    ":""].join(""),a[u.header.stateField]=z===!0||!!y||z&&z.checked):(z="undefined"==typeof z||null===z?u.options.undefinedText:z,u.options.cardView?(t=u.options.showHeader?'").concat(Ch.getFieldTitle(u.columns,c),""):"",w='
    '.concat(t,'').concat(z,"
    "),u.options.smartDisplay&&""===z&&(w='
    ')):w="").concat(z,"")),v.push(w)}}),t&&"right"===this.options.detailViewAlign&&v.push(t),this.options.cardView&&v.push("
    "),v.push(""),v.join("")}}},{key:"initBody",value:function(b){var c,d,e,f,g,h,i=this,j=this.getData();for(this.trigger("pre-body",j),this.$body=this.$el.find(">tbody"),this.$body.length||(this.$body=a("").appendTo(this.$el)),this.options.pagination&&"server"!==this.options.sidePagination||(this.pageFrom=1,this.pageTo=j.length),c=[],d=a(document.createDocumentFragment()),e=!1,this.autoMergeCells=Ch.checkAutoMergeCells(j.slice(this.pageFrom-1,this.pageTo)),f=this.pageFrom-1;f'.concat(Ch.sprintf('%s',this.getVisibleFields().length,this.options.formatNoMatches()),"")),b||this.scrollTo(0),this.initBodyEvent(),this.updateSelected(),this.initFooter(),this.resetView(),"server"!==this.options.sidePagination&&(this.options.totalRows=j.length),this.trigger("post-body",j)}},{key:"initBodyEvent",value:function(){var b=this;this.$body.find("> tr[data-index] > td").off("click dblclick").on("click dblclick",function(c){var d,e=a(c.currentTarget),f=e.parent(),g=a(c.target).parents(".card-views").children(),h=a(c.target).parents(".card-view"),i=f.data("index"),j=b.data[i],k=b.options.cardView?g.index(h):e[0].cellIndex,l=b.getVisibleFields(),m=l[Ch.hasDetailViewIcon(b.options)&&"right"!==b.options.detailViewAlign?k-1:k],n=b.columns[b.fieldsColumnsIndex[m]],o=Ch.getItemField(j,m,b.options.escape);e.find(".detail-icon").length||(b.trigger("click"===c.type?"click-cell":"dbl-click-cell",m,o,j,e),b.trigger("click"===c.type?"click-row":"dbl-click-row",j,f,m),"click"===c.type&&b.options.clickToSelect&&n.clickToSelect&&!Ch.calculateObjectValue(b.options,b.options.ignoreClickToSelectOn,[c.target])&&(d=f.find(Ch.sprintf('[name="%s"]',b.options.selectItemName)),d.length&&d[0].click()),"click"===c.type&&b.options.detailViewByClick&&b.toggleDetailView(i,b.header.detailFormatters[b.fieldsColumnsIndex[m]]))}).off("mousedown").on("mousedown",function(a){b.multipleSelectRowCtrlKey=a.ctrlKey||a.metaKey,b.multipleSelectRowShiftKey=a.shiftKey}),this.$body.find("> tr[data-index] > td > .detail-icon").off("click").on("click",function(c){return c.preventDefault(),b.toggleDetailView(a(c.currentTarget).parent().parent().data("index")),!1}),this.$selectItem=this.$body.find(Ch.sprintf('[name="%s"]',this.options.selectItemName)),this.$selectItem.off("click").on("click",function(c){c.stopImmediatePropagation();var d=a(c.currentTarget);b._toggleCheck(d.prop("checked"),d.data("index"))}),this.header.events.forEach(function(c,d){var e,f,g,h,i,j=c;if(j&&("string"==typeof j&&(j=Ch.calculateObjectValue(null,j)),e=b.header.fields[d],f=b.getVisibleFields().indexOf(e),-1!==f)){Ch.hasDetailViewIcon(b.options)&&"right"!==b.options.detailViewAlign&&(f+=1),g=function(c){if(!j.hasOwnProperty(c))return"continue";var d=j[c];b.$body.find(">tr:not(.no-records-found)").each(function(g,h){var i=a(h),j=i.find(b.options.cardView?".card-views>.card-view":">td").eq(f),k=c.indexOf(" "),l=c.substring(0,k),m=c.substring(k+1);j.find(m).off(l).on(l,function(a){var c=i.data("index"),f=b.data[c],g=f[e];d.apply(b,[a,g,f,c])})})};for(h in j)i=g(h)}})}},{key:"initServer",value:function(b,c,d){var e,f,g,h,i,j,k,l=this,m={},n=this.header.fields.indexOf(this.options.sortName),o={searchText:this.searchText,sortName:this.options.sortName,sortOrder:this.options.sortOrder};if(this.header.sortNames[n]&&(o.sortName=this.header.sortNames[n]),this.options.pagination&&"server"===this.options.sidePagination&&(o.pageSize=this.options.pageSize===this.options.formatAllRows()?this.options.totalRows:this.options.pageSize,o.pageNumber=this.options.pageNumber),!this.options.firstLoad&&!firstLoadTable.includes(this.options.id))return firstLoadTable.push(this.options.id),void 0;if(d||this.options.url||this.options.ajax){if("limit"===this.options.queryParamsType&&(o={search:o.searchText,sort:o.sortName,order:o.sortOrder},this.options.pagination&&"server"===this.options.sidePagination&&(o.offset=this.options.pageSize===this.options.formatAllRows()?0:this.options.pageSize*(this.options.pageNumber-1),o.limit=this.options.pageSize===this.options.formatAllRows()?this.options.totalRows:this.options.pageSize,0===o.limit&&delete o.limit)),this.options.search&&"server"===this.options.sidePagination&&this.columns.filter(function(a){return!a.searchable}).length){o.searchable=[],e=!0,f=!1,g=void 0;try{for(i=this.columns[Symbol.iterator]();!(e=(h=i.next()).done);e=!0)j=h.value,!j.checkbox&&j.searchable&&(this.options.visibleSearch&&j.visible||!this.options.visibleSearch)&&o.searchable.push(j.field)}catch(p){f=!0,g=p}finally{try{e||null==i.return||i.return()}finally{if(f)throw g}}}if(Ch.isEmptyObject(this.filterColumnsPartial)||(o.filter=JSON.stringify(this.filterColumnsPartial,null)),a.extend(o,c||{}),m=Ch.calculateObjectValue(this.options,this.options.queryParams,[o],m),m!==!1)return b||this.showLoading(),k=a.extend({},Ch.calculateObjectValue(null,this.options.ajaxOptions),{type:this.options.method,url:d||this.options.url,data:"application/json"===this.options.contentType&&"post"===this.options.method?JSON.stringify(m):m,cache:this.options.cache,contentType:this.options.contentType,dataType:this.options.dataType,success:function(a,c,d){var e=Ch.calculateObjectValue(l.options,l.options.responseHandler,[a,d],a); +l.load(e),l.trigger("load-success",e,d&&d.status,d),b||l.hideLoading(),"server"===l.options.sidePagination&&e[l.options.totalField]>0&&!e[l.options.dataField].length&&l.updatePagination()},error:function(a){var c=[];"server"===l.options.sidePagination&&(c={},c[l.options.totalField]=0,c[l.options.dataField]=[]),l.load(c),l.trigger("load-error",a&&a.status,a),b||l.$tableLoading.hide()}}),this.options.ajax?Ch.calculateObjectValue(this,this.options.ajax,[k],null):(this._xhr&&4!==this._xhr.readyState&&this._xhr.abort(),this._xhr=a.ajax(k)),m}}},{key:"initSearchText",value:function(){if(this.options.search&&(this.searchText="",""!==this.options.searchText)){var a=this.$toolbar.find(".search input");a.val(this.options.searchText),this.onSearch({currentTarget:a,firedByInitSearchText:!0})}}},{key:"getCaret",value:function(){var b=this;this.$header.find("th").each(function(c,d){a(d).find(".sortable").removeClass("desc asc").addClass(a(d).data("field")===b.options.sortName?b.options.sortOrder:"both")})}},{key:"updateSelected",value:function(){var b=this.$selectItem.filter(":enabled").length&&this.$selectItem.filter(":enabled").length===this.$selectItem.filter(":enabled").filter(":checked").length;this.$selectAll.add(this.$selectAll_).prop("checked",b),this.$selectItem.each(function(b,c){a(c).closest("tr")[a(c).prop("checked")?"addClass":"removeClass"]("selected")})}},{key:"updateRows",value:function(){var b=this;this.$selectItem.each(function(c,d){b.data[a(d).data("index")][b.header.stateField]=a(d).prop("checked")})}},{key:"resetRows",value:function(){var a,b,c,d=!0,e=!1,f=void 0;try{for(b=this.data[Symbol.iterator]();!(d=(a=b.next()).done);d=!0)c=a.value,this.$selectAll.prop("checked",!1),this.$selectItem.prop("checked",!1),this.header.stateField&&(c[this.header.stateField]=!1)}catch(g){e=!0,f=g}finally{try{d||null==b.return||b.return()}finally{if(e)throw f}}this.initHiddenRows()}},{key:"trigger",value:function(c){var d,e,f,g,h="".concat(c,".bs.table");for(e=arguments.length,f=new Array(e>1?e-1:0),g=1;e>g;g++)f[g-1]=arguments[g];(d=this.options)[b.EVENTS[h]].apply(d,f),this.$el.trigger(a.Event(h),f),this.options.onAll(h,f),this.$el.trigger(a.Event("all.bs.table"),[h,f])}},{key:"resetHeader",value:function(){var a=this;clearTimeout(this.timeoutId_),this.timeoutId_=setTimeout(function(){return a.fitHeader()},this.$el.is(":hidden")?100:0)}},{key:"fitHeader",value:function(){var b,c,d,e,f,g,h,i,j,k,l,m=this;if(this.$el.is(":hidden"))return this.timeoutId_=setTimeout(function(){return m.fitHeader()},100),void 0;for(b=this.$tableBody.get(0),c=b.scrollWidth>b.clientWidth&&b.scrollHeight>b.clientHeight+this.$header.outerHeight()?Ch.getScrollBarWidth():0,this.$el.css("margin-top",-this.$header.outerHeight()),d=a(":focus"),d.length>0&&(e=d.parents("th"),e.length>0&&(f=e.attr("data-field"),void 0!==f&&(g=this.$header.find("[data-field='".concat(f,"']")),g.length>0&&g.find(":input").addClass("focus-temp")))),this.$header_=this.$header.clone(!0,!0),this.$selectAll_=this.$header_.find('[name="btSelectAll"]'),this.$tableHeader.css("margin-right",c).find("table").css("width",this.$el.outerWidth()).html("").attr("class",this.$el.attr("class")).append(this.$header_),this.$tableLoading.css("width",this.$el.outerWidth()),h=a(".focus-temp:visible:eq(0)"),h.length>0&&(h.focus(),this.$header.find(".focus-temp").removeClass("focus-temp")),this.$header.find("th[data-field]").each(function(b,c){m.$header_.find(Ch.sprintf('th[data-field="%s"]',a(c).data("field"))).data(a(c).data())}),i=this.getVisibleFields(),j=this.$header_.find("th"),k=this.$body.find(">tr:not(.no-records-found,.virtual-scroll-top)").eq(0);k.length&&k.find('>td[colspan]:not([colspan="1"])').length;)k=k.next();l=k.find("> *").length,k.find("> *").each(function(b,c){var d,e,f,g,h,k=a(c);return Ch.hasDetailViewIcon(m.options)&&(0===b&&"right"!==m.options.detailViewAlign||b===l-1&&"right"===m.options.detailViewAlign)?(d=j.filter(".detail"),e=d.innerWidth()-d.find(".fht-cell").width(),d.find(".fht-cell").width(k.innerWidth()-e),void 0):(f=Ch.hasDetailViewIcon(m.options)&&"right"!==m.options.detailViewAlign?b-1:b,g=m.$header_.find(Ch.sprintf('th[data-field="%s"]',i[f])),g.length>1&&(g=a(j[k[0].cellIndex])),h=g.innerWidth()-g.find(".fht-cell").width(),g.find(".fht-cell").width(k.innerWidth()-h),void 0)}),this.horizontalScroll(),this.trigger("post-header")}},{key:"initFooter",value:function(){var a,b,c,d,e,f,g,i,j,k,l,m,n,o,p,q,r,s,t;if(this.options.showFooter&&!this.options.cardView){a=this.getData(),b=[],c="",Ch.hasDetailViewIcon(this.options)&&(c='
    '),c&&"right"!==this.options.detailViewAlign&&b.push(c),d=!0,e=!1,f=void 0;try{for(i=this.columns[Symbol.iterator]();!(d=(g=i.next()).done);d=!0)if(j=g.value,k="",l="",m=[],n={},o=Ch.sprintf(' class="%s"',j["class"]),j.visible){if(this.options.cardView&&!j.cardVisible)return;if(k=Ch.sprintf("text-align: %s; ",j.falign?j.falign:j.align),l=Ch.sprintf("vertical-align: %s; ",j.valign),n=Ch.calculateObjectValue(null,this.options.footerStyle,[j]),n&&n.css)for(p=0,q=Object.entries(n.css);p"),b.push('
    '),b.push(Ch.calculateObjectValue(j,j.footerFormatter,[a],this.footerData[0]&&this.footerData[0][j.field]||"")),b.push("
    "),b.push('
    '),b.push(""),b.push("")}}catch(u){e=!0,f=u}finally{try{d||null==i.return||i.return()}finally{if(e)throw f}}c&&"right"===this.options.detailViewAlign&&b.push(c),this.options.height||this.$tableFooter.length||(this.$el.append(""),this.$tableFooter=this.$el.find("tfoot")),this.$tableFooter.find("tr").html(b.join("")),this.trigger("post-footer",this.$tableFooter)}}},{key:"fitFooter",value:function(){var b,c,d,e,f,g=this;if(this.$el.is(":hidden"))return setTimeout(function(){return g.fitFooter()},100),void 0;for(b=this.$tableBody.get(0),c=b.scrollWidth>b.clientWidth&&b.scrollHeight>b.clientHeight+this.$header.outerHeight()?Ch.getScrollBarWidth():0,this.$tableFooter.css("margin-right",c).find("table").css("width",this.$el.outerWidth()).attr("class",this.$el.attr("class")),this.getVisibleFields(),d=this.$tableFooter.find("th"),e=this.$body.find(">tr:first-child:not(.no-records-found)");e.length&&e.find('>td[colspan]:not([colspan="1"])').length;)e=e.next();f=e.find("> *").length,e.find("> *").each(function(b,c){var e,h,i,j,k=a(c);return Ch.hasDetailViewIcon(g.options)&&(0===b&&"left"===g.options.detailViewAlign||b===f-1&&"right"===g.options.detailViewAlign)?(e=d.filter(".detail"),h=e.innerWidth()-e.find(".fht-cell").width(),e.find(".fht-cell").width(k.innerWidth()-h),void 0):(i=d.eq(b),j=i.innerWidth()-i.find(".fht-cell").width(),i.find(".fht-cell").width(k.innerWidth()-j),void 0)}),this.horizontalScroll()}},{key:"horizontalScroll",value:function(){var a=this;this.$tableBody.off("scroll").on("scroll",function(){var b=a.$tableBody.scrollLeft();a.options.showHeader&&a.options.height&&a.$tableHeader.scrollLeft(b),a.options.showFooter&&!a.options.cardView&&a.$tableFooter.scrollLeft(b),a.trigger("scroll-body",a.$tableBody)})}},{key:"getVisibleFields",value:function(){var a,b,c,d,e=[],f=!0,g=!1,h=void 0;try{for(b=this.header.fields[Symbol.iterator]();!(f=(a=b.next()).done);f=!0)c=a.value,d=this.columns[this.fieldsColumnsIndex[c]],d&&d.visible&&e.push(c)}catch(i){g=!0,h=i}finally{try{f||null==b.return||b.return()}finally{if(g)throw h}}return e}},{key:"initHiddenRows",value:function(){this.hiddenRows=[]}},{key:"getOptions",value:function(){var b=a.extend({},this.options);return delete b.data,a.extend(!0,{},b)}},{key:"refreshOptions",value:function(b){Ch.compareObjects(this.options,b,!0)||(this.options=a.extend(this.options,b),this.trigger("refresh-options",this.options),this.destroy(),this.init())}},{key:"getData",value:function(a){var b,c=this,d=this.options.data;return!(this.searchText||this.options.customSearch||this.options.sortName)&&Ch.isEmptyObject(this.filterColumns)&&Ch.isEmptyObject(this.filterColumnsPartial)||a&&a.unfiltered||(d=this.data),a&&a.useCurrentPage&&(d=d.slice(this.pageFrom-1,this.pageTo)),a&&!a.includeHiddenRows&&(b=this.getHiddenRows(),d=d.filter(function(a){return-1===Ch.findIndex(b,a)})),a&&a.formatted&&d.forEach(function(a){var b,d,e,f,g,i;for(b=0,d=Object.entries(a);b=0;b--)d=!1,c=this.options.data[b],(c.hasOwnProperty(a.field)||"$index"===a.field)&&(d=c.hasOwnProperty(a.field)||"$index"!==a.field?a.values.includes(c[a.field]):a.values.includes(b),d&&(this.options.data.splice(b,1),"server"===this.options.sidePagination&&(this.options.totalRows-=1)));e!==this.options.data.length&&(this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0))}}},{key:"removeAll",value:function(){this.options.data.length>0&&(this.options.data.splice(0,this.options.data.length),this.initSearch(),this.initPagination(),this.initBody(!0))}},{key:"insertRow",value:function(a){a.hasOwnProperty("index")&&a.hasOwnProperty("row")&&(this.options.data.splice(a.index,0,a.row),this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0))}},{key:"updateRow",value:function(b){var c,d,e,f=Array.isArray(b)?b:[b],g=!0,h=!1,i=void 0;try{for(d=f[Symbol.iterator]();!(g=(c=d.next()).done);g=!0)e=c.value,e.hasOwnProperty("index")&&e.hasOwnProperty("row")&&(e.hasOwnProperty("replace")&&e.replace?this.options.data[e.index]=e.row:a.extend(this.options.data[e.index],e.row))}catch(j){h=!0,i=j}finally{try{g||null==d.return||d.return()}finally{if(h)throw i}}this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0)}},{key:"getRowByUniqueId",value:function(a){var b,c,d,e=this.options.uniqueId,f=this.options.data.length,g=a,h=null;for(b=f-1;b>=0;b--){if(c=this.options.data[b],c.hasOwnProperty(e))d=c[e];else{if(!c._data||!c._data.hasOwnProperty(e))continue;d=c._data[e]}if("string"==typeof d?g=g.toString():"number"==typeof d&&(Number(d)===d&&0===d%1?g=parseInt(g):d===Number(d)&&0!==d&&(g=parseFloat(g))),d===g){h=c;break}}return h}},{key:"updateByUniqueId",value:function(b){var c,d,e,f,g=Array.isArray(b)?b:[b],h=!0,i=!1,j=void 0;try{for(d=g[Symbol.iterator]();!(h=(c=d.next()).done);h=!0)e=c.value,e.hasOwnProperty("id")&&e.hasOwnProperty("row")&&(f=this.options.data.indexOf(this.getRowByUniqueId(e.id)),-1!==f&&(e.hasOwnProperty("replace")&&e.replace?this.options.data[f]=e.row:a.extend(this.options.data[f],e.row)))}catch(k){i=!0,j=k}finally{try{h||null==d.return||d.return()}finally{if(i)throw j}}this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0)}},{key:"removeByUniqueId",value:function(a){var b=this.options.data.length,c=this.getRowByUniqueId(a);c&&this.options.data.splice(this.options.data.indexOf(c),1),b!==this.options.data.length&&(this.initSearch(),this.initPagination(),this.initBody(!0))}},{key:"updateCell",value:function(a){a.hasOwnProperty("index")&&a.hasOwnProperty("field")&&a.hasOwnProperty("value")&&(this.data[a.index][a.field]=a.value,a.reinit!==!1&&(this.initSort(),this.initBody(!0)))}},{key:"updateCellByUniqueId",value:function(a){var b=this,c=Array.isArray(a)?a:[a];c.forEach(function(a){var c=a.id,d=a.field,e=a.value,f=b.options.data.indexOf(b.getRowByUniqueId(c));-1!==f&&(b.options.data[f][d]=e)}),a.reinit!==!1&&(this.initSort(),this.initBody(!0))}},{key:"showRow",value:function(a){this._toggleRow(a,!0)}},{key:"hideRow",value:function(a){this._toggleRow(a,!1)}},{key:"_toggleRow",value:function(a,b){var c,d;a.hasOwnProperty("index")?c=this.getData()[a.index]:a.hasOwnProperty("uniqueId")&&(c=this.getRowByUniqueId(a.uniqueId)),c&&(d=Ch.findIndex(this.hiddenRows,c),b||-1!==d?b&&d>-1&&this.hiddenRows.splice(d,1):this.hiddenRows.push(c),this.initBody(!0),this.initPagination())}},{key:"getHiddenRows",value:function(a){var b,c,d,e,f,g,h,i;if(a)return this.initHiddenRows(),this.initBody(!0),this.initPagination(),void 0;b=this.getData(),c=[],d=!0,e=!1,f=void 0;try{for(h=b[Symbol.iterator]();!(d=(g=h.next()).done);d=!0)i=g.value,this.hiddenRows.includes(i)&&c.push(i)}catch(j){e=!0,f=j}finally{try{d||null==h.return||h.return()}finally{if(e)throw f}}return this.hiddenRows=c,c}},{key:"showColumn",value:function(a){var b=this,c=Array.isArray(a)?a:[a];c.forEach(function(a){b._toggleColumn(b.fieldsColumnsIndex[a],!0,!0)})}},{key:"hideColumn",value:function(a){var b=this,c=Array.isArray(a)?a:[a];c.forEach(function(a){b._toggleColumn(b.fieldsColumnsIndex[a],!1,!0)})}},{key:"_toggleColumn",value:function(a,b,c){if(-1!==a&&this.columns[a].visible!==b&&(this.columns[a].visible=b,this.initHeader(),this.initSearch(),this.initPagination(),this.initBody(),this.options.showColumns)){var d=this.$toolbar.find('.keep-open input:not(".toggle-all")').prop("disabled",!1);c&&d.filter(Ch.sprintf('[value="%s"]',a)).prop("checked",b),d.filter(":checked").length<=this.options.minimumCountColumns&&d.filter(":checked").prop("disabled",!0)}}},{key:"getVisibleColumns",value:function(){var a=this;return this.columns.filter(function(b){return b.visible&&!a.isSelectionColumn(b)})}},{key:"getHiddenColumns",value:function(){return this.columns.filter(function(a){var b=a.visible;return!b})}},{key:"isSelectionColumn",value:function(a){return a.radio||a.checkbox}},{key:"showAllColumns",value:function(){this._toggleAllColumns(!0)}},{key:"hideAllColumns",value:function(){this._toggleAllColumns(!1)}},{key:"_toggleAllColumns",value:function(b){var c,d,e,f,g=this,h=!0,i=!1,j=void 0;try{for(d=this.columns.slice().reverse()[Symbol.iterator]();!(h=(c=d.next()).done);h=!0)if(e=c.value,e.switchable){if(!b&&this.options.showColumns&&this.getVisibleColumns().length===this.options.minimumCountColumns)continue;e.visible=b}}catch(k){i=!0,j=k}finally{try{h||null==d.return||d.return()}finally{if(i)throw j}}this.initHeader(),this.initSearch(),this.initPagination(),this.initBody(),this.options.showColumns&&(f=this.$toolbar.find('.keep-open input[type="checkbox"]:not(".toggle-all")').prop("disabled",!1),b?f.prop("checked",b):f.get().reverse().forEach(function(c){f.filter(":checked").length>g.options.minimumCountColumns&&a(c).prop("checked",b)}),f.filter(":checked").length<=this.options.minimumCountColumns&&f.filter(":checked").prop("disabled",!0))}},{key:"mergeCells",value:function(a){var b,c,d,e=a.index,f=this.getVisibleFields().indexOf(a.field),g=a.rowspan||1,h=a.colspan||1,i=this.$body.find(">tr");if(Ch.hasDetailViewIcon(this.options)&&(f+=1),d=i.eq(e).find(">td").eq(f),!(0>e||0>f||e>=this.data.length)){for(b=e;e+g>b;b++)for(c=f;f+h>c;c++)i.eq(b).find(">td").eq(c).hide();d.attr("rowspan",g).attr("colspan",h).show()}}},{key:"checkAll",value:function(){this._toggleCheckAll(!0)}},{key:"uncheckAll",value:function(){this._toggleCheckAll(!1)}},{key:"_toggleCheckAll",value:function(a){var b,c=this.getSelections();return this.$selectAll.add(this.$selectAll_).prop("checked",a),this.$selectItem.filter(":enabled").prop("checked",a),this.updateRows(),b=this.getSelections(),a?(this.trigger("check-all",b,c),void 0):(this.trigger("uncheck-all",b,c),void 0)}},{key:"checkInvert",value:function(){var b=this.$selectItem.filter(":enabled"),c=b.filter(":checked");b.each(function(b,c){a(c).prop("checked",!a(c).prop("checked"))}),this.updateRows(),this.updateSelected(),this.trigger("uncheck-some",c),c=this.getSelections(),this.trigger("check-some",c)}},{key:"check",value:function(a){this._toggleCheck(!0,a)}},{key:"uncheck",value:function(a){this._toggleCheck(!1,a)}},{key:"_toggleCheck",value:function(a,b){var c,d,e,f,g,h,i,j,k=this.$selectItem.filter('[data-index="'.concat(b,'"]')),l=this.data[b];if(k.is(":radio")||this.options.singleSelect||this.options.multipleSelectRow&&!this.multipleSelectRowCtrlKey&&!this.multipleSelectRowShiftKey){c=!0,d=!1,e=void 0;try{for(g=this.options.data[Symbol.iterator]();!(c=(f=g.next()).done);c=!0)h=f.value,h[this.header.stateField]=!1}catch(m){d=!0,e=m}finally{try{c||null==g.return||g.return()}finally{if(d)throw e}}this.$selectItem.filter(":checked").not(k).prop("checked",!1)}if(l[this.header.stateField]=a,this.options.multipleSelectRow){if(this.multipleSelectRowShiftKey&&this.multipleSelectRowLastSelectedIndex>=0)for(i=[this.multipleSelectRowLastSelectedIndex,b].sort(),j=i[0]+1;j0&&this.$selectItem.length===this.$selectItem.filter(":checked").length),this.$tableContainer.toggleClass("has-card-view",this.options.cardView),!this.options.cardView&&this.options.showHeader&&this.options.height?(this.$tableHeader.show(),this.resetHeader(),h+=this.$header.outerHeight(!0)+1):(this.$tableHeader.hide(),this.trigger("post-header")),!this.options.cardView&&this.options.showFooter&&(this.$tableFooter.show(),this.fitFooter(),this.options.height&&(h+=this.$tableFooter.outerHeight(!0))),this.$container.hasClass("fullscreen")?(this.$tableContainer.css("height",""),this.$tableContainer.css("width","")):this.options.height&&(this.$tableBorder&&(this.$tableBorder.css("width",""),this.$tableBorder.css("height","")),b=this.$toolbar.outerHeight(!0),c=this.$pagination.outerHeight(!0),d=this.options.height-b-c,e=this.$tableBody.find(">table"),f=e.outerHeight(),this.$tableContainer.css("height","".concat(d,"px")),this.$tableBorder&&e.is(":visible")&&(g=d-f-2,this.$tableBody[0].scrollWidth-this.$tableBody.innerWidth()&&(g-=Ch.getScrollBarWidth()),this.$tableBorder.css("width","".concat(e.outerWidth(),"px")),this.$tableBorder.css("height","".concat(g,"px")))),this.options.cardView?(this.$el.css("margin-top","0"),this.$tableContainer.css("padding-bottom","0"),this.$tableFooter.hide()):(this.getCaret(),this.$tableContainer.css("padding-bottom","".concat(h,"px"))),this.trigger("reset-view")}},{key:"showLoading",value:function(){this.$tableLoading.css("display","flex");var a=this.options.loadingFontSize;"auto"===this.options.loadingFontSize&&(a=.04*this.$tableLoading.width(),a=Math.max(12,a),a=Math.min(32,a),a="".concat(a,"px")),this.$tableLoading.find(".loading-text").css("font-size",a)}},{key:"hideLoading",value:function(){this.$tableLoading.css("display","none")}},{key:"toggleShowSearch",value:function(){this.$el.parents(".select-table").siblings().slideToggle()}},{key:"togglePagination",value:function(){var a,b;this.options.pagination=!this.options.pagination,a=this.options.showButtonIcons?this.options.pagination?this.options.icons.paginationSwitchDown:this.options.icons.paginationSwitchUp:"",b=this.options.showButtonText?this.options.pagination?this.options.formatPaginationSwitchUp():this.options.formatPaginationSwitchDown():"",this.$toolbar.find('button[name="paginationSwitch"]').html(Ch.sprintf(this.constants.html.icon,this.options.iconsPrefix,a)+" "+b),this.updatePagination()}},{key:"toggleFullscreen",value:function(){this.$el.closest(".bootstrap-table").toggleClass("fullscreen"),this.resetView()}},{key:"toggleView",value:function(){var a,b;this.options.cardView=!this.options.cardView,this.initHeader(),a=this.options.showButtonIcons?this.options.cardView?this.options.icons.toggleOn:this.options.icons.toggleOff:"",b=this.options.showButtonText?this.options.cardView?this.options.formatToggleOff():this.options.formatToggleOn():"",this.$toolbar.find('button[name="toggle"]').html(Ch.sprintf(this.constants.html.icon,this.options.iconsPrefix,a)+" "+b),this.initBody(),this.trigger("toggle",this.options.cardView)}},{key:"resetSearch",value:function(a){var b=this.$toolbar.find(".search input");b.val(a||""),this.onSearch({currentTarget:b})}},{key:"filterBy",value:function(b,c){this.filterOptions=Ch.isEmptyObject(c)?this.options.filterOptions:a.extend(this.options.filterOptions,c),this.filterColumns=Ch.isEmptyObject(b)?{}:b,this.options.pageNumber=1,this.initSearch(),this.updatePagination()}},{key:"scrollTo",value:function c(b){var e,c;return"undefined"==typeof b?this.$tableBody.scrollTop():(e={unit:"px",value:0},"object"===d(b)?e=Object.assign(e,b):"string"==typeof b&&"bottom"===b?e.value=this.$tableBody[0].scrollHeight:("string"==typeof b||"number"==typeof b)&&(e.value=b),c=e.value,"rows"===e.unit&&(c=0,this.$body.find("> tr:lt(".concat(e.value,")")).each(function(b,d){c+=a(d).outerHeight(!0)})),this.$tableBody.scrollTop(c),void 0)}},{key:"getScrollPosition",value:function(){return this.scrollTo()}},{key:"selectPage",value:function(a){a>0&&a<=this.options.totalPages&&(this.options.pageNumber=a,this.updatePagination())}},{key:"prevPage",value:function(){this.options.pageNumber>1&&(this.options.pageNumber--,this.updatePagination())}},{key:"nextPage",value:function(){this.options.pageNumber tr[data-index="%s"]',a));c.next().is("tr.detail-view")?this.collapseRow(a):this.expandRow(a,b),this.resetView()}},{key:"expandRow",value:function(a,b){var c,d,e,f=this.data[a],g=this.$body.find(Ch.sprintf('> tr[data-index="%s"][data-has-detail-view]',a));g.next().is("tr.detail-view")||(this.options.detailViewIcon&&g.find("a.detail-icon").html(Ch.sprintf(this.constants.html.icon,this.options.iconsPrefix,this.options.icons.detailClose)),g.after(Ch.sprintf('',g.children("td").length)),c=g.next().find("td"),d=b||this.options.detailFormatter,e=Ch.calculateObjectValue(this.options,d,[a,f,c],""),1===c.length&&c.append(e),this.trigger("expand-row",a,f,c))}},{key:"expandRowByUniqueId",value:function(a){var b=this.getRowByUniqueId(a);b&&this.expandRow(this.data.indexOf(b))}},{key:"collapseRow",value:function(a){var b=this.data[a],c=this.$body.find(Ch.sprintf('> tr[data-index="%s"][data-has-detail-view]',a));c.next().is("tr.detail-view")&&(this.options.detailViewIcon&&c.find("a.detail-icon").html(Ch.sprintf(this.constants.html.icon,this.options.iconsPrefix,this.options.icons.detailOpen)),this.trigger("collapse-row",a,b,c.next()),c.next().remove())}},{key:"collapseRowByUniqueId",value:function(a){var b=this.getRowByUniqueId(a);b&&this.collapseRow(this.data.indexOf(b))}},{key:"expandAllRows",value:function(){var b,c=this.$body.find("> tr[data-index][data-has-detail-view]");for(b=0;b tr[data-index][data-has-detail-view]");for(b=0;b1?c-1:0),f=1;c>f;f++)e[f-1]=arguments[f];return this.each(function(c,f){var h,i=a(f).data("bootstrap.table"),j=a.extend({},Gh.DEFAULTS,a(f).data(),"object"===d(b)&&b);if("string"==typeof b){if(!qh.METHODS.includes(b))throw new Error("Unknown method: ".concat(b));if(!i)return;g=(h=i)[b].apply(h,e),"destroy"===b&&a(f).removeData("bootstrap.table")}i||a(f).data("bootstrap.table",i=new a.BootstrapTable(f,j))}),"undefined"==typeof g?this:g},a.fn.bootstrapTable.Constructor=Gh,a.fn.bootstrapTable.theme=qh.THEME,a.fn.bootstrapTable.VERSION=qh.VERSION,a.fn.bootstrapTable.defaults=Gh.DEFAULTS,a.fn.bootstrapTable.columnDefaults=Gh.COLUMN_DEFAULTS,a.fn.bootstrapTable.events=Gh.EVENTS,a.fn.bootstrapTable.locales=Gh.LOCALES,a.fn.bootstrapTable.methods=Gh.METHODS,a.fn.bootstrapTable.utils=Ch,a(function(){a('[data-toggle="table"]').bootstrapTable()}),Gh}),TABLE_EVENTS="all.bs.table click-cell.bs.table dbl-click-cell.bs.table click-row.bs.table dbl-click-row.bs.table sort.bs.table check.bs.table uncheck.bs.table onUncheck check-all.bs.table uncheck-all.bs.table check-some.bs.table uncheck-some.bs.table load-success.bs.table load-error.bs.table column-switch.bs.table page-change.bs.table search.bs.table toggle.bs.table show-search.bs.table expand-row.bs.table collapse-row.bs.table refresh-options.bs.table reset-view.bs.table refresh.bs.table",firstLoadTable=[],union=function(a,b){return $.isPlainObject(b)?addRememberRow(a,b):$.isArray(b)?$.each(b,function(b,c){$.isPlainObject(c)?addRememberRow(a,c):-1==$.inArray(c,a)&&(a[a.length]=c)}):-1==$.inArray(b,a)&&(a[a.length]=b),a},difference=function(a,b){if($.isPlainObject(b))removeRememberRow(a,b);else if($.isArray(b))$.each(b,function(b,c){if($.isPlainObject(c))removeRememberRow(a,c);else{var d=$.inArray(c,a);-1!=d&&a.splice(d,1)}});else{var c=$.inArray(b,a);-1!=c&&a.splice(c,1)}return a},_={union:union,difference:difference}; \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/auto-refresh/bootstrap-table-auto-refresh.min.js b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/auto-refresh/bootstrap-table-auto-refresh.min.js new file mode 100644 index 000000000..fa9432a24 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-table/extensions/auto-refresh/bootstrap-table-auto-refresh.min.js @@ -0,0 +1,10 @@ +/** + * bootstrap-table - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.17.1 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ + +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],e):e((t=t||self).jQuery)}(this,(function(t){"use strict";t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function n(t,e){return t(e={exports:{}},e.exports),e.exports}var r=function(t){return t&&t.Math==Math&&t},o=r("object"==typeof globalThis&&globalThis)||r("object"==typeof window&&window)||r("object"==typeof self&&self)||r("object"==typeof e&&e)||Function("return this")(),i=function(t){try{return!!t()}catch(t){return!0}},u=!i((function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})),c={}.propertyIsEnumerable,f=Object.getOwnPropertyDescriptor,a={f:f&&!c.call({1:2},1)?function(t){var e=f(this,t);return!!e&&e.enumerable}:c},s=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}},l={}.toString,p=function(t){return l.call(t).slice(8,-1)},h="".split,y=i((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==p(t)?h.call(t,""):Object(t)}:Object,d=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t},b=function(t){return y(d(t))},v=function(t){return"object"==typeof t?null!==t:"function"==typeof t},g=function(t,e){if(!v(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!v(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!v(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!v(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")},m={}.hasOwnProperty,w=function(t,e){return m.call(t,e)},O=o.document,j=v(O)&&v(O.createElement),S=function(t){return j?O.createElement(t):{}},R=!u&&!i((function(){return 7!=Object.defineProperty(S("div"),"a",{get:function(){return 7}}).a})),T=Object.getOwnPropertyDescriptor,P={f:u?T:function(t,e){if(t=b(t),e=g(e,!0),R)try{return T(t,e)}catch(t){}if(w(t,e))return s(!a.f.call(t,e),t[e])}},x=function(t){if(!v(t))throw TypeError(String(t)+" is not an object");return t},A=Object.defineProperty,E={f:u?A:function(t,e,n){if(x(t),e=g(e,!0),x(n),R)try{return A(t,e,n)}catch(t){}if("get"in n||"set"in n)throw TypeError("Accessors not supported");return"value"in n&&(t[e]=n.value),t}},_=u?function(t,e,n){return E.f(t,e,s(1,n))}:function(t,e,n){return t[e]=n,t},I=function(t,e){try{_(o,t,e)}catch(n){o[t]=e}return e},k=o["__core-js_shared__"]||I("__core-js_shared__",{}),M=Function.toString;"function"!=typeof k.inspectSource&&(k.inspectSource=function(t){return M.call(t)});var F,C,B,L=k.inspectSource,N=o.WeakMap,q="function"==typeof N&&/native code/.test(L(N)),z=n((function(t){(t.exports=function(t,e){return k[t]||(k[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.0",mode:"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})})),D=0,W=Math.random(),$=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++D+W).toString(36)},G=z("keys"),K=function(t){return G[t]||(G[t]=$(t))},Q={},V=o.WeakMap;if(q){var X=new V,Y=X.get,H=X.has,J=X.set;F=function(t,e){return J.call(X,t,e),e},C=function(t){return Y.call(X,t)||{}},B=function(t){return H.call(X,t)}}else{var U=K("state");Q[U]=!0,F=function(t,e){return _(t,U,e),e},C=function(t){return w(t,U)?t[U]:{}},B=function(t){return w(t,U)}}var Z,tt,et={set:F,get:C,has:B,enforce:function(t){return B(t)?C(t):F(t,{})},getterFor:function(t){return function(e){var n;if(!v(e)||(n=C(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}},nt=n((function(t){var e=et.get,n=et.enforce,r=String(String).split("String");(t.exports=function(t,e,i,u){var c=!!u&&!!u.unsafe,f=!!u&&!!u.enumerable,a=!!u&&!!u.noTargetGet;"function"==typeof i&&("string"!=typeof e||w(i,"name")||_(i,"name",e),n(i).source=r.join("string"==typeof e?e:"")),t!==o?(c?!a&&t[e]&&(f=!0):delete t[e],f?t[e]=i:_(t,e,i)):f?t[e]=i:I(e,i)})(Function.prototype,"toString",(function(){return"function"==typeof this&&e(this).source||L(this)}))})),rt=o,ot=function(t){return"function"==typeof t?t:void 0},it=function(t,e){return arguments.length<2?ot(rt[t])||ot(o[t]):rt[t]&&rt[t][e]||o[t]&&o[t][e]},ut=Math.ceil,ct=Math.floor,ft=function(t){return isNaN(t=+t)?0:(t>0?ct:ut)(t)},at=Math.min,st=function(t){return t>0?at(ft(t),9007199254740991):0},lt=Math.max,pt=Math.min,ht=function(t){return function(e,n,r){var o,i=b(e),u=st(i.length),c=function(t,e){var n=ft(t);return n<0?lt(n+e,0):pt(n,e)}(r,u);if(t&&n!=n){for(;u>c;)if((o=i[c++])!=o)return!0}else for(;u>c;c++)if((t||c in i)&&i[c]===n)return t||c||0;return!t&&-1}},yt={includes:ht(!0),indexOf:ht(!1)}.indexOf,dt=function(t,e){var n,r=b(t),o=0,i=[];for(n in r)!w(Q,n)&&w(r,n)&&i.push(n);for(;e.length>o;)w(r,n=e[o++])&&(~yt(i,n)||i.push(n));return i},bt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],vt=bt.concat("length","prototype"),gt={f:Object.getOwnPropertyNames||function(t){return dt(t,vt)}},mt={f:Object.getOwnPropertySymbols},wt=it("Reflect","ownKeys")||function(t){var e=gt.f(x(t)),n=mt.f;return n?e.concat(n(t)):e},Ot=function(t,e){for(var n=wt(e),r=E.f,o=P.f,i=0;i=74)&&(Z=Wt.match(/Chrome\/(\d+)/))&&(tt=Z[1]);var Qt,Vt=tt&&+tt,Xt=qt("species"),Yt=qt("isConcatSpreadable"),Ht=Vt>=51||!i((function(){var t=[];return t[Yt]=!1,t.concat()[0]!==t})),Jt=(Qt="concat",Vt>=51||!i((function(){var t=[];return(t.constructor={})[Xt]=function(){return{foo:1}},1!==t[Qt](Boolean).foo}))),Ut=function(t){if(!v(t))return!1;var e=t[Yt];return void 0!==e?!!e:It(t)};_t({target:"Array",proto:!0,forced:!Ht||!Jt},{concat:function(t){var e,n,r,o,i,u=kt(this),c=Dt(u,0),f=0;for(e=-1,r=arguments.length;e9007199254740991)throw TypeError("Maximum allowed index exceeded");for(n=0;n=9007199254740991)throw TypeError("Maximum allowed index exceeded");Mt(c,f++,i)}return c.length=f,c}});var Zt,te=function(t,e,n){if(function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function")}(t),void 0===e)return t;switch(n){case 0:return function(){return t.call(e)};case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}},ee=[].push,ne=function(t){var e=1==t,n=2==t,r=3==t,o=4==t,i=6==t,u=5==t||i;return function(c,f,a,s){for(var l,p,h=kt(c),d=y(h),b=te(f,a,3),v=st(d.length),g=0,m=s||Dt,w=e?m(c,v):n?m(c,0):void 0;v>g;g++)if((u||g in d)&&(p=b(l=d[g],g,h),t))if(e)w[g]=p;else if(p)switch(t){case 3:return!0;case 5:return l;case 6:return g;case 2:ee.call(w,l)}else if(o)return!1;return i?-1:r||o?o:w}},re={forEach:ne(0),map:ne(1),filter:ne(2),some:ne(3),every:ne(4),find:ne(5),findIndex:ne(6)},oe=Object.keys||function(t){return dt(t,bt)},ie=u?Object.defineProperties:function(t,e){x(t);for(var n,r=oe(e),o=r.length,i=0;o>i;)E.f(t,n=r[i++],e[n]);return t},ue=it("document","documentElement"),ce=K("IE_PROTO"),fe=function(){},ae=function(t){return" + + diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/grid.html b/ruoyi-admin/src/main/resources/templates/demo/form/grid.html index 1db0deffd..32e7fa91b 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/grid.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/grid.html @@ -14,13 +14,13 @@ - + @@ -124,13 +124,13 @@ - + @@ -183,13 +183,13 @@ - + @@ -227,13 +227,13 @@ - + @@ -270,13 +270,13 @@ - + @@ -285,7 +285,7 @@
    -

    在等宽的4网格中,网格不等高会碰到问题,为了解决这个问题,可使用.clearfix响应实用工具类 +

    在等宽的4网格中,网格不等高会碰到问题,为了解决这个问题,可使用.clearfix响应实用工具类

    @@ -315,13 +315,13 @@ - + @@ -358,13 +358,13 @@ - + @@ -401,13 +401,13 @@ - + diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/localrefresh.html b/ruoyi-admin/src/main/resources/templates/demo/form/localrefresh.html new file mode 100644 index 000000000..d919fe68d --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/form/localrefresh.html @@ -0,0 +1,61 @@ + + + + + + + + + + + diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/summernote.html b/ruoyi-admin/src/main/resources/templates/demo/form/summernote.html index 1222d98c6..e280b6b8e 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/summernote.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/summernote.html @@ -17,7 +17,7 @@

    若依后台管理系统

    ruoyi是一个完全响应式,基于Bootstrap3.3.6最新版本开发的扁平化主题,她采用了主流的左右两栏式布局,使用了Html5+CSS3等现代技术,她提供了诸多的强大的可以重新组合的UI组件,并集成了最新的jQuery版本(v2.1.1),当然,也集成了很多功能强大,用途广泛的就jQuery插件,她可以用于所有的Web应用程序,如网站管理后台网站会员中心CMSCRMOA等等,当然,您也可以对她进行深度定制,以做出更强系统。

    - 当前版本:v4.1.0 + 当前版本:v4.4.0

    免费开源 @@ -56,7 +56,7 @@

    你好,若依

    H+是一个完全响应式,基于Bootstrap3.3.6最新版本开发的扁平化主题,她采用了主流的左右两栏式布局,使用了Html5+CSS3等现代技术,她提供了诸多的强大的可以重新组合的UI组件,并集成了最新的jQuery版本(v2.1.1),当然,也集成了很多功能强大,用途广泛的就jQuery插件,她可以用于所有的Web应用程序,如网站管理后台网站会员中心CMSCRMOA等等,当然,您也可以对她进行深度定制,以做出更强系统。

    - 当前版本:v4.1.0 + 当前版本:v4.4.0

    开源免费 diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/tabs_panels.html b/ruoyi-admin/src/main/resources/templates/demo/form/tabs_panels.html index e7a8fa7fc..7e52e1986 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/tabs_panels.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/tabs_panels.html @@ -14,13 +14,13 @@ - +

    @@ -76,13 +76,13 @@
    @@ -273,13 +273,13 @@ - + @@ -293,7 +293,7 @@
    @@ -305,7 +305,7 @@
    @@ -317,7 +317,7 @@
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/icon/fontawesome.html b/ruoyi-admin/src/main/resources/templates/demo/icon/fontawesome.html index 7206094af..804d056ee 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/icon/fontawesome.html +++ b/ruoyi-admin/src/main/resources/templates/demo/icon/fontawesome.html @@ -19,13 +19,13 @@ - + diff --git a/ruoyi-admin/src/main/resources/templates/demo/icon/glyphicons.html b/ruoyi-admin/src/main/resources/templates/demo/icon/glyphicons.html index aaf71d467..cca7cf31d 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/icon/glyphicons.html +++ b/ruoyi-admin/src/main/resources/templates/demo/icon/glyphicons.html @@ -19,13 +19,13 @@ - + diff --git a/ruoyi-admin/src/main/resources/templates/demo/modal/form.html b/ruoyi-admin/src/main/resources/templates/demo/modal/form.html index ec294fb99..f9e201518 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/modal/form.html +++ b/ruoyi-admin/src/main/resources/templates/demo/modal/form.html @@ -9,7 +9,7 @@
    - +
    @@ -17,7 +17,7 @@
    - +
    @@ -30,7 +30,7 @@
    - +
    @@ -38,7 +38,7 @@
    - +
    @@ -48,7 +48,7 @@
    - +
    @@ -56,7 +56,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/operate/add.html b/ruoyi-admin/src/main/resources/templates/demo/operate/add.html index 3a95e7939..e1cf566ec 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/operate/add.html +++ b/ruoyi-admin/src/main/resources/templates/demo/operate/add.html @@ -13,7 +13,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/operate/detail.html b/ruoyi-admin/src/main/resources/templates/demo/operate/detail.html index 42eda918c..3a3c4e7d3 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/operate/detail.html +++ b/ruoyi-admin/src/main/resources/templates/demo/operate/detail.html @@ -11,7 +11,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/operate/edit.html b/ruoyi-admin/src/main/resources/templates/demo/operate/edit.html index d7d87fcfb..2e6adc073 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/operate/edit.html +++ b/ruoyi-admin/src/main/resources/templates/demo/operate/edit.html @@ -14,7 +14,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/report/echarts.html b/ruoyi-admin/src/main/resources/templates/demo/report/echarts.html index a61fe0c2a..668aa2ce6 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/report/echarts.html +++ b/ruoyi-admin/src/main/resources/templates/demo/report/echarts.html @@ -23,13 +23,13 @@ -
    + @@ -50,13 +50,13 @@ - + @@ -80,13 +80,13 @@ - + @@ -107,13 +107,13 @@ - + @@ -134,13 +134,13 @@ - + @@ -161,13 +161,13 @@ - + @@ -188,13 +188,13 @@ - + @@ -215,13 +215,13 @@ - + @@ -245,13 +245,13 @@ - + diff --git a/ruoyi-admin/src/main/resources/templates/demo/report/sparkline.html b/ruoyi-admin/src/main/resources/templates/demo/report/sparkline.html index 5ed6f05b2..1e060a824 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/report/sparkline.html +++ b/ruoyi-admin/src/main/resources/templates/demo/report/sparkline.html @@ -98,13 +98,13 @@ - + @@ -125,13 +125,13 @@ - + @@ -152,13 +152,13 @@ - + diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/child.html b/ruoyi-admin/src/main/resources/templates/demo/table/child.html index 73ad54472..8a50491f8 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/child.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/child.html @@ -77,12 +77,12 @@ }); initChildTable = function(index, row, $detail) { - var cur_table = $detail.html('
    ').find('table'); - $(cur_table).bootstrapTable({ + var childTable = $detail.html('
    ').find('table'); + $(childTable).bootstrapTable({ url: prefix + "/list", method: 'post', sidePagination: "server", - contentType: "application/x-www-form-urlencoded", // 编码类型 + contentType: "application/x-www-form-urlencoded", queryParams : { userName: '测试8' }, diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/data.html b/ruoyi-admin/src/main/resources/templates/demo/table/data.html new file mode 100644 index 000000000..818d5b7d1 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/data.html @@ -0,0 +1,76 @@ + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/editable.html b/ruoyi-admin/src/main/resources/templates/demo/table/editable.html index 345a74a05..3395e6d4e 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/editable.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/editable.html @@ -108,7 +108,7 @@ $.table.init(options); }); - function onEditableSave (field, row, oldValue, $el) { + function onEditableSave (field, row, rowIndex, oldValue, $el) { alert("字段名:" + field + ",当前值:" + row[field] + ",旧值:" + oldValue); } diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/export.html b/ruoyi-admin/src/main/resources/templates/demo/table/export.html index 1f014ca59..82be299a5 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/export.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/export.html @@ -12,6 +12,7 @@
    + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/headerStyle.html b/ruoyi-admin/src/main/resources/templates/demo/table/headerStyle.html new file mode 100644 index 000000000..0c862c739 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/headerStyle.html @@ -0,0 +1,91 @@ + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/multi.html b/ruoyi-admin/src/main/resources/templates/demo/table/multi.html index 155f687f3..a503ec95d 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/multi.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/multi.html @@ -35,7 +35,7 @@ 删除
    -
    +
    @@ -73,7 +73,7 @@ 删除
    -
    +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/print.html b/ruoyi-admin/src/main/resources/templates/demo/table/print.html new file mode 100644 index 000000000..fbf1f49f7 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/print.html @@ -0,0 +1,83 @@ + + + + + + +
    +
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/refresh.html b/ruoyi-admin/src/main/resources/templates/demo/table/refresh.html new file mode 100644 index 000000000..44fbb8878 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/refresh.html @@ -0,0 +1,79 @@ + + + + + + +
    +
    +
    + +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/search.html b/ruoyi-admin/src/main/resources/templates/demo/table/search.html index efd573de9..553cf71de 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/search.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/search.html @@ -35,7 +35,7 @@
    - +

    时间条件查询

    @@ -61,7 +61,30 @@
    - + +
    +

    多级联动下拉查询

    +
    +
    +
      +
    • + 商户编号: +
    • +
    • + 充值类型: +
    • +
    • + 充值路由: +
    • +
    • +  搜索 +  重置 +
    • +
    +
    +
    +
    +

    下拉多选条件查询

    @@ -90,26 +113,26 @@
    - +

    复杂条件查询

    • -

      商户编号:

      +
    • -

      订单号:

      +
    • -

      日期:

      +
    • -

      状态:

      +
    • -

      供货商通道:

      +
    • -

      来源:

      +
    • -

      运营商:

      +
    • -

      回调时间:

      + -
    • - +
    •  搜索  重置 @@ -164,5 +187,16 @@
    + + + diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/subdata.html b/ruoyi-admin/src/main/resources/templates/demo/table/subdata.html new file mode 100644 index 000000000..175e58c9e --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/subdata.html @@ -0,0 +1,207 @@ + + + + + + + +
    + + +

    客户信息

    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    +

    商品数据

    +
    +
    + + +
    +
    +
    +
    +
    + +
    + +
    +
    +   + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/error/unauth.html b/ruoyi-admin/src/main/resources/templates/error/unauth.html index fd5f03cf4..1704707dc 100644 --- a/ruoyi-admin/src/main/resources/templates/error/unauth.html +++ b/ruoyi-admin/src/main/resources/templates/error/unauth.html @@ -15,7 +15,7 @@
    对不起,您没有访问权限,请不要进行非法操作!您可以返回主页面 - 返回主页 + 返回主页
    - - - - - + + + - - - - - + +
    @@ -74,7 +71,7 @@
    - +
    @@ -95,12 +92,12 @@
    - -
    - + +
    +
    -
    - +
    +
    @@ -137,6 +134,11 @@
    + +
    + +
    +
    @@ -180,5 +182,26 @@
    - -
    \ No newline at end of file + +
    + + +
    + + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    diff --git a/ruoyi-admin/src/main/resources/templates/index-topnav.html b/ruoyi-admin/src/main/resources/templates/index-topnav.html new file mode 100644 index 000000000..d68bce4b6 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/index-topnav.html @@ -0,0 +1,396 @@ + + + + + + + 若依系统首页 + + + + + + + + + + + + +
    + + + + + + +
    + +
    + + + + 刷新 +
    + + + +
    + +
    + + +
    + +
    + + + + + + + + + + + + + + + + diff --git a/ruoyi-admin/src/main/resources/templates/index.html b/ruoyi-admin/src/main/resources/templates/index.html index 5ab14d044..bfc13e24e 100644 --- a/ruoyi-admin/src/main/resources/templates/index.html +++ b/ruoyi-admin/src/main/resources/templates/index.html @@ -5,17 +5,16 @@ 若依系统首页 - - + + + - +
    @@ -25,19 +24,19 @@ + + + - + - + - -
    -
    - @@ -250,8 +255,8 @@ - - + + - -
    @@ -39,18 +37,18 @@
  • Thymeleaf
  • Bootstrap
  • - 还没有账号? 立即注册» + 还没有账号? 立即注册»
    -
    +

    登录:

    你若不离不弃,我必生死相依

    - +
    @@ -80,7 +78,7 @@ - + diff --git a/ruoyi-admin/src/main/resources/templates/main.html b/ruoyi-admin/src/main/resources/templates/main.html index 490fbbabb..de96f88f8 100644 --- a/ruoyi-admin/src/main/resources/templates/main.html +++ b/ruoyi-admin/src/main/resources/templates/main.html @@ -16,10 +16,8 @@
    - 阿里云服务器89元/年,双12年末特惠,爆款产品限时1折 -
    https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link
    领取阿里云通用云产品1888优惠券 -
    https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=brki8iof
    +
    https://www.aliyun.com/minisite/goods?userCode=brki8iof
    领取腾讯云通用云产品2860优惠券
    https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console

    云产品通用红包,可叠加官网常规优惠使用。(仅限新用户)

    @@ -81,7 +79,7 @@

    官网:http://www.ruoyi.vip

    -

    QQ群:满1389287 满1679294 满1529866 满1772718 满1366522 满1382251 满1145125 满86752435 134072510 +

    QQ群:满1389287 满1679294 满1529866 满1772718 满1366522 满1382251 满1145125 满86752435 满134072510 满210336300 满339522636 130035985

    微信:/ *若依

    @@ -98,13 +96,223 @@
    +
    +
    +
    + v4.4.02020.08.24 +
    +
    +
    +
    +
      +
    1. 升级bootstrapTable到最新版本1.17.1
    2. +
    3. 升级shiro到最新版1.6.0 阻止权限绕过漏洞
    4. +
    5. 升级fastjson到最新版1.2.73
    6. +
    7. 代码生成支持同步数据库
    8. +
    9. 代码生成支持富文本控件
    10. +
    11. 用户密码支持自定义配置规则
    12. +
    13. 新增表格自动刷新插件
    14. +
    15. 新增表格打印配置插件
    16. +
    17. 更换图片裁剪工具为cropper
    18. +
    19. Excel支持sort导出排序
    20. +
    21. 代码生成支持自定义路径
    22. +
    23. 代码生成支持选择上级菜单
    24. +
    25. 代码生成支持上传控件
    26. +
    27. 新增表格参数(自定义加载文本的字体大小loadingFontSize)
    28. +
    29. Excel注解支持设置BigDecimal精度&舍入规则
    30. +
    31. 操作日志记录排除敏感属性字段
    32. +
    33. 修复不同浏览器附件下载中文名乱码的问题
    34. +
    35. 用户分配角色不允许选择超级管理员角色
    36. +
    37. 更换表格冻结列插件
    38. +
    39. 添加右侧冻结列示例
    40. +
    41. 升级表格行编辑&移动端适应插件
    42. +
    43. 修复更新表格插件后无法设置实例配置问题
    44. +
    45. 修复更新表格插件后导致的主子表错误
    46. +
    47. 修复页面存在多表格,回调函数res数据不正确问题
    48. +
    49. 强退&过期清理登录帐号缓存会话
    50. +
    51. 表格树标题内容支持html语义化标签
    52. +
    53. 修复配置应用的访问路径首页页签重复问题
    54. +
    55. 优化openTab打开时滚动到当前页签
    56. +
    57. 表格请求方式method支持自定义配置
    58. +
    59. 菜单页签联动优化
    60. +
    61. 用户邮箱长度限制修改为50
    62. +
    63. 主子表示例添加日期格式案例
    64. +
    65. 修改表格行内编辑示例旧值参数
    66. +
    67. 操作日志查询方式调整
    68. +
    69. 唯一限制条件只返回单条数据
    70. +
    71. 修改Excel设置STRING单元格类型
    72. +
    73. 添加获取当前的环境配置方法
    74. +
    75. 截取返回参数长度,防止超出异常
    76. +
    77. 定时任务cron表达式验证
    78. +
    79. 拆分表格插件,按需引入
    80. +
    81. 多行文本框补齐必填错误提示背景
    82. +
    83. 其他细节优化
    84. +
    +
    +
    +
    +
    +
    +
    + v4.3.12020.07.05 +
    +
    +
    +
    +
      +
    1. 国家信息安全漏洞(请务必保持cipherKey密钥唯一性)
    2. +
    3. 升级shiro到最新版1.5.3 阻止权限绕过漏洞
    4. +
    5. 修改验证码在使用后清除,防止多次使用
    6. +
    7. 检查字符支持小数点&降级改成异常提醒
    8. +
    9. openOptions函数中加入自定义maxmin属性
    10. +
    11. 支持openOptions方法最大化
    12. +
    13. 支持openOptions方法多个按钮回调
    14. +
    15. 新增isLinkage支持页签与菜单联动
    16. +
    17. 修改代码生成导入表结构出现异常页面不提醒问题
    18. +
    19. 优化用户头像发生错误,则显示一个默认头像
    20. +
    21. Excel导出支持字典类型
    22. +
    +
    +
    +
    +
    +
    +
    + v4.3.02020.06.22 +
    +
    +
    +
    +
      +
    1. 代码生成模板支持主子表
    2. +
    3. 代码生成显示类型支持复选框
    4. +
    5. 前端表单样式修改成圆角
    6. +
    7. 新增回显数据字典(字符串数组)
    8. +
    9. 修复浏览器手动缩放比例后菜单无法自适应问题
    10. +
    11. 限制用户不允许选择系统管理员角色
    12. +
    13. 用户信息添加输入框组图标&鼠标按下显示密码
    14. +
    15. 升级fastjson到最新版1.2.70 修复高危安全漏洞
    16. +
    17. 升级Bootstrap版本到v3.3.7
    18. +
    19. 修复selectColumns方法获取子对象数据无效问题
    20. +
    21. 修改数据源类型优先级,先根据方法,再根据类
    22. +
    23. 修改上级部门(选择项排除本身和下级)
    24. +
    25. 首页菜单显示调整
    26. +
    27. 添加是否开启swagger配置
    28. +
    29. 新增示例(主子表提交)
    30. +
    31. 新增示例(多级联动下拉示例)
    32. +
    33. 新增示例(表格属性data数据加载)
    34. +
    35. 新增表格列参数(是否列选项可见ignore)
    36. +
    37. 新增表格参数(是否启用显示卡片视图cardView)
    38. +
    39. 新增表格参数(是否显示全屏按钮showFullscreen)
    40. +
    41. 新增表格参数(是否启用分页条无限循环的功能paginationLoop)
    42. +
    43. 新增表格参数(是否显示表头showHeader)
    44. +
    45. 表格添加显示/隐藏所有列方法 showAllColumns/hideAllColumns
    46. +
    47. 修复部分情况节点不展开问题
    48. +
    49. 修复关闭标签页后刷新还是上次地址问题
    50. +
    51. 修复选择菜单后刷新页面,菜单箭头显示不对问题
    52. +
    53. 修复jquery表单序列化时复选框未选中不会序列化到对象中问题
    54. +
    55. Excel支持readConverterExp读取字符串组内容
    56. +
    57. 更换IP地址查询接口
    58. +
    59. 默认关闭获取ip地址
    60. +
    61. 操作处理ajaxSuccess判断修正
    62. +
    63. HttpUtils.sendPost()方法,参数无需拼接参数到url
    64. +
    65. 通用http发送方法增加参数 contentType 编码类型
    66. +
    67. HTML过滤器不替换&实体
    68. +
    69. 代码生成浮点型改用BigDecimal
    70. +
    71. 修复表单构建单选和多选框渲染问题
    72. +
    73. 代码生成模板调整,字段为String并且必填则加空串条件
    74. +
    75. 字典数据查询列表根据dictSort升序排序
    76. +
    77. 修复树表对imageView和tooltip方法无效问题
    78. +
    79. 修复Long类型比较相等问题调整
    80. +
    81. 示例demo页面清除html链接,防止点击后跳转出现404
    82. +
    83. 在线用户强退方法合并
    84. +
    85. 添加校验部门包含未停用的子部门
    86. +
    87. 取消回车自动提交表单
    88. +
    89. 'A','I','BUTTON' 标签忽略clickToSelect事件,防止点击操作按钮时选中
    90. +
    91. 邮箱显示截取部分字符串,防止低分辨率错位
    92. +
    93. 代码生成列属性根据sort排序
    94. +
    95. 修复更多操作部分浏览器不兼容情况
    96. +
    97. 图片预览事件属性修正
    98. +
    99. 修复冻结列排序样式无效问题
    100. +
    101. 修复context-path的情况下个人中心刷新导致样式问题
    102. +
    103. 全屏editFull打开适配表树
    104. +
    105. 其他细节优化
    106. +
    +
    +
    +
    +
    +
    +
    + v4.2.02020.03.23 +
    +
    +
    +
    +
      +
    1. 用户管理添加分配角色页面
    2. +
    3. 定时任务添加调度日志按钮
    4. +
    5. 新增是否开启用户注册功能
    6. +
    7. 新增页面滚动显示返回顶部按钮
    8. +
    9. 用户&角色&任务添加更多操作按钮
    10. +
    11. iframe框架页会话过期弹出超时提示
    12. +
    13. 移动端登录不显示左侧菜单
    14. +
    15. 侧边栏添加一套深蓝色主题
    16. +
    17. 首页logo固定,不随菜单滚动
    18. +
    19. 支持mode配置history(表示去掉地址栏的#)
    20. +
    21. 任务分组字典翻译(调度日志详细)
    22. +
    23. 字典管理添加缓存读取
    24. +
    25. 字典数据列表标签显示样式
    26. +
    27. 参数管理支持缓存操作
    28. +
    29. 日期控件清空结束时间设置开始默认值为2099-12-31
    30. +
    31. 表格树添加获取数据后响应回调处理
    32. +
    33. 批量替换表前缀调整
    34. +
    35. 支持表格导入模板的弹窗表单加入其它输入控件
    36. +
    37. 表单重置刷新表格树
    38. +
    39. 新增支持导出数据字段排序
    40. +
    41. 新增表格参数(是否单选checkbox)
    42. +
    43. druid未授权不允许访问
    44. +
    45. 表格树父节点兼容0,'0','',null
    46. +
    47. 表单必填的项添加星号
    48. +
    49. 修复select2不显示校验错误信息
    50. +
    51. 添加自定义HTML过滤器
    52. +
    53. 修复多数据源下开关关闭出现异常问题
    54. +
    55. 修复翻页记住选择项数据问题
    56. +
    57. 用户邮箱长度限制20
    58. +
    59. 修改错误页面返回主页出现嵌套问题
    60. +
    61. 表格浮动提示单双引号转义
    62. +
    63. 支持配置四级菜单
    64. +
    65. 升级shiro到最新版1.4.2 阻止rememberMe漏洞攻击
    66. +
    67. 升级summernote到最新版本v0.8.12
    68. +
    69. 导入Excel根据dateFormat属性格式处理
    70. +
    71. 修复War部署无法正常shutdown,ehcache内存泄漏
    72. +
    73. 修复代码生成短字段无法识别问题
    74. +
    75. 修复serviceImpl模版,修改方法判断日期错误
    76. +
    77. 代码生成模板增加导出功能日志记录
    78. +
    79. 代码生成唯一编号调整为tableId
    80. +
    81. 代码生成查询时忽略大小写
    82. +
    83. 代码生成支持翻页记住选中
    84. +
    85. 代码生成表注释未填写也允许导入
    86. +
    87. Global全局配置类修改为注解,防止多环境配置下读取问题
    88. +
    89. 修复多表格情况下,firstLoad只对第一个表格生效
    90. +
    91. 处理Maven打包出现警告问题
    92. +
    93. 默认主题样式,防止网速慢情况下出现空白
    94. +
    95. 修复文件上传多级目录识别问题
    96. +
    97. 锚链接解码url,防止中文导致页面不能加载问题
    98. +
    99. 修复右键Tab页刷新事件重复请求问题
    100. +
    101. 角色禁用&菜单隐藏不查询权限
    102. +
    103. 其他细节优化
    104. +
    +
    +
    +
    v4.1.02019.10.22
    -
    +
    1. 支持多表格实例操作
    2. @@ -144,7 +352,7 @@
    -
    +
    @@ -205,8 +413,8 @@
  • 其他细节优化
  • -
    -
    +
    +
    diff --git a/ruoyi-admin/src/main/resources/templates/monitor/online/online.html b/ruoyi-admin/src/main/resources/templates/monitor/online/online.html index f69fcdb5b..88e5a543f 100644 --- a/ruoyi-admin/src/main/resources/templates/monitor/online/online.html +++ b/ruoyi-admin/src/main/resources/templates/monitor/online/online.html @@ -37,6 +37,7 @@
    + diff --git a/ruoyi-admin/src/main/resources/templates/register.html b/ruoyi-admin/src/main/resources/templates/register.html new file mode 100644 index 000000000..a272d8153 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/register.html @@ -0,0 +1,83 @@ + + + + + + 注册若依系统 + + + + + + + + + + + + + + +
    +
    +
    + +
    +
    + +

    注册:

    +

    你若不离不弃,我必生死相依

    + + + +
    +
    + +
    +
    + + + +
    +
    +
    + + 使用条款 +
    + + +
    +
    + +
    + + + + + + + + + + + + + diff --git a/ruoyi-admin/src/main/resources/templates/skin.html b/ruoyi-admin/src/main/resources/templates/skin.html index deb19f026..5d8b9cd22 100644 --- a/ruoyi-admin/src/main/resources/templates/skin.html +++ b/ruoyi-admin/src/main/resources/templates/skin.html @@ -140,7 +140,7 @@ - + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/system/config/edit.html b/ruoyi-admin/src/main/resources/templates/system/config/edit.html index b74007e84..471e9e1ee 100644 --- a/ruoyi-admin/src/main/resources/templates/system/config/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/config/edit.html @@ -8,19 +8,19 @@
    - +
    - +
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/dept/add.html b/ruoyi-admin/src/main/resources/templates/system/dept/add.html index d2eb00949..e958ac516 100644 --- a/ruoyi-admin/src/main/resources/templates/system/dept/add.html +++ b/ruoyi-admin/src/main/resources/templates/system/dept/add.html @@ -8,7 +8,7 @@
    - +
    @@ -17,13 +17,13 @@
    - +
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/dept/edit.html b/ruoyi-admin/src/main/resources/templates/system/dept/edit.html index cde8c9302..45c5157d7 100644 --- a/ruoyi-admin/src/main/resources/templates/system/dept/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/dept/edit.html @@ -9,7 +9,7 @@
    - +
    @@ -18,13 +18,13 @@
    - +
    - +
    @@ -113,11 +113,12 @@ /*部门管理-修改-选择部门树*/ function selectDeptTree() { var deptId = $("#treeId").val(); + var excludeId = $("input[name='deptId']").val(); if(deptId > 0) { var options = { title: '部门选择', width: "380", - url: prefix + "/selectDeptTree/" + $("#treeId").val(), + url: prefix + "/selectDeptTree/" + $("#treeId").val() + "/" + excludeId, callBack: doSubmit }; $.modal.openOptions(options); diff --git a/ruoyi-admin/src/main/resources/templates/system/dept/tree.html b/ruoyi-admin/src/main/resources/templates/system/dept/tree.html index 0f35a4b4c..977f7f58d 100644 --- a/ruoyi-admin/src/main/resources/templates/system/dept/tree.html +++ b/ruoyi-admin/src/main/resources/templates/system/dept/tree.html @@ -28,8 +28,11 @@ \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/system/menu/add.html b/ruoyi-admin/src/main/resources/templates/system/menu/add.html index 3e4020031..39ebb7357 100644 --- a/ruoyi-admin/src/main/resources/templates/system/menu/add.html +++ b/ruoyi-admin/src/main/resources/templates/system/menu/add.html @@ -8,7 +8,7 @@
    - +
    @@ -17,7 +17,7 @@
    - +
    @@ -25,7 +25,7 @@
    - +
    @@ -53,7 +53,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/menu/edit.html b/ruoyi-admin/src/main/resources/templates/system/menu/edit.html index 9a31a5a49..66086cea7 100644 --- a/ruoyi-admin/src/main/resources/templates/system/menu/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/menu/edit.html @@ -9,7 +9,7 @@
    - +
    @@ -18,7 +18,7 @@
    - +
    @@ -26,7 +26,7 @@
    - +
    @@ -54,7 +54,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/menu/menu.html b/ruoyi-admin/src/main/resources/templates/system/menu/menu.html index 8208165b2..68e15d274 100644 --- a/ruoyi-admin/src/main/resources/templates/system/menu/menu.html +++ b/ruoyi-admin/src/main/resources/templates/system/menu/menu.html @@ -91,7 +91,10 @@ field: 'url', title: '请求地址', width: '15%', - align: "left" + align: "left", + formatter: function(value, row, index) { + return $.table.tooltip(value); + } }, { title: '类型', @@ -127,6 +130,9 @@ title: '权限标识', width: '15%', align: "left", + formatter: function(value, row, index) { + return $.table.tooltip(value); + } }, { title: '操作', diff --git a/ruoyi-admin/src/main/resources/templates/system/notice/add.html b/ruoyi-admin/src/main/resources/templates/system/notice/add.html index 4c1893e3e..50bd86347 100644 --- a/ruoyi-admin/src/main/resources/templates/system/notice/add.html +++ b/ruoyi-admin/src/main/resources/templates/system/notice/add.html @@ -8,7 +8,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/notice/edit.html b/ruoyi-admin/src/main/resources/templates/system/notice/edit.html index 8987df2c7..63a3f5e97 100644 --- a/ruoyi-admin/src/main/resources/templates/system/notice/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/notice/edit.html @@ -9,7 +9,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/post/add.html b/ruoyi-admin/src/main/resources/templates/system/post/add.html index cd84ada21..d76f4a1b8 100644 --- a/ruoyi-admin/src/main/resources/templates/system/post/add.html +++ b/ruoyi-admin/src/main/resources/templates/system/post/add.html @@ -7,19 +7,19 @@
    - +
    - +
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/post/edit.html b/ruoyi-admin/src/main/resources/templates/system/post/edit.html index 862e72119..50c5ef0d4 100644 --- a/ruoyi-admin/src/main/resources/templates/system/post/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/post/edit.html @@ -8,19 +8,19 @@
    - +
    - +
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/role/add.html b/ruoyi-admin/src/main/resources/templates/system/role/add.html index 91942e6a3..2675d093c 100644 --- a/ruoyi-admin/src/main/resources/templates/system/role/add.html +++ b/ruoyi-admin/src/main/resources/templates/system/role/add.html @@ -8,20 +8,20 @@
    - +
    - +
    控制器中定义的权限字符,如:@RequiresRoles("")
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/role/authUser.html b/ruoyi-admin/src/main/resources/templates/system/role/authUser.html index 33368201f..c1f3be5f7 100644 --- a/ruoyi-admin/src/main/resources/templates/system/role/authUser.html +++ b/ruoyi-admin/src/main/resources/templates/system/role/authUser.html @@ -1,7 +1,7 @@ - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/role/dataScope.html b/ruoyi-admin/src/main/resources/templates/system/role/dataScope.html index 7cb3d8cb1..d23fe5887 100644 --- a/ruoyi-admin/src/main/resources/templates/system/role/dataScope.html +++ b/ruoyi-admin/src/main/resources/templates/system/role/dataScope.html @@ -9,7 +9,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/role/edit.html b/ruoyi-admin/src/main/resources/templates/system/role/edit.html index 9d69115dc..440042481 100644 --- a/ruoyi-admin/src/main/resources/templates/system/role/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/role/edit.html @@ -9,20 +9,20 @@
    - +
    - +
    控制器中定义的权限字符,如:@RequiresRoles("")
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/role/role.html b/ruoyi-admin/src/main/resources/templates/system/role/role.html index 5e210f5b3..18628819e 100644 --- a/ruoyi-admin/src/main/resources/templates/system/role/role.html +++ b/ruoyi-admin/src/main/resources/templates/system/role/role.html @@ -114,9 +114,11 @@ formatter: function(value, row, index) { var actions = []; actions.push('编辑 '); - actions.push('数据权限 '); - actions.push('分配用户 '); actions.push('删除 '); + var more = []; + more.push("数据权限 "); + more.push("分配用户"); + actions.push('更多操作'); return actions.join(''); } }] diff --git a/ruoyi-admin/src/main/resources/templates/system/user/add.html b/ruoyi-admin/src/main/resources/templates/system/user/add.html index be1db31b5..e351d71e8 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/add.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/add.html @@ -12,7 +12,7 @@
    - +
    @@ -20,7 +20,7 @@
    - +
    @@ -33,17 +33,23 @@
    - +
    - +
    + + +
    - +
    - +
    + + +
    @@ -51,7 +57,7 @@
    - +
    @@ -59,9 +65,14 @@
    - +
    - +
    + + +
    @@ -210,22 +221,24 @@ }); function submitHandler() { - if ($.validate.form()) { + var chrtype = [[${#strings.defaultString(@config.getKey('sys.account.chrtype'), 0)}]]; + var password = $("#password").val(); + if ($.validate.form() && checkpwd(chrtype, password)) { var data = $("#form-user-add").serializeArray(); var status = $("input[id='status']").is(':checked') == true ? 0 : 1; var roleIds = $.form.selectCheckeds("role"); var postIds = $.form.selectSelects("post"); data.push({"name": "status", "value": status}); - data.push({"name": "roles", "value": roleIds}); - data.push({"name": "posts", "value": postIds}); + data.push({"name": "roleIds", "value": roleIds}); + data.push({"name": "postIds", "value": postIds}); $.operate.saveTab(prefix + "/add", data); } } - /*用户管理-新增-选择部门树*/ + /* 用户管理-新增-选择部门树 */ function selectDeptTree() { var treeId = $("#treeId").val(); - var deptId = $.common.isEmpty(treeId) ? "1" : $("#treeId").val(); + var deptId = $.common.isEmpty(treeId) ? "100" : $("#treeId").val(); var url = ctx + "system/dept/selectDeptTree/" + deptId; var options = { title: '选择部门', diff --git a/ruoyi-admin/src/main/resources/templates/system/user/authRole.html b/ruoyi-admin/src/main/resources/templates/system/user/authRole.html new file mode 100644 index 000000000..0e31bb61d --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/system/user/authRole.html @@ -0,0 +1,109 @@ + + + + + + +
    + + +

    基本信息

    +
    +
    +
    + +
    + +
    +
    +
    +
    +
    + +
    + +
    +
    +
    +
    + +

    分配角色

    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +   + +
    +
    + + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/system/user/edit.html b/ruoyi-admin/src/main/resources/templates/system/user/edit.html index b64f71d3e..fdcaa9107 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/edit.html @@ -13,7 +13,7 @@
    - +
    @@ -21,7 +21,7 @@
    - +
    @@ -34,17 +34,23 @@
    - +
    - +
    + + +
    - +
    - +
    + + +
    @@ -194,7 +200,7 @@ } } - /*用户管理-修改-选择部门树*/ + /* 用户管理-修改-选择部门树 */ function selectDeptTree() { var deptId = $.common.isEmpty($("#treeId").val()) ? "100" : $("#treeId").val(); var url = ctx + "system/dept/selectDeptTree/" + deptId; diff --git a/ruoyi-admin/src/main/resources/templates/system/user/profile/avatar.html b/ruoyi-admin/src/main/resources/templates/system/user/profile/avatar.html index a7064f648..75e825740 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/profile/avatar.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/profile/avatar.html @@ -2,82 +2,259 @@ - + + -
    -
    -
    - -
    -
    - - - - -
    -
    -
    +
    +
    +
    + +
    +
    + + + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    - + diff --git a/ruoyi-admin/src/main/resources/templates/system/user/profile/profile.html b/ruoyi-admin/src/main/resources/templates/system/user/profile/profile.html index 4accf3b5a..390293c95 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/profile/profile.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/profile/profile.html @@ -2,6 +2,7 @@ + @@ -15,7 +16,7 @@
      @@ -27,17 +28,17 @@ 手机号码:

      [[${user.phonenumber}]]

      -
    • +
    • 所属部门: -

      [[${user.dept?.deptName}]] / [[${#strings.defaultString(postGroup,'无岗位')}]]

      +

      [[${user.dept?.deptName}]] / [[${#strings.defaultString(postGroup,'无岗位')}]]

    • 邮箱地址: -

      [[${user.email}]]

      +

      [[${#strings.abbreviate(user.email, 16)}]]

    • 创建时间: -

      [[${#dates.format(user.createTime, 'yyyy-MM-dd')}]]

      +

      [[${#dates.format(user.createTime, 'yyyy-MM-dd')}]]

    @@ -76,7 +77,7 @@
    - +
    @@ -143,9 +144,28 @@ /*用户管理-头像*/ function avatar() { var url = ctx + 'system/user/profile/avatar'; - $.modal.open("修改头像", url); + top.layer.open({ + type: 2, + area: [$(window).width() + 'px', $(window).height() + 'px'], + fix: false, + //不固定 + maxmin: true, + shade: 0.3, + title: "修改头像", + content: url, + btn: ['确定', '关闭'], + // 弹层外区域关闭 + shadeClose: true, + yes: function(index, layero) { + var iframeWin = layero.find('iframe')[0]; + iframeWin.contentWindow.submitHandler(index, layero); + }, + cancel: function(index) { + return true; + } + }); } - + /*用户信息-修改*/ $("#form-user-edit").validate({ onkeyup: false, @@ -263,7 +283,9 @@ }); function submitChangPassword () { - if ($.validate.form("form-user-resetPwd")) { + var chrtype = [[${#strings.defaultString(@config.getKey('sys.account.chrtype'), 0)}]]; + var password = $("#newPassword").val(); + if ($.validate.form("form-user-resetPwd") && checkpwd(chrtype, password)) { $.operate.saveModal(ctx + "system/user/profile/resetPwd", $('#form-user-resetPwd').serialize()); } } diff --git a/ruoyi-admin/src/main/resources/templates/system/user/profile/resetPwd.html b/ruoyi-admin/src/main/resources/templates/system/user/profile/resetPwd.html index e6a87b68d..815f0af32 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/profile/resetPwd.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/profile/resetPwd.html @@ -8,7 +8,7 @@
    - +
    @@ -28,7 +28,7 @@
    - + 请再次输入您的密码
    @@ -57,7 +57,7 @@ minlength: 5, maxlength: 20 }, - confirm: { + confirmPassword: { required: true, equalTo: "#newPassword" } @@ -72,7 +72,7 @@ minlength: "密码不能小于6个字符", maxlength: "密码不能大于20个字符" }, - confirm: { + confirmPassword: { required: "请再次输入新密码", equalTo: "两次密码输入不一致" } @@ -82,7 +82,9 @@ }); function submitHandler() { - if ($.validate.form()) { + var chrtype = [[${#strings.defaultString(@config.getKey('sys.account.chrtype'), 0)}]]; + var password = $("#newPassword").val(); + if ($.validate.form() && checkpwd(chrtype, password)) { $.operate.save(ctx + "system/user/profile/resetPwd", $('#form-user-resetPwd').serialize()); } } diff --git a/ruoyi-admin/src/main/resources/templates/system/user/resetPwd.html b/ruoyi-admin/src/main/resources/templates/system/user/resetPwd.html index e20dc85b0..dd44b4159 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/resetPwd.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/resetPwd.html @@ -8,7 +8,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/user/user.html b/ruoyi-admin/src/main/resources/templates/system/user/user.html index b58ca59f6..29b0442b1 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/user.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/user.html @@ -166,7 +166,10 @@ var actions = []; actions.push('编辑 '); actions.push('删除 '); - actions.push('重置'); + var more = []; + more.push("重置密码 "); + more.push("分配角色"); + actions.push('更多操作'); return actions.join(''); } }] @@ -219,6 +222,12 @@ $.modal.open("重置密码", url, '800', '300'); } + /* 用户管理-分配角色 */ + function authRole(userId) { + var url = prefix + '/authRole/' + userId; + $.modal.openTab("用户分配角色", url); + } + /* 用户状态显示 */ function statusTools(row) { if (row.status == 1) { diff --git a/ruoyi-admin/src/main/resources/templates/tool/build/build.html b/ruoyi-admin/src/main/resources/templates/tool/build/build.html index e486bb576..daa8b44a9 100644 --- a/ruoyi-admin/src/main/resources/templates/tool/build/build.html +++ b/ruoyi-admin/src/main/resources/templates/tool/build/build.html @@ -162,12 +162,7 @@ + $(document).ready(function(){setup_draggable();$("#n-columns").on("change",function(){var v=$(this).val();if(v==="1"){var $col=$(".form-body .col-md-12").toggle(true);$(".form-body .col-md-6 .draggable").each(function(i,el){$(this).remove().appendTo($col)});$(".form-body .col-md-6").toggle(false)}else{var $col=$(".form-body .col-md-6").toggle(true);$(".form-body .col-md-12 .draggable").each(function(i,el){$(this).remove().appendTo(i%2?$col[1]:$col[0])});$(".form-body .col-md-12").toggle(false)}});$("#copy-to-clipboard").on("click",function(){var $copy=$(".form-body").clone().appendTo(document.body);$copy.find(".tools, :hidden").remove();$.each(["draggable","droppable","sortable","dropped","ui-sortable","ui-draggable","ui-droppable","form-body"],function(i,c){$copy.find("."+c).removeClass(c).removeAttr("style")});var html=html_beautify($copy.html());$copy.remove();$modal=get_modal(html).modal("show");$modal.find(".btn").remove();$modal.find(".modal-title").html("复制HTML代码");$modal.find(":input:first").select().focus();return false})});var setup_draggable=function(){$(".draggable").draggable({appendTo:"body",helper:"clone"});$(".droppable").droppable({accept:".draggable",helper:"clone",hoverClass:"droppable-active",drop:function(event,ui){$(".empty-form").remove();var $orig=$(ui.draggable);if(!$(ui.draggable).hasClass("dropped")){var $el=$orig.clone().addClass("dropped").css({"position":"static","left":null,"right":null}).appendTo(this);if($el.find("label").hasClass("radio-box")){$el=$el.html(''+'
    '+''+''+"
    ")}else{if($el.find("label").hasClass("check-box")){$el=$el.html(''+'
    '+''+''+''+"
    ")}}var id=$orig.find(":input").attr("id");if(id){id=id.split("-").slice(0,-1).join("-")+"-"+(parseInt(id.split("-").slice(-1)[0])+1);$orig.find(":input").attr("id",id);$orig.find("label").attr("for",id)}$('

    编辑HTML | 移除

    ').appendTo($el)}else{if($(this)[0]!=$orig.parent()[0]){var $el=$orig.clone().css({"position":"static","left":null,"right":null}).appendTo(this);$orig.remove()}}}}).sortable()};var get_modal=function(content){var modal=$('').appendTo(document.body);var doms=document.getElementsByClassName("textarea-show-src");for(var i=0;i diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 89d170ae1..5adbe2a15 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -5,103 +5,102 @@ ruoyi com.ruoyi - 4.1.0 + 4.4.0 4.0.0 - + ruoyi-common - - - common通用工具 - + + + common通用工具 + - - - - org.springframework - spring-context-support - - - - + + + + org.springframework + spring-context-support + + + + org.springframework spring-web - + - - org.apache.shiro - shiro-core - - - - javax.validation - validation-api + org.apache.shiro + shiro-core - - - - org.apache.commons - commons-lang3 - - - - - com.fasterxml.jackson.core - jackson-databind - - - - - com.alibaba - fastjson - - - - - commons-io - commons-io - - - - - commons-fileupload - commons-fileupload - - - - - org.apache.poi - poi-ooxml - - - - - org.yaml - snakeyaml - - - + + - javax.servlet - javax.servlet-api - + org.apache.shiro + shiro-ehcache + - - - org.springframework.boot - spring-boot-starter-data-jpa - + + + com.github.pagehelper + pagehelper-spring-boot-starter + - - - org.projectlombok - lombok - provided - + + + javax.validation + validation-api + + + + + org.apache.commons + commons-lang3 + + + + + com.fasterxml.jackson.core + jackson-databind + + + + + com.alibaba + fastjson + + + + + commons-io + commons-io + + + + + commons-fileupload + commons-fileupload + + + + + org.apache.poi + poi-ooxml + + + + + org.yaml + snakeyaml + + + + + javax.servlet + javax.servlet-api + + + - - \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java index f73eabebe..19d87e9b2 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java @@ -4,15 +4,22 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.math.BigDecimal; /** * 自定义导出Excel数据注解 - * + * * @author ruoyi */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) -public @interface Excel { +public @interface Excel +{ + /** + * 导出时在excel中排序 + */ + public int sort() default Integer.MAX_VALUE; + /** * 导出到Excel中的名字. */ @@ -23,11 +30,31 @@ public @interface Excel { */ public String dateFormat() default ""; + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + public String dictType() default ""; + /** * 读取内容转表达式 (如: 0=男,1=女,2=未知) */ public String readConverterExp() default ""; + /** + * 分隔符,读取字符串组内容 + */ + public String separator() default ","; + + /** + * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化) + */ + public int scale() default -1; + + /** + * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN + */ + public int roundingMode() default BigDecimal.ROUND_HALF_EVEN; + /** * 导出类型(0数字 1字符串) */ @@ -73,33 +100,44 @@ public @interface Excel { */ public String targetAttr() default ""; + /** + * 是否自动统计数据,在最后追加一行统计数据总和 + */ + public boolean isStatistics() default false; + /** * 字段类型(0:导出导入;1:仅导出;2:仅导入) */ Type type() default Type.ALL; - public enum Type { + public enum Type + { ALL(0), EXPORT(1), IMPORT(2); private final int value; - Type(int value) { + Type(int value) + { this.value = value; } - public int value() { + public int value() + { return this.value; } } - public enum ColumnType { + public enum ColumnType + { NUMERIC(0), STRING(1); private final int value; - ColumnType(int value) { + ColumnType(int value) + { this.value = value; } - public int value() { + public int value() + { return this.value; } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java index 40cb6feb0..0b33bc19e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java @@ -2,7 +2,6 @@ package com.ruoyi.common.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @@ -12,7 +11,6 @@ import java.lang.annotation.Target; * * @author ruoyi */ -@Inherited @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index 8a8066c1b..049d1e928 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -11,6 +11,11 @@ public class Constants { */ public static final String UTF8 = "UTF-8"; + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + /** * 通用成功标识 */ @@ -31,6 +36,11 @@ public class Constants { */ public static final String LOGOUT = "Logout"; + /** + * 注册 + */ + public static final String REGISTER = "Register"; + /** * 登录失败 */ @@ -61,6 +71,26 @@ public class Constants { */ public static final String IS_ASC = "isAsc"; + /** + * 参数管理 cache name + */ + public static final String SYS_CONFIG_CACHE = "sys-config"; + + /** + * 参数管理 cache key + */ + public static final String SYS_CONFIG_KEY = "sys_config:"; + + /** + * 字典管理 cache name + */ + public static final String SYS_DICT_CACHE = "sys-dict"; + + /** + * 字典管理 cache key + */ + public static final String SYS_DICT_KEY = "sys_dict:"; + /** * 资源映射路径 前缀 */ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java index baba26c09..712fa5d86 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java @@ -2,146 +2,108 @@ package com.ruoyi.common.constant; /** * 代码生成通用常量 - * + * * @author ruoyi */ -public class GenConstants { - /** - * 单表(增删改查) - */ +public class GenConstants +{ + /** 单表(增删改查) */ public static final String TPL_CRUD = "crud"; - /** - * 树表(增删改查) - */ + /** 树表(增删改查) */ public static final String TPL_TREE = "tree"; - /** - * 树编码字段 - */ + /** 主子表(增删改查) */ + public static final String TPL_SUB = "sub"; + + /** 树编码字段 */ public static final String TREE_CODE = "treeCode"; - /** - * 树父编码字段 - */ + /** 树父编码字段 */ public static final String TREE_PARENT_CODE = "treeParentCode"; - /** - * 树名称字段 - */ + /** 树名称字段 */ public static final String TREE_NAME = "treeName"; - /** - * 数据库字符串类型 - */ - public static final String[] COLUMNTYPE_STR = {"char", "varchar", "narchar", "varchar2", "tinytext", "text", - "mediumtext", "longtext"}; + /** 上级菜单ID字段 */ + public static final String PARENT_MENU_ID = "parentMenuId"; - /** - * 数据库时间类型 - */ - public static final String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"}; + /** 上级菜单名称字段 */ + public static final String PARENT_MENU_NAME = "parentMenuName"; - /** - * 数据库数字类型 - */ - public static final String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", - "bigint", "float", "float", "double", "decimal"}; + /** 数据库字符串类型 */ + public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2", "tinytext", "text", + "mediumtext", "longtext" }; - /** - * 页面不需要编辑字段 - */ - public static final String[] COLUMNNAME_NOT_EDIT = {"id", "create_by", "create_time", "del_flag"}; + /** 数据库时间类型 */ + public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" }; - /** - * 页面不需要显示的列表字段 - */ - public static final String[] COLUMNNAME_NOT_LIST = {"id", "create_by", "create_time", "del_flag", "update_by", - "update_time"}; + /** 数据库数字类型 */ + public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer", + "bigint", "float", "float", "double", "decimal" }; - /** - * 页面不需要查询字段 - */ - public static final String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by", - "update_time", "remark"}; + /** 页面不需要编辑字段 */ + public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" }; - /** - * Entity基类字段 - */ - public static final String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime", "remark"}; + /** 页面不需要显示的列表字段 */ + public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by", + "update_time" }; - /** - * Tree基类字段 - */ - public static final String[] TREE_ENTITY = {"parentName", "parentId", "orderNum", "ancestors"}; + /** 页面不需要查询字段 */ + public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark" }; - /** - * 文本框 - */ + /** Entity基类字段 */ + public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" }; + + /** Tree基类字段 */ + public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors" }; + + /** 文本框 */ public static final String HTML_INPUT = "input"; - /** - * 文本域 - */ + /** 文本域 */ public static final String HTML_TEXTAREA = "textarea"; - /** - * 下拉框 - */ + /** 下拉框 */ public static final String HTML_SELECT = "select"; - /** - * 单选框 - */ + /** 单选框 */ public static final String HTML_RADIO = "radio"; - /** - * 复选框 - */ + /** 复选框 */ public static final String HTML_CHECKBOX = "checkbox"; - /** - * 日期控件 - */ + /** 日期控件 */ public static final String HTML_DATETIME = "datetime"; - /** - * 字符串类型 - */ + /** 上传控件 */ + public static final String HTML_UPLOAD = "upload"; + + /** 富文本控件 */ + public static final String HTML_SUMMERNOTE = "summernote"; + + /** 字符串类型 */ public static final String TYPE_STRING = "String"; - /** - * 整型 - */ + /** 整型 */ public static final String TYPE_INTEGER = "Integer"; - /** - * 长整型 - */ + /** 长整型 */ public static final String TYPE_LONG = "Long"; - /** - * 浮点型 - */ + /** 浮点型 */ public static final String TYPE_DOUBLE = "Double"; - /** - * 高精度计算类型 - */ + /** 高精度计算类型 */ public static final String TYPE_BIGDECIMAL = "BigDecimal"; - /** - * 时间类型 - */ + /** 时间类型 */ public static final String TYPE_DATE = "Date"; - /** - * 模糊查询 - */ + /** 模糊查询 */ public static final String QUERY_LIKE = "LIKE"; - /** - * 需要 - */ + /** 需要 */ public static final String REQUIRE = "1"; } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java index c5f9fa0be..62ad81545 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java @@ -2,38 +2,30 @@ package com.ruoyi.common.constant; /** * 任务调度通用常量 - * + * * @author ruoyi */ -public interface ScheduleConstants { +public class ScheduleConstants +{ public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME"; - /** - * 执行目标key - */ + /** 执行目标key */ public static final String TASK_PROPERTIES = "TASK_PROPERTIES"; - /** - * 默认 - */ + /** 默认 */ public static final String MISFIRE_DEFAULT = "0"; - /** - * 立即触发执行 - */ + /** 立即触发执行 */ public static final String MISFIRE_IGNORE_MISFIRES = "1"; - /** - * 触发一次执行 - */ + /** 触发一次执行 */ public static final String MISFIRE_FIRE_AND_PROCEED = "2"; - /** - * 不触发立即执行 - */ + /** 不触发立即执行 */ public static final String MISFIRE_DO_NOTHING = "3"; - public enum Status { + public enum Status + { /** * 正常 */ @@ -45,11 +37,13 @@ public interface ScheduleConstants { private String value; - private Status(String value) { + private Status(String value) + { this.value = value; } - public String getValue() { + public String getValue() + { return value; } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ShiroConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ShiroConstants.java index a5a0c0c79..2e00a2ab1 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ShiroConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ShiroConstants.java @@ -2,10 +2,11 @@ package com.ruoyi.common.constant; /** * Shiro通用常量 - * + * * @author ruoyi */ -public interface ShiroConstants { +public class ShiroConstants +{ /** * 当前登录的用户 */ @@ -19,22 +20,22 @@ public interface ShiroConstants { /** * 消息key */ - public static String MESSAGE = "message"; + public static final String MESSAGE = "message"; /** * 错误key */ - public static String ERROR = "errorMsg"; + public static final String ERROR = "errorMsg"; /** * 编码格式 */ - public static String ENCODING = "UTF-8"; + public static final String ENCODING = "UTF-8"; /** * 当前在线会话 */ - public String ONLINE_SESSION = "online_session"; + public static final String ONLINE_SESSION = "online_session"; /** * 验证码key diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java index 27ce76cde..b31614169 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java @@ -2,48 +2,38 @@ package com.ruoyi.common.constant; /** * 用户常量信息 - * + * * @author ruoyi */ -public class UserConstants { +public class UserConstants +{ /** * 平台内系统用户的唯一标志 */ public static final String SYS_USER = "SYS_USER"; - /** - * 正常状态 - */ + /** 正常状态 */ public static final String NORMAL = "0"; - /** - * 异常状态 - */ + /** 异常状态 */ public static final String EXCEPTION = "1"; - /** - * 用户封禁状态 - */ - public static final String USER_BLOCKED = "1"; + /** 用户封禁状态 */ + public static final String USER_DISABLE = "1"; - /** - * 角色封禁状态 - */ - public static final String ROLE_BLOCKED = "1"; + /** 角色封禁状态 */ + public static final String ROLE_DISABLE = "1"; - /** - * 部门正常状态 - */ + /** 部门正常状态 */ public static final String DEPT_NORMAL = "0"; - /** - * 字典正常状态 - */ + /** 部门停用状态 */ + public static final String DEPT_DISABLE = "1"; + + /** 字典正常状态 */ public static final String DICT_NORMAL = "0"; - /** - * 是否为系统默认(是) - */ + /** 是否为系统默认(是) */ public static final String YES = "Y"; /** @@ -52,69 +42,47 @@ public class UserConstants { public static final int USERNAME_MIN_LENGTH = 2; public static final int USERNAME_MAX_LENGTH = 20; - /** - * 登录名称是否唯一的返回结果码 - */ + /** 登录名称是否唯一的返回结果码 */ public final static String USER_NAME_UNIQUE = "0"; public final static String USER_NAME_NOT_UNIQUE = "1"; - /** - * 手机号码是否唯一的返回结果 - */ + /** 手机号码是否唯一的返回结果 */ public final static String USER_PHONE_UNIQUE = "0"; public final static String USER_PHONE_NOT_UNIQUE = "1"; - /** - * e-mail 是否唯一的返回结果 - */ + /** e-mail 是否唯一的返回结果 */ public final static String USER_EMAIL_UNIQUE = "0"; public final static String USER_EMAIL_NOT_UNIQUE = "1"; - /** - * 部门名称是否唯一的返回结果码 - */ + /** 部门名称是否唯一的返回结果码 */ public final static String DEPT_NAME_UNIQUE = "0"; public final static String DEPT_NAME_NOT_UNIQUE = "1"; - /** - * 角色名称是否唯一的返回结果码 - */ + /** 角色名称是否唯一的返回结果码 */ public final static String ROLE_NAME_UNIQUE = "0"; public final static String ROLE_NAME_NOT_UNIQUE = "1"; - /** - * 岗位名称是否唯一的返回结果码 - */ + /** 岗位名称是否唯一的返回结果码 */ public final static String POST_NAME_UNIQUE = "0"; public final static String POST_NAME_NOT_UNIQUE = "1"; - /** - * 角色权限是否唯一的返回结果码 - */ + /** 角色权限是否唯一的返回结果码 */ public final static String ROLE_KEY_UNIQUE = "0"; public final static String ROLE_KEY_NOT_UNIQUE = "1"; - /** - * 岗位编码是否唯一的返回结果码 - */ + /** 岗位编码是否唯一的返回结果码 */ public final static String POST_CODE_UNIQUE = "0"; public final static String POST_CODE_NOT_UNIQUE = "1"; - /** - * 菜单名称是否唯一的返回结果码 - */ + /** 菜单名称是否唯一的返回结果码 */ public final static String MENU_NAME_UNIQUE = "0"; public final static String MENU_NAME_NOT_UNIQUE = "1"; - /** - * 字典类型是否唯一的返回结果码 - */ + /** 字典类型是否唯一的返回结果码 */ public final static String DICT_TYPE_UNIQUE = "0"; public final static String DICT_TYPE_NOT_UNIQUE = "1"; - /** - * 参数键名是否唯一的返回结果码 - */ + /** 参数键名是否唯一的返回结果码 */ public final static String CONFIG_KEY_UNIQUE = "0"; public final static String CONFIG_KEY_NOT_UNIQUE = "1"; @@ -124,6 +92,12 @@ public class UserConstants { public static final int PASSWORD_MIN_LENGTH = 5; public static final int PASSWORD_MAX_LENGTH = 20; + /** + * 用户类型 + */ + public static final String SYSTEM_USER_TYPE = "00"; + public static final String REGISTER_USER_TYPE = "01"; + /** * 手机号码格式限制 */ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java index 69d4bf49c..6adeffb47 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java @@ -46,6 +46,34 @@ public class BaseController { }); } + /** + * 设置请求分页数据 + */ + protected void startPage() + { + PageDomain pageDomain = TableSupport.buildPageRequest(); + Integer pageNum = pageDomain.getPageNum(); + Integer pageSize = pageDomain.getPageSize(); + if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) + { + String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); + PageHelper.startPage(pageNum, pageSize, orderBy); + } + } + + /** + * 设置请求排序数据 + */ + protected void startOrderBy() + { + PageDomain pageDomain = TableSupport.buildPageRequest(); + if (StringUtils.isNotEmpty(pageDomain.getOrderBy())) + { + String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy()); + PageHelper.orderBy(orderBy); + } + } + /** * 获取request */ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/CxSelect.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/CxSelect.java new file mode 100644 index 000000000..28c123520 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/CxSelect.java @@ -0,0 +1,69 @@ +package com.ruoyi.common.core.domain; + +import java.io.Serializable; +import java.util.List; + +/** + * CxSelect树结构实体类 + * + * @author ruoyi + */ +public class CxSelect implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** + * 数据值字段名称 + */ + private String v; + + /** + * 数据标题字段名称 + */ + private String n; + + /** + * 子集数据字段名称 + */ + private List s; + + public CxSelect() + { + } + + public CxSelect(String v, String n) + { + this.v = v; + this.n = n; + } + + public List getS() + { + return s; + } + + public void setN(String n) + { + this.n = n; + } + + public String getN() + { + return n; + } + + public void setS(List s) + { + this.s = s; + } + + public String getV() + { + return v; + } + + public void setV(String v) + { + this.v = v; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java index a7b8d4052..6fba8837e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java @@ -4,63 +4,69 @@ import com.ruoyi.common.utils.StringUtils; /** * 分页数据 - * + * * @author ruoyi */ -public class PageDomain { - /** - * 当前记录起始索引 - */ +public class PageDomain +{ + /** 当前记录起始索引 */ private Integer pageNum; - /** - * 每页显示记录数 - */ - private Integer pageSize; - /** - * 排序列 - */ - private String orderByColumn; - /** - * 排序的方向 "desc" 或者 "asc". - */ - private String isAsc; - public String getOrderBy() { - if (StringUtils.isEmpty(orderByColumn)) { + /** 每页显示记录数 */ + private Integer pageSize; + + /** 排序列 */ + private String orderByColumn; + + /** 排序的方向desc或者asc */ + private String isAsc = "asc"; + + public String getOrderBy() + { + if (StringUtils.isEmpty(orderByColumn)) + { return ""; } return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc; } - public Integer getPageNum() { + public Integer getPageNum() + { return pageNum; } - public void setPageNum(Integer pageNum) { + public void setPageNum(Integer pageNum) + { this.pageNum = pageNum; } - public Integer getPageSize() { + public Integer getPageSize() + { return pageSize; } - public void setPageSize(Integer pageSize) { + public void setPageSize(Integer pageSize) + { this.pageSize = pageSize; } - public String getOrderByColumn() { + public String getOrderByColumn() + { return orderByColumn; } - public void setOrderByColumn(String orderByColumn) { + public void setOrderByColumn(String orderByColumn) + { this.orderByColumn = orderByColumn; } - public String getIsAsc() { + public String getIsAsc() + { return isAsc; } - public void setIsAsc(String isAsc) { + public void setIsAsc(String isAsc) + { this.isAsc = isAsc; } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java index ac74e061e..373e59283 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java @@ -5,78 +5,81 @@ import java.util.List; /** * 表格分页数据对象 - * + * * @author ruoyi */ -public class TableDataInfo implements Serializable { +public class TableDataInfo implements Serializable +{ private static final long serialVersionUID = 1L; - /** - * 总记录数 - */ + /** 总记录数 */ private long total; - /** - * 列表数据 - */ + /** 列表数据 */ private List rows; - /** - * 消息状态码 - */ + /** 消息状态码 */ private int code; - /** - * 消息内容 - */ - private int msg; + /** 消息内容 */ + private String msg; /** * 表格数据对象 */ - public TableDataInfo() { + public TableDataInfo() + { } /** * 分页 - * - * @param list 列表数据 + * + * @param list 列表数据 * @param total 总记录数 */ - public TableDataInfo(List list, int total) { + public TableDataInfo(List list, int total) + { this.rows = list; this.total = total; } - public long getTotal() { + public long getTotal() + { return total; } - public void setTotal(long total) { + public void setTotal(long total) + { this.total = total; } - public List getRows() { + public List getRows() + { return rows; } - public void setRows(List rows) { + public void setRows(List rows) + { this.rows = rows; } - public int getCode() { + public int getCode() + { return code; } - public void setCode(int code) { + public void setCode(int code) + { this.code = code; } - public int getMsg() { + public String getMsg() + { return msg; } - public void setMsg(int msg) { + public void setMsg(String msg) + { this.msg = msg; } } \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java new file mode 100644 index 000000000..a544fb645 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.exception; + +/** + * 工具类异常 + * + * @author ruoyi + */ +public class UtilException extends RuntimeException +{ + private static final long serialVersionUID = 8247610319171014183L; + + public UtilException(Throwable e) + { + super(e.getMessage(), e); + } + + public UtilException(String message) + { + super(message); + } + + public UtilException(String message, Throwable throwable) + { + super(message, throwable); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java index ce5c7fdaf..9f845cbaf 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java @@ -1,60 +1,80 @@ package com.ruoyi.common.exception.file; import java.util.Arrays; - import org.apache.commons.fileupload.FileUploadException; /** * 文件上传 误异常类 - * + * * @author ruoyi */ -public class InvalidExtensionException extends FileUploadException { +public class InvalidExtensionException extends FileUploadException +{ private static final long serialVersionUID = 1L; private String[] allowedExtension; private String extension; private String filename; - public InvalidExtensionException(String[] allowedExtension, String extension, String filename) { + public InvalidExtensionException(String[] allowedExtension, String extension, String filename) + { super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]"); this.allowedExtension = allowedExtension; this.extension = extension; this.filename = filename; } - public String[] getAllowedExtension() { + public String[] getAllowedExtension() + { return allowedExtension; } - public String getExtension() { + public String getExtension() + { return extension; } - public String getFilename() { + public String getFilename() + { return filename; } - public static class InvalidImageExtensionException extends InvalidExtensionException { + public static class InvalidImageExtensionException extends InvalidExtensionException + { private static final long serialVersionUID = 1L; - public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename) { + public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename) + { super(allowedExtension, extension, filename); } } - public static class InvalidFlashExtensionException extends InvalidExtensionException { + public static class InvalidFlashExtensionException extends InvalidExtensionException + { private static final long serialVersionUID = 1L; - public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename) { + public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename) + { super(allowedExtension, extension, filename); } } - public static class InvalidMediaExtensionException extends InvalidExtensionException { + public static class InvalidMediaExtensionException extends InvalidExtensionException + { private static final long serialVersionUID = 1L; - public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename) { + public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename) + { + super(allowedExtension, extension, filename); + } + } + + public static class InvalidVideoExtensionException extends InvalidExtensionException + { + private static final long serialVersionUID = 1L; + + public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename) + { super(allowedExtension, extension, filename); } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/AddressUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/AddressUtils.java index 936247bee..71de58b10 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/AddressUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/AddressUtils.java @@ -2,43 +2,52 @@ package com.ruoyi.common.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.alibaba.fastjson.JSONObject; import com.ruoyi.common.config.Global; -import com.ruoyi.common.json.JSON; -import com.ruoyi.common.json.JSONObject; +import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.http.HttpUtils; /** * 获取地址类 - * + * * @author ruoyi */ -public class AddressUtils { +public class AddressUtils +{ private static final Logger log = LoggerFactory.getLogger(AddressUtils.class); - public static final String IP_URL = "http://ip.taobao.com/service/getIpInfo.php"; + // IP地址查询 + public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp"; - public static String getRealAddressByIP(String ip) { - String address = "XX XX"; + // 未知地址 + public static final String UNKNOWN = "XX XX"; + public static String getRealAddressByIP(String ip) + { + String address = UNKNOWN; // 内网不查询 - if (IpUtils.internalIp(ip)) { + if (IpUtils.internalIp(ip)) + { return "内网IP"; } - if (Global.isAddressEnabled()) { - String rspStr = HttpUtils.sendPost(IP_URL, "ip=" + ip); - if (StringUtils.isEmpty(rspStr)) { - log.error("获取地理位置异常 {}", ip); - return address; + if (Global.isAddressEnabled()) + { + try + { + String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK); + if (StringUtils.isEmpty(rspStr)) + { + log.error("获取地理位置异常 {}", ip); + return UNKNOWN; + } + JSONObject obj = JSONObject.parseObject(rspStr); + String region = obj.getString("pro"); + String city = obj.getString("city"); + return String.format("%s %s", region, city); } - JSONObject obj; - try { - obj = JSON.unmarshal(rspStr, JSONObject.class); - JSONObject data = obj.getObj("data"); - String region = data.getStr("region"); - String city = data.getStr("city"); - address = region + " " + city; - } catch (Exception e) { - log.error("获取地理位置异常 {}", ip); + catch (Exception e) + { + log.error("获取地理位置异常 {}", e); } } return address; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/CacheUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CacheUtils.java new file mode 100644 index 000000000..80dcda39c --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CacheUtils.java @@ -0,0 +1,187 @@ +package com.ruoyi.common.utils; + +import java.util.Iterator; +import java.util.Set; +import org.apache.shiro.cache.Cache; +import org.apache.shiro.cache.CacheManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.ruoyi.common.utils.spring.SpringUtils; + +/** + * Cache工具类 + * + * @author ruoyi + */ +public class CacheUtils +{ + private static Logger logger = LoggerFactory.getLogger(CacheUtils.class); + + private static CacheManager cacheManager = SpringUtils.getBean(CacheManager.class); + + private static final String SYS_CACHE = "sys-cache"; + + /** + * 获取SYS_CACHE缓存 + * + * @param key + * @return + */ + public static Object get(String key) + { + return get(SYS_CACHE, key); + } + + /** + * 获取SYS_CACHE缓存 + * + * @param key + * @param defaultValue + * @return + */ + public static Object get(String key, Object defaultValue) + { + Object value = get(key); + return value != null ? value : defaultValue; + } + + /** + * 写入SYS_CACHE缓存 + * + * @param key + * @return + */ + public static void put(String key, Object value) + { + put(SYS_CACHE, key, value); + } + + /** + * 从SYS_CACHE缓存中移除 + * + * @param key + * @return + */ + public static void remove(String key) + { + remove(SYS_CACHE, key); + } + + /** + * 获取缓存 + * + * @param cacheName + * @param key + * @return + */ + public static Object get(String cacheName, String key) + { + return getCache(cacheName).get(getKey(key)); + } + + /** + * 获取缓存 + * + * @param cacheName + * @param key + * @param defaultValue + * @return + */ + public static Object get(String cacheName, String key, Object defaultValue) + { + Object value = get(cacheName, getKey(key)); + return value != null ? value : defaultValue; + } + + /** + * 写入缓存 + * + * @param cacheName + * @param key + * @param value + */ + public static void put(String cacheName, String key, Object value) + { + getCache(cacheName).put(getKey(key), value); + } + + /** + * 从缓存中移除 + * + * @param cacheName + * @param key + */ + public static void remove(String cacheName, String key) + { + getCache(cacheName).remove(getKey(key)); + } + + /** + * 从缓存中移除所有 + * + * @param cacheName + */ + public static void removeAll(String cacheName) + { + Cache cache = getCache(cacheName); + Set keys = cache.keys(); + for (Iterator it = keys.iterator(); it.hasNext();) + { + cache.remove(it.next()); + } + logger.info("清理缓存: {} => {}", cacheName, keys); + } + + /** + * 从缓存中移除指定key + * + * @param keys + */ + public static void removeByKeys(Set keys) + { + removeByKeys(SYS_CACHE, keys); + } + + /** + * 从缓存中移除指定key + * + * @param cacheName + * @param keys + */ + public static void removeByKeys(String cacheName, Set keys) + { + for (Iterator it = keys.iterator(); it.hasNext();) + { + remove(it.next()); + } + logger.info("清理缓存: {} => {}", cacheName, keys); + } + + /** + * 获取缓存键名 + * + * @param key + * @return + */ + private static String getKey(String key) + { + return key; + } + + /** + * 获得一个Cache,没有则显示日志。 + * + * @param cacheName + * @return + */ + private static Cache getCache(String cacheName) + { + Cache cache = cacheManager.getCache(cacheName); + if (cache == null) + { + throw new RuntimeException("当前系统中没有定义“" + cacheName + "”这个缓存。"); + } + return cache; + } + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/CookieUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CookieUtils.java new file mode 100644 index 000000000..13c1d5ed0 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CookieUtils.java @@ -0,0 +1,138 @@ +package com.ruoyi.common.utils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Cookie工具类 + * + * @author ruoyi + */ +public class CookieUtils +{ + /** + * 设置 Cookie(生成时间为1天) + * + * @param name 名称 + * @param value 值 + */ + public static void setCookie(HttpServletResponse response, String name, String value) + { + setCookie(response, name, value, 60 * 60 * 24); + } + + /** + * 设置 Cookie + * + * @param name 名称 + * @param value 值 + * @param maxAge 生存时间(单位秒) + * @param uri 路径 + */ + public static void setCookie(HttpServletResponse response, String name, String value, String path) + { + setCookie(response, name, value, path, 60 * 60 * 24); + } + + /** + * 设置 Cookie + * + * @param name 名称 + * @param value 值 + * @param maxAge 生存时间(单位秒) + * @param uri 路径 + */ + public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) + { + setCookie(response, name, value, "/", maxAge); + } + + /** + * 设置 Cookie + * + * @param name 名称 + * @param value 值 + * @param maxAge 生存时间(单位秒) + * @param uri 路径 + */ + public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge) + { + Cookie cookie = new Cookie(name, null); + cookie.setPath(path); + cookie.setMaxAge(maxAge); + try + { + cookie.setValue(URLEncoder.encode(value, "utf-8")); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + response.addCookie(cookie); + } + + /** + * 获得指定Cookie的值 + * + * @param name 名称 + * @return 值 + */ + public static String getCookie(HttpServletRequest request, String name) + { + return getCookie(request, null, name, false); + } + + /** + * 获得指定Cookie的值,并删除。 + * + * @param name 名称 + * @return 值 + */ + public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name) + { + return getCookie(request, response, name, true); + } + + /** + * 获得指定Cookie的值 + * + * @param request 请求对象 + * @param response 响应对象 + * @param name 名字 + * @param isRemove 是否移除 + * @return 值 + */ + public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name, + boolean isRemove) + { + String value = null; + Cookie[] cookies = request.getCookies(); + if (cookies != null) + { + for (Cookie cookie : cookies) + { + if (cookie.getName().equals(name)) + { + try + { + value = URLDecoder.decode(cookie.getValue(), "utf-8"); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + if (isRemove) + { + cookie.setMaxAge(0); + response.addCookie(cookie); + } + } + } + } + return value; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/IpUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/IpUtils.java index f1b35cf13..cb1245e68 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/IpUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/IpUtils.java @@ -6,42 +6,53 @@ import javax.servlet.http.HttpServletRequest; /** * 获取IP方法 - * + * * @author ruoyi */ -public class IpUtils { - public static String getIpAddr(HttpServletRequest request) { - if (request == null) { +public class IpUtils +{ + public static String getIpAddr(HttpServletRequest request) + { + if (request == null) + { return "unknown"; } String ip = request.getHeader("x-forwarded-for"); - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { ip = request.getHeader("Proxy-Client-IP"); } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { ip = request.getHeader("X-Forwarded-For"); } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { ip = request.getHeader("WL-Proxy-Client-IP"); } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { ip = request.getHeader("X-Real-IP"); } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) + { ip = request.getRemoteAddr(); } return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; } - public static boolean internalIp(String ip) { + public static boolean internalIp(String ip) + { byte[] addr = textToNumericFormatV4(ip); return internalIp(addr) || "127.0.0.1".equals(ip); } - private static boolean internalIp(byte[] addr) { - if (StringUtils.isNull(addr) || addr.length < 2) { + private static boolean internalIp(byte[] addr) + { + if (StringUtils.isNull(addr) || addr.length < 2) + { return true; } final byte b0 = addr[0]; @@ -55,15 +66,18 @@ public class IpUtils { // 192.168.x.x/16 final byte SECTION_5 = (byte) 0xC0; final byte SECTION_6 = (byte) 0xA8; - switch (b0) { + switch (b0) + { case SECTION_1: return true; case SECTION_2: - if (b1 >= SECTION_3 && b1 <= SECTION_4) { + if (b1 >= SECTION_3 && b1 <= SECTION_4) + { return true; } case SECTION_5: - switch (b1) { + switch (b1) + { case SECTION_6: return true; } @@ -74,25 +88,30 @@ public class IpUtils { /** * 将IPv4地址转换成字节 - * + * * @param text IPv4地址 * @return byte 字节 */ - public static byte[] textToNumericFormatV4(String text) { - if (text.length() == 0) { + public static byte[] textToNumericFormatV4(String text) + { + if (text.length() == 0) + { return null; } byte[] bytes = new byte[4]; String[] elements = text.split("\\.", -1); - try { + try + { long l; int i; - switch (elements.length) { + switch (elements.length) + { case 1: l = Long.parseLong(elements[0]); - if ((l < 0L) || (l > 4294967295L)) + if ((l < 0L) || (l > 4294967295L)) { return null; + } bytes[0] = (byte) (int) (l >> 24 & 0xFF); bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); @@ -100,58 +119,75 @@ public class IpUtils { break; case 2: l = Integer.parseInt(elements[0]); - if ((l < 0L) || (l > 255L)) + if ((l < 0L) || (l > 255L)) { return null; + } bytes[0] = (byte) (int) (l & 0xFF); l = Integer.parseInt(elements[1]); - if ((l < 0L) || (l > 16777215L)) + if ((l < 0L) || (l > 16777215L)) { return null; + } bytes[1] = (byte) (int) (l >> 16 & 0xFF); bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 3: - for (i = 0; i < 2; ++i) { + for (i = 0; i < 2; ++i) + { l = Integer.parseInt(elements[i]); - if ((l < 0L) || (l > 255L)) + if ((l < 0L) || (l > 255L)) { return null; + } bytes[i] = (byte) (int) (l & 0xFF); } l = Integer.parseInt(elements[2]); - if ((l < 0L) || (l > 65535L)) + if ((l < 0L) || (l > 65535L)) { return null; + } bytes[2] = (byte) (int) (l >> 8 & 0xFF); bytes[3] = (byte) (int) (l & 0xFF); break; case 4: - for (i = 0; i < 4; ++i) { + for (i = 0; i < 4; ++i) + { l = Integer.parseInt(elements[i]); - if ((l < 0L) || (l > 255L)) + if ((l < 0L) || (l > 255L)) { return null; + } bytes[i] = (byte) (int) (l & 0xFF); } break; default: return null; } - } catch (NumberFormatException e) { + } + catch (NumberFormatException e) + { return null; } return bytes; } - public static String getHostIp() { - try { + public static String getHostIp() + { + try + { return InetAddress.getLocalHost().getHostAddress(); - } catch (UnknownHostException e) { + } + catch (UnknownHostException e) + { } return "127.0.0.1"; } - public static String getHostName() { - try { + public static String getHostName() + { + try + { return InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException e) { + } + catch (UnknownHostException e) + { } return "未知"; } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java index 650b97411..019339391 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java @@ -4,7 +4,6 @@ import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; - import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; @@ -12,77 +11,95 @@ import com.ruoyi.common.core.text.Convert; /** * 客户端工具类 - * + * * @author ruoyi */ -public class ServletUtils { +public class ServletUtils +{ + /** + * 定义移动端请求的所有可能类型 + */ + private final static String[] agent = { "Android", "iPhone", "iPod", "iPad", "Windows Phone", "MQQBrowser" }; + /** * 获取String参数 */ - public static String getParameter(String name) { + public static String getParameter(String name) + { return getRequest().getParameter(name); } /** * 获取String参数 */ - public static String getParameter(String name, String defaultValue) { + public static String getParameter(String name, String defaultValue) + { return Convert.toStr(getRequest().getParameter(name), defaultValue); } /** * 获取Integer参数 */ - public static Integer getParameterToInt(String name) { + public static Integer getParameterToInt(String name) + { return Convert.toInt(getRequest().getParameter(name)); } /** * 获取Integer参数 */ - public static Integer getParameterToInt(String name, Integer defaultValue) { + public static Integer getParameterToInt(String name, Integer defaultValue) + { return Convert.toInt(getRequest().getParameter(name), defaultValue); } /** * 获取request */ - public static HttpServletRequest getRequest() { + public static HttpServletRequest getRequest() + { return getRequestAttributes().getRequest(); } /** * 获取response */ - public static HttpServletResponse getResponse() { + public static HttpServletResponse getResponse() + { return getRequestAttributes().getResponse(); } /** * 获取session */ - public static HttpSession getSession() { + public static HttpSession getSession() + { return getRequest().getSession(); } - public static ServletRequestAttributes getRequestAttributes() { + public static ServletRequestAttributes getRequestAttributes() + { RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); return (ServletRequestAttributes) attributes; } /** * 将字符串渲染到客户端 - * + * * @param response 渲染对象 - * @param string 待渲染的字符串 + * @param string 待渲染的字符串 * @return null */ - public static String renderString(HttpServletResponse response, String string) { - try { + public static String renderString(HttpServletResponse response, String string) + { + try + { response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); response.getWriter().print(string); - } catch (IOException e) { + } + catch (IOException e) + { e.printStackTrace(); } return null; @@ -90,29 +107,58 @@ public class ServletUtils { /** * 是否是Ajax异步请求 - * + * * @param request */ - public static boolean isAjaxRequest(HttpServletRequest request) { + public static boolean isAjaxRequest(HttpServletRequest request) + { String accept = request.getHeader("accept"); - if (accept != null && accept.indexOf("application/json") != -1) { + if (accept != null && accept.indexOf("application/json") != -1) + { return true; } String xRequestedWith = request.getHeader("X-Requested-With"); - if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) { + if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) + { return true; } String uri = request.getRequestURI(); - if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) { + if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml")) + { return true; } String ajax = request.getParameter("__ajax"); - if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) { + if (StringUtils.inStringIgnoreCase(ajax, "json", "xml")) + { return true; } return false; } + + /** + * 判断User-Agent 是不是来自于手机 + */ + public static boolean checkAgentIsMobile(String ua) + { + boolean flag = false; + if (!ua.contains("Windows NT") || (ua.contains("Windows NT") && ua.contains("compatible; MSIE 9.0;"))) + { + // 排除 苹果桌面系统 + if (!ua.contains("Windows NT") && !ua.contains("Macintosh")) + { + for (String item : agent) + { + if (ua.contains(item)) + { + flag = true; + break; + } + } + } + } + return flag; + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java index 2a9e19830..19b825c8b 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java @@ -2,172 +2,186 @@ package com.ruoyi.common.utils; import java.util.Collection; import java.util.Map; - import com.ruoyi.common.core.text.StrFormatter; /** * 字符串工具类 - * + * * @author ruoyi */ -public class StringUtils extends org.apache.commons.lang3.StringUtils { - /** - * 空字符串 - */ +public class StringUtils extends org.apache.commons.lang3.StringUtils +{ + /** 空字符串 */ private static final String NULLSTR = ""; - /** - * 下划线 - */ + /** 下划线 */ private static final char SEPARATOR = '_'; /** * 获取参数不为空值 - * + * * @param value defaultValue 要判断的value * @return value 返回值 */ - public static T nvl(T value, T defaultValue) { + public static T nvl(T value, T defaultValue) + { return value != null ? value : defaultValue; } /** * * 判断一个Collection是否为空, 包含List,Set,Queue - * + * * @param coll 要判断的Collection * @return true:为空 false:非空 */ - public static boolean isEmpty(Collection coll) { + public static boolean isEmpty(Collection coll) + { return isNull(coll) || coll.isEmpty(); } /** * * 判断一个Collection是否非空,包含List,Set,Queue - * + * * @param coll 要判断的Collection * @return true:非空 false:空 */ - public static boolean isNotEmpty(Collection coll) { + public static boolean isNotEmpty(Collection coll) + { return !isEmpty(coll); } /** * * 判断一个对象数组是否为空 - * + * * @param objects 要判断的对象数组 - * * @return true:为空 false:非空 + ** @return true:为空 false:非空 */ - public static boolean isEmpty(Object[] objects) { + public static boolean isEmpty(Object[] objects) + { return isNull(objects) || (objects.length == 0); } /** * * 判断一个对象数组是否非空 - * + * * @param objects 要判断的对象数组 * @return true:非空 false:空 */ - public static boolean isNotEmpty(Object[] objects) { + public static boolean isNotEmpty(Object[] objects) + { return !isEmpty(objects); } /** * * 判断一个Map是否为空 - * + * * @param map 要判断的Map * @return true:为空 false:非空 */ - public static boolean isEmpty(Map map) { + public static boolean isEmpty(Map map) + { return isNull(map) || map.isEmpty(); } /** * * 判断一个Map是否为空 - * + * * @param map 要判断的Map * @return true:非空 false:空 */ - public static boolean isNotEmpty(Map map) { + public static boolean isNotEmpty(Map map) + { return !isEmpty(map); } /** * * 判断一个字符串是否为空串 - * + * * @param str String * @return true:为空 false:非空 */ - public static boolean isEmpty(String str) { + public static boolean isEmpty(String str) + { return isNull(str) || NULLSTR.equals(str.trim()); } /** * * 判断一个字符串是否为非空串 - * + * * @param str String * @return true:非空串 false:空串 */ - public static boolean isNotEmpty(String str) { + public static boolean isNotEmpty(String str) + { return !isEmpty(str); } /** * * 判断一个对象是否为空 - * + * * @param object Object * @return true:为空 false:非空 */ - public static boolean isNull(Object object) { + public static boolean isNull(Object object) + { return object == null; } /** * * 判断一个对象是否非空 - * + * * @param object Object * @return true:非空 false:空 */ - public static boolean isNotNull(Object object) { + public static boolean isNotNull(Object object) + { return !isNull(object); } /** * * 判断一个对象是否是数组类型(Java基本型别的数组) - * + * * @param object 对象 * @return true:是数组 false:不是数组 */ - public static boolean isArray(Object object) { + public static boolean isArray(Object object) + { return isNotNull(object) && object.getClass().isArray(); } /** * 去空格 */ - public static String trim(String str) { + public static String trim(String str) + { return (str == null ? "" : str.trim()); } /** * 截取字符串 - * - * @param str 字符串 + * + * @param str 字符串 * @param start 开始 * @return 结果 */ - public static String substring(final String str, int start) { - if (str == null) { + public static String substring(final String str, int start) + { + if (str == null) + { return NULLSTR; } - if (start < 0) { + if (start < 0) + { start = str.length() + start; } - if (start < 0) { + if (start < 0) + { start = 0; } - if (start > str.length()) { + if (start > str.length()) + { return NULLSTR; } @@ -176,36 +190,44 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 截取字符串 - * - * @param str 字符串 + * + * @param str 字符串 * @param start 开始 - * @param end 结束 + * @param end 结束 * @return 结果 */ - public static String substring(final String str, int start, int end) { - if (str == null) { + public static String substring(final String str, int start, int end) + { + if (str == null) + { return NULLSTR; } - if (end < 0) { + if (end < 0) + { end = str.length() + end; } - if (start < 0) { + if (start < 0) + { start = str.length() + start; } - if (end > str.length()) { + if (end > str.length()) + { end = str.length(); } - if (start > end) { + if (start > end) + { return NULLSTR; } - if (start < 0) { + if (start < 0) + { start = 0; } - if (end < 0) { + if (end < 0) + { end = 0; } @@ -220,13 +242,15 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
    * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
    * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
    - * + * * @param template 文本模板,被替换的部分用 {} 表示 - * @param params 参数值 + * @param params 参数值 * @return 格式化后的文本 */ - public static String format(String template, Object... params) { - if (isEmpty(params) || isEmpty(template)) { + public static String format(String template, Object... params) + { + if (isEmpty(params) || isEmpty(template)) + { return template; } return StrFormatter.format(template, params); @@ -235,8 +259,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 下划线转驼峰命名 */ - public static String toUnderScoreCase(String str) { - if (str == null) { + public static String toUnderScoreCase(String str) + { + if (str == null) + { return null; } StringBuilder sb = new StringBuilder(); @@ -246,42 +272,53 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { boolean curreCharIsUpperCase = true; // 下一字符是否大写 boolean nexteCharIsUpperCase = true; - for (int i = 0; i < str.length(); i++) { + for (int i = 0; i < str.length(); i++) + { char c = str.charAt(i); - if (i > 0) { + if (i > 0) + { preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); - } else { + } + else + { preCharIsUpperCase = false; } curreCharIsUpperCase = Character.isUpperCase(c); - if (i < (str.length() - 1)) { + if (i < (str.length() - 1)) + { nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); } - if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) + { sb.append(SEPARATOR); - } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { + } + else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) + { sb.append(SEPARATOR); } sb.append(Character.toLowerCase(c)); } - return sb.toString(); } /** * 是否包含字符串 - * - * @param str 验证字符串 + * + * @param str 验证字符串 * @param strs 字符串组 * @return 包含返回true */ - public static boolean inStringIgnoreCase(String str, String... strs) { - if (str != null && strs != null) { - for (String s : strs) { - if (str.equalsIgnoreCase(trim(s))) { + public static boolean inStringIgnoreCase(String str, String... strs) + { + if (str != null && strs != null) + { + for (String s : strs) + { + if (str.equalsIgnoreCase(trim(s))) + { return true; } } @@ -291,25 +328,31 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { /** * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld - * + * * @param name 转换前的下划线大写方式命名的字符串 * @return 转换后的驼峰式命名的字符串 */ - public static String convertToCamelCase(String name) { + public static String convertToCamelCase(String name) + { StringBuilder result = new StringBuilder(); // 快速检查 - if (name == null || name.isEmpty()) { + if (name == null || name.isEmpty()) + { // 没必要转换 return ""; - } else if (!name.contains("_")) { + } + else if (!name.contains("_")) + { // 不含下划线,仅将首字母大写 return name.substring(0, 1).toUpperCase() + name.substring(1); } // 用下划线将原始字符串分割 String[] camels = name.split("_"); - for (String camel : camels) { + for (String camel : camels) + { // 跳过原始字符串中开头、结尾的下换线或双重下划线 - if (camel.isEmpty()) { + if (camel.isEmpty()) + { continue; } // 首字母大写 @@ -320,27 +363,46 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { } /** - * 驼峰式命名法 例如:user_name->userName + * 驼峰式命名法 + * 例如:user_name->userName */ - public static String toCamelCase(String s) { - if (s == null) { + public static String toCamelCase(String s) + { + if (s == null) + { return null; } + if (s.indexOf(SEPARATOR) == -1) + { + return s; + } s = s.toLowerCase(); StringBuilder sb = new StringBuilder(s.length()); boolean upperCase = false; - for (int i = 0; i < s.length(); i++) { + for (int i = 0; i < s.length(); i++) + { char c = s.charAt(i); - if (c == SEPARATOR) { + if (c == SEPARATOR) + { upperCase = true; - } else if (upperCase) { + } + else if (upperCase) + { sb.append(Character.toUpperCase(c)); upperCase = false; - } else { + } + else + { sb.append(c); } } return sb.toString(); } -} \ No newline at end of file + + @SuppressWarnings("unchecked") + public static T cast(Object obj) + { + return (T) obj; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java index 4d4dfd777..850e1132d 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java @@ -2,7 +2,6 @@ package com.ruoyi.common.utils.file; import java.io.File; import java.io.IOException; - import org.apache.commons.io.FilenameUtils; import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.config.Global; @@ -12,14 +11,15 @@ import com.ruoyi.common.exception.file.FileSizeLimitExceededException; import com.ruoyi.common.exception.file.InvalidExtensionException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.common.utils.security.Md5Utils; +import com.ruoyi.common.utils.uuid.IdUtils; /** * 文件上传工具类 - * + * * @author ruoyi */ -public class FileUploadUtils { +public class FileUploadUtils +{ /** * 默认大小 50M */ @@ -35,13 +35,13 @@ public class FileUploadUtils { */ private static String defaultBaseDir = Global.getProfile(); - private static int counter = 0; - - public static void setDefaultBaseDir(String defaultBaseDir) { + public static void setDefaultBaseDir(String defaultBaseDir) + { FileUploadUtils.defaultBaseDir = defaultBaseDir; } - public static String getDefaultBaseDir() { + public static String getDefaultBaseDir() + { return defaultBaseDir; } @@ -52,10 +52,14 @@ public class FileUploadUtils { * @return 文件名称 * @throws Exception */ - public static final String upload(MultipartFile file) throws IOException { - try { + public static final String upload(MultipartFile file) throws IOException + { + try + { return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } catch (Exception e) { + } + catch (Exception e) + { throw new IOException(e.getMessage(), e); } } @@ -64,14 +68,18 @@ public class FileUploadUtils { * 根据文件路径上传 * * @param baseDir 相对应用的基目录 - * @param file 上传的文件 + * @param file 上传的文件 * @return 文件名称 * @throws IOException */ - public static final String upload(String baseDir, MultipartFile file) throws IOException { - try { + public static final String upload(String baseDir, MultipartFile file) throws IOException + { + try + { return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION); - } catch (Exception e) { + } + catch (Exception e) + { throw new IOException(e.getMessage(), e); } } @@ -79,20 +87,22 @@ public class FileUploadUtils { /** * 文件上传 * - * @param baseDir 相对应用的基目录 - * @param file 上传的文件 - * @param extension 上传文件类型 + * @param baseDir 相对应用的基目录 + * @param file 上传的文件 + * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 - * @throws FileSizeLimitExceededException 如果超出最大大小 + * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 - * @throws IOException 比如读写文件出错时 - * @throws InvalidExtensionException 文件校验异常 + * @throws IOException 比如读写文件出错时 + * @throws InvalidExtensionException 文件校验异常 */ public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, - InvalidExtensionException { + InvalidExtensionException + { int fileNamelength = file.getOriginalFilename().length(); - if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { + if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) + { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); } @@ -109,41 +119,37 @@ public class FileUploadUtils { /** * 编码文件名 */ - public static final String extractFilename(MultipartFile file) { + public static final String extractFilename(MultipartFile file) + { String fileName = file.getOriginalFilename(); String extension = getExtension(file); - fileName = DateUtils.datePath() + "/" + encodingFilename(fileName) + "." + extension; + fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; return fileName; } - private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException { + private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException + { File desc = new File(uploadDir + File.separator + fileName); - if (!desc.getParentFile().exists()) { + if (!desc.getParentFile().exists()) + { desc.getParentFile().mkdirs(); } - if (!desc.exists()) { + if (!desc.exists()) + { desc.createNewFile(); } return desc; } - private static final String getPathFileName(String uploadDir, String fileName) throws IOException { + private static final String getPathFileName(String uploadDir, String fileName) throws IOException + { int dirLastIndex = Global.getProfile().length() + 1; String currentDir = StringUtils.substring(uploadDir, dirLastIndex); String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName; return pathFileName; } - /** - * 编码文件名 - */ - private static final String encodingFilename(String fileName) { - fileName = fileName.replace("_", " "); - fileName = Md5Utils.hash(fileName + System.nanoTime() + counter++); - return fileName; - } - /** * 文件大小校验 * @@ -153,25 +159,40 @@ public class FileUploadUtils { * @throws InvalidExtensionException */ public static final void assertAllowed(MultipartFile file, String[] allowedExtension) - throws FileSizeLimitExceededException, InvalidExtensionException { + throws FileSizeLimitExceededException, InvalidExtensionException + { long size = file.getSize(); - if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) { + if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) + { throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024); } String fileName = file.getOriginalFilename(); String extension = getExtension(file); - if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) { - if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) { + if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) + { + if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) + { throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension, fileName); - } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) { + } + else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) + { throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension, fileName); - } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) { + } + else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) + { throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, fileName); - } else { + } + else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) + { + throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, + fileName); + } + else + { throw new InvalidExtensionException(allowedExtension, extension, fileName); } } @@ -185,9 +206,12 @@ public class FileUploadUtils { * @param allowedExtension * @return */ - public static final boolean isAllowedExtension(String extension, String[] allowedExtension) { - for (String str : allowedExtension) { - if (str.equalsIgnoreCase(extension)) { + public static final boolean isAllowedExtension(String extension, String[] allowedExtension) + { + for (String str : allowedExtension) + { + if (str.equalsIgnoreCase(extension)) + { return true; } } @@ -196,13 +220,15 @@ public class FileUploadUtils { /** * 获取文件名的后缀 - * + * * @param file 表单文件 * @return 后缀名 */ - public static final String getExtension(MultipartFile file) { + public static final String getExtension(MultipartFile file) + { String extension = FilenameUtils.getExtension(file.getOriginalFilename()); - if (StringUtils.isEmpty(extension)) { + if (StringUtils.isEmpty(extension)) + { extension = MimeTypeUtils.getExtension(file.getContentType()); } return extension; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java index e26e55446..ae0b8030f 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java @@ -7,50 +7,69 @@ import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * 文件处理工具类 - * + * * @author ruoyi */ -public class FileUtils { +public class FileUtils extends org.apache.commons.io.FileUtils +{ public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+"; /** * 输出指定文件的byte数组 - * + * * @param filePath 文件路径 - * @param os 输出流 + * @param os 输出流 * @return */ - public static void writeBytes(String filePath, OutputStream os) throws IOException { + public static void writeBytes(String filePath, OutputStream os) throws IOException + { FileInputStream fis = null; - try { + try + { File file = new File(filePath); - if (!file.exists()) { + if (!file.exists()) + { throw new FileNotFoundException(filePath); } fis = new FileInputStream(file); byte[] b = new byte[1024]; int length; - while ((length = fis.read(b)) > 0) { + while ((length = fis.read(b)) > 0) + { os.write(b, 0, length); } - } catch (IOException e) { + } + catch (IOException e) + { throw e; - } finally { - if (os != null) { - try { + } + finally + { + if (os != null) + { + try + { os.close(); - } catch (IOException e1) { + } + catch (IOException e1) + { e1.printStackTrace(); } } - if (fis != null) { - try { + if (fis != null) + { + try + { fis.close(); - } catch (IOException e1) { + } + catch (IOException e1) + { e1.printStackTrace(); } } @@ -59,15 +78,17 @@ public class FileUtils { /** * 删除文件 - * + * * @param filePath 文件 * @return */ - public static boolean deleteFile(String filePath) { + public static boolean deleteFile(String filePath) + { boolean flag = false; File file = new File(filePath); // 路径为文件且不为空则进行删除 - if (file.isFile() && file.exists()) { + if (file.isFile() && file.exists()) + { file.delete(); flag = true; } @@ -76,39 +97,82 @@ public class FileUtils { /** * 文件名称验证 - * + * * @param filename 文件名称 * @return true 正常 false 非法 */ - public static boolean isValidFilename(String filename) { + public static boolean isValidFilename(String filename) + { return filename.matches(FILENAME_PATTERN); } /** * 下载文件名重新编码 - * - * @param request 请求对象 + * + * @param request 请求对象 * @param fileName 文件名 * @return 编码后的文件名 */ public static String setFileDownloadHeader(HttpServletRequest request, String fileName) - throws UnsupportedEncodingException { + throws UnsupportedEncodingException + { final String agent = request.getHeader("USER-AGENT"); String filename = fileName; - if (agent.contains("MSIE")) { + if (agent.contains("MSIE")) + { // IE浏览器 filename = URLEncoder.encode(filename, "utf-8"); filename = filename.replace("+", " "); - } else if (agent.contains("Firefox")) { + } + else if (agent.contains("Firefox")) + { // 火狐浏览器 filename = new String(fileName.getBytes(), "ISO8859-1"); - } else if (agent.contains("Chrome")) { + } + else if (agent.contains("Chrome")) + { // google浏览器 filename = URLEncoder.encode(filename, "utf-8"); - } else { + } + else + { // 其它浏览器 filename = URLEncoder.encode(filename, "utf-8"); } return filename; } + + /** + * 下载文件名重新编码 + * + * @param response 响应对象 + * @param realFileName 真实文件名 + * @return + */ + public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException + { + String percentEncodedFileName = percentEncode(realFileName); + + StringBuilder contentDispositionValue = new StringBuilder(); + contentDispositionValue.append("attachment; filename=") + .append(percentEncodedFileName) + .append(";") + .append("filename*=") + .append("utf-8''") + .append(percentEncodedFileName); + + response.setHeader("Content-disposition", contentDispositionValue.toString()); + } + + /** + * 百分号编码工具方法 + * + * @param s 需要百分号编码的字符串 + * @return 百分号编码后的字符串 + */ + public static String percentEncode(String s) throws UnsupportedEncodingException + { + String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); + return encode.replaceAll("\\+", "%20"); + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java index 4369fc654..371e82323 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java @@ -2,10 +2,11 @@ package com.ruoyi.common.utils.file; /** * 媒体类型工具类 - * + * * @author ruoyi */ -public class MimeTypeUtils { +public class MimeTypeUtils +{ public static final String IMAGE_PNG = "image/png"; public static final String IMAGE_JPG = "image/jpg"; @@ -16,12 +17,14 @@ public class MimeTypeUtils { public static final String IMAGE_GIF = "image/gif"; - public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"}; + public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" }; - public static final String[] FLASH_EXTENSION = {"swf", "flv"}; + public static final String[] FLASH_EXTENSION = { "swf", "flv" }; - public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", - "asf", "rm", "rmvb"}; + public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", + "asf", "rm", "rmvb" }; + + public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" }; public static final String[] DEFAULT_ALLOWED_EXTENSION = { // 图片 @@ -30,11 +33,15 @@ public class MimeTypeUtils { "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", // 压缩文件 "rar", "zip", "gz", "bz2", + // 视频格式 + "mp4", "avi", "rmvb", // pdf - "pdf"}; + "pdf" }; - public static String getExtension(String prefix) { - switch (prefix) { + public static String getExtension(String prefix) + { + switch (prefix) + { case IMAGE_PNG: return "png"; case IMAGE_JPG: diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java index 7b9f0418f..f2e81f2c9 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java @@ -120,6 +120,9 @@ public class EscapeUtil { public static void main(String[] args) { String html = ""; + // String html = "ipt>alert(\"XSS\")ipt>"; + // String html = "<123"; + // String html = "123>"; System.out.println(EscapeUtil.clean(html)); System.out.println(EscapeUtil.escape(html)); System.out.println(EscapeUtil.unescape(html)); diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java index 6244cd57b..cd8cd4ff8 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java @@ -131,7 +131,7 @@ public final class HTMLFilter vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" }; stripComment = true; encodeQuotes = true; - alwaysMakeTags = true; + alwaysMakeTags = false; } /** @@ -208,7 +208,7 @@ public final class HTMLFilter s = processRemoveBlanks(s); - s = validateEntities(s); + // s = validateEntities(s); return s; } @@ -245,6 +245,7 @@ public final class HTMLFilter // try and form html // s = regexReplace(P_END_ARROW, "", s); + // 不追加结束标签 s = regexReplace(P_BODY_TO_END, "<$1>", s); s = regexReplace(P_XML_CONTENT, "$1<$2", s); diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java index 0a9321f59..f7a96e1c1 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java @@ -16,29 +16,45 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.ruoyi.common.constant.Constants; /** * 通用http发送方法 - * + * * @author ruoyi */ -public class HttpUtils { +public class HttpUtils +{ private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); /** * 向指定 URL 发送GET方法的请求 * - * @param url 发送请求的 URL + * @param url 发送请求的 URL * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return 所代表远程资源的响应结果 */ - public static String sendGet(String url, String param) { + public static String sendGet(String url, String param) + { + return sendGet(url, param, Constants.UTF8); + } + + /** + * 向指定 URL 发送GET方法的请求 + * + * @param url 发送请求的 URL + * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 + * @param contentType 编码类型 + * @return 所代表远程资源的响应结果 + */ + public static String sendGet(String url, String param, String contentType) + { StringBuilder result = new StringBuilder(); BufferedReader in = null; - try { + try + { String urlNameString = url + "?" + param; log.info("sendGet - {}", urlNameString); URL realUrl = new URL(urlNameString); @@ -47,26 +63,41 @@ public class HttpUtils { connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); connection.connect(); - in = new BufferedReader(new InputStreamReader(connection.getInputStream())); + in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); String line; - while ((line = in.readLine()) != null) { + while ((line = in.readLine()) != null) + { result.append(line); } log.info("recv - {}", result); - } catch (ConnectException e) { + } + catch (ConnectException e) + { log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e); - } catch (SocketTimeoutException e) { + } + catch (SocketTimeoutException e) + { log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e); - } catch (IOException e) { + } + catch (IOException e) + { log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e); - } catch (Exception e) { + } + catch (Exception e) + { log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e); - } finally { - try { - if (in != null) { + } + finally + { + try + { + if (in != null) + { in.close(); } - } catch (Exception ex) { + } + catch (Exception ex) + { log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); } } @@ -76,16 +107,18 @@ public class HttpUtils { /** * 向指定 URL 发送POST方法的请求 * - * @param url 发送请求的 URL + * @param url 发送请求的 URL * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 * @return 所代表远程资源的响应结果 */ - public static String sendPost(String url, String param) { + public static String sendPost(String url, String param) + { PrintWriter out = null; BufferedReader in = null; StringBuilder result = new StringBuilder(); - try { - String urlNameString = url + "?" + param; + try + { + String urlNameString = url; log.info("sendPost - {}", urlNameString); URL realUrl = new URL(urlNameString); URLConnection conn = realUrl.openConnection(); @@ -101,40 +134,58 @@ public class HttpUtils { out.flush(); in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); String line; - while ((line = in.readLine()) != null) { + while ((line = in.readLine()) != null) + { result.append(line); } log.info("recv - {}", result); - } catch (ConnectException e) { + } + catch (ConnectException e) + { log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e); - } catch (SocketTimeoutException e) { + } + catch (SocketTimeoutException e) + { log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); - } catch (IOException e) { + } + catch (IOException e) + { log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e); - } catch (Exception e) { + } + catch (Exception e) + { log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e); - } finally { - try { - if (out != null) { + } + finally + { + try + { + if (out != null) + { out.close(); } - if (in != null) { + if (in != null) + { in.close(); } - } catch (IOException ex) { + } + catch (IOException ex) + { log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); } } return result.toString(); } - public static String sendSSLPost(String url, String param) { + public static String sendSSLPost(String url, String param) + { StringBuilder result = new StringBuilder(); String urlNameString = url + "?" + param; - try { + try + { log.info("sendSSLPost - {}", urlNameString); SSLContext sc = SSLContext.getInstance("SSL"); - sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom()); + sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom()); URL console = new URL(urlNameString); HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); conn.setRequestProperty("accept", "*/*"); @@ -151,44 +202,60 @@ public class HttpUtils { InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String ret = ""; - while ((ret = br.readLine()) != null) { - if (ret != null && !ret.trim().equals("")) { + while ((ret = br.readLine()) != null) + { + if (ret != null && !ret.trim().equals("")) + { result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8")); } } log.info("recv - {}", result); conn.disconnect(); br.close(); - } catch (ConnectException e) { + } + catch (ConnectException e) + { log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e); - } catch (SocketTimeoutException e) { + } + catch (SocketTimeoutException e) + { log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e); - } catch (IOException e) { + } + catch (IOException e) + { log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e); - } catch (Exception e) { + } + catch (Exception e) + { log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e); } return result.toString(); } - private static class TrustAnyTrustManager implements X509TrustManager { + private static class TrustAnyTrustManager implements X509TrustManager + { @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) { + public void checkClientTrusted(X509Certificate[] chain, String authType) + { } @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) { + public void checkServerTrusted(X509Certificate[] chain, String authType) + { } @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[]{}; + public X509Certificate[] getAcceptedIssuers() + { + return new X509Certificate[] {}; } } - private static class TrustAnyHostnameVerifier implements HostnameVerifier { + private static class TrustAnyHostnameVerifier implements HostnameVerifier + { @Override - public boolean verify(String hostname, SSLSession session) { + public boolean verify(String hostname, SSLSession session) + { return true; } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java index 44a683f87..a315d3ac2 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java @@ -11,12 +11,14 @@ import java.math.BigDecimal; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; - +import java.util.stream.Collectors; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; @@ -51,13 +53,15 @@ import com.ruoyi.common.exception.BusinessException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.reflect.ReflectUtils; +import com.ruoyi.common.utils.spring.SpringUtils; /** * Excel相关处理 - * + * * @author ruoyi */ -public class ExcelUtil { +public class ExcelUtil +{ private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); /** @@ -100,17 +104,30 @@ public class ExcelUtil { */ private List fields; + /** + * 统计列表 + */ + private Map statistics = new HashMap(); + + /** + * 数字格式 + */ + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + /** * 实体对象 */ public Class clazz; - public ExcelUtil(Class clazz) { + public ExcelUtil(Class clazz) + { this.clazz = clazz; } - public void init(List list, String sheetName, Type type) { - if (list == null) { + public void init(List list, String sheetName, Type type) + { + if (list == null) + { list = new ArrayList(); } this.list = list; @@ -122,51 +139,62 @@ public class ExcelUtil { /** * 对excel表单默认第一个索引名转换成list - * + * * @param is 输入流 * @return 转换后集合 */ - public List importExcel(InputStream is) throws Exception { + public List importExcel(InputStream is) throws Exception + { return importExcel(StringUtils.EMPTY, is); } /** * 对excel表单指定表格索引名转换成list - * + * * @param sheetName 表格索引名 - * @param is 输入流 + * @param is 输入流 * @return 转换后集合 */ - public List importExcel(String sheetName, InputStream is) throws Exception { + public List importExcel(String sheetName, InputStream is) throws Exception + { this.type = Type.IMPORT; this.wb = WorkbookFactory.create(is); List list = new ArrayList(); Sheet sheet = null; - if (StringUtils.isNotEmpty(sheetName)) { + if (StringUtils.isNotEmpty(sheetName)) + { // 如果指定sheet名,则取指定sheet中的内容. sheet = wb.getSheet(sheetName); - } else { + } + else + { // 如果传入的sheet名不存在则默认指向第1个sheet. sheet = wb.getSheetAt(0); } - if (sheet == null) { + if (sheet == null) + { throw new IOException("文件sheet不存在"); } int rows = sheet.getPhysicalNumberOfRows(); - if (rows > 0) { + if (rows > 0) + { // 定义一个map用于存放excel列的序号和field. Map cellMap = new HashMap(); // 获取表头 Row heard = sheet.getRow(0); - for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) { + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) + { Cell cell = heard.getCell(i); - if (StringUtils.isNotNull(cell != null)) { + if (StringUtils.isNotNull(cell)) + { String value = this.getCellValue(heard, i).toString(); cellMap.put(value, i); - } else { + } + else + { cellMap.put(null, i); } } @@ -174,21 +202,25 @@ public class ExcelUtil { Field[] allFields = clazz.getDeclaredFields(); // 定义一个map用于存放列的序号和field. Map fieldsMap = new HashMap(); - for (int col = 0; col < allFields.length; col++) { + for (int col = 0; col < allFields.length; col++) + { Field field = allFields[col]; Excel attr = field.getAnnotation(Excel.class); - if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) { + if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) + { // 设置类的私有字段属性可访问. field.setAccessible(true); Integer column = cellMap.get(attr.name()); fieldsMap.put(column, field); } } - for (int i = 1; i < rows; i++) { + for (int i = 1; i < rows; i++) + { // 从第2行开始取数据,默认第一行是表头. Row row = sheet.getRow(i); T entity = null; - for (Map.Entry entry : fieldsMap.entrySet()) { + for (Map.Entry entry : fieldsMap.entrySet()) + { Object val = this.getCellValue(row, entry.getKey()); // 如果不存在实例则新建. @@ -197,42 +229,72 @@ public class ExcelUtil { Field field = fieldsMap.get(entry.getKey()); // 取得类型,并根据对象类型设置值. Class fieldType = field.getType(); - if (String.class == fieldType) { + if (String.class == fieldType) + { String s = Convert.toStr(val); - if (StringUtils.endsWith(s, ".0")) { + if (StringUtils.endsWith(s, ".0")) + { val = StringUtils.substringBefore(s, ".0"); - } else { + } + else + { String dateFormat = field.getAnnotation(Excel.class).dateFormat(); - if (StringUtils.isNotEmpty(dateFormat)) { + if (StringUtils.isNotEmpty(dateFormat)) + { val = DateUtils.parseDateToStr(dateFormat, (Date) val); - } else { + } + else + { val = Convert.toStr(val); } } - } else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) { + } + else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) + { val = Convert.toInt(val); - } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) { + } + else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) + { val = Convert.toLong(val); - } else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) { + } + else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) + { val = Convert.toDouble(val); - } else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) { + } + else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) + { val = Convert.toFloat(val); - } else if (BigDecimal.class == fieldType) { + } + else if (BigDecimal.class == fieldType) + { val = Convert.toBigDecimal(val); - } else if (Date.class == fieldType) { - if (val instanceof String) { + } + else if (Date.class == fieldType) + { + if (val instanceof String) + { val = DateUtils.parseDate(val); - } else if (val instanceof Double) { + } + else if (val instanceof Double) + { val = DateUtil.getJavaDate((Double) val); } } - if (StringUtils.isNotNull(fieldType)) { + if (StringUtils.isNotNull(fieldType)) + { Excel attr = field.getAnnotation(Excel.class); String propertyName = field.getName(); - if (StringUtils.isNotEmpty(attr.targetAttr())) { + if (StringUtils.isNotEmpty(attr.targetAttr())) + { propertyName = field.getName() + "." + attr.targetAttr(); - } else if (StringUtils.isNotEmpty(attr.readConverterExp())) { - val = reverseByExp(String.valueOf(val), attr.readConverterExp()); + } + else if (StringUtils.isNotEmpty(attr.readConverterExp())) + { + val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator()); + } + else if (StringUtils.isNotEmpty(attr.dictType())) + { + val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator()); } ReflectUtils.invokeSetter(entity, propertyName, val); } @@ -245,71 +307,91 @@ public class ExcelUtil { /** * 对list数据源将其里面的数据导入到excel表单 - * - * @param list 导出数据集合 + * + * @param list 导出数据集合 * @param sheetName 工作表的名称 * @return 结果 */ - public AjaxResult exportExcel(List list, String sheetName) { + public AjaxResult exportExcel(List list, String sheetName) + { this.init(list, sheetName, Type.EXPORT); return exportExcel(); } /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @param sheetName 工作表的名称 * @return 结果 */ - public AjaxResult importTemplateExcel(String sheetName) { + public AjaxResult importTemplateExcel(String sheetName) + { this.init(null, sheetName, Type.IMPORT); return exportExcel(); } /** * 对list数据源将其里面的数据导入到excel表单 - * + * * @return 结果 */ - public AjaxResult exportExcel() { + public AjaxResult exportExcel() + { OutputStream out = null; - try { + try + { // 取出一共有多少个sheet. double sheetNo = Math.ceil(list.size() / sheetSize); - for (int index = 0; index <= sheetNo; index++) { + for (int index = 0; index <= sheetNo; index++) + { createSheet(sheetNo, index); // 产生一行 Row row = sheet.createRow(0); int column = 0; // 写入各个字段的列头名称 - for (Object[] os : fields) { + for (Object[] os : fields) + { Excel excel = (Excel) os[1]; this.createCell(excel, row, column++); } - if (Type.EXPORT.equals(type)) { + if (Type.EXPORT.equals(type)) + { fillExcelData(index, row); + addStatisticsRow(); } } String filename = encodingFilename(sheetName); out = new FileOutputStream(getAbsoluteFile(filename)); wb.write(out); return AjaxResult.success(filename); - } catch (Exception e) { + } + catch (Exception e) + { log.error("导出Excel异常{}", e.getMessage()); throw new BusinessException("导出Excel失败,请联系网站管理员!"); - } finally { - if (wb != null) { - try { + } + finally + { + if (wb != null) + { + try + { wb.close(); - } catch (IOException e1) { + } + catch (IOException e1) + { e1.printStackTrace(); } } - if (out != null) { - try { + if (out != null) + { + try + { out.close(); - } catch (IOException e1) { + } + catch (IOException e1) + { e1.printStackTrace(); } } @@ -318,19 +400,22 @@ public class ExcelUtil { /** * 填充excel数据 - * + * * @param index 序号 - * @param row 单元格行 + * @param row 单元格行 */ - public void fillExcelData(int index, Row row) { + public void fillExcelData(int index, Row row) + { int startNo = index * sheetSize; int endNo = Math.min(startNo + sheetSize, list.size()); - for (int i = startNo; i < endNo; i++) { + for (int i = startNo; i < endNo; i++) + { row = sheet.createRow(i + 1 - startNo); // 得到导出对象. T vo = (T) list.get(i); int column = 0; - for (Object[] os : fields) { + for (Object[] os : fields) + { Field field = (Field) os[0]; Excel excel = (Excel) os[1]; // 设置实体类私有属性可访问 @@ -342,11 +427,12 @@ public class ExcelUtil { /** * 创建表格样式 - * + * * @param wb 工作薄对象 * @return 样式列表 */ - private Map createStyles(Workbook wb) { + private Map createStyles(Workbook wb) + { // 写入各条记录,每条记录对应excel表中的一行 Map styles = new HashMap(); CellStyle style = wb.createCellStyle(); @@ -379,6 +465,15 @@ public class ExcelUtil { headerFont.setColor(IndexedColors.WHITE.getIndex()); style.setFont(headerFont); styles.put("header", style); + + style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font totalFont = wb.createFont(); + totalFont.setFontName("Arial"); + totalFont.setFontHeightInPoints((short) 10); + style.setFont(totalFont); + styles.put("total", style); return styles; } @@ -386,7 +481,8 @@ public class ExcelUtil { /** * 创建单元格 */ - public Cell createCell(Excel attr, Row row, int column) { + public Cell createCell(Excel attr, Row row, int column) + { // 创建列 Cell cell = row.createCell(column); // 写入列信息 @@ -398,39 +494,49 @@ public class ExcelUtil { /** * 设置单元格信息 - * + * * @param value 单元格值 - * @param attr 注解相关 - * @param cell 单元格信息 + * @param attr 注解相关 + * @param cell 单元格信息 */ - public void setCellVo(Object value, Excel attr, Cell cell) { - if (ColumnType.STRING == attr.cellType()) { - cell.setCellType(CellType.NUMERIC); + public void setCellVo(Object value, Excel attr, Cell cell) + { + if (ColumnType.STRING == attr.cellType()) + { + cell.setCellType(CellType.STRING); cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); - } else if (ColumnType.NUMERIC == attr.cellType()) { + } + else if (ColumnType.NUMERIC == attr.cellType()) + { cell.setCellType(CellType.NUMERIC); - cell.setCellValue(Integer.parseInt(value + "")); + cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value)); } } /** * 创建表格样式 */ - public void setDataValidation(Excel attr, Row row, int column) { - if (attr.name().indexOf("注:") >= 0) { + public void setDataValidation(Excel attr, Row row, int column) + { + if (attr.name().indexOf("注:") >= 0) + { sheet.setColumnWidth(column, 6000); - } else { + } + else + { // 设置列宽 sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); row.setHeight((short) (attr.height() * 20)); } // 如果设置了提示信息则鼠标放上去提示. - if (StringUtils.isNotEmpty(attr.prompt())) { + if (StringUtils.isNotEmpty(attr.prompt())) + { // 这里默认设了2-101列提示. setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); } // 如果设置了combo属性则本列只能选择不能输入 - if (attr.combo().length > 0) { + if (attr.combo().length > 0) + { // 这里默认设了2-101列只能选择不能输入. setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); } @@ -439,13 +545,16 @@ public class ExcelUtil { /** * 添加单元格 */ - public Cell addCell(Excel attr, Row row, T vo, Field field, int column) { + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) + { Cell cell = null; - try { + try + { // 设置行高 row.setHeight((short) (attr.height() * 20)); // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. - if (attr.isExport()) { + if (attr.isExport()) + { // 创建cell cell = row.createCell(column); cell.setCellStyle(styles.get("data")); @@ -454,16 +563,34 @@ public class ExcelUtil { Object value = getTargetValue(vo, field, attr); String dateFormat = attr.dateFormat(); String readConverterExp = attr.readConverterExp(); - if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) { + String separator = attr.separator(); + String dictType = attr.dictType(); + if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value)) + { cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value)); - } else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) { - cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp)); - } else { + } + else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value)) + { + cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); + } + else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) + { + cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); + } + else if (value instanceof BigDecimal && -1 != attr.scale()) + { + cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString()); + } + else + { // 设置列类型 setCellVo(value, attr, cell); } + addStatisticsData(column, Convert.toStr(value), attr); } - } catch (Exception e) { + } + catch (Exception e) + { log.error("导出Excel失败{}", e); } return cell; @@ -471,17 +598,18 @@ public class ExcelUtil { /** * 设置 POI XSSFSheet 单元格提示 - * - * @param sheet 表单 - * @param promptTitle 提示标题 + * + * @param sheet 表单 + * @param promptTitle 提示标题 * @param promptContent 提示内容 - * @param firstRow 开始行 - * @param endRow 结束行 - * @param firstCol 开始列 - * @param endCol 结束列 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 */ public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow, - int firstCol, int endCol) { + int firstCol, int endCol) + { DataValidationHelper helper = sheet.getDataValidationHelper(); DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); @@ -493,16 +621,17 @@ public class ExcelUtil { /** * 设置某些列的值只能输入预制的数据,显示下拉框. - * - * @param sheet 要设置的sheet. + * + * @param sheet 要设置的sheet. * @param textlist 下拉框显示的内容 * @param firstRow 开始行 - * @param endRow 结束行 + * @param endRow 结束行 * @param firstCol 开始列 - * @param endCol 结束列 + * @param endCol 结束列 * @return 设置好的sheet. */ - public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) { + public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) + { DataValidationHelper helper = sheet.getDataValidationHelper(); // 加载下拉列表内容 DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); @@ -511,10 +640,13 @@ public class ExcelUtil { // 数据有效性对象 DataValidation dataValidation = helper.createValidation(constraint, regions); // 处理Excel兼容性问题 - if (dataValidation instanceof XSSFDataValidation) { + if (dataValidation instanceof XSSFDataValidation) + { dataValidation.setSuppressDropDownArrow(true); dataValidation.setShowErrorBox(true); - } else { + } + else + { dataValidation.setSuppressDropDownArrow(false); } @@ -523,67 +655,186 @@ public class ExcelUtil { /** * 解析导出值 0=男,1=女,2=未知 - * + * * @param propertyValue 参数值 - * @param converterExp 翻译注解 + * @param converterExp 翻译注解 + * @param separator 分隔符 * @return 解析后值 * @throws Exception */ - public static String convertByExp(String propertyValue, String converterExp) throws Exception { - try { + public static String convertByExp(String propertyValue, String converterExp, String separator) throws Exception + { + StringBuilder propertyString = new StringBuilder(); + try + { String[] convertSource = converterExp.split(","); - for (String item : convertSource) { + for (String item : convertSource) + { String[] itemArray = item.split("="); - if (itemArray[0].equals(propertyValue)) { - return itemArray[1]; + if (StringUtils.containsAny(separator, propertyValue)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[0].equals(value)) + { + propertyString.append(itemArray[1] + separator); + break; + } + } + } + else + { + if (itemArray[0].equals(propertyValue)) + { + return itemArray[1]; + } } } - } catch (Exception e) { + } + catch (Exception e) + { throw e; } - return propertyValue; + return StringUtils.stripEnd(propertyString.toString(), separator); } /** * 反向解析值 男=0,女=1,未知=2 - * + * * @param propertyValue 参数值 - * @param converterExp 翻译注解 + * @param converterExp 翻译注解 + * @param separator 分隔符 * @return 解析后值 * @throws Exception */ - public static String reverseByExp(String propertyValue, String converterExp) throws Exception { - try { - String[] convertSource = converterExp.split(","); - for (String item : convertSource) { - String[] itemArray = item.split("="); - if (itemArray[1].equals(propertyValue)) { + public static String reverseByExp(String propertyValue, String converterExp, String separator) throws Exception + { + StringBuilder propertyString = new StringBuilder(); + String[] convertSource = converterExp.split(","); + for (String item : convertSource) + { + String[] itemArray = item.split("="); + if (StringUtils.containsAny(separator, propertyValue)) + { + for (String value : propertyValue.split(separator)) + { + if (itemArray[1].equals(value)) + { + propertyString.append(itemArray[0] + separator); + break; + } + } + } + else + { + if (itemArray[1].equals(propertyValue)) + { return itemArray[0]; } } - } catch (Exception e) { - throw e; } - return propertyValue; + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 解析字典值 + * + * @param dictValue 字典值 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String convertDictByExp(String dictValue, String dictType, String separator) throws Exception + { + Object bean = SpringUtils.getBean("dictUtils"); + String methodName = "getDictLabel"; + Method method = bean.getClass().getDeclaredMethod(methodName, String.class, String.class, String.class); + return Convert.toStr(method.invoke(bean, dictType, dictValue, separator)); + } + + /** + * 反向解析值字典值 + * + * @param dictLabel 字典标签 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典值 + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) throws Exception + { + Object bean = SpringUtils.getBean("dictUtils"); + String methodName = "getDictValue"; + Method method = bean.getClass().getDeclaredMethod(methodName, String.class, String.class, String.class); + return Convert.toStr(method.invoke(bean, dictType, dictLabel, separator)); + } + + /** + * 合计统计信息 + */ + private void addStatisticsData(Integer index, String text, Excel entity) + { + if (entity != null && entity.isStatistics()) + { + Double temp = 0D; + if (!statistics.containsKey(index)) + { + statistics.put(index, temp); + } + try + { + temp = Double.valueOf(text); + } + catch (NumberFormatException e) + { + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 创建统计行 + */ + public void addStatisticsRow() + { + if (statistics.size() > 0) + { + Cell cell = null; + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + cell = row.createCell(0); + cell.setCellStyle(styles.get("total")); + cell.setCellValue("合计"); + + for (Integer key : keys) + { + cell = row.createCell(key); + cell.setCellStyle(styles.get("total")); + cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key))); + } + statistics.clear(); + } } /** * 编码文件名 */ - public String encodingFilename(String filename) { + public String encodingFilename(String filename) + { filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; return filename; } /** * 获取下载路径 - * + * * @param filename 文件名称 */ - public String getAbsoluteFile(String filename) { + public String getAbsoluteFile(String filename) + { String downloadPath = Global.getDownloadPath() + filename; File desc = new File(downloadPath); - if (!desc.getParentFile().exists()) { + if (!desc.getParentFile().exists()) + { desc.getParentFile().mkdirs(); } return downloadPath; @@ -591,23 +842,29 @@ public class ExcelUtil { /** * 获取bean中的属性值 - * - * @param vo 实体对象 + * + * @param vo 实体对象 * @param field 字段 * @param excel 注解 * @return 最终的属性值 * @throws Exception */ - private Object getTargetValue(T vo, Field field, Excel excel) throws Exception { + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception + { Object o = field.get(vo); - if (StringUtils.isNotEmpty(excel.targetAttr())) { + if (StringUtils.isNotEmpty(excel.targetAttr())) + { String target = excel.targetAttr(); - if (target.indexOf(".") > -1) { + if (target.indexOf(".") > -1) + { String[] targets = target.split("[.]"); - for (String name : targets) { + for (String name : targets) + { o = getValue(o, name); } - } else { + } + else + { o = getValue(o, target); } } @@ -616,18 +873,20 @@ public class ExcelUtil { /** * 以类的属性的get方法方法形式获取值 - * + * * @param o * @param name * @return value * @throws Exception */ - private Object getValue(Object o, String name) throws Exception { - if (StringUtils.isNotEmpty(name)) { + private Object getValue(Object o, String name) throws Exception + { + if (StringUtils.isNotEmpty(name)) + { Class clazz = o.getClass(); - String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1); - Method method = clazz.getMethod(methodName); - o = method.invoke(o); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); } return o; } @@ -635,97 +894,129 @@ public class ExcelUtil { /** * 得到所有定义字段 */ - private void createExcelField() { + private void createExcelField() + { this.fields = new ArrayList(); List tempFields = new ArrayList<>(); tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); - for (Field field : tempFields) { + for (Field field : tempFields) + { // 单注解 - if (field.isAnnotationPresent(Excel.class)) { + if (field.isAnnotationPresent(Excel.class)) + { putToField(field, field.getAnnotation(Excel.class)); } // 多注解 - if (field.isAnnotationPresent(Excels.class)) { + if (field.isAnnotationPresent(Excels.class)) + { Excels attrs = field.getAnnotation(Excels.class); Excel[] excels = attrs.value(); - for (Excel excel : excels) { + for (Excel excel : excels) + { putToField(field, excel); } } } + this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); } /** * 放到字段集合中 */ - private void putToField(Field field, Excel attr) { - if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) { - this.fields.add(new Object[]{field, attr}); + 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() { + public void createWorkbook() + { this.wb = new SXSSFWorkbook(500); } /** * 创建工作表 - * + * * @param sheetNo sheet数量 - * @param index 序号 + * @param index 序号 */ - public void createSheet(double sheetNo, int index) { + public void createSheet(double sheetNo, int index) + { this.sheet = wb.createSheet(); this.styles = createStyles(wb); // 设置工作表的名称. - if (sheetNo == 0) { + if (sheetNo == 0) + { wb.setSheetName(index, sheetName); - } else { + } + else + { wb.setSheetName(index, sheetName + index); } } /** * 获取单元格值 - * - * @param row 获取的行 + * + * @param row 获取的行 * @param column 获取单元格列号 * @return 单元格值 */ - public Object getCellValue(Row row, int column) { - if (row == null) { + public Object getCellValue(Row row, int column) + { + if (row == null) + { return row; } Object val = ""; - try { + try + { Cell cell = row.getCell(column); - if (cell != null) { - if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) { + if (StringUtils.isNotNull(cell)) + { + if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) + { val = cell.getNumericCellValue(); - if (HSSFDateUtil.isCellDateFormatted(cell)) { + if (HSSFDateUtil.isCellDateFormatted(cell)) + { val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 - } else { - if ((Double) val % 1 > 0) { - val = new DecimalFormat("0.00").format(val); - } else { + } + else + { + if ((Double) val % 1 > 0) + { + val = new BigDecimal(val.toString()); + } + else + { val = new DecimalFormat("0").format(val); } } - } else if (cell.getCellTypeEnum() == CellType.STRING) { + } + else if (cell.getCellTypeEnum() == CellType.STRING) + { val = cell.getStringCellValue(); - } else if (cell.getCellTypeEnum() == CellType.BOOLEAN) { + } + else if (cell.getCellTypeEnum() == CellType.BOOLEAN) + { val = cell.getBooleanCellValue(); - } else if (cell.getCellTypeEnum() == CellType.ERROR) { + } + else if (cell.getCellTypeEnum() == CellType.ERROR) + { val = cell.getErrorCellValue(); } } - } catch (Exception e) { + } + catch (Exception e) + { return val; } return val; diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java index 4cdbf14ff..01fa5193f 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java @@ -5,34 +5,47 @@ import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; +import com.ruoyi.common.utils.StringUtils; /** * spring工具类 方便在非spring管理环境中获取bean - * + * * @author ruoyi */ @Component -public final class SpringUtils implements BeanFactoryPostProcessor { - /** - * Spring应用上下文环境 - */ +public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware +{ + /** Spring应用上下文环境 */ private static ConfigurableListableBeanFactory beanFactory; + private static ApplicationContext applicationContext; + @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException + { SpringUtils.beanFactory = beanFactory; } + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + SpringUtils.applicationContext = applicationContext; + } + /** * 获取对象 * * @param name * @return Object 一个以所给名字注册的bean的实例 * @throws org.springframework.beans.BeansException + * */ @SuppressWarnings("unchecked") - public static T getBean(String name) throws BeansException { + public static T getBean(String name) throws BeansException + { return (T) beanFactory.getBean(name); } @@ -42,8 +55,10 @@ public final class SpringUtils implements BeanFactoryPostProcessor { * @param clz * @return * @throws org.springframework.beans.BeansException + * */ - public static T getBean(Class clz) throws BeansException { + public static T getBean(Class clz) throws BeansException + { T result = (T) beanFactory.getBean(clz); return result; } @@ -54,7 +69,8 @@ public final class SpringUtils implements BeanFactoryPostProcessor { * @param name * @return boolean */ - public static boolean containsBean(String name) { + public static boolean containsBean(String name) + { return beanFactory.containsBean(name); } @@ -64,8 +80,10 @@ public final class SpringUtils implements BeanFactoryPostProcessor { * @param name * @return boolean * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * */ - public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException { + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException + { return beanFactory.isSingleton(name); } @@ -73,8 +91,10 @@ public final class SpringUtils implements BeanFactoryPostProcessor { * @param name * @return Class 注册对象的类型 * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * */ - public static Class getType(String name) throws NoSuchBeanDefinitionException { + public static Class getType(String name) throws NoSuchBeanDefinitionException + { return beanFactory.getType(name); } @@ -84,19 +104,43 @@ public final class SpringUtils implements BeanFactoryPostProcessor { * @param name * @return * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * */ - public static String[] getAliases(String name) throws NoSuchBeanDefinitionException { + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException + { return beanFactory.getAliases(name); } /** * 获取aop代理对象 - * + * * @param invoker * @return */ @SuppressWarnings("unchecked") - public static T getAopProxy(T invoker) { + public static T getAopProxy(T invoker) + { return (T) AopContext.currentProxy(); } + + /** + * 获取当前的环境配置,无配置返回null + * + * @return 当前的环境配置 + */ + public static String[] getActiveProfiles() + { + return applicationContext.getEnvironment().getActiveProfiles(); + } + + /** + * 获取当前的环境配置,当有多个环境配置时,只获取第一个 + * + * @return 当前的环境配置 + */ + public static String getActiveProfile() + { + final String[] activeProfiles = getActiveProfiles(); + return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null; + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java index 088893315..1c4c1713e 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java @@ -1,24 +1,28 @@ package com.ruoyi.common.utils.sql; +import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.StringUtils; /** * sql操作工具类 - * + * * @author ruoyi */ -public class SqlUtil { +public class SqlUtil +{ /** - * 仅支持字母、数字、下划线、空格、逗号(支持多个字段排序) + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) */ - public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,]+"; + public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; /** * 检查字符,防止注入绕过 */ - public static String escapeOrderBySql(String value) { - if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { - return StringUtils.EMPTY; + public static String escapeOrderBySql(String value) + { + if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) + { + throw new BaseException("参数不符合规范,不能进行查询"); } return value; } @@ -26,7 +30,8 @@ public class SqlUtil { /** * 验证 order by 语法是否符合规范 */ - public static boolean isValidOrderBySql(String value) { + public static boolean isValidOrderBySql(String value) + { return value.matches(SQL_PATTERN); } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java new file mode 100644 index 000000000..0256511f1 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java @@ -0,0 +1,49 @@ +package com.ruoyi.common.utils.uuid; + +/** + * ID生成器工具类 + * + * @author ruoyi + */ +public class IdUtils +{ + /** + * 获取随机UUID + * + * @return 随机UUID + */ + public static String randomUUID() + { + return UUID.randomUUID().toString(); + } + + /** + * 简化的UUID,去掉了横线 + * + * @return 简化的UUID,去掉了横线 + */ + public static String simpleUUID() + { + return UUID.randomUUID().toString(true); + } + + /** + * 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID + * + * @return 随机UUID + */ + public static String fastUUID() + { + return UUID.fastUUID().toString(); + } + + /** + * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID + * + * @return 简化的UUID,去掉了横线 + */ + public static String fastSimpleUUID() + { + return UUID.fastUUID().toString(true); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java new file mode 100644 index 000000000..eef72ee0b --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java @@ -0,0 +1,484 @@ +package com.ruoyi.common.utils.uuid; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import com.ruoyi.common.exception.UtilException; + +/** + * 提供通用唯一识别码(universally unique identifier)(UUID)实现 + * + * @author ruoyi + */ +public final class UUID implements java.io.Serializable, Comparable +{ + private static final long serialVersionUID = -1185015143654744140L; + + /** + * SecureRandom 的单例 + * + */ + private static class Holder + { + static final SecureRandom numberGenerator = getSecureRandom(); + } + + /** 此UUID的最高64有效位 */ + private final long mostSigBits; + + /** 此UUID的最低64有效位 */ + private final long leastSigBits; + + /** + * 私有构造 + * + * @param data 数据 + */ + private UUID(byte[] data) + { + long msb = 0; + long lsb = 0; + assert data.length == 16 : "data must be 16 bytes in length"; + for (int i = 0; i < 8; i++) + { + msb = (msb << 8) | (data[i] & 0xff); + } + for (int i = 8; i < 16; i++) + { + lsb = (lsb << 8) | (data[i] & 0xff); + } + this.mostSigBits = msb; + this.leastSigBits = lsb; + } + + /** + * 使用指定的数据构造新的 UUID。 + * + * @param mostSigBits 用于 {@code UUID} 的最高有效 64 位 + * @param leastSigBits 用于 {@code UUID} 的最低有效 64 位 + */ + public UUID(long mostSigBits, long leastSigBits) + { + this.mostSigBits = mostSigBits; + this.leastSigBits = leastSigBits; + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID fastUUID() + { + return randomUUID(false); + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 + * + * @return 随机生成的 {@code UUID} + */ + public static UUID randomUUID() + { + return randomUUID(true); + } + + /** + * 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。 + * + * @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能 + * @return 随机生成的 {@code UUID} + */ + public static UUID randomUUID(boolean isSecure) + { + final Random ng = isSecure ? Holder.numberGenerator : getRandom(); + + byte[] randomBytes = new byte[16]; + ng.nextBytes(randomBytes); + randomBytes[6] &= 0x0f; /* clear version */ + randomBytes[6] |= 0x40; /* set to version 4 */ + randomBytes[8] &= 0x3f; /* clear variant */ + randomBytes[8] |= 0x80; /* set to IETF variant */ + return new UUID(randomBytes); + } + + /** + * 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。 + * + * @param name 用于构造 UUID 的字节数组。 + * + * @return 根据指定数组生成的 {@code UUID} + */ + public static UUID nameUUIDFromBytes(byte[] name) + { + MessageDigest md; + try + { + md = MessageDigest.getInstance("MD5"); + } + catch (NoSuchAlgorithmException nsae) + { + throw new InternalError("MD5 not supported"); + } + byte[] md5Bytes = md.digest(name); + md5Bytes[6] &= 0x0f; /* clear version */ + md5Bytes[6] |= 0x30; /* set to version 3 */ + md5Bytes[8] &= 0x3f; /* clear variant */ + md5Bytes[8] |= 0x80; /* set to IETF variant */ + return new UUID(md5Bytes); + } + + /** + * 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。 + * + * @param name 指定 {@code UUID} 字符串 + * @return 具有指定值的 {@code UUID} + * @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常 + * + */ + public static UUID fromString(String name) + { + String[] components = name.split("-"); + if (components.length != 5) + { + throw new IllegalArgumentException("Invalid UUID string: " + name); + } + for (int i = 0; i < 5; i++) + { + components[i] = "0x" + components[i]; + } + + long mostSigBits = Long.decode(components[0]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[1]).longValue(); + mostSigBits <<= 16; + mostSigBits |= Long.decode(components[2]).longValue(); + + long leastSigBits = Long.decode(components[3]).longValue(); + leastSigBits <<= 48; + leastSigBits |= Long.decode(components[4]).longValue(); + + return new UUID(mostSigBits, leastSigBits); + } + + /** + * 返回此 UUID 的 128 位值中的最低有效 64 位。 + * + * @return 此 UUID 的 128 位值中的最低有效 64 位。 + */ + public long getLeastSignificantBits() + { + return leastSigBits; + } + + /** + * 返回此 UUID 的 128 位值中的最高有效 64 位。 + * + * @return 此 UUID 的 128 位值中最高有效 64 位。 + */ + public long getMostSignificantBits() + { + return mostSigBits; + } + + /** + * 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。 + *

    + * 版本号具有以下含意: + *

      + *
    • 1 基于时间的 UUID + *
    • 2 DCE 安全 UUID + *
    • 3 基于名称的 UUID + *
    • 4 随机生成的 UUID + *
    + * + * @return 此 {@code UUID} 的版本号 + */ + public int version() + { + // Version is bits masked by 0x000000000000F000 in MS long + return (int) ((mostSigBits >> 12) & 0x0f); + } + + /** + * 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。 + *

    + * 变体号具有以下含意: + *

      + *
    • 0 为 NCS 向后兼容保留 + *
    • 2 IETF RFC 4122(Leach-Salz), 用于此类 + *
    • 6 保留,微软向后兼容 + *
    • 7 保留供以后定义使用 + *
    + * + * @return 此 {@code UUID} 相关联的变体号 + */ + public int variant() + { + // This field is composed of a varying number of bits. + // 0 - - Reserved for NCS backward compatibility + // 1 0 - The IETF aka Leach-Salz variant (used by this class) + // 1 1 0 Reserved, Microsoft backward compatibility + // 1 1 1 Reserved for future definition. + return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63)); + } + + /** + * 与此 UUID 相关联的时间戳值。 + * + *

    + * 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。
    + * 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。 + * + *

    + * 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。
    + * 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 + * + * @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。 + */ + public long timestamp() throws UnsupportedOperationException + { + checkTimeBase(); + return (mostSigBits & 0x0FFFL) << 48// + | ((mostSigBits >> 16) & 0x0FFFFL) << 32// + | mostSigBits >>> 32; + } + + /** + * 与此 UUID 相关联的时钟序列值。 + * + *

    + * 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。 + *

    + * {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出 + * UnsupportedOperationException。 + * + * @return 此 {@code UUID} 的时钟序列 + * + * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 + */ + public int clockSequence() throws UnsupportedOperationException + { + checkTimeBase(); + return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48); + } + + /** + * 与此 UUID 相关的节点值。 + * + *

    + * 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。 + *

    + * 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。
    + * 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。 + * + * @return 此 {@code UUID} 的节点值 + * + * @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1 + */ + public long node() throws UnsupportedOperationException + { + checkTimeBase(); + return leastSigBits & 0x0000FFFFFFFFFFFFL; + } + + /** + * 返回此{@code UUID} 的字符串表现形式。 + * + *

    + * UUID 的字符串表示形式由此 BNF 描述: + * + *

    +     * {@code
    +     * UUID                   = ----
    +     * time_low               = 4*
    +     * time_mid               = 2*
    +     * time_high_and_version  = 2*
    +     * variant_and_sequence   = 2*
    +     * node                   = 6*
    +     * hexOctet               = 
    +     * hexDigit               = [0-9a-fA-F]
    +     * }
    +     * 
    + * + *
    + * + * @return 此{@code UUID} 的字符串表现形式 + * @see #toString(boolean) + */ + @Override + public String toString() + { + return toString(false); + } + + /** + * 返回此{@code UUID} 的字符串表现形式。 + * + *

    + * UUID 的字符串表示形式由此 BNF 描述: + * + *

    +     * {@code
    +     * UUID                   = ----
    +     * time_low               = 4*
    +     * time_mid               = 2*
    +     * time_high_and_version  = 2*
    +     * variant_and_sequence   = 2*
    +     * node                   = 6*
    +     * hexOctet               = 
    +     * hexDigit               = [0-9a-fA-F]
    +     * }
    +     * 
    + * + * + * + * @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串 + * @return 此{@code UUID} 的字符串表现形式 + */ + public String toString(boolean isSimple) + { + final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36); + // time_low + builder.append(digits(mostSigBits >> 32, 8)); + if (false == isSimple) + { + builder.append('-'); + } + // time_mid + builder.append(digits(mostSigBits >> 16, 4)); + if (false == isSimple) + { + builder.append('-'); + } + // time_high_and_version + builder.append(digits(mostSigBits, 4)); + if (false == isSimple) + { + builder.append('-'); + } + // variant_and_sequence + builder.append(digits(leastSigBits >> 48, 4)); + if (false == isSimple) + { + builder.append('-'); + } + // node + builder.append(digits(leastSigBits, 12)); + + return builder.toString(); + } + + /** + * 返回此 UUID 的哈希码。 + * + * @return UUID 的哈希码值。 + */ + @Override + public int hashCode() + { + long hilo = mostSigBits ^ leastSigBits; + return ((int) (hilo >> 32)) ^ (int) hilo; + } + + /** + * 将此对象与指定对象比较。 + *

    + * 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。 + * + * @param obj 要与之比较的对象 + * + * @return 如果对象相同,则返回 {@code true};否则返回 {@code false} + */ + @Override + public boolean equals(Object obj) + { + if ((null == obj) || (obj.getClass() != UUID.class)) + { + return false; + } + UUID id = (UUID) obj; + return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits); + } + + // Comparison Operations + + /** + * 将此 UUID 与指定的 UUID 比较。 + * + *

    + * 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。 + * + * @param val 与此 UUID 比较的 UUID + * + * @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。 + * + */ + @Override + public int compareTo(UUID val) + { + // The ordering is intentionally set up so that the UUIDs + // can simply be numerically compared as two numbers + return (this.mostSigBits < val.mostSigBits ? -1 : // + (this.mostSigBits > val.mostSigBits ? 1 : // + (this.leastSigBits < val.leastSigBits ? -1 : // + (this.leastSigBits > val.leastSigBits ? 1 : // + 0)))); + } + + // ------------------------------------------------------------------------------------------------------------------- + // Private method start + /** + * 返回指定数字对应的hex值 + * + * @param val 值 + * @param digits 位 + * @return 值 + */ + private static String digits(long val, int digits) + { + long hi = 1L << (digits * 4); + return Long.toHexString(hi | (val & (hi - 1))).substring(1); + } + + /** + * 检查是否为time-based版本UUID + */ + private void checkTimeBase() + { + if (version() != 1) + { + throw new UnsupportedOperationException("Not a time-based UUID"); + } + } + + /** + * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG) + * + * @return {@link SecureRandom} + */ + public static SecureRandom getSecureRandom() + { + try + { + return SecureRandom.getInstance("SHA1PRNG"); + } + catch (NoSuchAlgorithmException e) + { + throw new UtilException(e); + } + } + + /** + * 获取随机数生成器对象
    + * ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。 + * + * @return {@link ThreadLocalRandom} + */ + public static ThreadLocalRandom getRandom() + { + return ThreadLocalRandom.current(); + } +} diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml index 64e719736..8ff3f8ee5 100644 --- a/ruoyi-framework/pom.xml +++ b/ruoyi-framework/pom.xml @@ -5,20 +5,20 @@ ruoyi com.ruoyi - 4.1.0 + 4.4.0 4.0.0 - + ruoyi-framework - - - framework框架核心 - - + + + framework框架核心 + + - - + + org.springframework.boot spring-boot-starter-web @@ -31,74 +31,68 @@ - - org.springframework.boot - spring-boot-starter-aop - + + org.springframework.boot + spring-boot-starter-aop + - - + + com.alibaba druid-spring-boot-starter - - - - com.github.penggle - kaptcha - - - javax.servlet-api - javax.servlet - - - - - - org.apache.shiro - shiro-spring - + + + com.github.penggle + kaptcha + + + javax.servlet-api + javax.servlet + + + - - - org.apache.shiro - shiro-ehcache - - - - - com.github.theborakompanioni - thymeleaf-extras-shiro - + + + org.apache.shiro + shiro-spring + - - - eu.bitwalker - UserAgentUtils - + + + com.github.theborakompanioni + thymeleaf-extras-shiro + + + + + eu.bitwalker + UserAgentUtils + + + + + com.github.oshi + oshi-core + + + + net.java.dev.jna + jna + + + + net.java.dev.jna + jna-platform + com.ruoyi ruoyi-system - - - - com.github.oshi - oshi-core - - - - net.java.dev.jna - jna - - - - net.java.dev.jna - jna-platform - org.hibernate @@ -117,5 +111,5 @@ 3.8.0 - + \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java index 7412b9047..fff3cdd33 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java @@ -1,14 +1,6 @@ package com.ruoyi.framework.aspectj; -import com.querydsl.core.types.ExpressionUtils; -import com.querydsl.core.types.Predicate; -import com.ruoyi.common.annotation.DataScope; -import com.ruoyi.common.core.domain.BaseEntity; -import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysRole; -import com.ruoyi.system.domain.SysUser; -import com.ruoyi.system.service.ISysUserService; +import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.After; diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java index 9a3dda63f..4b053de30 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java @@ -42,7 +42,9 @@ public class DataSourceAspect { try { return point.proceed(); - } finally { + } + finally + { // 销毁数据源 在执行方法之后 DynamicDataSourceContextHolder.clearDataSourceType(); } @@ -53,14 +55,12 @@ public class DataSourceAspect { */ public DataSource getDataSource(ProceedingJoinPoint point) { MethodSignature signature = (MethodSignature) point.getSignature(); - Class targetClass = point.getTarget().getClass(); - DataSource targetDataSource = targetClass.getAnnotation(DataSource.class); - if (StringUtils.isNotNull(targetDataSource)) { - return targetDataSource; - } else { - Method method = signature.getMethod(); - DataSource dataSource = method.getAnnotation(DataSource.class); + DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); + if (Objects.nonNull(dataSource)) + { return dataSource; } + + return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java index fa33d3f8d..159ea7fb7 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java @@ -1,5 +1,19 @@ package com.ruoyi.framework.aspectj; +import java.lang.reflect.Method; +import java.util.Map; +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; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.support.spring.PropertyPreFilters; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.enums.BusinessStatus; import com.ruoyi.common.json.JSON; @@ -10,38 +24,25 @@ import com.ruoyi.framework.manager.factory.AsyncFactory; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysOperLog; import com.ruoyi.system.domain.SysUser; -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.beans.factory.annotation.Autowired; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.stereotype.Component; - -import java.lang.reflect.Method; -import java.util.Map; /** * 操作日志记录处理 - * + * * @author ruoyi */ @Aspect @Component -public class LogAspect { +public class LogAspect +{ private static final Logger log = LoggerFactory.getLogger(LogAspect.class); - @Autowired - private MappingJackson2HttpMessageConverter converter; + /** 排除敏感属性字段 */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; // 配置织入点 @Pointcut("@annotation(com.ruoyi.common.annotation.Log)") - public void logPointCut() { + public void logPointCut() + { } /** @@ -50,26 +51,31 @@ public class LogAspect { * @param joinPoint 切点 */ @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult") - public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) { + public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) + { handleLog(joinPoint, null, jsonResult); } /** * 拦截异常操作 - * + * * @param joinPoint 切点 - * @param e 异常 + * @param e 异常 */ @AfterThrowing(value = "logPointCut()", throwing = "e") - public void doAfterThrowing(JoinPoint joinPoint, Exception e) { + public void doAfterThrowing(JoinPoint joinPoint, Exception e) + { handleLog(joinPoint, e, null); } - protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) { - try { + protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) + { + try + { // 获得注解 Log controllerLog = getAnnotationLog(joinPoint); - if (controllerLog == null) { + if (controllerLog == null) + { return; } @@ -83,18 +89,21 @@ public class LogAspect { String ip = ShiroUtils.getIp(); operLog.setOperIp(ip); // 返回参数 - operLog.setJsonResult(converter.getObjectMapper().writeValueAsString(jsonResult)); + operLog.setJsonResult(StringUtils.substring(JSON.marshal(jsonResult), 0, 2000)); operLog.setOperUrl(ServletUtils.getRequest().getRequestURI()); - if (currentUser != null) { + if (currentUser != null) + { operLog.setOperName(currentUser.getLoginName()); if (StringUtils.isNotNull(currentUser.getDept()) - && StringUtils.isNotEmpty(currentUser.getDept().getDeptName())) { + && StringUtils.isNotEmpty(currentUser.getDept().getDeptName())) + { operLog.setDeptName(currentUser.getDept().getDeptName()); } } - if (e != null) { + if (e != null) + { operLog.setStatus(BusinessStatus.FAIL.ordinal()); operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000)); } @@ -108,7 +117,9 @@ public class LogAspect { getControllerMethodDescription(controllerLog, operLog); // 保存数据库 AsyncManager.me().execute(AsyncFactory.recordOper(operLog)); - } catch (Exception exp) { + } + catch (Exception exp) + { // 记录本地异常日志 log.error("==前置通知异常=="); log.error("异常信息:{}", exp.getMessage()); @@ -118,12 +129,13 @@ public class LogAspect { /** * 获取注解中对方法的描述信息 用于Controller层注解 - * - * @param log 日志 + * + * @param log 日志 * @param operLog 操作日志 * @throws Exception */ - public void getControllerMethodDescription(Log log, SysOperLog operLog) throws Exception { + public void getControllerMethodDescription(Log log, SysOperLog operLog) throws Exception + { // 设置action动作 operLog.setBusinessType(log.businessType().ordinal()); // 设置标题 @@ -131,7 +143,8 @@ public class LogAspect { // 设置操作人类别 operLog.setOperatorType(log.operatorType().ordinal()); // 是否需要保存request,参数和值 - if (log.isSaveRequestData()) { + if (log.isSaveRequestData()) + { // 获取参数的信息,传入到数据库中。 setRequestValue(operLog); } @@ -139,25 +152,33 @@ public class LogAspect { /** * 获取请求的参数,放到log中 - * + * * @param operLog 操作日志 * @throws Exception 异常 */ - private void setRequestValue(SysOperLog operLog) throws Exception { + private void setRequestValue(SysOperLog operLog) throws Exception + { Map map = ServletUtils.getRequest().getParameterMap(); - String params = JSON.marshal(map); - operLog.setOperParam(StringUtils.substring(params, 0, 2000)); + if (StringUtils.isNotEmpty(map)) + { + PropertyPreFilters.MySimplePropertyPreFilter excludefilter = new PropertyPreFilters().addFilter(); + excludefilter.addExcludes(EXCLUDE_PROPERTIES); + String params = JSONObject.toJSONString(map, excludefilter); + operLog.setOperParam(StringUtils.substring(params, 0, 2000)); + } } /** * 是否存在注解,如果存在就获取 */ - private Log getAnnotationLog(JoinPoint joinPoint) throws Exception { + private Log getAnnotationLog(JoinPoint joinPoint) throws Exception + { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); - if (method != null) { + if (method != null) + { return method.getAnnotation(Log.class); } return null; diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java index 16312da17..ff7a52326 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ShiroConfig.java @@ -6,7 +6,6 @@ import java.io.InputStream; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.Filter; - import org.apache.commons.io.IOUtils; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.codec.Base64; @@ -38,58 +37,89 @@ import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; /** * 权限配置加载 - * + * * @author ruoyi */ @Configuration -public class ShiroConfig { +public class ShiroConfig +{ public static final String PREMISSION_STRING = "perms[\"{0}\"]"; - // Session超时时间,单位为毫秒(默认30分钟) + /** + * Session超时时间,单位为毫秒(默认30分钟) + */ @Value("${shiro.session.expireTime}") private int expireTime; - // 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟 + /** + * 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟 + */ @Value("${shiro.session.validationInterval}") private int validationInterval; - // 同一个用户最大会话数 + /** + * 同一个用户最大会话数 + */ @Value("${shiro.session.maxSession}") private int maxSession; - // 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户 + /** + * 踢出之前登录的/之后登录的用户,默认踢出之前登录的用户 + */ @Value("${shiro.session.kickoutAfter}") private boolean kickoutAfter; - // 验证码开关 + /** + * 验证码开关 + */ @Value("${shiro.user.captchaEnabled}") private boolean captchaEnabled; - // 验证码类型 + /** + * 验证码类型 + */ @Value("${shiro.user.captchaType}") private String captchaType; - // 设置Cookie的域名 + /** + * 设置Cookie的域名 + */ @Value("${shiro.cookie.domain}") private String domain; - // 设置cookie的有效访问路径 + /** + * 设置cookie的有效访问路径 + */ @Value("${shiro.cookie.path}") private String path; - // 设置HttpOnly属性 + /** + * 设置HttpOnly属性 + */ @Value("${shiro.cookie.httpOnly}") private boolean httpOnly; - // 设置Cookie的过期时间,秒为单位 + /** + * 设置Cookie的过期时间,秒为单位 + */ @Value("${shiro.cookie.maxAge}") private int maxAge; - // 登录地址 + /** + * 设置cipherKey密钥 + */ + @Value("${shiro.cookie.cipherKey}") + private String cipherKey; + + /** + * 登录地址 + */ @Value("${shiro.user.loginUrl}") private String loginUrl; - // 权限认证失败地址 + /** + * 权限认证失败地址 + */ @Value("${shiro.user.unauthorizedUrl}") private String unauthorizedUrl; @@ -97,13 +127,17 @@ public class ShiroConfig { * 缓存管理器 使用Ehcache实现 */ @Bean - public EhCacheManager getEhCacheManager() { + public EhCacheManager getEhCacheManager() + { net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.getCacheManager("ruoyi"); EhCacheManager em = new EhCacheManager(); - if (StringUtils.isNull(cacheManager)) { + if (StringUtils.isNull(cacheManager)) + { em.setCacheManager(new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream())); return em; - } else { + } + else + { em.setCacheManager(cacheManager); return em; } @@ -112,18 +146,24 @@ public class ShiroConfig { /** * 返回配置文件流 避免ehcache配置文件一直被占用,无法完全销毁项目重新部署 */ - protected InputStream getCacheManagerConfigFileInputStream() { + protected InputStream getCacheManagerConfigFileInputStream() + { String configFile = "classpath:ehcache/ehcache-shiro.xml"; InputStream inputStream = null; - try { + try + { inputStream = ResourceUtils.getInputStreamForPath(configFile); byte[] b = IOUtils.toByteArray(inputStream); InputStream in = new ByteArrayInputStream(b); return in; - } catch (IOException e) { + } + catch (IOException e) + { throw new ConfigurationException( "Unable to obtain input stream for cacheManagerConfigFile [" + configFile + "]", e); - } finally { + } + finally + { IOUtils.closeQuietly(inputStream); } } @@ -132,7 +172,8 @@ public class ShiroConfig { * 自定义Realm */ @Bean - public UserRealm userRealm(EhCacheManager cacheManager) { + public UserRealm userRealm(EhCacheManager cacheManager) + { UserRealm userRealm = new UserRealm(); userRealm.setCacheManager(cacheManager); return userRealm; @@ -142,7 +183,8 @@ public class ShiroConfig { * 自定义sessionDAO会话 */ @Bean - public OnlineSessionDAO sessionDAO() { + public OnlineSessionDAO sessionDAO() + { OnlineSessionDAO sessionDAO = new OnlineSessionDAO(); return sessionDAO; } @@ -151,7 +193,8 @@ public class ShiroConfig { * 自定义sessionFactory会话 */ @Bean - public OnlineSessionFactory sessionFactory() { + public OnlineSessionFactory sessionFactory() + { OnlineSessionFactory sessionFactory = new OnlineSessionFactory(); return sessionFactory; } @@ -160,7 +203,8 @@ public class ShiroConfig { * 会话管理器 */ @Bean - public OnlineWebSessionManager sessionManager() { + public OnlineWebSessionManager sessionManager() + { OnlineWebSessionManager manager = new OnlineWebSessionManager(); // 加入缓存管理器 manager.setCacheManager(getEhCacheManager()); @@ -185,7 +229,8 @@ public class ShiroConfig { * 安全管理器 */ @Bean - public SecurityManager securityManager(UserRealm userRealm) { + public SecurityManager securityManager(UserRealm userRealm) + { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm. securityManager.setRealm(userRealm); @@ -201,9 +246,9 @@ public class ShiroConfig { /** * 退出过滤器 */ - public LogoutFilter logoutFilter() { + public LogoutFilter logoutFilter() + { LogoutFilter logoutFilter = new LogoutFilter(); - logoutFilter.setCacheManager(getEhCacheManager()); logoutFilter.setLoginUrl(loginUrl); return logoutFilter; } @@ -212,7 +257,8 @@ public class ShiroConfig { * Shiro过滤器配置 */ @Bean - public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { + public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) + { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // Shiro的核心安全接口,这个属性是必须的 shiroFilterFactoryBean.setSecurityManager(securityManager); @@ -232,12 +278,13 @@ public class ShiroConfig { filterChainDefinitionMap.put("/ajax/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/ruoyi/**", "anon"); - filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/captcha/captchaImage**", "anon"); // 退出 logout地址,shiro去清除session filterChainDefinitionMap.put("/logout", "logout"); // 不需要拦截的访问 filterChainDefinitionMap.put("/login", "anon,captchaValidate"); + // 注册相关 + filterChainDefinitionMap.put("/register", "anon,captchaValidate"); // 系统权限列表 // filterChainDefinitionMap.putAll(SpringUtils.getBean(IMenuService.class).selectPermsAll()); @@ -261,7 +308,8 @@ public class ShiroConfig { * 自定义在线用户处理过滤器 */ @Bean - public OnlineSessionFilter onlineSessionFilter() { + public OnlineSessionFilter onlineSessionFilter() + { OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter(); onlineSessionFilter.setLoginUrl(loginUrl); return onlineSessionFilter; @@ -271,7 +319,8 @@ public class ShiroConfig { * 自定义在线用户同步过滤器 */ @Bean - public SyncOnlineSessionFilter syncOnlineSessionFilter() { + public SyncOnlineSessionFilter syncOnlineSessionFilter() + { SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter(); return syncOnlineSessionFilter; } @@ -280,7 +329,8 @@ public class ShiroConfig { * 自定义验证码过滤器 */ @Bean - public CaptchaValidateFilter captchaValidateFilter() { + public CaptchaValidateFilter captchaValidateFilter() + { CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter(); captchaValidateFilter.setCaptchaEnabled(captchaEnabled); captchaValidateFilter.setCaptchaType(captchaType); @@ -290,7 +340,8 @@ public class ShiroConfig { /** * cookie 属性设置 */ - public SimpleCookie rememberMeCookie() { + public SimpleCookie rememberMeCookie() + { SimpleCookie cookie = new SimpleCookie("rememberMe"); cookie.setDomain(domain); cookie.setPath(path); @@ -302,17 +353,19 @@ public class ShiroConfig { /** * 记住我 */ - public CookieRememberMeManager rememberMeManager() { + public CookieRememberMeManager rememberMeManager() + { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); - cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ==")); + cookieRememberMeManager.setCipherKey(Base64.decode(cipherKey)); return cookieRememberMeManager; } /** * 同一个用户多设备登录限制 */ - public KickoutSessionFilter kickoutSessionFilter() { + public KickoutSessionFilter kickoutSessionFilter() + { KickoutSessionFilter kickoutSessionFilter = new KickoutSessionFilter(); kickoutSessionFilter.setCacheManager(getEhCacheManager()); kickoutSessionFilter.setSessionManager(sessionManager()); @@ -329,7 +382,8 @@ public class ShiroConfig { * thymeleaf模板引擎和shiro框架的整合 */ @Bean - public ShiroDialect shiroDialect() { + public ShiroDialect shiroDialect() + { return new ShiroDialect(); } @@ -338,7 +392,8 @@ public class ShiroConfig { */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor( - @Qualifier("securityManager") SecurityManager securityManager) { + @Qualifier("securityManager") SecurityManager securityManager) + { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java index 913d51cba..35076b595 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java @@ -3,7 +3,6 @@ package com.ruoyi.framework.interceptor; import java.lang.reflect.Method; 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; @@ -14,34 +13,41 @@ import com.ruoyi.common.utils.ServletUtils; /** * 防止重复提交拦截器 - * + * * @author ruoyi */ @Component -public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter { +public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter +{ @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - if (handler instanceof HandlerMethod) { + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception + { + if (handler instanceof HandlerMethod) + { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class); - if (annotation != null) { - if (this.isRepeatSubmit(request)) { + if (annotation != null) + { + if (this.isRepeatSubmit(request)) + { AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试"); ServletUtils.renderString(response, JSON.marshal(ajaxResult)); return false; } } return true; - } else { + } + else + { return super.preHandle(request, response, handler); } } /** * 验证是否重复提交由子类实现具体的防重复提交的规则 - * - * @param httpServletRequest + * + * @param request * @return * @throws Exception */ diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java index 6312e8ea0..8f664ed9f 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java @@ -1,12 +1,12 @@ package com.ruoyi.framework.manager.factory; import java.util.TimerTask; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.AddressUtils; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.shiro.session.OnlineSession; import com.ruoyi.framework.util.LogUtils; @@ -21,22 +21,27 @@ import eu.bitwalker.useragentutils.UserAgent; /** * 异步工厂(产生任务用) - * + * * @author liuhulu + * */ -public class AsyncFactory { +public class AsyncFactory +{ private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user"); /** * 同步session到数据库 - * + * * @param session 在线用户会话 * @return 任务task */ - public static TimerTask syncSessionToDb(final OnlineSession session) { - return new TimerTask() { + public static TimerTask syncSessionToDb(final OnlineSession session) + { + return new TimerTask() + { @Override - public void run() { + public void run() + { SysUserOnline online = new SysUserOnline(); online.setSessionId(String.valueOf(session.getId())); online.setDeptName(session.getDeptName()); @@ -57,14 +62,17 @@ public class AsyncFactory { /** * 操作日志记录 - * + * * @param operLog 操作日志信息 * @return 任务task */ - public static TimerTask recordOper(final SysOperLog operLog) { - return new TimerTask() { + public static TimerTask recordOper(final SysOperLog operLog) + { + return new TimerTask() + { @Override - public void run() { + public void run() + { // 远程查询操作地点 operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp())); SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog); @@ -74,19 +82,22 @@ public class AsyncFactory { /** * 记录登陆信息 - * + * * @param username 用户名 - * @param status 状态 - * @param message 消息 - * @param args 列表 + * @param status 状态 + * @param message 消息 + * @param args 列表 * @return 任务task */ - public static TimerTask recordLogininfor(final String username, final String status, final String message, final Object... args) { + public static TimerTask recordLogininfor(final String username, final String status, final String message, final Object... args) + { final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); final String ip = ShiroUtils.getIp(); - return new TimerTask() { + return new TimerTask() + { @Override - public void run() { + public void run() + { String address = AddressUtils.getRealAddressByIP(ip); StringBuilder s = new StringBuilder(); s.append(LogUtils.getBlock(ip)); @@ -109,9 +120,12 @@ public class AsyncFactory { logininfor.setOs(os); logininfor.setMsg(message); // 日志状态 - if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status)) { + if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER)) + { logininfor.setStatus(Constants.SUCCESS); - } else if (Constants.LOGIN_FAIL.equals(status)) { + } + else if (Constants.LOGIN_FAIL.equals(status)) + { logininfor.setStatus(Constants.FAIL); } // 插入数据 diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysLoginService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysLoginService.java index 651b62d2a..d7a331cdf 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysLoginService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysLoginService.java @@ -23,11 +23,12 @@ import com.ruoyi.system.service.ISysUserService; /** * 登录校验方法 - * + * * @author ruoyi */ @Component -public class SysLoginService { +public class SysLoginService +{ @Autowired private SysPasswordService passwordService; @@ -37,27 +38,32 @@ public class SysLoginService { /** * 登录 */ - public SysUser login(String username, String password) { + public SysUser login(String username, String password) + { // 验证码校验 - if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) { + if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); throw new CaptchaException(); } // 用户名或密码为空 错误 - if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { + if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null"))); throw new UserNotExistsException(); } // 密码如果不在指定范围内 错误 if (password.length() < UserConstants.PASSWORD_MIN_LENGTH - || password.length() > UserConstants.PASSWORD_MAX_LENGTH) { + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); throw new UserPasswordNotMatchException(); } // 用户名不在指定范围内 错误 if (username.length() < UserConstants.USERNAME_MIN_LENGTH - || username.length() > UserConstants.USERNAME_MAX_LENGTH) { + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); throw new UserPasswordNotMatchException(); } @@ -65,25 +71,32 @@ public class SysLoginService { // 查询用户信息 SysUser user = userService.selectUserByLoginName(username); - if (user == null && maybeMobilePhoneNumber(username)) { + /** + if (user == null && maybeMobilePhoneNumber(username)) + { user = userService.selectUserByPhoneNumber(username); } - if (user == null && maybeEmail(username)) { + if (user == null && maybeEmail(username)) + { user = userService.selectUserByEmail(username); } + */ - if (user == null) { + if (user == null) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists"))); throw new UserNotExistsException(); } - - if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { + + if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.delete"))); throw new UserDeleteException(); } - - if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + + if (UserStatus.DISABLE.getCode().equals(user.getStatus())) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.blocked", user.getRemark()))); throw new UserBlockedException(); } @@ -95,24 +108,31 @@ public class SysLoginService { return user; } - private boolean maybeEmail(String username) { - if (!username.matches(UserConstants.EMAIL_PATTERN)) { + /** + private boolean maybeEmail(String username) + { + if (!username.matches(UserConstants.EMAIL_PATTERN)) + { return false; } return true; } - private boolean maybeMobilePhoneNumber(String username) { - if (!username.matches(UserConstants.MOBILE_PHONE_NUMBER_PATTERN)) { + private boolean maybeMobilePhoneNumber(String username) + { + if (!username.matches(UserConstants.MOBILE_PHONE_NUMBER_PATTERN)) + { return false; } return true; } + */ /** * 记录登录信息 */ - public void recordLoginInfo(SysUser user) { + public void recordLoginInfo(SysUser user) + { user.setLoginIp(ShiroUtils.getIp()); user.setLoginDate(DateUtils.getNowDate()); userService.updateUserInfo(user); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysPasswordService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysPasswordService.java index 283ef869a..8c4b80fe4 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysPasswordService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysPasswordService.java @@ -2,7 +2,6 @@ package com.ruoyi.framework.shiro.service; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.PostConstruct; - import org.apache.shiro.cache.Cache; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.crypto.hash.Md5Hash; @@ -20,11 +19,12 @@ import com.ruoyi.system.domain.SysUser; /** * 登录密码方法 - * + * * @author ruoyi */ @Component -public class SysPasswordService { +public class SysPasswordService +{ @Autowired private CacheManager cacheManager; @@ -34,47 +34,57 @@ public class SysPasswordService { private String maxRetryCount; @PostConstruct - public void init() { + public void init() + { loginRecordCache = cacheManager.getCache(ShiroConstants.LOGINRECORDCACHE); } - public void validate(SysUser user, String password) { + public void validate(SysUser user, String password) + { String loginName = user.getLoginName(); AtomicInteger retryCount = loginRecordCache.get(loginName); - if (retryCount == null) { + if (retryCount == null) + { retryCount = new AtomicInteger(0); loginRecordCache.put(loginName, retryCount); } - if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue()) { + if (retryCount.incrementAndGet() > Integer.valueOf(maxRetryCount).intValue()) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount))); throw new UserPasswordRetryLimitExceedException(Integer.valueOf(maxRetryCount).intValue()); } - if (!matches(user, password)) { + if (!matches(user, password)) + { AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", retryCount))); loginRecordCache.put(loginName, retryCount); throw new UserPasswordNotMatchException(); - } else { + } + else + { clearLoginRecordCache(loginName); } } - public boolean matches(SysUser user, String newPassword) { + public boolean matches(SysUser user, String newPassword) + { return user.getPassword().equals(encryptPassword(user.getLoginName(), newPassword, user.getSalt())); } - public void clearLoginRecordCache(String username) { + public void clearLoginRecordCache(String username) + { loginRecordCache.remove(username); } - public String encryptPassword(String username, String password, String salt) { - return new Md5Hash(username + password + salt).toHex().toString(); + public String encryptPassword(String username, String password, String salt) + { + return new Md5Hash(username + password + salt).toHex(); } - public void unlock(String loginName) { + public void unlock(String loginName) + { loginRecordCache.remove(loginName); } - } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysRegisterService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysRegisterService.java new file mode 100644 index 000000000..97dfd1022 --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysRegisterService.java @@ -0,0 +1,80 @@ +package com.ruoyi.framework.shiro.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.ShiroConstants; +import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.utils.MessageUtils; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.framework.manager.AsyncManager; +import com.ruoyi.framework.manager.factory.AsyncFactory; +import com.ruoyi.framework.util.ShiroUtils; +import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.service.ISysUserService; + +/** + * 注册校验方法 + * + * @author ruoyi + */ +@Component +public class SysRegisterService +{ + @Autowired + private ISysUserService userService; + + @Autowired + private SysPasswordService passwordService; + + /** + * 注册 + */ + public String register(SysUser user) + { + String msg = "", username = user.getLoginName(), password = user.getPassword(); + + if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) + { + msg = "验证码错误"; + } + else if (StringUtils.isEmpty(username)) + { + msg = "用户名不能为空"; + } + else if (StringUtils.isEmpty(password)) + { + msg = "用户密码不能为空"; + } + else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + msg = "密码长度必须在5到20个字符之间"; + } + else if (username.length() < UserConstants.USERNAME_MIN_LENGTH + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { + msg = "账户长度必须在2到20个字符之间"; + } + else if (UserConstants.USER_NAME_NOT_UNIQUE.equals(userService.checkLoginNameUnique(username))) + { + msg = "保存用户'" + username + "'失败,注册账号已存在"; + } + else + { + user.setSalt(ShiroUtils.randomSalt()); + user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt())); + boolean regFlag = userService.registerUser(user); + if (!regFlag) + { + msg = "注册失败,请联系系统管理人员"; + } + else + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success"))); + } + } + return msg; + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java index 49da39d17..30a949412 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionDAO.java @@ -1,28 +1,24 @@ package com.ruoyi.framework.shiro.session; +import java.io.Serializable; +import java.util.Date; +import org.apache.shiro.session.Session; +import org.apache.shiro.session.UnknownSessionException; +import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import com.ruoyi.common.enums.OnlineStatus; import com.ruoyi.framework.manager.AsyncManager; import com.ruoyi.framework.manager.factory.AsyncFactory; import com.ruoyi.framework.shiro.service.SysShiroService; -import org.apache.shiro.session.Session; -import org.apache.shiro.session.UnknownSessionException; -import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; - -import java.io.Serializable; -import java.util.Date; /** * 针对自定义的ShiroSession的db操作 - * + * * @author ruoyi */ -public class OnlineSessionDAO extends EnterpriseCacheSessionDAO { - - private static final Logger logger = LoggerFactory.getLogger(OnlineSessionDAO.class); +public class OnlineSessionDAO extends EnterpriseCacheSessionDAO +{ /** * 同步session到数据库的周期 单位为毫秒(默认1分钟) */ @@ -37,11 +33,13 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO { @Autowired private SysShiroService sysShiroService; - public OnlineSessionDAO() { + public OnlineSessionDAO() + { super(); } - public OnlineSessionDAO(long expireTime) { + public OnlineSessionDAO(long expireTime) + { super(); } @@ -52,24 +50,29 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO { * @return ShiroSession */ @Override - protected Session doReadSession(Serializable sessionId) { + protected Session doReadSession(Serializable sessionId) + { return sysShiroService.getSession(sessionId); } @Override - public void update(Session session) throws UnknownSessionException { + public void update(Session session) throws UnknownSessionException + { super.update(session); } /** * 更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用 */ - public void syncToDb(OnlineSession onlineSession) { + public void syncToDb(OnlineSession onlineSession) + { Date lastSyncTimestamp = (Date) onlineSession.getAttribute(LAST_SYNC_DB_TIMESTAMP); - if (lastSyncTimestamp != null) { + if (lastSyncTimestamp != null) + { boolean needSync = true; long deltaTime = onlineSession.getLastAccessTime().getTime() - lastSyncTimestamp.getTime(); - if (deltaTime < dbSyncPeriod * 60 * 1000) { + if (deltaTime < dbSyncPeriod * 60 * 1000) + { // 时间差不足 无需同步 needSync = false; } @@ -77,18 +80,21 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO { boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L; // session 数据变更了 同步 - if (isGuest == false && onlineSession.isAttributeChanged()) { + if (!isGuest == false && onlineSession.isAttributeChanged()) + { needSync = true; } - if (needSync == false) { + if (!needSync) + { return; } } // 更新上次同步数据库时间 onlineSession.setAttribute(LAST_SYNC_DB_TIMESTAMP, onlineSession.getLastAccessTime()); // 更新完后 重置标识 - if (onlineSession.isAttributeChanged()) { + if (onlineSession.isAttributeChanged()) + { onlineSession.resetAttributeChanged(); } AsyncManager.me().execute(AsyncFactory.syncSessionToDb(onlineSession)); @@ -98,16 +104,14 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO { * 当会话过期/停止(如用户退出时)属性等会调用 */ @Override - protected void doDelete(Session session) { + protected void doDelete(Session session) + { OnlineSession onlineSession = (OnlineSession) session; - if (null == onlineSession) { + if (null == onlineSession) + { return; } onlineSession.setStatus(OnlineStatus.off_line); - try{ - sysShiroService.deleteSession(onlineSession); - }catch (Exception e){ - logger.info("delete OnlineSession error : {}", e); - } + sysShiroService.deleteSession(onlineSession); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/LogoutFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/LogoutFilter.java index 9b73275f4..28e5df5df 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/LogoutFilter.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/LogoutFilter.java @@ -1,31 +1,28 @@ package com.ruoyi.framework.shiro.web.filter; -import java.io.Serializable; -import java.util.Deque; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; - -import org.apache.shiro.cache.Cache; -import org.apache.shiro.cache.CacheManager; import org.apache.shiro.session.SessionException; import org.apache.shiro.subject.Subject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ruoyi.common.constant.Constants; -import com.ruoyi.common.constant.ShiroConstants; import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.manager.AsyncManager; import com.ruoyi.framework.manager.factory.AsyncFactory; import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysUser; +import com.ruoyi.system.service.ISysUserOnlineService; /** * 退出过滤器 - * + * * @author ruoyi */ -public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter { +public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter +{ private static final Logger log = LoggerFactory.getLogger(LogoutFilter.class); /** @@ -33,37 +30,45 @@ public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter */ private String loginUrl; - private Cache> cache; - - public String getLoginUrl() { + public String getLoginUrl() + { return loginUrl; } - public void setLoginUrl(String loginUrl) { + public void setLoginUrl(String loginUrl) + { this.loginUrl = loginUrl; } @Override - protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { - try { + protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception + { + try + { Subject subject = getSubject(request, response); String redirectUrl = getRedirectUrl(request, response, subject); - try { + try + { SysUser user = ShiroUtils.getSysUser(); - if (StringUtils.isNotNull(user)) { + if (StringUtils.isNotNull(user)) + { String loginName = user.getLoginName(); // 记录用户退出日志 AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success"))); // 清理缓存 - cache.remove(loginName); + SpringUtils.getBean(ISysUserOnlineService.class).removeUserCache(loginName, ShiroUtils.getSessionId()); } // 退出登录 subject.logout(); - } catch (SessionException ise) { + } + catch (SessionException ise) + { log.error("logout fail.", ise); } issueRedirect(request, response, redirectUrl); - } catch (Exception e) { + } + catch (Exception e) + { log.error("Encountered session exception during logout. This can generally safely be ignored.", e); } return false; @@ -73,17 +78,13 @@ public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter * 退出跳转URL */ @Override - protected String getRedirectUrl(ServletRequest request, ServletResponse response, Subject subject) { + protected String getRedirectUrl(ServletRequest request, ServletResponse response, Subject subject) + { String url = getLoginUrl(); - if (StringUtils.isNotEmpty(url)) { + if (StringUtils.isNotEmpty(url)) + { return url; } return super.getRedirectUrl(request, response, subject); } - - // 设置Cache的key的前缀 - public void setCacheManager(CacheManager cacheManager) { - // 必须和ehcache缓存配置中的缓存name一致 - this.cache = cacheManager.getCache(ShiroConstants.SYS_USERCACHE); - } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java index 331f31a72..0ba5894bc 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/captcha/CaptchaValidateFilter.java @@ -55,6 +55,8 @@ public class CaptchaValidateFilter extends AccessControlFilter { public boolean validateResponse(HttpServletRequest request, String validateCode) { Object obj = ShiroUtils.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY); String code = String.valueOf(obj != null ? obj : ""); + // 验证码清除,防止多次使用。 + request.getSession().removeAttribute(Constants.KAPTCHA_SESSION_KEY); if (StringUtils.isEmpty(validateCode) || !validateCode.equalsIgnoreCase(code)) { return false; } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/OnlineWebSessionManager.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/OnlineWebSessionManager.java index b834d602b..85c615a66 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/OnlineWebSessionManager.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/OnlineWebSessionManager.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; - import org.apache.commons.lang3.time.DateUtils; import org.apache.shiro.session.ExpiredSessionException; import org.apache.shiro.session.InvalidSessionException; @@ -24,43 +23,53 @@ import com.ruoyi.system.service.ISysUserOnlineService; /** * 主要是在此如果会话的属性修改了 就标识下其修改了 然后方便 OnlineSessionDao同步 - * + * * @author ruoyi */ -public class OnlineWebSessionManager extends DefaultWebSessionManager { +public class OnlineWebSessionManager extends DefaultWebSessionManager +{ private static final Logger log = LoggerFactory.getLogger(OnlineWebSessionManager.class); @Override - public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) throws InvalidSessionException { + public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) throws InvalidSessionException + { super.setAttribute(sessionKey, attributeKey, value); - if (value != null && needMarkAttributeChanged(attributeKey)) { + if (value != null && needMarkAttributeChanged(attributeKey)) + { OnlineSession session = getOnlineSession(sessionKey); session.markAttributeChanged(); } } - private boolean needMarkAttributeChanged(Object attributeKey) { - if (attributeKey == null) { + private boolean needMarkAttributeChanged(Object attributeKey) + { + if (attributeKey == null) + { return false; } String attributeKeyStr = attributeKey.toString(); // 优化 flash属性没必要持久化 - if (attributeKeyStr.startsWith("org.springframework")) { + if (attributeKeyStr.startsWith("org.springframework")) + { return false; } - if (attributeKeyStr.startsWith("javax.servlet")) { + if (attributeKeyStr.startsWith("javax.servlet")) + { return false; } - if (attributeKeyStr.equals(ShiroConstants.CURRENT_USERNAME)) { + if (attributeKeyStr.equals(ShiroConstants.CURRENT_USERNAME)) + { return false; } return true; } @Override - public Object removeAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException { + public Object removeAttribute(SessionKey sessionKey, Object attributeKey) throws InvalidSessionException + { Object removed = super.removeAttribute(sessionKey, attributeKey); - if (removed != null) { + if (removed != null) + { OnlineSession s = getOnlineSession(sessionKey); s.markAttributeChanged(); } @@ -68,10 +77,12 @@ public class OnlineWebSessionManager extends DefaultWebSessionManager { return removed; } - public OnlineSession getOnlineSession(SessionKey sessionKey) { + public OnlineSession getOnlineSession(SessionKey sessionKey) + { OnlineSession session = null; Object obj = doGetSession(sessionKey); - if (StringUtils.isNotNull(obj)) { + if (StringUtils.isNotNull(obj)) + { session = new OnlineSession(); BeanUtils.copyBeanProp(session, obj); } @@ -82,8 +93,10 @@ public class OnlineWebSessionManager extends DefaultWebSessionManager { * 验证session是否有效 用于删除过期session */ @Override - public void validateSessions() { - if (log.isInfoEnabled()) { + public void validateSessions() + { + if (log.isInfoEnabled()) + { log.info("invalidation sessions..."); } @@ -95,15 +108,21 @@ public class OnlineWebSessionManager extends DefaultWebSessionManager { List userOnlineList = userOnlineService.selectOnlineByExpired(expiredDate); // 批量过期删除 List needOfflineIdList = new ArrayList(); - for (SysUserOnline userOnline : userOnlineList) { - try { + for (SysUserOnline userOnline : userOnlineList) + { + try + { SessionKey key = new DefaultSessionKey(userOnline.getSessionId()); Session session = retrieveSession(key); - if (session != null) { + if (session != null) + { throw new InvalidSessionException(); } - } catch (InvalidSessionException e) { - if (log.isDebugEnabled()) { + } + catch (InvalidSessionException e) + { + if (log.isDebugEnabled()) + { boolean expired = (e instanceof ExpiredSessionException); String msg = "Invalidated session with id [" + userOnline.getSessionId() + "]" + (expired ? " (expired)" : " (stopped)"); @@ -111,22 +130,31 @@ public class OnlineWebSessionManager extends DefaultWebSessionManager { } invalidCount++; needOfflineIdList.add(userOnline.getSessionId()); + userOnlineService.removeUserCache(userOnline.getLoginName(), userOnline.getSessionId()); } } - if (needOfflineIdList.size() > 0) { - try { + if (needOfflineIdList.size() > 0) + { + try + { userOnlineService.batchDeleteOnline(needOfflineIdList); - } catch (Exception e) { + } + catch (Exception e) + { log.error("batch delete db session error.", e); } } - if (log.isInfoEnabled()) { + if (log.isInfoEnabled()) + { String msg = "Finished invalidation session."; - if (invalidCount > 0) { + if (invalidCount > 0) + { msg += " [" + invalidCount + "] sessions were stopped."; - } else { + } + else + { msg += " No sessions were stopped."; } log.info(msg); @@ -135,7 +163,8 @@ public class OnlineWebSessionManager extends DefaultWebSessionManager { } @Override - protected Collection getActiveSessions() { + protected Collection getActiveSessions() + { throw new UnsupportedOperationException("getActiveSessions method not supported"); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/ConfigService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/ConfigService.java index 2a0d66645..316d70e34 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/ConfigService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/ConfigService.java @@ -16,7 +16,6 @@ public class ConfigService { /** * 根据键名查询参数配置信息 - * * @param configKey 参数名称 * @return 参数键值 */ diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml index 2c82b1fc9..3e24ccd64 100644 --- a/ruoyi-generator/pom.xml +++ b/ruoyi-generator/pom.xml @@ -5,24 +5,24 @@ ruoyi com.ruoyi - 4.1.0 + 4.4.0 4.0.0 ruoyi-generator - - - generator代码生成 - - + + + generator代码生成 + + - + org.apache.velocity velocity - + com.ruoyi @@ -30,5 +30,5 @@ - + \ No newline at end of file diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java index 3955a4e47..e60c27a1d 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java @@ -1,37 +1,45 @@ package com.ruoyi.generator.controller; -import com.ruoyi.common.annotation.Log; -import com.ruoyi.common.core.controller.BaseController; -import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.core.page.TableDataInfo; -import com.ruoyi.common.core.text.Convert; -import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.security.PermissionUtils; -import com.ruoyi.generator.domain.GenTable; -import com.ruoyi.generator.domain.GenTableColumn; -import com.ruoyi.generator.service.IGenTableColumnService; -import com.ruoyi.generator.service.IGenTableService; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.List; -import java.util.Map; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import com.alibaba.fastjson.JSON; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.CxSelect; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.security.PermissionUtils; +import com.ruoyi.generator.domain.GenTable; +import com.ruoyi.generator.domain.GenTableColumn; +import com.ruoyi.generator.service.IGenTableColumnService; +import com.ruoyi.generator.service.IGenTableService; /** * 代码生成 操作处理 - * + * * @author ruoyi */ @Controller @RequestMapping("/tool/gen") -public class GenController extends BaseController { +public class GenController extends BaseController +{ private String prefix = "tool/gen"; @Autowired @@ -42,7 +50,8 @@ public class GenController extends BaseController { @RequiresPermissions("tool:gen:view") @GetMapping() - public String gen() { + public String gen() + { return prefix + "/gen"; } @@ -52,8 +61,11 @@ public class GenController extends BaseController { @RequiresPermissions("tool:gen:list") @PostMapping("/list") @ResponseBody - public TableDataInfo genList(GenTable genTable) { - return getDataTable(genTableService.selectGenTableList(genTable, getPageRequest())); + public TableDataInfo genList(GenTable genTable) + { + startPage(); + List list = genTableService.selectGenTableList(genTable); + return getDataTable(list); } /** @@ -62,8 +74,11 @@ public class GenController extends BaseController { @RequiresPermissions("tool:gen:list") @PostMapping("/db/list") @ResponseBody - public TableDataInfo dataList(GenTable genTable) { - return getDataTable(genTableService.selectDbTableList(genTable, getPageRequest())); + public TableDataInfo dataList(GenTable genTable) + { + startPage(); + List list = genTableService.selectDbTableList(genTable); + return getDataTable(list); } /** @@ -72,9 +87,10 @@ public class GenController extends BaseController { @RequiresPermissions("tool:gen:list") @PostMapping("/column/list") @ResponseBody - public TableDataInfo columnList(GenTable genTable) { + public TableDataInfo columnList(GenTableColumn genTableColumn) + { TableDataInfo dataInfo = new TableDataInfo(); - List list = genTableService.selectGenTableById(genTable.getTableId()).getColumns(); + List list = genTableColumnService.selectGenTableColumnListByTableId(genTableColumn); dataInfo.setRows(list); dataInfo.setTotal(list.size()); return dataInfo; @@ -85,7 +101,8 @@ public class GenController extends BaseController { */ @RequiresPermissions("tool:gen:list") @GetMapping("/importTable") - public String importTable() { + public String importTable() + { return prefix + "/importTable"; } @@ -96,7 +113,8 @@ public class GenController extends BaseController { @Log(title = "代码生成", businessType = BusinessType.IMPORT) @PostMapping("/importTable") @ResponseBody - public AjaxResult importTableSave(String tables) { + public AjaxResult importTableSave(String tables) + { String[] tableNames = Convert.toStrArray(tables); // 查询表信息 List tableList = genTableService.selectDbTableListByNames(tableNames); @@ -109,9 +127,27 @@ public class GenController extends BaseController { * 修改代码生成业务 */ @GetMapping("/edit/{tableId}") - public String edit(@PathVariable("tableId") Long tableId, ModelMap mmap) { + public String edit(@PathVariable("tableId") Long tableId, ModelMap mmap) + { GenTable table = genTableService.selectGenTableById(tableId); + List genTables = genTableService.selectGenTableAll(); + List cxSelect = new ArrayList(); + for (GenTable genTable : genTables) + { + if (!StringUtils.equals(table.getTableName(), genTable.getTableName())) + { + CxSelect cxTable = new CxSelect(genTable.getTableName(), genTable.getTableName() + ':' + genTable.getTableComment()); + List cxColumns = new ArrayList(); + for (GenTableColumn tableColumn : genTable.getColumns()) + { + cxColumns.add(new CxSelect(tableColumn.getColumnName(), tableColumn.getColumnName() + ':' + tableColumn.getColumnComment())); + } + cxTable.setS(cxColumns); + cxSelect.add(cxTable); + } + } mmap.put("table", table); + mmap.put("data", JSON.toJSON(cxSelect)); return prefix + "/edit"; } @@ -122,7 +158,8 @@ public class GenController extends BaseController { @Log(title = "代码生成", businessType = BusinessType.UPDATE) @PostMapping("/edit") @ResponseBody - public AjaxResult editSave(@Validated GenTable genTable) { + public AjaxResult editSave(@Validated GenTable genTable) + { genTableService.validateEdit(genTable); genTableService.updateGenTable(genTable); return AjaxResult.success(); @@ -132,7 +169,8 @@ public class GenController extends BaseController { @Log(title = "代码生成", businessType = BusinessType.DELETE) @PostMapping("/remove") @ResponseBody - public AjaxResult remove(String ids) { + public AjaxResult remove(String ids) + { genTableService.deleteGenTableByIds(ids); return AjaxResult.success(); } @@ -143,20 +181,48 @@ public class GenController extends BaseController { @RequiresPermissions("tool:gen:preview") @GetMapping("/preview/{tableId}") @ResponseBody - public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException { + public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException + { Map dataMap = genTableService.previewCode(tableId); return AjaxResult.success(dataMap); } /** - * 生成代码 + * 生成代码(下载方式) + */ + @RequiresPermissions("tool:gen:code") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/download/{tableName}") + public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException + { + byte[] data = genTableService.downloadCode(tableName); + genCode(response, data); + } + + /** + * 生成代码(自定义路径) */ @RequiresPermissions("tool:gen:code") @Log(title = "代码生成", businessType = BusinessType.GENCODE) @GetMapping("/genCode/{tableName}") - public void genCode(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException { - byte[] data = genTableService.generatorCode(tableName); - genCode(response, data); + @ResponseBody + public AjaxResult genCode(@PathVariable("tableName") String tableName) + { + genTableService.generatorCode(tableName); + return AjaxResult.success(); + } + + /** + * 同步数据库 + */ + @RequiresPermissions("tool:gen:edit") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @GetMapping("/synchDb/{tableName}") + @ResponseBody + public AjaxResult synchDb(@PathVariable("tableName") String tableName) + { + genTableService.synchDb(tableName); + return AjaxResult.success(); } /** @@ -166,16 +232,18 @@ public class GenController extends BaseController { @Log(title = "代码生成", businessType = BusinessType.GENCODE) @GetMapping("/batchGenCode") @ResponseBody - public void batchGenCode(HttpServletResponse response, String tables) throws IOException { + public void batchGenCode(HttpServletResponse response, String tables) throws IOException + { String[] tableNames = Convert.toStrArray(tables); - byte[] data = genTableService.generatorCode(tableNames); + byte[] data = genTableService.downloadCode(tableNames); genCode(response, data); } /** * 生成zip文件 */ - private void genCode(HttpServletResponse response, byte[] data) throws IOException { + private void genCode(HttpServletResponse response, byte[] data) throws IOException + { response.reset(); response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\""); response.addHeader("Content-Length", "" + data.length); diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java index 748edd962..269779cf2 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java @@ -1,277 +1,372 @@ package com.ruoyi.generator.domain; +import java.util.List; +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import org.apache.commons.lang3.ArrayUtils; import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.utils.StringUtils; -import javax.persistence.*; -import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import java.util.List; - /** * 业务表 gen_table - * + * * @author ruoyi */ -@Entity -@Table(name = "gen_table") -public class GenTable extends BaseEntity { +public class GenTable extends BaseEntity +{ private static final long serialVersionUID = 1L; - /** - * 编号 - */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) + /** 编号 */ private Long tableId; - /** - * 表名称 - */ + /** 表名称 */ @NotBlank(message = "表名称不能为空") private String tableName; - /** - * 表描述 - */ + /** 表描述 */ + @NotBlank(message = "表描述不能为空") private String tableComment; - /** - * 实体类名称(首字母大写) - */ + /** 关联父表的表名 */ + private String subTableName; + + /** 本表关联父表的外键名 */ + private String subTableFkName; + + /** 实体类名称(首字母大写) */ @NotBlank(message = "实体类名称不能为空") private String className; - /** - * 使用的模板(crud单表操作 tree树表操作) - */ + /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */ private String tplCategory; - /** - * 生成包路径 - */ + /** 生成包路径 */ @NotBlank(message = "生成包路径不能为空") private String packageName; - /** - * 生成模块名 - */ + /** 生成模块名 */ @NotBlank(message = "生成模块名不能为空") private String moduleName; - /** - * 生成业务名 - */ + /** 生成业务名 */ @NotBlank(message = "生成业务名不能为空") private String businessName; - /** - * 生成功能名 - */ + /** 生成功能名 */ + @NotBlank(message = "生成功能名不能为空") private String functionName; - /** - * 生成作者 - */ + /** 生成作者 */ @NotBlank(message = "作者不能为空") private String functionAuthor; - /** - * 主键信息 - */ - @Transient + /** 生成代码方式(0zip压缩包 1自定义路径) */ + private String genType; + + /** 生成路径(不填默认项目路径) */ + private String genPath; + + /** 主键信息 */ private GenTableColumn pkColumn; - /** - * 表列信息 - */ + /** 子表信息 */ + private GenTable subTable; + + /** 表列信息 */ @Valid - @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) - @JoinTable(name = "gen_table_columns", - joinColumns = @JoinColumn(name = "genTableTableId", referencedColumnName = "tableId"), - inverseJoinColumns = @JoinColumn(name = "columnsColumnId", referencedColumnName = "columnId")) private List columns; - /** - * 其它生成选项 - */ + /** 其它生成选项 */ private String options; - /** - * 树编码字段 - */ + /** 树编码字段 */ private String treeCode; - /** - * 树父编码字段 - */ + /** 树父编码字段 */ private String treeParentCode; - /** - * 树名称字段 - */ + /** 树名称字段 */ private String treeName; - public Long getTableId() { + /** 上级菜单ID字段 */ + private String parentMenuId; + + /** 上级菜单名称字段 */ + private String parentMenuName; + + public Long getTableId() + { return tableId; } - public void setTableId(Long tableId) { + public void setTableId(Long tableId) + { this.tableId = tableId; } - public String getTableName() { + public String getTableName() + { return tableName; } - public void setTableName(String tableName) { + public void setTableName(String tableName) + { this.tableName = tableName; } - public String getTableComment() { + public String getTableComment() + { return tableComment; } - public void setTableComment(String tableComment) { + public void setTableComment(String tableComment) + { this.tableComment = tableComment; } - public String getClassName() { + public String getSubTableName() + { + return subTableName; + } + + public void setSubTableName(String subTableName) + { + this.subTableName = subTableName; + } + + public String getSubTableFkName() + { + return subTableFkName; + } + + public void setSubTableFkName(String subTableFkName) + { + this.subTableFkName = subTableFkName; + } + + public String getClassName() + { return className; } - public void setClassName(String className) { + public void setClassName(String className) + { this.className = className; } - public String getTplCategory() { + public String getTplCategory() + { return tplCategory; } - public void setTplCategory(String tplCategory) { + public void setTplCategory(String tplCategory) + { this.tplCategory = tplCategory; } - public String getPackageName() { + public String getPackageName() + { return packageName; } - public void setPackageName(String packageName) { + public void setPackageName(String packageName) + { this.packageName = packageName; } - public String getModuleName() { + public String getModuleName() + { return moduleName; } - public void setModuleName(String moduleName) { + public void setModuleName(String moduleName) + { this.moduleName = moduleName; } - public String getBusinessName() { + public String getBusinessName() + { return businessName; } - public void setBusinessName(String businessName) { + public void setBusinessName(String businessName) + { this.businessName = businessName; } - public String getFunctionName() { + public String getFunctionName() + { return functionName; } - public void setFunctionName(String functionName) { + public void setFunctionName(String functionName) + { this.functionName = functionName; } - public String getFunctionAuthor() { + public String getFunctionAuthor() + { return functionAuthor; } - public void setFunctionAuthor(String functionAuthor) { + public void setFunctionAuthor(String functionAuthor) + { this.functionAuthor = functionAuthor; } - public GenTableColumn getPkColumn() { + public String getGenType() + { + return genType; + } + + public void setGenType(String genType) + { + this.genType = genType; + } + + public String getGenPath() + { + return genPath; + } + + public void setGenPath(String genPath) + { + this.genPath = genPath; + } + + public GenTableColumn getPkColumn() + { return pkColumn; } - public void setPkColumn(GenTableColumn pkColumn) { + public void setPkColumn(GenTableColumn pkColumn) + { this.pkColumn = pkColumn; } - public List getColumns() { + public GenTable getSubTable() + { + return subTable; + } + + public void setSubTable(GenTable subTable) + { + this.subTable = subTable; + } + + public List getColumns() + { return columns; } - public void setColumns(List columns) { + public void setColumns(List columns) + { this.columns = columns; } - public String getOptions() { + public String getOptions() + { return options; } - public void setOptions(String options) { + public void setOptions(String options) + { this.options = options; } - public String getTreeCode() { + public String getTreeCode() + { return treeCode; } - public void setTreeCode(String treeCode) { + public void setTreeCode(String treeCode) + { this.treeCode = treeCode; } - public String getTreeParentCode() { + public String getTreeParentCode() + { return treeParentCode; } - public void setTreeParentCode(String treeParentCode) { + public void setTreeParentCode(String treeParentCode) + { this.treeParentCode = treeParentCode; } - public String getTreeName() { + public String getTreeName() + { return treeName; } - public void setTreeName(String treeName) { + public void setTreeName(String treeName) + { this.treeName = treeName; } - public boolean isTree() { + public String getParentMenuId() + { + return parentMenuId; + } + + public void setParentMenuId(String parentMenuId) + { + this.parentMenuId = parentMenuId; + } + + public String getParentMenuName() + { + return parentMenuName; + } + + public void setParentMenuName(String parentMenuName) + { + this.parentMenuName = parentMenuName; + } + + public boolean isSub() + { + return isSub(this.tplCategory); + } + + public static boolean isSub(String tplCategory) + { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory); + } + + public boolean isTree() + { return isTree(this.tplCategory); } - public static boolean isTree(String tplCategory) { + public static boolean isTree(String tplCategory) + { return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory); } - public boolean isCrud() { + public boolean isCrud() + { return isCrud(this.tplCategory); } - public static boolean isCrud(String tplCategory) { + public static boolean isCrud(String tplCategory) + { return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); } - public boolean isSuperColumn(String javaField) { + public boolean isSuperColumn(String javaField) + { return isSuperColumn(this.tplCategory, javaField); } - public static boolean isSuperColumn(String tplCategory, String javaField) { - if (isTree(tplCategory)) { - StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.TREE_ENTITY); + public static boolean isSuperColumn(String tplCategory, String javaField) + { + if (isTree(tplCategory)) + { + return StringUtils.equalsAnyIgnoreCase(javaField, + ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY)); } return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); } - - public GenTable() { - } - - public GenTable(Long tableId) { - this.tableId = tableId; - } } \ No newline at end of file diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java index 6fb3f1ad0..f421da864 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java @@ -1,340 +1,373 @@ package com.ruoyi.generator.domain; +import javax.validation.constraints.NotBlank; import com.ruoyi.common.core.domain.BaseEntity; import com.ruoyi.common.utils.StringUtils; -import javax.persistence.*; -import javax.validation.constraints.NotBlank; - /** * 代码生成业务字段表 gen_table_column - * + * * @author ruoyi */ -@Entity -@Table(name = "gen_table_column") -public class GenTableColumn extends BaseEntity { +public class GenTableColumn extends BaseEntity +{ private static final long serialVersionUID = 1L; - /** - * 编号 - */ - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) + /** 编号 */ private Long columnId; - /** - * 列名称 - */ + /** 归属表编号 */ + private Long tableId; + + /** 列名称 */ private String columnName; - /** - * 列描述 - */ + /** 列描述 */ private String columnComment; - /** - * 列类型 - */ + /** 列类型 */ private String columnType; - /** - * JAVA类型 - */ + /** JAVA类型 */ private String javaType; - /** - * JAVA字段名 - */ + /** JAVA字段名 */ @NotBlank(message = "Java属性不能为空") private String javaField; - /** - * 是否主键(1是) - */ + /** 是否主键(1是) */ private String isPk; - /** - * 是否自增(1是) - */ + /** 是否自增(1是) */ private String isIncrement; - /** - * 是否必填(1是) - */ + /** 是否必填(1是) */ private String isRequired; - /** - * 是否为插入字段(1是) - */ + /** 是否为插入字段(1是) */ private String isInsert; - /** - * 是否编辑字段(1是) - */ + /** 是否编辑字段(1是) */ private String isEdit; - /** - * 是否列表字段(1是) - */ + /** 是否列表字段(1是) */ private String isList; - /** - * 是否查询字段(1是) - */ + /** 是否查询字段(1是) */ private String isQuery; - /** - * 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) - */ + /** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */ private String queryType; - /** - * 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件) - */ + /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、upload上传控件、summernote富文本控件) */ private String htmlType; - /** - * 字典类型 - */ + /** 字典类型 */ private String dictType; - /** - * 排序 - */ + /** 排序 */ private Integer sort; - public void setColumnId(Long columnId) { + public void setColumnId(Long columnId) + { this.columnId = columnId; } - public Long getColumnId() { + public Long getColumnId() + { return columnId; } - public void setColumnName(String columnName) { + public void setTableId(Long tableId) + { + this.tableId = tableId; + } + + public Long getTableId() + { + return tableId; + } + + public void setColumnName(String columnName) + { this.columnName = columnName; } - public String getColumnName() { + public String getColumnName() + { return columnName; } - public void setColumnComment(String columnComment) { + public void setColumnComment(String columnComment) + { this.columnComment = columnComment; } - public String getColumnComment() { + public String getColumnComment() + { return columnComment; } - public void setColumnType(String columnType) { + public void setColumnType(String columnType) + { this.columnType = columnType; } - public String getColumnType() { + public String getColumnType() + { return columnType; } - public void setJavaType(String javaType) { + public void setJavaType(String javaType) + { this.javaType = javaType; } - public String getJavaType() { + public String getJavaType() + { return javaType; } - public void setJavaField(String javaField) { + public void setJavaField(String javaField) + { this.javaField = javaField; } - public String getJavaField() { + public String getJavaField() + { return javaField; } - public void setIsPk(String isPk) { + public String getCapJavaField() + { + return StringUtils.capitalize(javaField); + } + + public void setIsPk(String isPk) + { this.isPk = isPk; } - public String getIsPk() { + public String getIsPk() + { return isPk; } - public boolean isPk() { + public boolean isPk() + { return isPk(this.isPk); } - public boolean isPk(String isPk) { + public boolean isPk(String isPk) + { return isPk != null && StringUtils.equals("1", isPk); } - public String getIsIncrement() { + public String getIsIncrement() + { return isIncrement; } - public void setIsIncrement(String isIncrement) { + public void setIsIncrement(String isIncrement) + { this.isIncrement = isIncrement; } - public boolean isIncrement() { + public boolean isIncrement() + { return isIncrement(this.isIncrement); } - public boolean isIncrement(String isIncrement) { + public boolean isIncrement(String isIncrement) + { return isIncrement != null && StringUtils.equals("1", isIncrement); } - public void setIsRequired(String isRequired) { + public void setIsRequired(String isRequired) + { this.isRequired = isRequired; } - public String getIsRequired() { + public String getIsRequired() + { return isRequired; } - public boolean isRequired() { + public boolean isRequired() + { return isRequired(this.isRequired); } - public boolean isRequired(String isRequired) { + public boolean isRequired(String isRequired) + { return isRequired != null && StringUtils.equals("1", isRequired); } - public void setIsInsert(String isInsert) { + public void setIsInsert(String isInsert) + { this.isInsert = isInsert; } - public String getIsInsert() { + public String getIsInsert() + { return isInsert; } - public boolean isInsert() { + public boolean isInsert() + { return isInsert(this.isInsert); } - public boolean isInsert(String isInsert) { + public boolean isInsert(String isInsert) + { return isInsert != null && StringUtils.equals("1", isInsert); } - public void setIsEdit(String isEdit) { + public void setIsEdit(String isEdit) + { this.isEdit = isEdit; } - public String getIsEdit() { + public String getIsEdit() + { return isEdit; } - public boolean isEdit() { + public boolean isEdit() + { return isInsert(this.isEdit); } - public boolean isEdit(String isEdit) { + public boolean isEdit(String isEdit) + { return isEdit != null && StringUtils.equals("1", isEdit); } - public void setIsList(String isList) { + public void setIsList(String isList) + { this.isList = isList; } - public String getIsList() { + public String getIsList() + { return isList; } - public boolean isList() { + public boolean isList() + { return isList(this.isList); } - public boolean isList(String isList) { + public boolean isList(String isList) + { return isList != null && StringUtils.equals("1", isList); } - public void setIsQuery(String isQuery) { + public void setIsQuery(String isQuery) + { this.isQuery = isQuery; } - public String getIsQuery() { + public String getIsQuery() + { return isQuery; } - public boolean isQuery() { + public boolean isQuery() + { return isQuery(this.isQuery); } - public boolean isQuery(String isQuery) { + public boolean isQuery(String isQuery) + { return isQuery != null && StringUtils.equals("1", isQuery); } - public void setQueryType(String queryType) { + public void setQueryType(String queryType) + { this.queryType = queryType; } - public String getQueryType() { + public String getQueryType() + { return queryType; } - public String getHtmlType() { + public String getHtmlType() + { return htmlType; } - public void setHtmlType(String htmlType) { + public void setHtmlType(String htmlType) + { this.htmlType = htmlType; } - public void setDictType(String dictType) { + public void setDictType(String dictType) + { this.dictType = dictType; } - public String getDictType() { + public String getDictType() + { return dictType; } - public void setSort(Integer sort) { + public void setSort(Integer sort) + { this.sort = sort; } - public Integer getSort() { + public Integer getSort() + { return sort; } - public boolean isSuperColumn() { + public boolean isSuperColumn() + { return isSuperColumn(this.javaField); } - public static boolean isSuperColumn(String javaField) { + public static boolean isSuperColumn(String javaField) + { return StringUtils.equalsAnyIgnoreCase(javaField, - //BaseEntity + // BaseEntity "createBy", "createTime", "updateBy", "updateTime", "remark", - //TreeEntity + // TreeEntity "parentName", "parentId", "orderNum", "ancestors"); } - public boolean isUsableColumn() { + public boolean isUsableColumn() + { return isUsableColumn(javaField); } - public static boolean isUsableColumn(String javaField) { - //isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 - return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum"); + public static boolean isUsableColumn(String javaField) + { + // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); } - public String readConverterExp() { + public String readConverterExp() + { String remarks = StringUtils.substringBetween(this.columnComment, "(", ")"); StringBuffer sb = new StringBuffer(); - if (StringUtils.isNotEmpty(remarks)) { - for (String value : remarks.split(" ")) { - if (StringUtils.isNotEmpty(value)) { + if (StringUtils.isNotEmpty(remarks)) + { + for (String value : remarks.split(" ")) + { + if (StringUtils.isNotEmpty(value)) + { Object startStr = value.subSequence(0, 1); String endStr = value.substring(1); sb.append("").append(startStr).append("=").append(endStr).append(","); } } return sb.deleteCharAt(sb.length() - 1).toString(); - } else { + } + else + { return this.columnComment; } } - - public String capital(){ - return StringUtils.capitalize(this.javaField); - } } \ No newline at end of file diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java new file mode 100644 index 000000000..0b7bdb5e8 --- /dev/null +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java @@ -0,0 +1,60 @@ +package com.ruoyi.generator.mapper; + +import java.util.List; +import com.ruoyi.generator.domain.GenTableColumn; + +/** + * 业务字段 数据层 + * + * @author ruoyi + */ +public interface GenTableColumnMapper +{ + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @return 列信息 + */ + public List selectDbTableColumnsByName(String tableName); + + /** + * 查询业务字段列表 + * + * @param genTableColumn 业务字段信息 + * @return 业务字段集合 + */ + public List selectGenTableColumnListByTableId(GenTableColumn genTableColumn); + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int insertGenTableColumn(GenTableColumn genTableColumn); + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int updateGenTableColumn(GenTableColumn genTableColumn); + + /** + * 删除业务字段 + * + * @param genTableColumns 列数据 + * @return 结果 + */ + public int deleteGenTableColumns(List genTableColumns); + + /** + * 批量删除业务字段 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableColumnByIds(Long[] ids); +} diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java new file mode 100644 index 000000000..2119f4b2a --- /dev/null +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java @@ -0,0 +1,83 @@ +package com.ruoyi.generator.mapper; + +import java.util.List; +import com.ruoyi.generator.domain.GenTable; + +/** + * 业务 数据层 + * + * @author ruoyi + */ +public interface GenTableMapper +{ + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List selectDbTableListByNames(String[] tableNames); + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List selectGenTableAll(); + + /** + * 查询表ID业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + public GenTable selectGenTableById(Long id); + + /** + * 查询表名称业务信息 + * + * @param tableName 表名称 + * @return 业务信息 + */ + public GenTable selectGenTableByName(String tableName); + + /** + * 新增业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public int insertGenTable(GenTable genTable); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public int updateGenTable(GenTable genTable); + + /** + * 批量删除业务 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableByIds(Long[] ids); +} \ No newline at end of file diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java index 57ed5bce5..50e75e88b 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java @@ -1,45 +1,50 @@ package com.ruoyi.generator.service; -import com.ruoyi.generator.domain.GenTable; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; - import java.util.List; import java.util.Map; +import com.ruoyi.generator.domain.GenTable; /** * 业务 服务层 - * + * * @author ruoyi */ -public interface IGenTableService { +public interface IGenTableService +{ /** * 查询业务列表 - * + * * @param genTable 业务信息 * @return 业务集合 */ - public Page selectGenTableList(GenTable genTable, Pageable pageable); + public List selectGenTableList(GenTable genTable); /** * 查询据库列表 - * + * * @param genTable 业务信息 * @return 数据库表集合 */ - public Page selectDbTableList(GenTable genTable, Pageable pageable); + public List selectDbTableList(GenTable genTable); /** * 查询据库列表 - * + * * @param tableNames 表名称组 * @return 数据库表集合 */ public List selectDbTableListByNames(String[] tableNames); + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List selectGenTableAll(); + /** * 查询业务信息 - * + * * @param id 业务ID * @return 业务信息 */ @@ -47,7 +52,7 @@ public interface IGenTableService { /** * 修改业务 - * + * * @param genTable 业务信息 * @return 结果 */ @@ -55,7 +60,7 @@ public interface IGenTableService { /** * 删除业务信息 - * + * * @param ids 需要删除的数据ID * @return 结果 */ @@ -63,39 +68,53 @@ public interface IGenTableService { /** * 导入表结构 - * + * * @param tableList 导入表列表 - * @param operName 操作人员 + * @param operName 操作人员 */ public void importGenTable(List tableList, String operName); /** * 预览代码 - * + * * @param tableId 表编号 * @return 预览数据列表 */ public Map previewCode(Long tableId); /** - * 生成代码 - * + * 生成代码(下载方式) + * * @param tableName 表名称 * @return 数据 */ - public byte[] generatorCode(String tableName); + public byte[] downloadCode(String tableName); /** - * 批量生成代码 - * + * 生成代码(自定义路径) + * + * @param tableName 表名称 + */ + public void generatorCode(String tableName); + + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + public void synchDb(String tableName); + + /** + * 批量生成代码(下载方式) + * * @param tableNames 表数组 * @return 数据 */ - public byte[] generatorCode(String[] tableNames); + public byte[] downloadCode(String[] tableNames); /** * 修改保存参数校验 - * + * * @param genTable 业务信息 */ public void validateEdit(GenTable genTable); diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/GenTableServiceImpl.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/GenTableServiceImpl.java index b59ce6643..7274cf065 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/GenTableServiceImpl.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/impl/GenTableServiceImpl.java @@ -1,24 +1,15 @@ package com.ruoyi.generator.service.impl; -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; -import com.querydsl.core.types.ExpressionUtils; -import com.querydsl.core.types.Predicate; -import com.ruoyi.common.base.BaseService; -import com.ruoyi.common.constant.Constants; -import com.ruoyi.common.constant.GenConstants; -import com.ruoyi.common.core.text.Convert; -import com.ruoyi.common.exception.BusinessException; -import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.generator.domain.GenTable; -import com.ruoyi.generator.domain.GenTableColumn; -import com.ruoyi.generator.domain.QGenTable; -import com.ruoyi.generator.repository.GenTableColumnRepository; -import com.ruoyi.generator.repository.GenTableRepository; -import com.ruoyi.generator.service.IGenTableService; -import com.ruoyi.generator.util.GenUtils; -import com.ruoyi.generator.util.VelocityInitializer; -import com.ruoyi.generator.util.VelocityUtils; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import org.apache.commons.io.IOUtils; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; @@ -26,213 +17,198 @@ import org.apache.velocity.app.Velocity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.jdbc.core.BeanPropertyRowMapper; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.GenConstants; +import com.ruoyi.common.core.text.CharsetKit; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.exception.BusinessException; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.file.FileUtils; +import com.ruoyi.generator.domain.GenTable; +import com.ruoyi.generator.domain.GenTableColumn; +import com.ruoyi.generator.mapper.GenTableColumnMapper; +import com.ruoyi.generator.mapper.GenTableMapper; +import com.ruoyi.generator.service.IGenTableService; +import com.ruoyi.generator.util.GenUtils; +import com.ruoyi.generator.util.VelocityInitializer; +import com.ruoyi.generator.util.VelocityUtils; /** * 业务 服务层实现 - * + * * @author ruoyi */ @Service -public class GenTableServiceImpl extends BaseService implements IGenTableService { - - private static final String QUARTZ_TABLE_PREFIX = "qrtz_"; - private static final String GEN_TABLE_PREFIX = "gen_"; +public class GenTableServiceImpl implements IGenTableService +{ private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class); @Autowired - private GenTableRepository genTableRepository; + private GenTableMapper genTableMapper; + @Autowired - private JdbcTemplate jdbcTemplate; - @Autowired - private GenTableColumnRepository genTableColumnRepository; + private GenTableColumnMapper genTableColumnMapper; /** * 查询业务信息 - * + * * @param id 业务ID * @return 业务信息 */ @Override - public GenTable selectGenTableById(Long id) { - GenTable genTable = genTableRepository.findById(id).get(); + public GenTable selectGenTableById(Long id) + { + GenTable genTable = genTableMapper.selectGenTableById(id); setTableFromOptions(genTable); return genTable; } /** * 查询业务列表 - * + * * @param genTable 业务信息 * @return 业务集合 */ @Override - public Page selectGenTableList(GenTable genTable, Pageable pageable) { - return genTableRepository.findAll(getPredicate(genTable), pageable); + public List selectGenTableList(GenTable genTable) + { + return genTableMapper.selectGenTableList(genTable); } /** * 查询据库列表 - * + * * @param genTable 业务信息 * @return 数据库表集合 */ - public Page selectDbTableList(GenTable genTable, Pageable pageable) { - String sql = " select table_name, table_comment, create_time, update_time from information_schema.tables " + - " where table_schema = (select database()) " + - " AND table_name NOT LIKE '"+QUARTZ_TABLE_PREFIX+"%' AND table_name NOT LIKE '"+GEN_TABLE_PREFIX+"%' " + - " AND table_name NOT IN (select table_name from gen_table) "; - if(StringUtils.isNotEmpty(genTable.getTableName())){ - sql += " AND lower(table_name) like lower(concat('%', " + genTable.getTableName()+ ", '%')) "; - } - if(StringUtils.isNotEmpty(genTable.getTableName())){ - sql += " AND lower(table_comment) like lower(concat('%', " + genTable.getTableComment() + ", '%'))"; - } - String countSql = "select count(0) from ( " + sql + " ) t"; - if(pageable.isPaged()){ - int page = pageable.getPageNumber(); - int size = pageable.getPageSize(); - int start = 0; - if(page > 0){ - start = page * size ; - } - sql += " limit " + start + "," + size; - } - List tables = jdbcTemplate.query(sql, new BeanPropertyRowMapper(GenTable.class)); - int count = jdbcTemplate.queryForObject(countSql, Integer.class); - return new PageImpl(tables, pageable, count); - } - - private Predicate getPredicate(GenTable genTable){ - QGenTable qGenTable = QGenTable.genTable; - List predicates = new ArrayList<>(); - predicates.add(notStartWith(qGenTable.tableName, QUARTZ_TABLE_PREFIX)); - predicates.add(notStartWith(qGenTable.tableName, GEN_TABLE_PREFIX)); - if(StringUtils.isNotEmpty(genTable.getTableName())){ - predicates.add(buildLike(qGenTable.tableName, genTable.getTableName())); - } - if(StringUtils.isNotEmpty(genTable.getTableComment())){ - predicates.add(buildLike(qGenTable.tableComment, genTable.getTableComment())); - } - return ExpressionUtils.allOf(predicates); + @Override + public List selectDbTableList(GenTable genTable) + { + return genTableMapper.selectDbTableList(genTable); } /** * 查询据库列表 - * + * * @param tableNames 表名称组 * @return 数据库表集合 */ - public List selectDbTableListByNames(String[] tableNames) { - String sql = "select table_name, table_comment, create_time, update_time from information_schema.tables " + - " where table_name NOT LIKE '"+QUARTZ_TABLE_PREFIX+"%' and table_name NOT LIKE '"+GEN_TABLE_PREFIX+"%' and table_schema = (select database()) " + - " and table_name in ("; - for(int i=0;i(GenTable.class)); + @Override + public List selectDbTableListByNames(String[] tableNames) + { + return genTableMapper.selectDbTableListByNames(tableNames); + } + + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + @Override + public List selectGenTableAll() + { + return genTableMapper.selectGenTableAll(); } /** * 修改业务 - * + * * @param genTable 业务信息 * @return 结果 */ @Override @Transactional - public void updateGenTable(GenTable genTable) { + public void updateGenTable(GenTable genTable) + { String options = JSON.toJSONString(genTable.getParams()); genTable.setOptions(options); - genTableRepository.save(genTable); - for (GenTableColumn cenTableColumn : genTable.getColumns()) { - genTableColumnRepository.save(cenTableColumn); + int row = genTableMapper.updateGenTable(genTable); + if (row > 0) + { + for (GenTableColumn cenTableColumn : genTable.getColumns()) + { + genTableColumnMapper.updateGenTableColumn(cenTableColumn); + } } } /** * 删除业务对象 - * + * * @param ids 需要删除的数据ID * @return 结果 */ @Override @Transactional - public void deleteGenTableByIds(String ids) { - for(Long id : Convert.toLongArray(ids)){ - genTableRepository.deleteById(id); - } + public void deleteGenTableByIds(String ids) + { + genTableMapper.deleteGenTableByIds(Convert.toLongArray(ids)); + genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids)); } /** * 导入表结构 - * + * * @param tableList 导入表列表 - * @param operName 操作人员 + * @param operName 操作人员 */ @Override @Transactional - public void importGenTable(List tableList, String operName) { - for (GenTable table : tableList) { - try { + public void importGenTable(List tableList, String operName) + { + try + { + for (GenTable table : tableList) + { + String tableName = table.getTableName(); GenUtils.initTable(table, operName); - List columns = new ArrayList<>(); - String sql = "select column_name, (case when (is_nullable = 'no' && column_key != 'PRI') then '1' else null end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type " + - " from information_schema.columns where table_schema = (select database()) and table_name = '" + table.getTableName() + "'" + - " order by ordinal_position"; - List genTableColumns = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(GenTableColumn.class)); - for (GenTableColumn column : genTableColumns) { - GenUtils.initColumnField(column, table); - columns.add(column); + int row = genTableMapper.insertGenTable(table); + if (row > 0) + { + // 保存列信息 + List genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + for (GenTableColumn column : genTableColumns) + { + GenUtils.initColumnField(column, table); + genTableColumnMapper.insertGenTableColumn(column); + } } - table.setColumns(columns); - genTableRepository.save(table); - } catch (Exception e) { - log.error("表名 " + table.getTableName() + " 导入失败:", e); } } + catch (Exception e) + { + throw new BusinessException("导入失败:" + e.getMessage()); + } } /** * 预览代码 - * + * * @param tableId 表编号 * @return 预览数据列表 */ - public Map previewCode(Long tableId) { + @Override + public Map previewCode(Long tableId) + { Map dataMap = new LinkedHashMap<>(); // 查询表信息 - GenTable table = genTableRepository.findById(tableId).get(); - // 查询列信息 - List columns = table.getColumns(); - setPkColumn(table, columns); + GenTable table = genTableMapper.selectGenTableById(tableId); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); VelocityInitializer.initVelocity(); VelocityContext context = VelocityUtils.prepareContext(table); // 获取模板列表 List templates = VelocityUtils.getTemplateList(table.getTplCategory()); - for (String template : templates) { + for (String template : templates) + { // 渲染模板 StringWriter sw = new StringWriter(); Template tpl = Velocity.getTemplate(template, Constants.UTF8); @@ -243,31 +219,112 @@ public class GenTableServiceImpl extends BaseService implements IGenTableService } /** - * 生成代码 - * + * 生成代码(下载方式) + * * @param tableName 表名称 * @return 数据 */ @Override - public byte[] generatorCode(String tableName) { + public byte[] downloadCode(String tableName) + { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(outputStream); generatorCode(tableName, zip); IOUtils.closeQuietly(zip); return outputStream.toByteArray(); } + + /** + * 生成代码(自定义路径) + * + * @param tableName 表名称 + */ + @Override + public void generatorCode(String tableName) + { + // 查询表信息 + GenTable table = genTableMapper.selectGenTableByName(tableName); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); + + VelocityInitializer.initVelocity(); + + VelocityContext context = VelocityUtils.prepareContext(table); + + // 获取模板列表 + List templates = VelocityUtils.getTemplateList(table.getTplCategory()); + for (String template : templates) + { + if (!StringUtils.contains(template, "sql.vm")) + { + // 渲染模板 + StringWriter sw = new StringWriter(); + Template tpl = Velocity.getTemplate(template, Constants.UTF8); + tpl.merge(context, sw); + try + { + String path = getGenPath(table, template); + FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8); + } + catch (IOException e) + { + throw new BusinessException("渲染模板失败,表名:" + table.getTableName()); + } + } + } + } + + /** + * 同步数据库 + * + * @param tableName 表名称 + */ + @Override + @Transactional + public void synchDb(String tableName) + { + GenTable table = genTableMapper.selectGenTableByName(tableName); + List tableColumns = table.getColumns(); + List tableColumnNames = tableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); + + List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + if (StringUtils.isEmpty(dbTableColumns)) + { + throw new BusinessException("同步数据失败,原表结构不存在"); + } + List dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList()); + + dbTableColumns.forEach(column -> { + if (!tableColumnNames.contains(column.getColumnName())) + { + GenUtils.initColumnField(column, table); + genTableColumnMapper.insertGenTableColumn(column); + } + }); + + List delColumns = tableColumns.stream() + .filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList()); + if (StringUtils.isNotEmpty(delColumns)) + { + genTableColumnMapper.deleteGenTableColumns(delColumns); + } + } /** * 批量生成代码 - * + * * @param tableNames 表数组 * @return 数据 */ @Override - public byte[] generatorCode(String[] tableNames) { + public byte[] downloadCode(String[] tableNames) + { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(outputStream); - for (String tableName : tableNames) { + for (String tableName : tableNames) + { generatorCode(tableName, zip); } IOUtils.closeQuietly(zip); @@ -277,12 +334,14 @@ public class GenTableServiceImpl extends BaseService implements IGenTableService /** * 查询表信息并生成代码 */ - private void generatorCode(String tableName, ZipOutputStream zip) { + private void generatorCode(String tableName, ZipOutputStream zip) + { // 查询表信息 - GenTable table = genTableRepository.findFirstByTableName(tableName); - // 查询列信息 - List columns = table.getColumns(); - setPkColumn(table, columns); + GenTable table = genTableMapper.selectGenTableByName(tableName); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); VelocityInitializer.initVelocity(); @@ -290,18 +349,23 @@ public class GenTableServiceImpl extends BaseService implements IGenTableService // 获取模板列表 List templates = VelocityUtils.getTemplateList(table.getTplCategory()); - for (String template : templates) { + for (String template : templates) + { // 渲染模板 StringWriter sw = new StringWriter(); Template tpl = Velocity.getTemplate(template, Constants.UTF8); tpl.merge(context, sw); - try { + try + { // 添加到zip zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table))); IOUtils.write(sw.toString(), zip, Constants.UTF8); IOUtils.closeQuietly(sw); + zip.flush(); zip.closeEntry(); - } catch (IOException e) { + } + catch (IOException e) + { log.error("渲染模板失败,表名:" + table.getTableName(), e); } } @@ -309,55 +373,130 @@ public class GenTableServiceImpl extends BaseService implements IGenTableService /** * 修改保存参数校验 - * + * * @param genTable 业务信息 */ - public void validateEdit(GenTable genTable) { - if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) { + @Override + public void validateEdit(GenTable genTable) + { + if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) + { String options = JSON.toJSONString(genTable.getParams()); JSONObject paramsObj = JSONObject.parseObject(options); - if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) { + if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) + { throw new BusinessException("树编码字段不能为空"); - } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) { + } + else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) + { throw new BusinessException("树父编码字段不能为空"); - } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) { + } + else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) + { throw new BusinessException("树名称字段不能为空"); } } + else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory())) + { + if (StringUtils.isEmpty(genTable.getSubTableName())) + { + throw new BusinessException("关联子表的表名不能为空"); + } + else if (StringUtils.isEmpty(genTable.getSubTableFkName())) + { + throw new BusinessException("子表关联的外键名不能为空"); + } + } } /** * 设置主键列信息 - * + * * @param table 业务表信息 - * @param columns 业务字段列表 */ - public void setPkColumn(GenTable table, List columns) { - for (GenTableColumn column : columns) { - if (column.isPk()) { + public void setPkColumn(GenTable table) + { + for (GenTableColumn column : table.getColumns()) + { + if (column.isPk()) + { table.setPkColumn(column); break; } } - if (StringUtils.isNull(table.getPkColumn())) { - table.setPkColumn(columns.get(0)); + if (StringUtils.isNull(table.getPkColumn())) + { + table.setPkColumn(table.getColumns().get(0)); + } + if (GenConstants.TPL_SUB.equals(table.getTplCategory())) + { + for (GenTableColumn column : table.getSubTable().getColumns()) + { + if (column.isPk()) + { + table.getSubTable().setPkColumn(column); + break; + } + } + if (StringUtils.isNull(table.getSubTable().getPkColumn())) + { + table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0)); + } + } + } + + /** + * 设置主子表信息 + * + * @param table 业务表信息 + */ + public void setSubTable(GenTable table) + { + String subTableName = table.getSubTableName(); + if (StringUtils.isNotEmpty(subTableName)) + { + table.setSubTable(genTableMapper.selectGenTableByName(subTableName)); } } /** * 设置代码生成其他选项值 - * + * * @param genTable 设置后的生成对象 */ - public void setTableFromOptions(GenTable genTable) { + public void setTableFromOptions(GenTable genTable) + { JSONObject paramsObj = JSONObject.parseObject(genTable.getOptions()); - if (StringUtils.isNotNull(paramsObj)) { + if (StringUtils.isNotNull(paramsObj)) + { String treeCode = paramsObj.getString(GenConstants.TREE_CODE); String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE); String treeName = paramsObj.getString(GenConstants.TREE_NAME); + String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID); + String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME); + genTable.setTreeCode(treeCode); genTable.setTreeParentCode(treeParentCode); genTable.setTreeName(treeName); + genTable.setParentMenuId(parentMenuId); + genTable.setParentMenuName(parentMenuName); } } + + /** + * 获取代码生成地址 + * + * @param table 业务表信息 + * @param template 模板文件路径 + * @return 生成地址 + */ + public static String getGenPath(GenTable table, String template) + { + String genPath = table.getGenPath(); + if (StringUtils.equals(genPath, "/")) + { + return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table); + } + return genPath + File.separator + VelocityUtils.getFileName(template, table); + } } \ No newline at end of file diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java index 192a50415..baf461755 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java @@ -1,24 +1,25 @@ package com.ruoyi.generator.util; +import java.util.Arrays; +import org.apache.commons.lang3.RegExUtils; import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.generator.config.GenConfig; import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTableColumn; -import org.apache.commons.lang3.RegExUtils; - -import java.util.Arrays; /** * 代码生成器 工具类 - * + * * @author ruoyi */ -public class GenUtils { +public class GenUtils +{ /** * 初始化表信息 */ - public static void initTable(GenTable genTable, String operName) { + public static void initTable(GenTable genTable, String operName) + { genTable.setClassName(convertClassName(genTable.getTableName())); genTable.setPackageName(GenConfig.getPackageName()); genTable.setModuleName(getModuleName(GenConfig.getPackageName())); @@ -31,36 +32,46 @@ public class GenUtils { /** * 初始化列属性字段 */ - public static void initColumnField(GenTableColumn column, GenTable table) { + public static void initColumnField(GenTableColumn column, GenTable table) + { String dataType = getDbType(column.getColumnType()); String columnName = column.getColumnName(); + column.setTableId(table.getTableId()); column.setCreateBy(table.getCreateBy()); // 设置java字段名 column.setJavaField(StringUtils.toCamelCase(columnName)); - if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType)) { + if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType)) + { column.setJavaType(GenConstants.TYPE_STRING); // 字符串长度超过500设置为文本域 Integer columnLength = getColumnLength(column.getColumnType()); String htmlType = columnLength >= 500 ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT; column.setHtmlType(htmlType); - } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) { + } + else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) + { column.setJavaType(GenConstants.TYPE_DATE); column.setHtmlType(GenConstants.HTML_DATETIME); - } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) { + } + else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) + { column.setHtmlType(GenConstants.HTML_INPUT); // 如果是浮点型 String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ","); - if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) { - column.setJavaType(GenConstants.TYPE_DOUBLE); + if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) + { + column.setJavaType(GenConstants.TYPE_BIGDECIMAL); } // 如果是整形 - else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) { + else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) + { column.setJavaType(GenConstants.TYPE_INTEGER); } // 长整形 - else { + else + { column.setJavaType(GenConstants.TYPE_LONG); } } @@ -69,51 +80,69 @@ public class GenUtils { column.setIsInsert(GenConstants.REQUIRE); // 编辑字段 - if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk()) { + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk()) + { column.setIsEdit(GenConstants.REQUIRE); } // 列表字段 - if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk()) { + if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk()) + { column.setIsList(GenConstants.REQUIRE); } // 查询字段 - if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) { + if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) + { column.setIsQuery(GenConstants.REQUIRE); } // 查询字段类型 - if (StringUtils.endsWithIgnoreCase(columnName, "name")) { + if (StringUtils.endsWithIgnoreCase(columnName, "name")) + { column.setQueryType(GenConstants.QUERY_LIKE); } // 状态字段设置单选框 - if (StringUtils.endsWithIgnoreCase(columnName, "status")) { + if (StringUtils.endsWithIgnoreCase(columnName, "status")) + { column.setHtmlType(GenConstants.HTML_RADIO); } // 类型&性别字段设置下拉框 else if (StringUtils.endsWithIgnoreCase(columnName, "type") - || StringUtils.endsWithIgnoreCase(columnName, "sex")) { + || StringUtils.endsWithIgnoreCase(columnName, "sex")) + { column.setHtmlType(GenConstants.HTML_SELECT); } + // 文件字段设置上传控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "file")) + { + column.setHtmlType(GenConstants.HTML_UPLOAD); + } + // 内容字段设置富文本控件 + else if (StringUtils.endsWithIgnoreCase(columnName, "content")) + { + column.setHtmlType(GenConstants.HTML_SUMMERNOTE); + } } /** * 校验数组是否包含指定值 - * - * @param arr 数组 + * + * @param arr 数组 * @param targetValue 值 * @return 是否包含 */ - public static boolean arraysContains(String[] arr, String targetValue) { + public static boolean arraysContains(String[] arr, String targetValue) + { return Arrays.asList(arr).contains(targetValue); } /** * 获取模块名 - * + * * @param packageName 包名 * @return 模块名 */ - public static String getModuleName(String packageName) { + public static String getModuleName(String packageName) + { int lastIndex = packageName.lastIndexOf("."); int nameLength = packageName.length(); String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength); @@ -122,11 +151,12 @@ public class GenUtils { /** * 获取业务名 - * + * * @param tableName 表名 * @return 业务名 */ - public static String getBusinessName(String tableName) { + public static String getBusinessName(String tableName) + { int lastIndex = tableName.lastIndexOf("_"); int nameLength = tableName.length(); String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength); @@ -135,69 +165,102 @@ public class GenUtils { /** * 表名转换成Java类名 - * + * * @param tableName 表名称 * @return 类名 */ - public static String convertClassName(String tableName) { + public static String convertClassName(String tableName) + { boolean autoRemovePre = GenConfig.getAutoRemovePre(); String tablePrefix = GenConfig.getTablePrefix(); - if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) { + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) + { String[] searchList = StringUtils.split(tablePrefix, ","); - String[] replacementList = emptyList(searchList.length); - tableName = StringUtils.replaceEach(tableName, searchList, replacementList); + tableName = replaceFirst(tableName, searchList); } return StringUtils.convertToCamelCase(tableName); } + /** + * 批量替换前缀 + * + * @param replacementm 替换值 + * @param searchList 替换列表 + * @return + */ + public static String replaceFirst(String replacementm, String[] searchList) + { + String text = replacementm; + for (String searchString : searchList) + { + if (replacementm.startsWith(searchString)) + { + text = replacementm.replaceFirst(searchString, ""); + break; + } + } + return text; + } + /** * 关键字替换 - * + * * @param text 需要被替换的名字 * @return 替换后的名字 */ - public static String replaceText(String text) { + public static String replaceText(String text) + { return RegExUtils.replaceAll(text, "(?:表|若依)", ""); } /** * 获取数据库类型字段 - * + * * @param columnType 列类型 * @return 截取后的列类型 */ - public static String getDbType(String columnType) { - if (StringUtils.indexOf(columnType, "(") > 0) { + public static String getDbType(String columnType) + { + if (StringUtils.indexOf(columnType, "(") > 0) + { return StringUtils.substringBefore(columnType, "("); - } else { + } + else + { return columnType; } } /** * 获取字段长度 - * + * * @param columnType 列类型 * @return 截取后的列类型 */ - public static Integer getColumnLength(String columnType) { - if (StringUtils.indexOf(columnType, "(") > 0) { + public static Integer getColumnLength(String columnType) + { + if (StringUtils.indexOf(columnType, "(") > 0) + { String length = StringUtils.substringBetween(columnType, "(", ")"); return Integer.valueOf(length); - } else { + } + else + { return 0; } } /** * 获取空数组列表 - * + * * @param length 长度 * @return 数组信息 */ - public static String[] emptyList(int length) { + public static String[] emptyList(int length) + { String[] values = new String[length]; - for (int i = 0; i < length; i++) { + for (int i = 0; i < length; i++) + { values[i] = StringUtils.EMPTY; } return values; diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java index 01cbe6dde..798768110 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java @@ -1,5 +1,9 @@ package com.ruoyi.generator.util; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import org.apache.velocity.VelocityContext; import com.alibaba.fastjson.JSONObject; import com.ruoyi.common.constant.GenConstants; import com.ruoyi.common.utils.DateUtils; @@ -7,34 +11,28 @@ import com.ruoyi.common.utils.StringUtils; import com.ruoyi.generator.config.GenConfig; import com.ruoyi.generator.domain.GenTable; import com.ruoyi.generator.domain.GenTableColumn; -import org.apache.velocity.VelocityContext; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -public class VelocityUtils { - /** - * 项目空间路径 - */ +public class VelocityUtils +{ + /** 项目空间路径 */ private static final String PROJECT_PATH = "main/java"; - /** - * mybatis空间路径 - */ + /** mybatis空间路径 */ private static final String MYBATIS_PATH = "main/resources/mapper"; - /** - * html空间路径 - */ + /** html空间路径 */ private static final String TEMPLATES_PATH = "main/resources/templates"; + + /** 默认上级菜单,系统工具 */ + private static final String DEFAULT_PARENT_MENU_ID = "3"; /** * 设置模板变量信息 - * + * * @return 模板列表 */ - public static VelocityContext prepareContext(GenTable genTable) { + public static VelocityContext prepareContext(GenTable genTable) + { String moduleName = genTable.getModuleName(); String businessName = genTable.getBusinessName(); String packageName = genTable.getPackageName(); @@ -47,7 +45,6 @@ public class VelocityUtils { velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); velocityContext.put("ClassName", genTable.getClassName()); velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); - velocityContext.put("classname", StringUtils.uncapitalize(genTable.getClassName())); velocityContext.put("moduleName", genTable.getModuleName()); velocityContext.put("businessName", genTable.getBusinessName()); velocityContext.put("basePackage", getPackagePrefix(packageName)); @@ -55,18 +52,32 @@ public class VelocityUtils { velocityContext.put("author", genTable.getFunctionAuthor()); velocityContext.put("datetime", DateUtils.getDate()); velocityContext.put("pkColumn", genTable.getPkColumn()); - velocityContext.put("primaryKeyType", genTable.getPkColumn().getJavaType()); - velocityContext.put("importList", getImportList(genTable.getColumns())); + velocityContext.put("importList", getImportList(genTable)); velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); velocityContext.put("columns", genTable.getColumns()); velocityContext.put("table", genTable); - if (GenConstants.TPL_TREE.equals(tplCategory)) { + setMenuVelocityContext(velocityContext, genTable); + if (GenConstants.TPL_TREE.equals(tplCategory)) + { setTreeVelocityContext(velocityContext, genTable); } + if (GenConstants.TPL_SUB.equals(tplCategory)) + { + setSubVelocityContext(velocityContext, genTable); + } return velocityContext; } - public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) { + public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSONObject.parseObject(options); + String parentMenuId = getParentMenuId(paramsObj); + context.put("parentMenuId", parentMenuId); + } + + public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) + { String options = genTable.getOptions(); JSONObject paramsObj = JSONObject.parseObject(options); String treeCode = getTreecode(paramsObj); @@ -77,32 +88,62 @@ public class VelocityUtils { context.put("treeParentCode", treeParentCode); context.put("treeName", treeName); context.put("expandColumn", getExpandColumn(genTable)); - if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + { context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE)); } - if (paramsObj.containsKey(GenConstants.TREE_NAME)) { + if (paramsObj.containsKey(GenConstants.TREE_NAME)) + { context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME)); } } + public static void setSubVelocityContext(VelocityContext context, GenTable genTable) + { + GenTable subTable = genTable.getSubTable(); + String subTableName = genTable.getSubTableName(); + String subTableFkName = genTable.getSubTableFkName(); + String subClassName = genTable.getSubTable().getClassName(); + String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName); + + context.put("subTable", subTable); + context.put("subTableName", subTableName); + context.put("subTableFkName", subTableFkName); + context.put("subTableFkClassName", subTableFkClassName); + context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName)); + context.put("subClassName", subClassName); + context.put("subclassName", StringUtils.uncapitalize(subClassName)); + context.put("subImportList", getImportList(genTable.getSubTable())); + } + /** * 获取模板信息 - * + * * @return 模板列表 */ - public static List getTemplateList(String tplCategory) { + public static List getTemplateList(String tplCategory) + { List templates = new ArrayList(); templates.add("vm/java/domain.java.vm"); - templates.add("vm/java/repository.java.vm"); + templates.add("vm/java/mapper.java.vm"); templates.add("vm/java/service.java.vm"); + templates.add("vm/java/serviceImpl.java.vm"); templates.add("vm/java/controller.java.vm"); templates.add("vm/xml/mapper.xml.vm"); - if (GenConstants.TPL_CRUD.equals(tplCategory)) { + if (GenConstants.TPL_CRUD.equals(tplCategory)) + { templates.add("vm/html/list.html.vm"); - } else if (GenConstants.TPL_TREE.equals(tplCategory)) { + } + else if (GenConstants.TPL_TREE.equals(tplCategory)) + { templates.add("vm/html/tree.html.vm"); templates.add("vm/html/list-tree.html.vm"); } + else if (GenConstants.TPL_SUB.equals(tplCategory)) + { + templates.add("vm/html/list.html.vm"); + templates.add("vm/java/sub-domain.java.vm"); + } templates.add("vm/html/add.html.vm"); templates.add("vm/html/edit.html.vm"); templates.add("vm/sql/sql.vm"); @@ -112,7 +153,8 @@ public class VelocityUtils { /** * 获取文件名 */ - public static String getFileName(String template, GenTable genTable) { + public static String getFileName(String template, GenTable genTable) + { // 文件名称 String fileName = ""; // 包路径 @@ -128,31 +170,56 @@ public class VelocityUtils { String mybatisPath = MYBATIS_PATH + "/" + moduleName; String htmlPath = TEMPLATES_PATH + "/" + moduleName + "/" + businessName; - if (template.contains("domain.java.vm")) { - fileName = StringUtils.format("{}/entity/{}.java", javaPath, className); - } else if (template.contains("mapper.java.vm")) { + if (template.contains("domain.java.vm")) + { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, className); + } + if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory())) + { + fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName()); + } + else if (template.contains("mapper.java.vm")) + { fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className); - } else if (template.contains("repository.java.vm")) { - fileName = StringUtils.format("{}/repository/{}Repository.java", javaPath, className); - } else if (template.contains("service.java.vm")) { - fileName = StringUtils.format("{}/service/{}Service.java", javaPath, className); - } else if (template.contains("serviceImpl.java.vm")) { + } + else if (template.contains("service.java.vm")) + { + fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className); + } + else if (template.contains("serviceImpl.java.vm")) + { fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className); - } else if (template.contains("controller.java.vm")) { + } + else if (template.contains("controller.java.vm")) + { fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className); - } else if (template.contains("mapper.xml.vm")) { + } + else if (template.contains("mapper.xml.vm")) + { fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); - } else if (template.contains("list.html.vm")) { + } + else if (template.contains("list.html.vm")) + { fileName = StringUtils.format("{}/{}.html", htmlPath, businessName); - } else if (template.contains("list-tree.html.vm")) { + } + else if (template.contains("list-tree.html.vm")) + { fileName = StringUtils.format("{}/{}.html", htmlPath, businessName); - } else if (template.contains("tree.html.vm")) { + } + else if (template.contains("tree.html.vm")) + { fileName = StringUtils.format("{}/tree.html", htmlPath); - } else if (template.contains("add.html.vm")) { + } + else if (template.contains("add.html.vm")) + { fileName = StringUtils.format("{}/add.html", htmlPath); - } else if (template.contains("edit.html.vm")) { + } + else if (template.contains("edit.html.vm")) + { fileName = StringUtils.format("{}/edit.html", htmlPath); - } else if (template.contains("sql.vm")) { + } + else if (template.contains("sql.vm")) + { fileName = businessName + "Menu.sql"; } return fileName; @@ -160,10 +227,11 @@ public class VelocityUtils { /** * 获取项目文件路径 - * + * * @return 路径 */ - public static String getProjectPath() { + public static String getProjectPath() + { String packageName = GenConfig.getPackageName(); StringBuffer projectPath = new StringBuffer(); projectPath.append("main/java/"); @@ -174,11 +242,12 @@ public class VelocityUtils { /** * 获取包前缀 - * + * * @param packageName 包名称 * @return 包前缀名称 */ - public static String getPackagePrefix(String packageName) { + public static String getPackagePrefix(String packageName) + { int lastIndex = packageName.lastIndexOf("."); String basePackage = StringUtils.substring(packageName, 0, lastIndex); return basePackage; @@ -186,16 +255,27 @@ public class VelocityUtils { /** * 根据列类型获取导入包 - * - * @param column 列集合 + * + * @param genTable 业务表对象 * @return 返回需要导入的包列表 */ - public static HashSet getImportList(List columns) { + public static HashSet getImportList(GenTable genTable) + { + List columns = genTable.getColumns(); + GenTable subGenTable = genTable.getSubTable(); HashSet importList = new HashSet(); - for (GenTableColumn column : columns) { - if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) { + if (StringUtils.isNotNull(subGenTable)) + { + importList.add("java.util.List"); + } + for (GenTableColumn column : columns) + { + if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) + { importList.add("java.util.Date"); - } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) { + } + else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) + { importList.add("java.math.BigDecimal"); } } @@ -204,71 +284,96 @@ public class VelocityUtils { /** * 获取权限前缀 - * - * @param moduleName 模块名称 + * + * @param moduleName 模块名称 * @param businessName 业务名称 * @return 返回权限前缀 */ - public static String getPermissionPrefix(String moduleName, String businessName) { + public static String getPermissionPrefix(String moduleName, String businessName) + { return StringUtils.format("{}:{}", moduleName, businessName); + } + /** + * 获取上级菜单ID字段 + * + * @param options 生成其他选项 + * @return 上级菜单ID字段 + */ + public static String getParentMenuId(JSONObject paramsObj) + { + if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)) + { + return paramsObj.getString(GenConstants.PARENT_MENU_ID); + } + return DEFAULT_PARENT_MENU_ID; } /** * 获取树编码 - * + * * @param options 生成其他选项 * @return 树编码 */ - public static String getTreecode(JSONObject paramsObj) { - if (paramsObj.containsKey(GenConstants.TREE_CODE)) { + public static String getTreecode(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_CODE)) + { return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE)); } - return ""; + return StringUtils.EMPTY; } /** * 获取树父编码 - * + * * @param options 生成其他选项 * @return 树父编码 */ - public static String getTreeParentCode(JSONObject paramsObj) { - if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) { + public static String getTreeParentCode(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + { return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE)); } - return ""; + return StringUtils.EMPTY; } /** * 获取树名称 - * + * * @param options 生成其他选项 * @return 树名称 */ - public static String getTreeName(JSONObject paramsObj) { - if (paramsObj.containsKey(GenConstants.TREE_NAME)) { + public static String getTreeName(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_NAME)) + { return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME)); } - return ""; + return StringUtils.EMPTY; } /** * 获取需要在哪一列上面显示展开按钮 - * + * * @param genTable 业务表对象 * @return 展开按钮列序号 */ - public static int getExpandColumn(GenTable genTable) { + public static int getExpandColumn(GenTable genTable) + { String options = genTable.getOptions(); JSONObject paramsObj = JSONObject.parseObject(options); String treeName = paramsObj.getString(GenConstants.TREE_NAME); int num = 0; - for (GenTableColumn column : genTable.getColumns()) { - if (column.isList()) { + for (GenTableColumn column : genTable.getColumns()) + { + if (column.isList()) + { num++; String columnName = column.getColumnName(); - if (columnName.equals(treeName)) { + if (columnName.equals(treeName)) + { break; } } diff --git a/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml new file mode 100644 index 000000000..86f62deda --- /dev/null +++ b/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_by, create_time, update_by, update_time from gen_table_column + + + + + + + + insert into gen_table_column ( + table_id, + column_name, + column_comment, + column_type, + java_type, + java_field, + is_pk, + is_increment, + is_required, + is_insert, + is_edit, + is_list, + is_query, + query_type, + html_type, + dict_type, + sort, + create_by, + create_time + )values( + #{tableId}, + #{columnName}, + #{columnComment}, + #{columnType}, + #{javaType}, + #{javaField}, + #{isPk}, + #{isIncrement}, + #{isRequired}, + #{isInsert}, + #{isEdit}, + #{isList}, + #{isQuery}, + #{queryType}, + #{htmlType}, + #{dictType}, + #{sort}, + #{createBy}, + sysdate() + ) + + + + update gen_table_column + + column_comment = #{columnComment}, + java_type = #{javaType}, + java_field = #{javaField}, + is_insert = #{isInsert}, + is_edit = #{isEdit}, + is_list = #{isList}, + is_query = #{isQuery}, + is_required = #{isRequired}, + query_type = #{queryType}, + html_type = #{htmlType}, + dict_type = #{dictType}, + sort = #{sort}, + update_by = #{updateBy}, + update_time = sysdate() + + where column_id = #{columnId} + + + + delete from gen_table_column where table_id in + + #{tableId} + + + + + delete from gen_table_column where column_id in + + #{item.columnId} + + + + \ No newline at end of file diff --git a/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml new file mode 100644 index 000000000..934210c2d --- /dev/null +++ b/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table + + + + + + + + + + + + + + + + + + insert into gen_table ( + table_name, + table_comment, + class_name, + tpl_category, + package_name, + module_name, + business_name, + function_name, + function_author, + gen_type, + gen_path, + remark, + create_by, + create_time + )values( + #{tableName}, + #{tableComment}, + #{className}, + #{tplCategory}, + #{packageName}, + #{moduleName}, + #{businessName}, + #{functionName}, + #{functionAuthor}, + #{genType}, + #{genPath}, + #{remark}, + #{createBy}, + sysdate() + ) + + + + update gen_table + + table_name = #{tableName}, + table_comment = #{tableComment}, + sub_table_name = #{subTableName}, + sub_table_fk_name = #{subTableFkName}, + class_name = #{className}, + function_author = #{functionAuthor}, + gen_type = #{genType}, + gen_path = #{genPath}, + tpl_category = #{tplCategory}, + package_name = #{packageName}, + module_name = #{moduleName}, + business_name = #{businessName}, + function_name = #{functionName}, + options = #{options}, + update_by = #{updateBy}, + remark = #{remark}, + update_time = sysdate() + + where table_id = #{tableId} + + + + delete from gen_table where table_id in + + #{tableId} + + + + \ No newline at end of file diff --git a/ruoyi-generator/src/main/resources/templates/tool/gen/edit.html b/ruoyi-generator/src/main/resources/templates/tool/gen/edit.html index cde416e9f..d64973396 100644 --- a/ruoyi-generator/src/main/resources/templates/tool/gen/edit.html +++ b/ruoyi-generator/src/main/resources/templates/tool/gen/edit.html @@ -30,7 +30,7 @@

    - +
    @@ -38,7 +38,7 @@
    - +
    @@ -48,7 +48,7 @@
    - +
    @@ -56,7 +56,7 @@
    - +
    @@ -87,18 +87,19 @@
    - +
    - +
    @@ -108,7 +109,7 @@
    - +
    @@ -116,7 +117,7 @@
    - +
    @@ -126,19 +127,85 @@
    - +
    +
    +
    + +
    + +
    + + +
    +
    +
    +
    +
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + +