diff --git a/README.md b/README.md index 2e28de74d..f037c0003 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,14 @@ 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适的。于是利用空闲休息时间开始自己写了一套后台系统。如此有了若依。她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。 -性别男,若依是给还没有出生女儿取的名字(寓意:你若不离不弃,我必生死相依) +性别男,若依是给女儿取的名字(寓意:你若不离不弃,我必生死相依) -若依参考后台模板。有需要可自行到群内下载。 +若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 -> 如需单应用,请移步 [RuoYi-fast](https://gitee.com/y_project/RuoYi-fast) `(保持同步更新)`,如需其他版本,请移步 [项目扩展](http://doc.ruoyi.vip/#/standard/xmkz) `(不定时更新)` - -> 阿里云通用云产品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)  `(仅限新用户)` +* 前后端分离版本,请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud) +* 感谢 [hplus](https://gitee.com/hplus_admin/hplus) 后台主题 UI 框架。 +* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)   +* 阿里云优惠券:[点我领取](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)   ## 内置功能 @@ -26,65 +25,66 @@ 10. 登录日志:系统登录日志记录查询包含登录异常。 11. 在线用户:当前系统中活跃用户状态监控。 12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 -13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 +13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 14. 系统接口:根据业务代码自动生成相关的api接口文档。 15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。 16. 在线构建器:拖动表单元素生成相应的HTML代码。 17. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。 + ## 在线体验 -> admin/admin123 -> 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。 + +- admin/admin123 +- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。 演示地址:http://ruoyi.vip - 文档地址:http://doc.ruoyi.vip ## 演示图 - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + +
## 若依交流群 -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) 点击按钮入群。 \ 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 b13b00693..aa0f76a7f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,39 +1,38 @@ - - 4.0.0 - + + 4.0.0 + com.ruoyi ruoyi - 4.0.0 + 4.5.1 ruoyi - http://www.ruoyi.vip + http://www.ruoyi.vip 若依管理系统 - 4.0.0 - UTF-8 - UTF-8 - 1.8 - 1.4.0 - 2.0.0 - 1.3.2 - 1.1.14 - 1.19 - 2.3.2 - 2.9.2 - 1.2.5 - 1.2.47 - 3.9.1 - 2.5 - 1.3.3 - 1.11.3 - 3.17 - 1.7 - - + 4.5.1 + UTF-8 + UTF-8 + 1.8 + 3.1.1 + 1.7.0 + 2.0.0 + 1.2.2 + 1.21 + 2.3.2 + 2.9.2 + 1.3.0 + 1.2.74 + 5.3.6 + 5.6.0 + 2.5 + 1.3.3 + 4.1.2 + 1.7 + + @@ -42,200 +41,204 @@ org.springframework.boot spring-boot-dependencies - 2.1.1.RELEASE + 2.2.12.RELEASE pom import - - 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} + + + + net.java.dev.jna + jna + ${jna.version} + + + + net.java.dev.jna + jna-platform + ${jna.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.jsoup - jsoup - ${jsoup.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 - + - + - - - + org.apache.maven.plugins maven-compiler-plugin + 3.1 ${java.version} ${java.version} @@ -245,29 +248,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 87311e4f8..07c5adde2 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -5,18 +5,18 @@ ruoyi com.ruoyi - 4.0.0 + 4.5.1 4.0.0 - jar + jar ruoyi-admin - - - web服务入口 - + + + web服务入口 + - + org.springframework.boot @@ -24,55 +24,61 @@ - - 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 - + com.ruoyi ruoyi-quartz - + com.ruoyi ruoyi-generator - + @@ -80,9 +86,10 @@ org.springframework.boot spring-boot-maven-plugin + 2.1.1.RELEASE - true - + true + @@ -97,11 +104,11 @@ 3.0.0 false - ${artifactId} + ${project.artifactId} - + - ${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 fa80f5f10..a84897def 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 @@ -5,13 +5,15 @@ 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; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; -import com.ruoyi.common.config.Global; +import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.config.ServerConfig; +import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.file.FileUploadUtils; @@ -41,17 +43,15 @@ public class CommonController { try { - if (!FileUtils.isValidFilename(fileName)) + if (!FileUtils.checkAllowDownload(fileName)) { throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); } String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); - String filePath = Global.getDownloadPath() + fileName; + String filePath = RuoYiConfig.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) { @@ -74,7 +74,7 @@ public class CommonController try { // 上传文件路径 - String filePath = Global.getUploadPath(); + String filePath = RuoYiConfig.getUploadPath(); // 上传并返回新文件名称 String fileName = FileUploadUtils.upload(filePath, file); String url = serverConfig.getUrl() + fileName; @@ -88,4 +88,33 @@ public class CommonController return AjaxResult.error(e.getMessage()); } } + + /** + * 本地资源通用下载 + */ + @GetMapping("/common/download/resource") + public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) + throws Exception + { + try + { + if (!FileUtils.checkAllowDownload(resource)) + { + throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource)); + } + // 本地资源路径 + String localPath = RuoYiConfig.getProfile(); + // 数据库资源地址 + String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX); + // 下载名称 + String downloadName = StringUtils.substringAfterLast(downloadPath, "/"); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + FileUtils.setAttachmentResponseHeader(response, downloadName); + FileUtils.writeBytes(downloadPath, response.getOutputStream()); + } + catch (Exception e) + { + log.error("下载文件失败", e); + } + } } 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 fb43aa73f..e523dd6fc 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 @@ -3,10 +3,17 @@ 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; /** * 表单相关 @@ -46,6 +53,15 @@ public class DemoFormController return prefix + "/select"; } + /** + * 时间轴 + */ + @GetMapping("/timeline") + public String timeline() + { + return prefix + "/timeline"; + } + /** * 表单校验 */ @@ -73,6 +89,24 @@ public class DemoFormController return prefix + "/sortable"; } + /** + * 单据打印 + */ + @GetMapping("/invoice") + public String invoice() + { + return prefix + "/invoice"; + } + + /** + * 标签 & 提示 + */ + @GetMapping("/labels_tips") + public String labels_tips() + { + return prefix + "/labels_tips"; + } + /** * 选项卡 & 面板 */ @@ -163,6 +197,101 @@ public class DemoFormController 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; + } + /** * 获取用户数据 */ 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 8c35b23eb..c7544a325 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 @@ -21,6 +21,7 @@ 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; /** @@ -103,6 +104,17 @@ public class DemoOperateController extends BaseController } } } + else if (StringUtils.isNotEmpty(userModel.getUserName())) + { + userList.clear(); + 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()) { @@ -142,6 +154,17 @@ public class DemoOperateController extends BaseController return AjaxResult.success(users.put(userId, user)); } + /** + * 新增保存主子表信息 + */ + @PostMapping("/customer/add") + @ResponseBody + public AjaxResult addSave(CustomerModel customerModel) + { + System.out.println(customerModel.toString()); + return AjaxResult.success(); + } + /** * 修改用户 */ 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 a698896a9..0af6a8d40 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 @@ -6,6 +6,7 @@ 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; @@ -140,6 +141,16 @@ public class DemoTableController extends BaseController return prefix + "/button"; } + /** + * 直接加载表格数据 + */ + @GetMapping("/data") + public String data(ModelMap mmap) + { + mmap.put("users", users); + return prefix + "/data"; + } + /** * 表格冻结列 */ @@ -167,6 +178,15 @@ public class DemoTableController extends BaseController return prefix + "/detail"; } + /** + * 表格父子视图 + */ + @GetMapping("/child") + public String child() + { + return prefix + "/child"; + } + /** * 表格图片预览 */ @@ -194,6 +214,60 @@ public class DemoTableController extends BaseController return prefix + "/reorder"; } + /** + * 表格列宽拖动 + */ + @GetMapping("/resizable") + public String resizable() + { + return prefix + "/resizable"; + } + + /** + * 表格行内编辑操作 + */ + @GetMapping("/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"; + } + /** * 表格其他操作 */ 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 ac95abf2f..3324cc7ca 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 @@ -135,11 +135,13 @@ public class UserOperateModel extends BaseEntity this.status = status; } + @Override public Date getCreateTime() { return createTime; } + @Override public void setCreateTime(Date createTime) { this.createTime = createTime; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java new file mode 100644 index 000000000..1ba897cf1 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java @@ -0,0 +1,82 @@ +package com.ruoyi.web.controller.monitor; + +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.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +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.web.service.CacheService; + +/** + * 缓存监控 + * + * @author ruoyi + */ +@Controller +@RequestMapping("/monitor/cache") +public class CacheController extends BaseController +{ + private String prefix = "monitor/cache"; + + @Autowired + private CacheService cacheService; + + @GetMapping() + public String cache(ModelMap mmap) + { + mmap.put("cacheNames", cacheService.getCacheNames()); + return prefix + "/cache"; + } + + @PostMapping("/getNames") + public String getCacheNames(String fragment, ModelMap mmap) + { + mmap.put("cacheNames", cacheService.getCacheNames()); + return prefix + "/cache::" + fragment; + } + + @PostMapping("/getKeys") + public String getCacheKeys(String fragment, String cacheName, ModelMap mmap) + { + mmap.put("cacheName", cacheName); + mmap.put("cacheKyes", cacheService.getCacheKeys(cacheName)); + return prefix + "/cache::" + fragment; + } + + @PostMapping("/getValue") + public String getCacheValue(String fragment, String cacheName, String cacheKey, ModelMap mmap) + { + mmap.put("cacheName", cacheName); + mmap.put("cacheKey", cacheKey); + mmap.put("cacheValue", cacheService.getCacheValue(cacheName, cacheKey)); + return prefix + "/cache::" + fragment; + } + + @PostMapping("/clearCacheName") + @ResponseBody + public AjaxResult clearCacheName(String cacheName, ModelMap mmap) + { + cacheService.clearCacheName(cacheName); + return AjaxResult.success(); + } + + @PostMapping("/clearCacheKey") + @ResponseBody + public AjaxResult clearCacheKey(String cacheName, String cacheKey, ModelMap mmap) + { + cacheService.clearCacheKey(cacheName, cacheKey); + return AjaxResult.success(); + } + + @GetMapping("/clearAll") + @ResponseBody + public AjaxResult clearAll(ModelMap mmap) + { + cacheService.clearAll(); + return AjaxResult.success(); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java index 6f04cab78..c18c860dd 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java @@ -1,6 +1,7 @@ package com.ruoyi.web.controller.monitor; import java.util.List; +import com.ruoyi.framework.shiro.service.SysPasswordService; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @@ -31,6 +32,9 @@ public class SysLogininforController extends BaseController @Autowired private ISysLogininforService logininforService; + @Autowired + private SysPasswordService passwordService; + @RequiresPermissions("monitor:logininfor:view") @GetMapping() public String logininfor() @@ -48,7 +52,7 @@ public class SysLogininforController extends BaseController return getDataTable(list); } - @Log(title = "登陆日志", businessType = BusinessType.EXPORT) + @Log(title = "登录日志", businessType = BusinessType.EXPORT) @RequiresPermissions("monitor:logininfor:export") @PostMapping("/export") @ResponseBody @@ -56,11 +60,11 @@ public class SysLogininforController extends BaseController { List list = logininforService.selectLogininforList(logininfor); ExcelUtil util = new ExcelUtil(SysLogininfor.class); - return util.exportExcel(list, "登陆日志"); + return util.exportExcel(list, "登录日志"); } @RequiresPermissions("monitor:logininfor:remove") - @Log(title = "登陆日志", businessType = BusinessType.DELETE) + @Log(title = "登录日志", businessType = BusinessType.DELETE) @PostMapping("/remove") @ResponseBody public AjaxResult remove(String ids) @@ -69,7 +73,7 @@ public class SysLogininforController extends BaseController } @RequiresPermissions("monitor:logininfor:remove") - @Log(title = "登陆日志", businessType = BusinessType.CLEAN) + @Log(title = "登录日志", businessType = BusinessType.CLEAN) @PostMapping("/clean") @ResponseBody public AjaxResult clean() @@ -77,4 +81,14 @@ public class SysLogininforController extends BaseController logininforService.cleanLogininfor(); return success(); } + + @RequiresPermissions("monitor:logininfor:unlock") + @Log(title = "账户解锁", businessType = BusinessType.OTHER) + @PostMapping("/unlock") + @ResponseBody + public AjaxResult unlock(String loginName) + { + passwordService.clearLoginRecordCache(loginName); + return success(); + } } 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 c3ea3ad72..3ae9e81ea 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,23 +1,24 @@ 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.RequestParam; 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.common.utils.ShiroUtils; import com.ruoyi.framework.shiro.session.OnlineSession; 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; @@ -55,13 +56,13 @@ public class SysUserOnlineController extends BaseController 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) + public AjaxResult batchForceLogout(String ids) { - for (String sessionId : ids) + for (String sessionId : Convert.toStrArray(ids)) { SysUserOnline online = userOnlineService.selectOnlineById(sessionId); if (online == null) @@ -75,40 +76,13 @@ public class SysUserOnlineController extends BaseController } if (sessionId.equals(ShiroUtils.getSessionId())) { - return error("当前登陆用户无法强退"); + 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 139469d25..96307b84f 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 @@ -17,8 +17,8 @@ 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.enums.BusinessType; +import com.ruoyi.common.utils.ShiroUtils; 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; @@ -132,6 +132,19 @@ public class SysConfigController extends BaseController return toAjax(configService.deleteConfigByIds(ids)); } + /** + * 清空缓存 + */ + @RequiresPermissions("system:config:remove") + @Log(title = "参数管理", businessType = BusinessType.CLEAN) + @GetMapping("/clearCache") + @ResponseBody + public AjaxResult clearCache() + { + configService.clearCache(); + return success(); + } + /** * 校验参数键名 */ 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 bb17d9f3b..b0cba0472 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 @@ -16,11 +16,11 @@ 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.core.domain.entity.SysDept; +import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.ShiroUtils; 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; /** @@ -112,6 +112,11 @@ public class SysDeptController extends BaseController { 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()); return toAjax(deptService.updateDept(dept)); } @@ -148,11 +153,16 @@ public class SysDeptController extends BaseController /** * 选择部门树 + * + * @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"; } @@ -167,6 +177,19 @@ public class SysDeptController extends BaseController 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; + } + /** * 加载角色部门(数据权限)列表树 */ diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java index 945109858..87109589d 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java @@ -14,11 +14,11 @@ 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.domain.entity.SysDictData; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.poi.ExcelUtil; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysDictData; import com.ruoyi.system.service.ISysDictDataService; /** 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 bc8950d76..e8b352190 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 @@ -16,11 +16,11 @@ 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.core.domain.entity.SysDictType; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.ShiroUtils; 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; /** @@ -125,14 +125,20 @@ public class SysDictTypeController extends BaseController @ResponseBody public AjaxResult remove(String ids) { - try - { - return toAjax(dictTypeService.deleteDictTypeByIds(ids)); - } - catch (Exception e) - { - return error(e.getMessage()); - } + return toAjax(dictTypeService.deleteDictTypeByIds(ids)); + } + + /** + * 清空缓存 + */ + @RequiresPermissions("system:dict:remove") + @Log(title = "字典类型", businessType = BusinessType.CLEAN) + @GetMapping("/clearCache") + @ResponseBody + public AjaxResult clearCache() + { + dictTypeService.clearCache(); + return success(); } /** 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 3c736270a..4ac9fb758 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 @@ -1,15 +1,30 @@ package com.ruoyi.web.controller.system; +import java.util.Date; 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 com.ruoyi.common.config.Global; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.constant.ShiroConstants; import com.ruoyi.common.core.controller.BaseController; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysMenu; -import com.ruoyi.system.domain.SysUser; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.SysMenu; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.utils.CookieUtils; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.ShiroUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.shiro.service.SysPasswordService; +import com.ruoyi.system.service.ISysConfigService; import com.ruoyi.system.service.ISysMenuService; /** @@ -23,6 +38,12 @@ public class SysIndexController extends BaseController @Autowired private ISysMenuService menuService; + @Autowired + private ISysConfigService configService; + + @Autowired + private SysPasswordService passwordService; + // 系统首页 @GetMapping("/index") public String index(ModelMap mmap) @@ -33,16 +54,103 @@ public class SysIndexController extends BaseController List menus = menuService.selectMenusByUser(user); mmap.put("menus", menus); mmap.put("user", user); - mmap.put("copyrightYear", Global.getCopyrightYear()); - mmap.put("demoEnabled", Global.isDemoEnabled()); - return "index"; + 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", RuoYiConfig.getCopyrightYear()); + mmap.put("demoEnabled", RuoYiConfig.isDemoEnabled()); + mmap.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate())); + mmap.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate())); + + // 菜单导航显示风格 + 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("/lockscreen") + public String lockscreen(ModelMap mmap) + { + mmap.put("user", ShiroUtils.getSysUser()); + ServletUtils.getSession().setAttribute(ShiroConstants.LOCK_SCREEN, true); + return "lock"; + } + + // 解锁屏幕 + @PostMapping("/unlockscreen") + @ResponseBody + public AjaxResult unlockscreen(String password) + { + SysUser user = ShiroUtils.getSysUser(); + if (StringUtils.isNull(user)) + { + return AjaxResult.error("服务器超时,请重新登陆"); + } + if (passwordService.matches(user, password)) + { + ServletUtils.getSession().removeAttribute(ShiroConstants.LOCK_SCREEN); + return AjaxResult.success(); + } + return AjaxResult.error("密码不正确,请重新输入。"); + } + + // 切换主题 + @GetMapping("/system/switchSkin") + 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) { - mmap.put("version", Global.getVersion()); + mmap.put("version", RuoYiConfig.getVersion()); return "main"; } + + // 检查初始密码是否提醒修改 + public boolean initPasswordIsModify(Date pwdUpdateDate) + { + Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify")); + return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null; + } + + // 检查密码是否过期 + public boolean passwordIsExpiration(Date pwdUpdateDate) + { + Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays")); + if (passwordValidateDays != null && passwordValidateDays > 0) + { + if (StringUtils.isNull(pwdUpdateDate)) + { + // 如果从未修改过初始密码,直接提醒过期 + return true; + } + Date nowDate = DateUtils.getNowDate(); + return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays; + } + return false; + } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java index 3615c7599..05d6e2595 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java @@ -16,10 +16,11 @@ 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.core.domain.entity.SysMenu; +import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysMenu; -import com.ruoyi.system.domain.SysRole; +import com.ruoyi.common.utils.ShiroUtils; +import com.ruoyi.framework.shiro.util.AuthorizationUtils; import com.ruoyi.system.service.ISysMenuService; /** @@ -70,7 +71,7 @@ public class SysMenuController extends BaseController { return AjaxResult.warn("菜单已分配,不允许删除"); } - ShiroUtils.clearCachedAuthorizationInfo(); + AuthorizationUtils.clearAllCachedAuthorizationInfo(); return toAjax(menuService.deleteMenuById(menuId)); } @@ -109,7 +110,7 @@ public class SysMenuController extends BaseController return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); } menu.setCreateBy(ShiroUtils.getLoginName()); - ShiroUtils.clearCachedAuthorizationInfo(); + AuthorizationUtils.clearAllCachedAuthorizationInfo(); return toAjax(menuService.insertMenu(menu)); } @@ -137,7 +138,7 @@ public class SysMenuController extends BaseController return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在"); } menu.setUpdateBy(ShiroUtils.getLoginName()); - ShiroUtils.clearCachedAuthorizationInfo(); + AuthorizationUtils.clearAllCachedAuthorizationInfo(); return toAjax(menuService.updateMenu(menu)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java index 671dc11e3..5b3d478d6 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java @@ -15,7 +15,7 @@ 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.enums.BusinessType; -import com.ruoyi.framework.util.ShiroUtils; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.system.domain.SysNotice; import com.ruoyi.system.service.ISysNoticeService; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java index d6db9fdf0..966361b95 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java @@ -17,8 +17,8 @@ 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.enums.BusinessType; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.poi.ExcelUtil; -import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysPost; import com.ruoyi.system.service.ISysPostService; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java index f8a462dda..880dab685 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java @@ -12,15 +12,15 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.annotation.Log; -import com.ruoyi.common.config.Global; +import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.file.FileUploadUtils; import com.ruoyi.framework.shiro.service.SysPasswordService; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysUser; import com.ruoyi.system.service.ISysUserService; /** @@ -81,21 +81,23 @@ public class SysProfileController extends BaseController public AjaxResult resetPwd(String oldPassword, String newPassword) { SysUser user = ShiroUtils.getSysUser(); - if (StringUtils.isNotEmpty(newPassword) && passwordService.matches(user, oldPassword)) - { - user.setSalt(ShiroUtils.randomSalt()); - user.setPassword(passwordService.encryptPassword(user.getLoginName(), newPassword, user.getSalt())); - if (userService.resetUserPwd(user) > 0) - { - ShiroUtils.setSysUser(userService.selectUserById(user.getUserId())); - return success(); - } - return error(); - } - else + if (!passwordService.matches(user, oldPassword)) { return error("修改密码失败,旧密码错误"); } + if (passwordService.matches(user, newPassword)) + { + return error("新密码不能与旧密码相同"); + } + user.setSalt(ShiroUtils.randomSalt()); + user.setPassword(passwordService.encryptPassword(user.getLoginName(), newPassword, user.getSalt())); + user.setPwdUpdateDate(DateUtils.getNowDate()); + if (userService.resetUserPwd(user) > 0) + { + ShiroUtils.setSysUser(userService.selectUserById(user.getUserId())); + return success(); + } + return error("修改密码异常,请联系管理员"); } /** @@ -154,7 +156,7 @@ public class SysProfileController extends BaseController { if (!file.isEmpty()) { - String avatar = FileUploadUtils.upload(Global.getAvatarPath(), file); + String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file); currentUser.setAvatar(avatar); if (userService.updateUserInfo(currentUser) > 0) { 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..24f67ac6a --- /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.common.core.domain.entity.SysUser; +import com.ruoyi.framework.shiro.service.SysRegisterService; +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/SysRoleController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java index 66532db82..a48cca245 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java @@ -15,12 +15,13 @@ 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.entity.SysRole; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.poi.ExcelUtil; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysRole; -import com.ruoyi.system.domain.SysUser; +import com.ruoyi.framework.shiro.util.AuthorizationUtils; import com.ruoyi.system.domain.SysUserRole; import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysUserService; @@ -97,7 +98,7 @@ public class SysRoleController extends BaseController return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在"); } role.setCreateBy(ShiroUtils.getLoginName()); - ShiroUtils.clearCachedAuthorizationInfo(); + AuthorizationUtils.clearAllCachedAuthorizationInfo(); return toAjax(roleService.insertRole(role)); } @@ -121,6 +122,7 @@ public class SysRoleController extends BaseController @ResponseBody public AjaxResult editSave(@Validated SysRole role) { + roleService.checkRoleAllowed(role); if (UserConstants.ROLE_NAME_NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role))) { return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在"); @@ -130,7 +132,7 @@ public class SysRoleController extends BaseController return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在"); } role.setUpdateBy(ShiroUtils.getLoginName()); - ShiroUtils.clearCachedAuthorizationInfo(); + AuthorizationUtils.clearAllCachedAuthorizationInfo(); return toAjax(roleService.updateRole(role)); } @@ -153,6 +155,7 @@ public class SysRoleController extends BaseController @ResponseBody public AjaxResult authDataScopeSave(SysRole role) { + roleService.checkRoleAllowed(role); role.setUpdateBy(ShiroUtils.getLoginName()); if (roleService.authDataScope(role) > 0) { @@ -168,14 +171,7 @@ public class SysRoleController extends BaseController @ResponseBody public AjaxResult remove(String ids) { - try - { - return toAjax(roleService.deleteRoleByIds(ids)); - } - catch (Exception e) - { - return error(e.getMessage()); - } + return toAjax(roleService.deleteRoleByIds(ids)); } /** @@ -216,6 +212,7 @@ public class SysRoleController extends BaseController @ResponseBody public AjaxResult changeStatus(SysRole role) { + roleService.checkRoleAllowed(role); return toAjax(roleService.changeStatus(role)); } 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 4a98acf7e..9b40cfa13 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,6 +1,7 @@ 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; @@ -16,13 +17,14 @@ 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.entity.SysRole; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.StringUtils; 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.SysUser; import com.ruoyi.system.service.ISysPostService; import com.ruoyi.system.service.ISysRoleService; import com.ruoyi.system.service.ISysUserService; @@ -106,7 +108,7 @@ public class SysUserController extends BaseController @GetMapping("/add") public String add(ModelMap mmap) { - mmap.put("roles", roleService.selectRoleAll()); + mmap.put("roles", roleService.selectRoleAll().stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); mmap.put("posts", postService.selectPostAll()); return prefix + "/add"; } @@ -124,11 +126,13 @@ public class SysUserController extends BaseController { return error("新增用户'" + user.getLoginName() + "'失败,登录账号已存在"); } - else if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) + else if (StringUtils.isNotEmpty(user.getPhonenumber()) + && 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 (StringUtils.isNotEmpty(user.getEmail()) + && UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { return error("新增用户'" + user.getLoginName() + "'失败,邮箱账号已存在"); } @@ -144,8 +148,9 @@ public class SysUserController extends BaseController @GetMapping("/edit/{userId}") public String edit(@PathVariable("userId") Long userId, ModelMap mmap) { + List roles = roleService.selectRolesByUserId(userId); mmap.put("user", userService.selectUserById(userId)); - mmap.put("roles", roleService.selectRolesByUserId(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"; } @@ -159,15 +164,14 @@ public class SysUserController extends BaseController @ResponseBody public AjaxResult editSave(@Validated SysUser user) { - if (StringUtils.isNotNull(user.getUserId()) && SysUser.isAdmin(user.getUserId())) - { - return error("不允许修改超级管理员用户"); - } - else if (UserConstants.USER_PHONE_NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) + userService.checkUserAllowed(user); + if (StringUtils.isNotEmpty(user.getPhonenumber()) + && 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 (StringUtils.isNotEmpty(user.getEmail()) + && UserConstants.USER_EMAIL_NOT_UNIQUE.equals(userService.checkEmailUnique(user))) { return error("修改用户'" + user.getLoginName() + "'失败,邮箱账号已存在"); } @@ -176,7 +180,6 @@ public class SysUserController extends BaseController } @RequiresPermissions("system:user:resetPwd") - @Log(title = "重置密码", businessType = BusinessType.UPDATE) @GetMapping("/resetPwd/{userId}") public String resetPwd(@PathVariable("userId") Long userId, ModelMap mmap) { @@ -190,11 +193,12 @@ public class SysUserController extends BaseController @ResponseBody public AjaxResult resetPwdSave(SysUser user) { + userService.checkUserAllowed(user); user.setSalt(ShiroUtils.randomSalt()); user.setPassword(passwordService.encryptPassword(user.getLoginName(), user.getPassword(), user.getSalt())); if (userService.resetUserPwd(user) > 0) { - if (ShiroUtils.getUserId() == user.getUserId()) + if (ShiroUtils.getUserId().longValue() == user.getUserId().longValue()) { ShiroUtils.setSysUser(userService.selectUserById(user.getUserId())); } @@ -203,20 +207,40 @@ public class SysUserController extends BaseController 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(); + } + @RequiresPermissions("system:user:remove") @Log(title = "用户管理", businessType = BusinessType.DELETE) @PostMapping("/remove") @ResponseBody public AjaxResult remove(String ids) { - try - { - return toAjax(userService.deleteUserByIds(ids)); - } - catch (Exception e) - { - return error(e.getMessage()); - } + return toAjax(userService.deleteUserByIds(ids)); } /** @@ -258,6 +282,7 @@ public class SysUserController extends BaseController @ResponseBody public AjaxResult changeStatus(SysUser user) { + userService.checkUserAllowed(user); 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 43353914a..d4f020098 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,8 +1,9 @@ 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; +import com.ruoyi.common.config.RuoYiConfig; import io.swagger.annotations.ApiOperation; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; @@ -22,6 +23,10 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2; @EnableSwagger2 public class SwaggerConfig { + /** 是否开启swagger */ + @Value("${swagger.enabled}") + private boolean enabled; + /** * 创建API */ @@ -29,6 +34,8 @@ public class SwaggerConfig public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) + // 是否启用Swagger + .enable(enabled) // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息) .apiInfo(apiInfo()) // 设置哪些接口暴露给Swagger展示 @@ -54,9 +61,9 @@ public class SwaggerConfig // 描述 .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...") // 作者信息 - .contact(new Contact(Global.getName(), null, null)) + .contact(new Contact(RuoYiConfig.getName(), null, null)) // 版本 - .version("版本号:" + Global.getVersion()) + .version("版本号:" + RuoYiConfig.getVersion()) .build(); } } diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 15e79712b..74874830f 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.0.0 + version: 4.5.1 # 版权年份 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: @@ -73,7 +73,7 @@ spring: # MyBatis mybatis: # 搜索指定包别名 - typeAliasesPackage: com.ruoyi + typeAliasesPackage: com.ruoyi.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 mapperLocations: classpath*:mapper/**/*Mapper.xml # 加载全局的配置文件 @@ -108,8 +108,10 @@ 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超时时间(默认30分钟) + # Session超时时间,-1代表永不过期(默认30分钟) expireTime: 30 # 同步session到数据库的周期(默认1分钟) dbSyncPeriod: 1 @@ -128,3 +130,8 @@ xss: excludes: /system/notice/* # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* + +# Swagger配置 +swagger: + # 是否开启swagger + enabled: true diff --git a/ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml b/ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml index 66c01c30b..8ffd5ed04 100644 --- a/ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml +++ b/ruoyi-admin/src/main/resources/ehcache/ehcache-shiro.xml @@ -3,7 +3,15 @@ - + + + + + + + + + + statistics="false"> - - + + - - + statistics="false"> + + + + + + + + + + + + + + + + + + + + \ 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-fileinput/fileinput.css b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.css index 2aa3b59f7..3ca482d51 100644 --- a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.css +++ b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.css @@ -1,11 +1,11 @@ /*! - * bootstrap-fileinput v5.0.4 + * bootstrap-fileinput v5.1.3 * http://plugins.krajee.com/file-input * * Krajee default styling for bootstrap-fileinput. * * Author: Kartik Visweswaran - * Copyright: 2014 - 2019, Kartik Visweswaran, Krajee.com + * Copyright: 2014 - 2020, Kartik Visweswaran, Krajee.com * * Licensed under the BSD-3-Clause * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md @@ -60,10 +60,9 @@ height: 16px; } -.krajee-default .file-thumb-progress .progress, .krajee-default .file-thumb-progress .progress-bar { - height: 11px; +.file-thumb-progress .progress, .file-thumb-progress .progress-bar { font-family: Verdana, Helvetica, sans-serif; - font-size: 9px; + font-size: 0.7rem; } .krajee-default .file-thumb-progress .progress, .kv-upload-progress .progress { @@ -201,12 +200,16 @@ .file-preview-image { font: 40px Impact, Charcoal, sans-serif; color: #008000; + width:auto; + height:auto; + max-width:100%; + max-height:100%; } .krajee-default.file-preview-frame { margin: 8px; - border: 1px solid rgba(0,0,0,0.2); - box-shadow: 0 0 10px 0 rgba(0,0,0,0.2); + border: 1px solid rgba(0, 0, 0, 0.2); + box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2); padding: 6px; float: left; text-align: center; @@ -237,24 +240,19 @@ } .krajee-default.file-preview-frame:not(.file-preview-error):hover { - border: 1px solid rgba(0,0,0,0.3); - box-shadow: 0 0 10px 0 rgba(0,0,0,0.4); + border: 1px solid rgba(0, 0, 0, 0.3); + box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.4); } .krajee-default .file-preview-text { - display: block; color: #428bca; border: 1px solid #ddd; - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; outline: none; - padding: 8px; resize: none; } .krajee-default .file-preview-html { border: 1px solid #ddd; - padding: 8px; - overflow: auto; } .krajee-default .file-other-icon { @@ -292,7 +290,6 @@ } .krajee-default .file-thumb-progress { - height: 11px; top: 37px; left: 0; right: 0; @@ -340,13 +337,13 @@ .file-zoom-dialog .btn-navigate { padding: 0; - margin: 0; + margin: -60px 0 0; + font-size: 60px; background: transparent; text-decoration: none; outline: none; opacity: 0.7; - top: 45%; - font-size: 4em; + top: 50%; color: #1c94c4; } @@ -402,6 +399,7 @@ .file-drop-zone { border: 1px dashed #aaa; + min-height: 260px; border-radius: 4px; text-align: center; vertical-align: middle; @@ -424,6 +422,7 @@ .file-drop-zone-title { color: #aaa; font-size: 1.6em; + text-align:center; padding: 85px 10px; cursor: default; } @@ -434,7 +433,7 @@ } .file-uploading { - background: url(loading-sm.gif) no-repeat center bottom 10px; + background: url(../img/loading-sm.gif) no-repeat center bottom 10px; opacity: 0.65; } @@ -467,8 +466,8 @@ } .file-zoom-content { - height: 480px; text-align: center; + min-height: 300px; } .file-zoom-content .file-preview-image { @@ -532,19 +531,33 @@ padding-right: 20px; } -.file-sortable .file-drag-handle { - cursor: move; - opacity: 1; +.clickable .file-drop-zone-title { + cursor: pointer; } .file-sortable .file-drag-handle:hover { opacity: 0.7; } -.clickable .file-drop-zone-title { - cursor: pointer; +.file-sortable .file-drag-handle { + cursor: grab; + opacity: 1; } -.file-preview-initial.sortable-chosen { +.file-grabbing, .file-grabbing * { + cursor: not-allowed !important; +} + +.file-grabbing .file-preview-thumbnails * { + cursor: grabbing !important; +} + +.file-preview-frame.sortable-chosen { background-color: #d9edf7; + border-color: #17a2b8; + box-shadow: none !important; +} + +.file-preview .kv-zoom-cache { + display: none; } \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.js b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.js index c0723da97..d75554924 100644 --- a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.js +++ b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.js @@ -1,26 +1,22 @@ /*! - * bootstrap-fileinput v5.0.4 + * bootstrap-fileinput v5.1.3 * http://plugins.krajee.com/file-input * * Author: Kartik Visweswaran - * Copyright: 2014 - 2019, Kartik Visweswaran, Krajee.com + * Copyright: 2014 - 2020, Kartik Visweswaran, Krajee.com * * Licensed under the BSD-3-Clause * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md */ (function (factory) { 'use strict'; - //noinspection JSUnresolvedVariable - if (typeof define === 'function' && define.amd) { // jshint ignore:line - // AMD. Register as an anonymous module. - define(['jquery'], factory); // jshint ignore:line - } else { // noinspection JSUnresolvedVariable - if (typeof module === 'object' && module.exports) { // jshint ignore:line - // Node/CommonJS - // noinspection JSUnresolvedVariable - module.exports = factory(require('jquery')); // jshint ignore:line + if (typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } else { + if (typeof module === 'object' && module.exports) { + //noinspection NpmUsedModulesInstalled + module.exports = factory(require('jquery')); } else { - // Browser globals factory(window.jQuery); } } @@ -41,22 +37,28 @@ return str; }; + if (!Array.prototype.flatMap) { // polyfill flatMap + Array.prototype.flatMap = function (lambda) { + return [].concat(this.map(lambda)); + }; + } + var $h, FileInput; // fileinput helper object for all global variables and internal helper methods - //noinspection JSUnresolvedVariable $h = { FRAMES: '.kv-preview-thumb', SORT_CSS: 'file-sortable', + INIT_FLAG: 'init-', OBJECT_PARAMS: '\n' + - '\n' + - '\n' + - '\n' + - '\n' + - '\n', + '\n' + + '\n' + + '\n' + + '\n' + + '\n', DEFAULT_PREVIEW: '
\n' + - '{previewFileIcon}\n' + - '
', + '{previewFileIcon}\n' + + '', MODAL_ID: 'kvFileinputModal', MODAL_EVENTS: ['show', 'shown', 'hide', 'hidden', 'loaded'], logMessages: { @@ -65,25 +67,37 @@ badExifParser: 'Error loading the piexif.js library. {details}', badInputType: 'The input "type" must be set to "file" for initializing the "bootstrap-fileinput" plugin.', exifWarning: 'To avoid this warning, either set "autoOrientImage" to "false" OR ensure you have loaded ' + - 'the "piexif.js" library correctly on your page before the "fileinput.js" script.', + 'the "piexif.js" library correctly on your page before the "fileinput.js" script.', invalidChunkSize: 'Invalid upload chunk size: "{chunkSize}". Resumable uploads are disabled.', invalidThumb: 'Invalid thumb frame with id: "{id}".', noResumableSupport: 'The browser does not support resumable or chunk uploads.', noUploadUrl: 'The "uploadUrl" is not set. Ajax uploads and resumable uploads have been disabled.', - retryStatus: 'Retrying upload for chunk # {chunk} for {filename}... retry # {retry}.' + retryStatus: 'Retrying upload for chunk # {chunk} for {filename}... retry # {retry}.', + chunkQueueError: 'Could not push task to ajax pool for chunk index # {index}.', + resumableMaxRetriesReached: 'Maximum resumable ajax retries ({n}) reached.', + resumableRetryError: 'Could not retry the resumable request (try # {n})... aborting.', + resumableAborting: 'Aborting / cancelling the resumable request.' + }, objUrl: window.URL || window.webkitURL, now: function () { - return new Date(); + return new Date().getTime(); }, round: function (num) { num = parseFloat(num); return isNaN(num) ? 0 : Math.floor(Math.round(num)); }, + getArray: function (obj) { + var i, arr = [], len = obj && obj.length || 0; + for (i = 0; i < len; i++) { + arr.push(obj[i]); + } + return arr; + }, getFileRelativePath: function (file) { /** @namespace file.relativePath */ /** @namespace file.webkitRelativePath */ - return String(file.relativePath || file.webkitRelativePath || $h.getFileName(file) || null); + return String(file.newPath || file.relativePath || file.webkitRelativePath || $h.getFileName(file) || null); }, getFileId: function (file, generateFileId) { @@ -97,7 +111,20 @@ if (!relativePath) { return null; } - return (file.size + '_' + relativePath.replace(/\s/img, '_')); + return (file.size + '_' + encodeURIComponent(relativePath).replace(/%/g, '_')); + }, + getFrameSelector: function (id, selector) { + selector = selector || ''; + return '[id="' + id + '"]' + selector; + }, + getZoomSelector: function (id, selector) { + return $h.getFrameSelector('zoom-' + id, selector); + }, + getFrameElement: function ($element, id, selector) { + return $element.find($h.getFrameSelector(id, selector)); + }, + getZoomElement: function ($element, id, selector) { + return $element.find($h.getZoomSelector(id, selector)); }, getElapsed: function (seconds) { var delta = seconds, out = '', result = {}, structure = { @@ -109,7 +136,7 @@ minute: 60, second: 1 }; - Object.keys(structure).forEach(function (key) { + $h.getObjectKeys(structure).forEach(function (key) { result[key] = Math.floor(delta / structure[key]); delta -= result[key] * structure[key]; }); @@ -168,6 +195,12 @@ div.parentNode.removeChild(div); return status; }, + canOrientImage: function ($el) { + var $img = $(document.createElement('img')).css({width: '1px', height: '1px'}).insertAfter($el), + flag = $img.css('image-orientation'); + $img.remove(); + return !!flag; + }, canAssignFilesToInput: function () { var input = document.createElement('input'); try { @@ -196,8 +229,12 @@ $modal.appendTo($body); } }, + isFunction: function (v) { + return typeof v === 'function'; + }, isEmpty: function (value, trim) { - return value === undefined || value === null || value.length === 0 || (trim && $.trim(value) === ''); + return value === undefined || value === null || (!$h.isFunction( + value) && (value.length === 0 || (trim && $.trim(value) === ''))); }, isArray: function (a) { return Array.isArray(a) || Object.prototype.toString.call(a) === '[object Array]'; @@ -279,7 +316,6 @@ (!!Blob.prototype.webkitSlice || !!Blob.prototype.mozSlice || !!Blob.prototype.slice || false); }, dataURI2Blob: function (dataURI) { - //noinspection JSUnresolvedVariable var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, canBlob = $h.hasBlobSupport(), byteStr, arrayBuffer, intArray, i, mimeStr, bb, canProceed = (canBlob || BlobBuilder) && window.atob && window.ArrayBuffer && window.Uint8Array; @@ -305,9 +341,7 @@ return bb.getBlob(mimeStr); }, arrayBuffer2String: function (buffer) { - //noinspection JSUnresolvedVariable if (window.TextDecoder) { - // noinspection JSUnresolvedFunction return new TextDecoder('utf-8').decode(buffer); } var array = Array.prototype.slice.apply(new Uint8Array(buffer)), out = '', i = 0, len, c, char2, char3; @@ -363,7 +397,7 @@ case 'ffd8ffe1': case 'ffd8ffe2': return 'image/jpeg'; - case '89504E47': + case '89504e47': return 'image/png'; case '47494638': return 'image/gif'; @@ -430,8 +464,59 @@ getElement: function (options, param, value) { return ($h.isEmpty(options) || $h.isEmpty(options[param])) ? value : $(options[param]); }, + createElement: function (str, tag) { + tag = tag || 'div'; + return $($.parseHTML('<' + tag + '>' + str + '')); + }, uniqId: function () { - return Math.round(new Date().getTime()) + '_' + Math.round(Math.random() * 100); + return (new Date().getTime() + Math.floor(Math.random() * Math.pow(10, 15))).toString(36); + }, + cspBuffer: { + CSP_ATTRIB: 'data-csp-01928735', // a randomly named temporary attribute to store the CSP elem id + domElementsStyles: {}, + stash: function (htmlString) { + var self = this, outerDom = $.parseHTML('
' + htmlString + '
'), $el = $(outerDom); + $el.find('[style]').each(function (key, elem) { + var $elem = $(elem), styleString = $elem.attr('style'), id = $h.uniqId(), styles = {}; + if (styleString && styleString.length) { + if (styleString.indexOf(';') === -1) { + styleString += ';'; + } + styleString.slice(0, styleString.length - 1).split(';').map(function (str) { + str = str.split(':'); + if (str[0]) { + styles[str[0]] = str[1] ? str[1] : ''; + } + }); + self.domElementsStyles[id] = styles; + $elem.removeAttr('style').attr(self.CSP_ATTRIB, id); + } + }); + $el.filter('*').removeAttr('style'); // make sure all style attr are removed + var values = Object.values ? Object.values(outerDom) : Object.keys(outerDom).map(function (itm) { + return outerDom[itm]; + }); + return values.flatMap(function (elem) { + return elem.innerHTML; + }).join(''); + }, + apply: function (domElement) { + var self = this, $el = $(domElement); + $el.find('[' + self.CSP_ATTRIB + ']').each(function (key, elem) { + var $elem = $(elem), id = $elem.attr(self.CSP_ATTRIB), styles = self.domElementsStyles[id]; + if (styles) { + $elem.css(styles); + } + $elem.removeAttr(self.CSP_ATTRIB); + }); + self.domElementsStyles = {}; + } + }, + setHtml: function ($elem, htmlString) { + var buf = $h.cspBuffer; + $elem.html(buf.stash(htmlString)); + buf.apply($elem); + return $elem; }, htmlEncode: function (str, undefVal) { if (str === undefined) { @@ -468,18 +553,12 @@ return filePath.split(filePath.substring(sepIndex, sepIndex + 1)).pop(); }, checkFullScreen: function () { - //noinspection JSUnresolvedVariable return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement; }, toggleFullScreen: function (maximize) { - var doc = document, de = doc.documentElement; - if (de && maximize && !$h.checkFullScreen()) { - /** @namespace document.requestFullscreen */ - /** @namespace document.msRequestFullscreen */ - /** @namespace document.mozRequestFullScreen */ - /** @namespace document.webkitRequestFullscreen */ - /** @namespace Element.ALLOW_KEYBOARD_INPUT */ + var doc = document, de = doc.documentElement, isFullScreen = $h.checkFullScreen(); + if (de && maximize && !isFullScreen) { if (de.requestFullscreen) { de.requestFullscreen(); } else { @@ -496,21 +575,19 @@ } } } else { - /** @namespace document.exitFullscreen */ - /** @namespace document.msExitFullscreen */ - /** @namespace document.mozCancelFullScreen */ - /** @namespace document.webkitExitFullscreen */ - if (doc.exitFullscreen) { - doc.exitFullscreen(); - } else { - if (doc.msExitFullscreen) { - doc.msExitFullscreen(); + if (isFullScreen) { + if (doc.exitFullscreen) { + doc.exitFullscreen(); } else { - if (doc.mozCancelFullScreen) { - doc.mozCancelFullScreen(); + if (doc.msExitFullscreen) { + doc.msExitFullscreen(); } else { - if (doc.webkitExitFullscreen) { - doc.webkitExitFullscreen(); + if (doc.mozCancelFullScreen) { + doc.mozCancelFullScreen(); + } else { + if (doc.webkitExitFullscreen) { + doc.webkitExitFullscreen(); + } } } } @@ -534,13 +611,6 @@ } return newArr; }, - cleanZoomCache: function ($el) { - var $cache = $el.closest('.kv-zoom-cache-theme'); - if (!$cache.length) { - $cache = $el.closest('.kv-zoom-cache'); - } - $cache.remove(); - }, closeButton: function (css) { css = css ? 'close ' + css : 'close'; return ''; - //noinspection HtmlUnknownAttribute + //noinspection HtmlUnknownTarget,HtmlUnknownAttribute tBtnLink = '{icon} {label}'; //noinspection HtmlUnknownAttribute tBtnBrowse = '
{icon} {label}
'; + tModalLabel = $h.MODAL_ID + 'Label'; tModalMain = ''; + 'tabindex="-1" aria-labelledby="' + tModalLabel + '">'; tModal = '\n'; tGeneric = '{content}\n'; tStyle = ' {style}'; - tHtml = '
{data}
\n'; - tImage = '\n'; - tText = '\n'; + tHtml = renderObject('html', 'text/html'); + tText = renderObject('text', 'text/plain;charset=UTF-8'); + tPdf = renderObject('pdf', 'application/pdf'); + tImage = '{alt}\n'; tOffice = ''; tGdocs = '' + pdfRendererTemplate: '' }; // noinspection HtmlUnknownAttribute @@ -5516,13 +5967,14 @@ msgNoFilesSelected: 'No files selected', msgCancelled: 'Cancelled', msgPaused: 'Paused', - msgPlaceholder: 'Select {files}...', + msgPlaceholder: 'Select {files} ...', msgZoomModalHeading: 'Detailed Preview', msgFileRequired: 'You must select a file to upload.', msgSizeTooSmall: 'File "{name}" ({size} KB) is too small and must be larger than {minSize} KB.', msgSizeTooLarge: 'File "{name}" ({size} KB) exceeds maximum allowed upload size of {maxSize} KB.', msgFilesTooLess: 'You must select at least {n} {files} to upload.', msgFilesTooMany: 'Number of files selected for upload ({n}) exceeds maximum allowed limit of {m}.', + msgTotalFilesTooMany: 'You can upload a maximum of {m} files ({n} files detected).', msgFileNotFound: 'File "{name}" not found!', msgFileSecured: 'Security restrictions prevent reading the file "{name}".', msgFileNotReadable: 'File "{name}" is not readable.', @@ -5542,10 +5994,10 @@ 'object': 'object' }, msgUploadAborted: 'The file upload was aborted', - msgUploadThreshold: 'Processing...', - msgUploadBegin: 'Initializing...', + msgUploadThreshold: 'Processing …', + msgUploadBegin: 'Initializing …', msgUploadEnd: 'Done', - msgUploadResume: 'Resuming upload...', + msgUploadResume: 'Resuming upload …', msgUploadEmpty: 'No valid data available for upload.', msgUploadError: 'Upload Error', msgDeleteError: 'Delete Error', @@ -5601,13 +6053,14 @@ msgNoFilesSelected: '未选择文件', msgPaused: 'Paused', msgCancelled: '取消', - msgPlaceholder: '选择 {files}...', + msgPlaceholder: '选择 {files} ...', msgZoomModalHeading: '详细预览', msgFileRequired: '必须选择一个文件上传.', msgSizeTooSmall: '文件 "{name}" ({size} KB) 必须大于限定大小 {minSize} KB.', msgSizeTooLarge: '文件 "{name}" ({size} KB) 超过了允许大小 {maxSize} KB.', msgFilesTooLess: '你必须选择最少 {n} {files} 来上传. ', msgFilesTooMany: '选择的上传文件个数 ({n}) 超出最大文件的限制个数 {m}.', + msgTotalFilesTooMany: 'You can upload a maximum of {m} files ({n} files detected).', msgFileNotFound: '文件 "{name}" 未找到!', msgFileSecured: '安全限制,为了防止读取文件 "{name}".', msgFileNotReadable: '文件 "{name}" 不可读.', @@ -5627,10 +6080,10 @@ 'object': 'object' }, msgUploadAborted: '该文件上传被中止', - msgUploadThreshold: '处理中...', - msgUploadBegin: '正在初始化...', + msgUploadThreshold: '处理中 …', + msgUploadBegin: '正在初始化 …', msgUploadEnd: '完成', - msgUploadResume: 'Resuming upload...', + msgUploadResume: 'Resuming upload …', msgUploadEmpty: '无效的文件上传.', msgUploadError: 'Upload Error', msgDeleteError: 'Delete Error', @@ -5671,7 +6124,7 @@ indicatorSuccessTitle: '上传', indicatorErrorTitle: '上传错误', indicatorPausedTitle: 'Upload Paused', - indicatorLoadingTitle: '上传 ...' + indicatorLoadingTitle: '上传 …' }, previewZoomButtonTitles: { prev: '预览上一个文件', @@ -5682,7 +6135,7 @@ close: '关闭当前预览' } }; - + $.fn.fileinput.Constructor = FileInput; /** diff --git a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.min.css b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.min.css index 92a84a783..8d9a08570 100644 --- a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.min.css +++ b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.min.css @@ -1,12 +1,13 @@ /*! - * bootstrap-fileinput v5.0.4 + * bootstrap-fileinput v5.1.3 * http://plugins.krajee.com/file-input * * Krajee default styling for bootstrap-fileinput. * * Author: Kartik Visweswaran - * Copyright: 2014 - 2019, Kartik Visweswaran, Krajee.com + * Copyright: 2014 - 2020, Kartik Visweswaran, Krajee.com * * Licensed under the BSD-3-Clause * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md - */.btn-file input[type=file],.file-caption-icon,.file-no-browse,.file-preview .fileinput-remove,.file-zoom-dialog .btn-navigate,.file-zoom-dialog .floating-buttons,.krajee-default .file-thumb-progress{position:absolute}.file-loading input[type=file],input[type=file].file-loading{width:0;height:0}.file-no-browse{left:50%;bottom:20%;width:1px;height:1px;font-size:0;opacity:0;border:none;background:0 0;outline:0;box-shadow:none}.file-caption-icon,.file-input-ajax-new .fileinput-remove-button,.file-input-ajax-new .fileinput-upload-button,.file-input-ajax-new .no-browse .input-group-btn,.file-input-new .close,.file-input-new .file-preview,.file-input-new .fileinput-remove-button,.file-input-new .fileinput-upload-button,.file-input-new .glyphicon-file,.file-input-new .no-browse .input-group-btn,.file-zoom-dialog .modal-header:after,.file-zoom-dialog .modal-header:before,.hide-content .kv-file-content,.is-locked .fileinput-remove-button,.is-locked .fileinput-upload-button,.kv-hidden{display:none}.file-caption-icon .kv-caption-icon{line-height:inherit}.btn-file,.file-caption,.file-input,.file-loading:before,.file-preview,.file-zoom-dialog .modal-dialog,.krajee-default .file-thumbnail-footer,.krajee-default.file-preview-frame{position:relative}.file-error-message pre,.file-error-message ul,.krajee-default .file-actions,.krajee-default .file-other-error{text-align:left}.file-error-message pre,.file-error-message ul{margin:0}.krajee-default .file-drag-handle,.krajee-default .file-upload-indicator{float:left;margin-top:10px;width:16px;height:16px}.krajee-default .file-thumb-progress .progress,.krajee-default .file-thumb-progress .progress-bar{height:11px;font-family:Verdana,Helvetica,sans-serif;font-size:9px}.krajee-default .file-thumb-progress .progress,.kv-upload-progress .progress{background-color:#ccc}.krajee-default .file-caption-info,.krajee-default .file-size-info{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:160px;height:15px;margin:auto}.file-zoom-content>.file-object.type-flash,.file-zoom-content>.file-object.type-image,.file-zoom-content>.file-object.type-video{max-width:100%;max-height:100%;width:auto}.file-zoom-content>.file-object.type-flash,.file-zoom-content>.file-object.type-video{height:100%}.file-zoom-content>.file-object.type-default,.file-zoom-content>.file-object.type-html,.file-zoom-content>.file-object.type-pdf,.file-zoom-content>.file-object.type-text{width:100%}.file-loading:before{content:" Loading...";display:inline-block;padding-left:20px;line-height:16px;font-size:13px;font-variant:small-caps;color:#999;background:url(loading.gif) top left no-repeat}.file-object{margin:0 0 -5px;padding:0}.btn-file{overflow:hidden}.btn-file input[type=file]{top:0;left:0;min-width:100%;min-height:100%;text-align:right;opacity:0;background:none;cursor:inherit;display:block}.btn-file ::-ms-browse{font-size:10000px;width:100%;height:100%}.file-caption .file-caption-name{width:100%;margin:0;padding:0;box-shadow:none;border:none;background:0 0;outline:0}.file-caption.icon-visible .file-caption-icon{display:inline-block}.file-caption.icon-visible .file-caption-name{padding-left:15px}.file-caption-icon{left:8px}.file-error-message{color:#a94442;background-color:#f2dede;margin:5px;border:1px solid #ebccd1;border-radius:4px;padding:15px}.file-error-message pre{margin:5px 0}.file-caption-disabled{background-color:#eee;cursor:not-allowed;opacity:1}.file-preview{border-radius:5px;border:1px solid #ddd;padding:8px;width:100%;margin-bottom:5px}.file-preview .btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.file-preview .fileinput-remove{top:1px;right:1px;line-height:10px}.file-preview .clickable{cursor:pointer}.file-preview-image{font:40px Impact,Charcoal,sans-serif;color:green}.krajee-default.file-preview-frame{margin:8px;border:1px solid rgba(0,0,0,.2);box-shadow:0 0 10px 0 rgba(0,0,0,.2);padding:6px;float:left;text-align:center}.krajee-default.file-preview-frame .kv-file-content{width:213px;height:160px}.krajee-default .file-preview-other-frame{display:flex;align-items:center;justify-content:center}.krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered{width:400px}.krajee-default.file-preview-frame[data-template=audio] .kv-file-content{width:240px;height:55px}.krajee-default.file-preview-frame .file-thumbnail-footer{height:70px}.krajee-default.file-preview-frame:not(.file-preview-error):hover{border:1px solid rgba(0,0,0,.3);box-shadow:0 0 10px 0 rgba(0,0,0,.4)}.krajee-default .file-preview-text{display:block;color:#428bca;border:1px solid #ddd;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;outline:0;padding:8px;resize:none}.krajee-default .file-preview-html{border:1px solid #ddd;padding:8px;overflow:auto}.krajee-default .file-other-icon{font-size:6em;line-height:1}.krajee-default .file-footer-buttons{float:right}.krajee-default .file-footer-caption{display:block;text-align:center;padding-top:4px;font-size:11px;color:#777;margin-bottom:30px}.file-upload-stats{font-size:10px;text-align:center;width:100%}.kv-upload-progress .file-upload-stats{font-size:12px;margin:-10px 0 5px}.krajee-default .file-preview-error{opacity:.65;box-shadow:none}.krajee-default .file-thumb-progress{height:11px;top:37px;left:0;right:0}.krajee-default.kvsortable-ghost{background:#e1edf7;border:2px solid #a1abff}.krajee-default .file-preview-other:hover{opacity:.8}.krajee-default .file-preview-frame:not(.file-preview-error) .file-footer-caption:hover{color:#000}.kv-upload-progress .progress{height:20px;margin:10px 0;overflow:hidden}.kv-upload-progress .progress-bar{height:20px;font-family:Verdana,Helvetica,sans-serif}.file-zoom-dialog .file-other-icon{font-size:22em;font-size:50vmin}.file-zoom-dialog .modal-dialog{width:auto}.file-zoom-dialog .modal-header{display:flex;align-items:center;justify-content:space-between}.file-zoom-dialog .btn-navigate{padding:0;margin:0;background:0 0;text-decoration:none;outline:0;opacity:.7;top:45%;font-size:4em;color:#1c94c4}.file-zoom-dialog .btn-navigate:not([disabled]):hover{outline:0;box-shadow:none;opacity:.6}.file-zoom-dialog .floating-buttons{top:5px;right:10px}.file-zoom-dialog .btn-navigate[disabled]{opacity:.3}.file-zoom-dialog .btn-prev{left:1px}.file-zoom-dialog .btn-next{right:1px}.file-zoom-dialog .kv-zoom-title{font-weight:300;color:#999;max-width:50%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.file-input-ajax-new .no-browse .form-control,.file-input-new .no-browse .form-control{border-top-right-radius:4px;border-bottom-right-radius:4px}.file-caption-main{width:100%}.file-thumb-loading{background:url(loading.gif) center center no-repeat content-box!important}.file-drop-zone{border:1px dashed #aaa;border-radius:4px;text-align:center;vertical-align:middle;margin:12px 15px 12px 12px;padding:5px}.file-drop-zone.clickable:hover{border:2px dashed #999}.file-drop-zone.clickable:focus{border:2px solid #5acde2}.file-drop-zone .file-preview-thumbnails{cursor:default}.file-drop-zone-title{color:#aaa;font-size:1.6em;padding:85px 10px;cursor:default}.file-highlighted{border:2px dashed #999!important;background-color:#eee}.file-uploading{background:url(loading-sm.gif) center bottom 10px no-repeat;opacity:.65}.file-zoom-fullscreen .modal-dialog{min-width:100%;margin:0}.file-zoom-fullscreen .modal-content{border-radius:0;box-shadow:none;min-height:100vh}.file-zoom-fullscreen .modal-body{overflow-y:auto}.floating-buttons{z-index:3000}.floating-buttons .btn-kv{margin-left:3px;z-index:3000}.kv-zoom-actions .btn-kv{margin-left:3px}.file-zoom-content{height:480px;text-align:center}.file-zoom-content .file-preview-image,.file-zoom-content .file-preview-video{max-height:100%}.file-zoom-content>.file-object.type-image{height:auto;min-height:inherit}.file-zoom-content>.file-object.type-audio{width:auto;height:30px}@media (min-width:576px){.file-zoom-dialog .modal-dialog{max-width:500px}}@media (min-width:992px){.file-zoom-dialog .modal-lg{max-width:800px}}@media (max-width:767px){.file-preview-thumbnails{display:flex;justify-content:center;align-items:center;flex-direction:column}.file-zoom-dialog .modal-header{flex-direction:column}}@media (max-width:350px){.krajee-default.file-preview-frame:not([data-template=audio]) .kv-file-content{width:160px}}@media (max-width:420px){.krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered{width:100%}}.file-loading[dir=rtl]:before{background:url(loading.gif) top right no-repeat;padding-left:0;padding-right:20px}.file-sortable .file-drag-handle{cursor:move;opacity:1}.file-sortable .file-drag-handle:hover{opacity:.7}.clickable .file-drop-zone-title{cursor:pointer}.file-preview-initial.sortable-chosen{background-color:#d9edf7} \ No newline at end of file + */ +.file-loading input[type=file],input[type=file].file-loading{width:0;height:0}.file-no-browse{position:absolute;left:50%;bottom:20%;width:1px;height:1px;font-size:0;opacity:0;border:0;background:0;outline:0;box-shadow:none}.kv-hidden,.file-caption-icon,.file-zoom-dialog .modal-header:before,.file-zoom-dialog .modal-header:after,.file-input-new .file-preview,.file-input-new .close,.file-input-new .glyphicon-file,.file-input-new .fileinput-remove-button,.file-input-new .fileinput-upload-button,.file-input-new .no-browse .input-group-btn,.file-input-ajax-new .fileinput-remove-button,.file-input-ajax-new .fileinput-upload-button,.file-input-ajax-new .no-browse .input-group-btn,.hide-content .kv-file-content,.is-locked .fileinput-upload-button,.is-locked .fileinput-remove-button{display:none}.btn-file input[type=file],.file-caption-icon,.file-preview .fileinput-remove,.krajee-default .file-thumb-progress,.file-zoom-dialog .btn-navigate,.file-zoom-dialog .floating-buttons{position:absolute}.file-caption-icon .kv-caption-icon{line-height:inherit}.file-input,.file-loading:before,.btn-file,.file-caption,.file-preview,.krajee-default.file-preview-frame,.krajee-default .file-thumbnail-footer,.file-zoom-dialog .modal-dialog{position:relative}.file-error-message pre,.file-error-message ul,.krajee-default .file-actions,.krajee-default .file-other-error{text-align:left}.file-error-message pre,.file-error-message ul{margin:0}.krajee-default .file-drag-handle,.krajee-default .file-upload-indicator{float:left;margin-top:10px;width:16px;height:16px}.file-thumb-progress .progress,.file-thumb-progress .progress-bar{font-family:Verdana,Helvetica,sans-serif;font-size:.7rem}.krajee-default .file-thumb-progress .progress,.kv-upload-progress .progress{background-color:#ccc}.krajee-default .file-caption-info,.krajee-default .file-size-info{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;width:160px;height:15px;margin:auto}.file-zoom-content>.file-object.type-video,.file-zoom-content>.file-object.type-flash,.file-zoom-content>.file-object.type-image{max-width:100%;max-height:100%;width:auto}.file-zoom-content>.file-object.type-video,.file-zoom-content>.file-object.type-flash{height:100%}.file-zoom-content>.file-object.type-pdf,.file-zoom-content>.file-object.type-html,.file-zoom-content>.file-object.type-text,.file-zoom-content>.file-object.type-default{width:100%}.file-loading:before{content:" Loading...";display:inline-block;padding-left:20px;line-height:16px;font-size:13px;font-variant:small-caps;color:#999;background:transparent url(loading.gif) top left no-repeat}.file-object{margin:0 0 -5px 0;padding:0}.btn-file{overflow:hidden}.btn-file input[type=file]{top:0;left:0;min-width:100%;min-height:100%;text-align:right;opacity:0;background:none repeat scroll 0 0 transparent;cursor:inherit;display:block}.btn-file ::-ms-browse{font-size:10000px;width:100%;height:100%}.file-caption .file-caption-name{width:100%;margin:0;padding:0;box-shadow:none;border:0;background:0;outline:0}.file-caption.icon-visible .file-caption-icon{display:inline-block}.file-caption.icon-visible .file-caption-name{padding-left:15px}.file-caption-icon{left:8px}.file-error-message{color:#a94442;background-color:#f2dede;margin:5px;border:1px solid #ebccd1;border-radius:4px;padding:15px}.file-error-message pre{margin:5px 0}.file-caption-disabled{background-color:#eee;cursor:not-allowed;opacity:1}.file-preview{border-radius:5px;border:1px solid #ddd;padding:8px;width:100%;margin-bottom:5px}.file-preview .btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.file-preview .fileinput-remove{top:1px;right:1px;line-height:10px}.file-preview .clickable{cursor:pointer}.file-preview-image{font:40px Impact,Charcoal,sans-serif;color:#008000;width:auto;height:auto;max-width:100%;max-height:100%}.krajee-default.file-preview-frame{margin:8px;border:1px solid rgba(0,0,0,0.2);box-shadow:0 0 10px 0 rgba(0,0,0,0.2);padding:6px;float:left;text-align:center}.krajee-default.file-preview-frame .kv-file-content{width:213px;height:160px}.krajee-default .file-preview-other-frame{display:flex;align-items:center;justify-content:center}.krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered{width:400px}.krajee-default.file-preview-frame[data-template="audio"] .kv-file-content{width:240px;height:55px}.krajee-default.file-preview-frame .file-thumbnail-footer{height:70px}.krajee-default.file-preview-frame:not(.file-preview-error):hover{border:1px solid rgba(0,0,0,0.3);box-shadow:0 0 10px 0 rgba(0,0,0,0.4)}.krajee-default .file-preview-text{color:#428bca;border:1px solid #ddd;outline:0;resize:none}.krajee-default .file-preview-html{border:1px solid #ddd}.krajee-default .file-other-icon{font-size:6em;line-height:1}.krajee-default .file-footer-buttons{float:right}.krajee-default .file-footer-caption{display:block;text-align:center;padding-top:4px;font-size:11px;color:#777;margin-bottom:30px}.file-upload-stats{font-size:10px;text-align:center;width:100%}.kv-upload-progress .file-upload-stats{font-size:12px;margin:-10px 0 5px}.krajee-default .file-preview-error{opacity:.65;box-shadow:none}.krajee-default .file-thumb-progress{top:37px;left:0;right:0}.krajee-default.kvsortable-ghost{background:#e1edf7;border:2px solid #a1abff}.krajee-default .file-preview-other:hover{opacity:.8}.krajee-default .file-preview-frame:not(.file-preview-error) .file-footer-caption:hover{color:#000}.kv-upload-progress .progress{height:20px;margin:10px 0;overflow:hidden}.kv-upload-progress .progress-bar{height:11px;font-family:Verdana,Helvetica,sans-serif}.file-zoom-dialog .file-other-icon{font-size:22em;font-size:50vmin}.file-zoom-dialog .modal-dialog{width:auto}.file-zoom-dialog .modal-header{display:flex;align-items:center;justify-content:space-between}.file-zoom-dialog .btn-navigate{padding:0;margin:-60px 0 0;font-size:60px;background:transparent;text-decoration:none;outline:0;opacity:.7;top:50%;color:#1c94c4}.file-zoom-dialog .btn-navigate:not([disabled]):hover{outline:0;box-shadow:none;opacity:.6}.file-zoom-dialog .floating-buttons{top:5px;right:10px}.file-zoom-dialog .btn-navigate[disabled]{opacity:.3}.file-zoom-dialog .btn-prev{left:1px}.file-zoom-dialog .btn-next{right:1px}.file-zoom-dialog .kv-zoom-title{font-weight:300;color:#999;max-width:50%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.file-input-new .no-browse .form-control{border-top-right-radius:4px;border-bottom-right-radius:4px}.file-input-ajax-new .no-browse .form-control{border-top-right-radius:4px;border-bottom-right-radius:4px}.file-caption-main{width:100%}.file-thumb-loading{background:transparent url(loading.gif) no-repeat scroll center center content-box!important}.file-drop-zone{border:1px dashed #aaa;min-height:260px;border-radius:4px;text-align:center;vertical-align:middle;margin:12px 15px 12px 12px;padding:5px}.file-drop-zone.clickable:hover{border:2px dashed #999}.file-drop-zone.clickable:focus{border:2px solid #5acde2}.file-drop-zone .file-preview-thumbnails{cursor:default}.file-drop-zone-title{color:#aaa;font-size:1.6em;text-align:center;padding:85px 10px;cursor:default}.file-highlighted{border:2px dashed #999!important;background-color:#eee}.file-uploading{background:url(../img/loading-sm.gif) no-repeat center bottom 10px;opacity:.65}.file-zoom-fullscreen .modal-dialog{min-width:100%;margin:0}.file-zoom-fullscreen .modal-content{border-radius:0;box-shadow:none;min-height:100vh}.file-zoom-fullscreen .modal-body{overflow-y:auto}.floating-buttons{z-index:3000}.floating-buttons .btn-kv{margin-left:3px;z-index:3000}.kv-zoom-actions .btn-kv{margin-left:3px}.file-zoom-content{text-align:center;min-height:300px}.file-zoom-content .file-preview-image{max-height:100%}.file-zoom-content .file-preview-video{max-height:100%}.file-zoom-content>.file-object.type-image{height:auto;min-height:inherit}.file-zoom-content>.file-object.type-audio{width:auto;height:30px}@media(min-width:576px){.file-zoom-dialog .modal-dialog{max-width:500px}}@media(min-width:992px){.file-zoom-dialog .modal-lg{max-width:800px}}@media(max-width:767px){.file-preview-thumbnails{display:flex;justify-content:center;align-items:center;flex-direction:column}.file-zoom-dialog .modal-header{flex-direction:column}}@media(max-width:350px){.krajee-default.file-preview-frame:not([data-template="audio"]) .kv-file-content{width:160px}}@media(max-width:420px){.krajee-default.file-preview-frame .kv-file-content.kv-pdf-rendered{width:100%}}.file-loading[dir=rtl]:before{background:transparent url(loading.gif) top right no-repeat;padding-left:0;padding-right:20px}.clickable .file-drop-zone-title{cursor:pointer}.file-sortable .file-drag-handle:hover{opacity:.7}.file-sortable .file-drag-handle{cursor:grab;opacity:1}.file-grabbing,.file-grabbing *{cursor:not-allowed!important}.file-grabbing .file-preview-thumbnails *{cursor:grabbing!important}.file-preview-frame.sortable-chosen{background-color:#d9edf7;border-color:#17a2b8;box-shadow:none!important}.file-preview .kv-zoom-cache{display:none} \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.min.js b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.min.js index 2a2206afa..763f17c24 100644 --- a/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.min.js +++ b/ruoyi-admin/src/main/resources/static/ajax/libs/bootstrap-fileinput/fileinput.min.js @@ -1,10 +1,11 @@ /*! - bootstrap-fileinput v5.0.4 - http://plugins.krajee.com/file-input - - Author: Kartik Visweswaran - Copyright: 2014 - 2019, Kartik Visweswaran, Krajee.com - - Licensed under the BSD-3-Clause - https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md - */(function(factory){'use strict';if(typeof define==='function'&&define.amd){define(['jquery'],factory);}else{if(typeof module==='object'&&module.exports){module.exports=factory(require('jquery'));}else{factory(window.jQuery);}}}(function($){'use strict';$.fn.fileinputLocales={};$.fn.fileinputThemes={};String.prototype.setTokens=function(replacePairs){var str=this.toString(),key,re;for(key in replacePairs){if(replacePairs.hasOwnProperty(key)){re=new RegExp('\{'+key+'\}','g');str=str.replace(re,replacePairs[key]);}}return str;};var $h,FileInput;$h={FRAMES:'.kv-preview-thumb',SORT_CSS:'file-sortable',OBJECT_PARAMS:'\n'+'\n'+'\n'+'\n'+'\n'+'\n',DEFAULT_PREVIEW:'
\n'+'{previewFileIcon}\n'+'
',MODAL_ID:'kvFileinputModal',MODAL_EVENTS:['show','shown','hide','hidden','loaded'],logMessages:{ajaxError:'{status}: {error}. Error Details: {text}.',badDroppedFiles:'Error scanning dropped files!',badExifParser:'Error loading the piexif.js library. {details}',badInputType:'The input "type" must be set to "file" for initializing the "bootstrap-fileinput" plugin.',exifWarning:'To avoid this warning, either set "autoOrientImage" to "false" OR ensure you have loaded '+'the "piexif.js" library correctly on your page before the "fileinput.js" script.',invalidChunkSize:'Invalid upload chunk size: "{chunkSize}". Resumable uploads are disabled.',invalidThumb:'Invalid thumb frame with id: "{id}".',noResumableSupport:'The browser does not support resumable or chunk uploads.',noUploadUrl:'The "uploadUrl" is not set. Ajax uploads and resumable uploads have been disabled.',retryStatus:'Retrying upload for chunk # {chunk} for {filename}... retry # {retry}.'},objUrl:window.URL||window.webkitURL,now:function(){return new Date();},round:function(num){num=parseFloat(num);return isNaN(num)?0:Math.floor(Math.round(num));},getFileRelativePath:function(file){return String(file.relativePath||file.webkitRelativePath||$h.getFileName(file)||null);},getFileId:function(file,generateFileId){var relativePath=$h.getFileRelativePath(file);if(typeof generateFileId==='function'){return generateFileId(file);}if(!file){return null;}if(!relativePath){return null;}return(file.size+'_'+relativePath.replace(/\s/img,'_'));},getElapsed:function(seconds){var delta=seconds,out='',result={},structure={year:31536000,month:2592000,week:604800,day:86400,hour:3600,minute:60,second:1};Object.keys(structure).forEach(function(key){result[key]=Math.floor(delta/structure[key]);delta-=result[key]*structure[key];});$.each(result,function(key,value){if(value>0){out+=(out?' ':'')+value+key.substring(0,1);}});return out;},debounce:function(func,delay){var inDebounce;return function(){var args=arguments,context=this;clearTimeout(inDebounce);inDebounce=setTimeout(function(){func.apply(context,args);},delay);};},stopEvent:function(e){e.stopPropagation();e.preventDefault();},getFileName:function(file){return file?(file.fileName||file.name||''):'';},createObjectURL:function(data){if($h.objUrl&&$h.objUrl.createObjectURL&&data){return $h.objUrl.createObjectURL(data);}return'';},revokeObjectURL:function(data){if($h.objUrl&&$h.objUrl.revokeObjectURL&&data){$h.objUrl.revokeObjectURL(data);}},compare:function(input,str,exact){return input!==undefined&&(exact?input===str:input.match(str));},isIE:function(ver){var div,status;if(navigator.appName!=='Microsoft Internet Explorer'){return false;}if(ver===10){return new RegExp('msie\\s'+ver,'i').test(navigator.userAgent);}div=document.createElement('div');div.innerHTML='';status=div.getElementsByTagName('i').length;document.body.appendChild(div);div.parentNode.removeChild(div);return status;},canAssignFilesToInput:function(){var input=document.createElement('input');try{input.type='file';input.files=null;return true;}catch(err){return false;}},getDragDropFolders:function(items){var i,item,len=items?items.length:0,folders=0;if(len>0&&items[0].webkitGetAsEntry()){for(i=0;i=0){byteStr=atob(dataURI.split(',')[1]);}else{byteStr=decodeURIComponent(dataURI.split(',')[1]);}arrayBuffer=new ArrayBuffer(byteStr.length);intArray=new Uint8Array(arrayBuffer);for(i=0;i>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:out+=String.fromCharCode(c);break;case 12:case 13:char2=array[i++];out+=String.fromCharCode(((c&0x1F)<<6)|(char2&0x3F));break;case 14:char2=array[i++];char3=array[i++];out+=String.fromCharCode(((c&0x0F)<<12)|((char2&0x3F)<<6)|((char3&0x3F)<<0));break;}}return out;},isHtml:function(str){var a=document.createElement('div');a.innerHTML=str;for(var c=a.childNodes,i=c.length;i--;){if(c[i].nodeType===1){return true;}}return false;},isSvg:function(str){return str.match(/^\s*<\?xml/i)&&(str.match(//g,'>').replace(/"/g,'"').replace(/'/g,''');},replaceTags:function(str,tags){var out=str;if(!tags){return out;}$.each(tags,function(key,value){if(typeof value==='function'){value=value();}out=out.split(key).join(value);});return out;},cleanMemory:function($thumb){var data=$thumb.is('img')?$thumb.attr('src'):$thumb.find('source').attr('src');$h.revokeObjectURL(data);},findFileName:function(filePath){var sepIndex=filePath.lastIndexOf('/');if(sepIndex===-1){sepIndex=filePath.lastIndexOf('\\');}return filePath.split(filePath.substring(sepIndex,sepIndex+1)).pop();},checkFullScreen:function(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;},toggleFullScreen:function(maximize){var doc=document,de=doc.documentElement;if(de&&maximize&&!$h.checkFullScreen()){if(de.requestFullscreen){de.requestFullscreen();}else{if(de.msRequestFullscreen){de.msRequestFullscreen();}else{if(de.mozRequestFullScreen){de.mozRequestFullScreen();}else{if(de.webkitRequestFullscreen){de.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);}}}}}else{if(doc.exitFullscreen){doc.exitFullscreen();}else{if(doc.msExitFullscreen){doc.msExitFullscreen();}else{if(doc.mozCancelFullScreen){doc.mozCancelFullScreen();}else{if(doc.webkitExitFullscreen){doc.webkitExitFullscreen();}}}}}},moveArray:function(arr,oldIndex,newIndex,reverseOrder){var newArr=$.extend(true,[],arr);if(reverseOrder){newArr.reverse();}if(newIndex>=newArr.length){var k=newIndex-newArr.length;while((k--)+1){newArr.push(undefined);}}newArr.splice(newIndex,0,newArr.splice(oldIndex,1)[0]);if(reverseOrder){newArr.reverse();}return newArr;},cleanZoomCache:function($el){var $cache=$el.closest('.kv-zoom-cache-theme');if(!$cache.length){$cache=$el.closest('.kv-zoom-cache');}$cache.remove();},closeButton:function(css){css=css?'close '+css:'close';return'';},getRotation:function(value){switch(value){case 2:return'rotateY(180deg)';case 3:return'rotate(180deg)';case 4:return'rotate(180deg) rotateY(180deg)';case 5:return'rotate(270deg) rotateY(180deg)';case 6:return'rotate(90deg)';case 7:return'rotate(90deg) rotateY(180deg)';case 8:return'rotate(270deg)';default:return'';}},setTransform:function(el,val){if(!el){return;}el.style.transform=val;el.style.webkitTransform=val;el.style['-moz-transform']=val;el.style['-ms-transform']=val;el.style['-o-transform']=val;}};FileInput=function(element,options){var self=this;self.$element=$(element);self.$parent=self.$element.parent();if(!self._validate()){return;}self.isPreviewable=$h.hasFileAPISupport();self.isIE9=$h.isIE(9);self.isIE10=$h.isIE(10);if(self.isPreviewable||self.isIE9){self._init(options);self._listen();}self.$element.removeClass('file-loading');};FileInput.prototype={constructor:FileInput,_cleanup:function(){var self=this;self.reader=null;self.clearFileStack();self.fileBatchCompleted=true;self.isError=false;self.cancelling=false;self.paused=false;self.lastProgress=0;self._initAjax();},_initAjax:function(){var self=this;self.ajaxQueue=[];self.ajaxRequests=[];self.ajaxQueueIntervalId=null;self.ajaxCurrentThreads=0;self.ajaxAborted=false;},_init:function(options,refreshMode){var self=this,f,$el=self.$element,$cont,t,tmp;self.options=options;$.each(options,function(key,value){switch(key){case'minFileCount':case'maxFileCount':case'minFileSize':case'maxFileSize':case'maxFilePreviewSize':case'resizeImageQuality':case'resizeIfSizeMoreThan':case'progressUploadThreshold':case'initialPreviewCount':case'zoomModalHeight':case'minImageHeight':case'maxImageHeight':case'minImageWidth':case'maxImageWidth':self[key]=$h.getNum(value);break;default:self[key]=value;break;}});if(self.rtl){tmp=self.previewZoomButtonIcons.prev;self.previewZoomButtonIcons.prev=self.previewZoomButtonIcons.next;self.previewZoomButtonIcons.next=tmp;}if(!isNaN(self.maxAjaxThreads)&&self.maxAjaxThreadsrm.file.size?rm.file.size:size;},getTotalChunks:function(){var rm=self.resumableManager,chunkSize=parseFloat(rm.chunkSize);if(!isNaN(chunkSize)&&chunkSize>0){return Math.ceil(rm.file.size/chunkSize);}return 0;},getProgress:function(){var rm=self.resumableManager,processed=rm.processedResumables(),total=rm.chunkCount;if(total===0){return 0;}return Math.ceil(processed/total*100);},checkAborted:function(intervalId){if(self.paused||self.cancelling){clearInterval(intervalId);self.unlock();}},upload:function(){var rm=self.resumableManager,fm=self.fileManager,ids=fm.getIdList(),flag='new',intervalId;intervalId=setInterval(function(){var id;rm.checkAborted(intervalId);if(flag==='new'){self.lock();flag='processing';id=ids.shift();fm.initStats(id);if(fm.stack[id]){rm.init(id,fm.stack[id],fm.getIndex(id));rm.testUpload();rm.uploadResumable();}}if(!fm.isPending(id)&&rm.completed){flag='new';}if(fm.isProcessed()){var $initThumbs=self.$preview.find('.file-preview-initial');if($initThumbs.length){$h.addCss($initThumbs,$h.SORT_CSS);self._initSortable();}clearInterval(intervalId);self._clearFileInput();self.unlock();setTimeout(function(){var data=self.previewCache.data;if(data){self.initialPreview=data.content;self.initialPreviewConfig=data.config;self.initialPreviewThumbTags=data.tags;}self._raise('filebatchuploadcomplete',[self.initialPreview,self.initialPreviewConfig,self.initialPreviewThumbTags,self._getExtraData()]);},self.processDelay);}},self.processDelay);},uploadResumable:function(){var i,rm=self.resumableManager,total=rm.chunkCount;for(i=0;iopts.maxRetries){rm.setProcessed('error');return;}var fd,outData,fnBefore,fnSuccess,fnError,fnComplete,slice=file.slice?'slice':(file.mozSlice?'mozSlice':(file.webkitSlice?'webkitSlice':'slice')),blob=file[slice](chunkSize*index,chunkSize*(index+1));fd=new FormData();f=fm.stack[id];self._setUploadData(fd,{chunkCount:rm.chunkCount,chunkIndex:index,chunkSize:chunkSize,chunkSizeStart:chunkSize*index,fileBlob:[blob,rm.fileName],fileId:id,fileName:rm.fileName,fileRelativePath:f.relativePath,fileSize:file.size,retryCount:retry});if(rm.$progress&&rm.$progress.length){rm.$progress.show();}fnBefore=function(jqXHR){outData=self._getOutData(fd,jqXHR);if(self.showPreview){if(!$thumb.hasClass('file-preview-success')){self._setThumbStatus($thumb,'Loading');$h.addCss($thumb,'file-uploading');}$btnDelete.attr('disabled',true);}self._raise('filechunkbeforesend',[id,index,retry,fm,rm,outData]);};fnSuccess=function(data,textStatus,jqXHR){outData=self._getOutData(fd,jqXHR,data);var paramNames=self.uploadParamNames,chunkIndex=paramNames.chunkIndex||'chunkIndex',opts=self.resumableUploadOptions,params=[id,index,retry,fm,rm,outData];rm.currThreads--;if(data.error){if(opts.showErrorLog){self._log(logs.retryStatus,{retry:retry+1,filename:rm.fileName,chunk:index});}rm.pushAjax(index,retry+1);rm.error=data.error;self._raise('filechunkerror',params);}else{rm.logs[data[chunkIndex]]=true;if(!rm.processed[id]){rm.processed[id]={};}rm.processed[id][data[chunkIndex]]=true;rm.processed[id].data=data;self._raise('filechunksuccess',params);rm.check();}};fnError=function(jqXHR,textStatus,errorThrown){outData=self._getOutData(fd,jqXHR);rm.currThreads--;rm.error=errorThrown;rm.logAjaxError(jqXHR,textStatus,errorThrown);self._raise('filechunkajaxerror',[id,index,retry,fm,rm,outData]);rm.pushAjax(index,retry+1);};fnComplete=function(){self._raise('filechunkcomplete',[id,index,retry,fm,rm,self._getOutData(fd)]);};self._ajaxSubmit(fnBefore,fnSuccess,fnComplete,fnError,fd,id,rm.fileIndex);},loopAjax:function(){var rm=self.resumableManager;if(rm.currThreads=rm.getTotalChunks()){rm.setProcessed('success');clearInterval(rm.chunkIntervalId);}}}}}};self.resumableManager.reset();},_initTemplateDefaults:function(){var self=this,tMain1,tMain2,tPreview,tFileIcon,tClose,tCaption,tBtnDefault,tBtnLink,tBtnBrowse,tModalMain,tModal,tProgress,tSize,tFooter,tActions,tActionDelete,tActionUpload,tActionDownload,tActionZoom,tActionDrag,tIndicator,tTagBef,tTagBef1,tTagBef2,tTagAft,tGeneric,tHtml,tImage,tText,tOffice,tGdocs,tVideo,tAudio,tFlash,tObject,tPdf,tOther,tStyle,tZoomCache,vDefaultDim,tStats;tMain1='{preview}\n'+'
\n'+'
\n'+' {caption}\n'+'
\n'+' {remove}\n'+' {cancel}\n'+' {pause}\n'+' {upload}\n'+' {browse}\n'+'
\n'+'
';tMain2='{preview}\n
\n
\n'+'{remove}\n{cancel}\n{upload}\n{browse}\n';tPreview='
\n'+' {close}'+'
\n'+'
\n'+'
\n'+'
'+'
\n'+'
\n'+'
\n'+'
';tClose=$h.closeButton('fileinput-remove');tFileIcon='';tCaption='
\n'+' \n'+' \n'+'
';tBtnDefault='';tBtnLink='{icon} {label}';tBtnBrowse='
{icon} {label}
';tModalMain='';tModal='\n';tProgress='
\n'+'
\n'+' {status}\n'+'
\n'+'
{stats}';tStats='
'+'{pendingTime} '+'{uploadSpeed}'+'
';tSize=' ({sizeText})';tFooter='';tActions='
\n'+' \n'+'
\n'+'{drag}\n'+'
';tActionDelete='\n';tActionUpload='';tActionDownload='{downloadIcon}';tActionZoom='';tActionDrag='{dragIcon}';tIndicator='
{indicator}
';tTagBef='
\n';tTagBef2=tTagBef+' title="{caption}">
\n';tTagAft='
{footer}\n
\n';tGeneric='{content}\n';tStyle=' {style}';tHtml='
{data}
\n';tImage='\n';tText='\n';tOffice='';tGdocs='';tVideo='\n';tAudio='\n';tFlash='\n';tPdf='\n';tObject='\n'+'\n'+$h.OBJECT_PARAMS+' '+$h.DEFAULT_PREVIEW+'\n\n';tOther='
\n'+$h.DEFAULT_PREVIEW+'\n
\n';tZoomCache='';vDefaultDim={width:'100%',height:'100%','min-height':'480px'};if(self._isPdfRendered()){tPdf=self.pdfRendererTemplate.replace('{renderer}',self._encodeURI(self.pdfRendererUrl));}self.defaults={layoutTemplates:{main1:tMain1,main2:tMain2,preview:tPreview,close:tClose,fileIcon:tFileIcon,caption:tCaption,modalMain:tModalMain,modal:tModal,progress:tProgress,stats:tStats,size:tSize,footer:tFooter,indicator:tIndicator,actions:tActions,actionDelete:tActionDelete,actionUpload:tActionUpload,actionDownload:tActionDownload,actionZoom:tActionZoom,actionDrag:tActionDrag,btnDefault:tBtnDefault,btnLink:tBtnLink,btnBrowse:tBtnBrowse,zoomCache:tZoomCache},previewMarkupTags:{tagBefore1:tTagBef1,tagBefore2:tTagBef2,tagAfter:tTagAft},previewContentTemplates:{generic:tGeneric,html:tHtml,image:tImage,text:tText,office:tOffice,gdocs:tGdocs,video:tVideo,audio:tAudio,flash:tFlash,object:tObject,pdf:tPdf,other:tOther},allowedPreviewTypes:['image','html','text','video','audio','flash','pdf','object'],previewTemplates:{},previewSettings:{image:{width:'auto',height:'auto','max-width':'100%','max-height':'100%'},html:{width:'213px',height:'160px'},text:{width:'213px',height:'160px'},office:{width:'213px',height:'160px'},gdocs:{width:'213px',height:'160px'},video:{width:'213px',height:'160px'},audio:{width:'100%',height:'30px'},flash:{width:'213px',height:'160px'},object:{width:'213px',height:'160px'},pdf:{width:'100%',height:'160px'},other:{width:'213px',height:'160px'}},previewSettingsSmall:{image:{width:'auto',height:'auto','max-width':'100%','max-height':'100%'},html:{width:'100%',height:'160px'},text:{width:'100%',height:'160px'},office:{width:'100%',height:'160px'},gdocs:{width:'100%',height:'160px'},video:{width:'100%',height:'auto'},audio:{width:'100%',height:'30px'},flash:{width:'100%',height:'auto'},object:{width:'100%',height:'auto'},pdf:{width:'100%',height:'160px'},other:{width:'100%',height:'160px'}},previewZoomSettings:{image:{width:'auto',height:'auto','max-width':'100%','max-height':'100%'},html:vDefaultDim,text:vDefaultDim,office:{width:'100%',height:'100%','max-width':'100%','min-height':'480px'},gdocs:{width:'100%',height:'100%','max-width':'100%','min-height':'480px'},video:{width:'auto',height:'100%','max-width':'100%'},audio:{width:'100%',height:'30px'},flash:{width:'auto',height:'480px'},object:{width:'auto',height:'100%','max-width':'100%','min-height':'480px'},pdf:vDefaultDim,other:{width:'auto',height:'100%','min-height':'480px'}},mimeTypeAliases:{'video/quicktime':'video/mp4'},fileTypeSettings:{image:function(vType,vName){return($h.compare(vType,'image.*')&&!$h.compare(vType,/(tiff?|wmf)$/i)||$h.compare(vName,/\.(gif|png|jpe?g)$/i));},html:function(vType,vName){return $h.compare(vType,'text/html')||$h.compare(vName,/\.(htm|html)$/i);},office:function(vType,vName){return $h.compare(vType,/(word|excel|powerpoint|office)$/i)||$h.compare(vName,/\.(docx?|xlsx?|pptx?|pps|potx?)$/i);},gdocs:function(vType,vName){return $h.compare(vType,/(word|excel|powerpoint|office|iwork-pages|tiff?)$/i)||$h.compare(vName,/\.(docx?|xlsx?|pptx?|pps|potx?|rtf|ods|odt|pages|ai|dxf|ttf|tiff?|wmf|e?ps)$/i);},text:function(vType,vName){return $h.compare(vType,'text.*')||$h.compare(vName,/\.(xml|javascript)$/i)||$h.compare(vName,/\.(txt|md|csv|nfo|ini|json|php|js|css)$/i);},video:function(vType,vName){return $h.compare(vType,'video.*')&&($h.compare(vType,/(ogg|mp4|mp?g|mov|webm|3gp)$/i)||$h.compare(vName,/\.(og?|mp4|webm|mp?g|mov|3gp)$/i));},audio:function(vType,vName){return $h.compare(vType,'audio.*')&&($h.compare(vName,/(ogg|mp3|mp?g|wav)$/i)||$h.compare(vName,/\.(og?|mp3|mp?g|wav)$/i));},flash:function(vType,vName){return $h.compare(vType,'application/x-shockwave-flash',true)||$h.compare(vName,/\.(swf)$/i);},pdf:function(vType,vName){return $h.compare(vType,'application/pdf',true)||$h.compare(vName,/\.(pdf)$/i);},object:function(){return true;},other:function(){return true;}},fileActionSettings:{showRemove:true,showUpload:true,showDownload:true,showZoom:true,showDrag:true,removeIcon:'',removeClass:'btn btn-sm btn-kv btn-default btn-outline-secondary',removeErrorClass:'btn btn-sm btn-kv btn-danger',removeTitle:'Remove file',uploadIcon:'',uploadClass:'btn btn-sm btn-kv btn-default btn-outline-secondary',uploadTitle:'Upload file',uploadRetryIcon:'',uploadRetryTitle:'Retry upload',downloadIcon:'',downloadClass:'btn btn-sm btn-kv btn-default btn-outline-secondary',downloadTitle:'Download file',zoomIcon:'',zoomClass:'btn btn-sm btn-kv btn-default btn-outline-secondary',zoomTitle:'View Details',dragIcon:'',dragClass:'text-info',dragTitle:'Move / Rearrange',dragSettings:{},indicatorNew:'',indicatorSuccess:'',indicatorError:'',indicatorLoading:'',indicatorPaused:'',indicatorNewTitle:'Not uploaded yet',indicatorSuccessTitle:'Uploaded',indicatorErrorTitle:'Upload Error',indicatorLoadingTitle:'Uploading ...',indicatorPausedTitle:'Upload Paused'}};$.each(self.defaults,function(key,setting){if(key==='allowedPreviewTypes'){if(self.allowedPreviewTypes===undefined){self.allowedPreviewTypes=setting;}return;}self[key]=$.extend(true,{},setting,self[key]);});self._initPreviewTemplates();},_initPreviewTemplates:function(){var self=this,tags=self.previewMarkupTags,tagBef,tagAft=tags.tagAfter;$.each(self.previewContentTemplates,function(key,value){if($h.isEmpty(self.previewTemplates[key])){tagBef=tags.tagBefore2;if(key==='generic'||key==='image'||key==='html'||key==='text'){tagBef=tags.tagBefore1;}if(self._isPdfRendered()&&key==='pdf'){tagBef=tagBef.replace('kv-file-content','kv-file-content kv-pdf-rendered');}self.previewTemplates[key]=tagBef+value+tagAft;}});},_initPreviewCache:function(){var self=this;self.previewCache={data:{},init:function(){var content=self.initialPreview;if(content.length>0&&!$h.isArray(content)){content=content.split(self.initialPreviewDelimiter);}self.previewCache.data={content:content,config:self.initialPreviewConfig,tags:self.initialPreviewThumbTags};},count:function(skipNull){if(!self.previewCache.data||!self.previewCache.data.content){return 0;}if(skipNull){var chk=self.previewCache.data.content.filter(function(n){return n!==null;});return chk.length;}return self.previewCache.data.content.length;},get:function(i,isDisabled){var ind='init_'+i,data=self.previewCache.data,config=data.config[i],fileId,content=data.content[i],previewId=self.previewInitId+'-'+ind,out,$tmp,cat,ftr,fname,ftype,frameClass,asData=$h.ifSet('previewAsData',config,self.initialPreviewAsData),a=config?{title:config.title||null,alt:config.alt||null}:{title:null,alt:null},parseTemplate=function(cat,dat,fn,ft,id,ftr,ind,fc,t){fc=' file-preview-initial '+$h.SORT_CSS+(fc?' '+fc:'');fileId=config&&config.fileId||'file_'+id;return self._generatePreviewTemplate(cat,dat,fn,ft,id,fileId,false,null,fc,ftr,ind,t,a,config&&config.zoomData||dat);};if(!content||!content.length){return'';}isDisabled=isDisabled===undefined?true:isDisabled;cat=$h.ifSet('type',config,self.initialPreviewFileType||'generic');fname=$h.ifSet('filename',config,$h.ifSet('caption',config));ftype=$h.ifSet('filetype',config,cat);ftr=self.previewCache.footer(i,isDisabled,(config&&config.size||null));frameClass=$h.ifSet('frameClass',config);if(asData){out=parseTemplate(cat,content,fname,ftype,previewId,ftr,ind,frameClass);}else{out=parseTemplate('generic',content,fname,ftype,previewId,ftr,ind,frameClass,cat).setTokens({'content':data.content[i]});}if(data.tags.length&&data.tags[i]){out=$h.replaceTags(out,data.tags[i]);}if(!$h.isEmpty(config)&&!$h.isEmpty(config.frameAttr)){$tmp=$(document.createElement('div')).html(out);$tmp.find('.file-preview-initial').attr(config.frameAttr);out=$tmp.html();$tmp.remove();}return out;},clean:function(data){data.content=$h.cleanArray(data.content);data.config=$h.cleanArray(data.config);data.tags=$h.cleanArray(data.tags);self.previewCache.data=data;},add:function(content,config,tags,append){var data=self.previewCache.data,index=content.length-1;if(!content||!content.length){return index;}if(!$h.isArray(content)){content=content.split(self.initialPreviewDelimiter);}if(append){index=data.content.push(content[0])-1;data.config[index]=config;data.tags[index]=tags;}else{data.content=content;data.config=config;data.tags=tags;}self.previewCache.clean(data);return index;},set:function(content,config,tags,append){var data=self.previewCache.data,i,chk;if(!content||!content.length){return;}if(!$h.isArray(content)){content=content.split(self.initialPreviewDelimiter);}chk=content.filter(function(n){return n!==null;});if(!chk.length){return;}if(data.content===undefined){data.content=[];}if(data.config===undefined){data.config=[];}if(data.tags===undefined){data.tags=[];}if(append){for(i=0;i'+msg+'':'
  • '+msg+'
  • ';if($error.find('ul').length===0){self._addError('
      '+e+'
    ');}else{$error.find('ul').append(e);}$error.fadeIn(800);self._raise(ev,[params,msg]);self._setValidationError('file-input-new');return true;},_showError:function(msg,params,event){var self=this,$error=self.$errorContainer,ev=event||'fileerror';params=params||{};params.reader=self.reader;self._addError(msg);$error.fadeIn(800);self._raise(ev,[params,msg]);if(!self.isAjaxUpload){self._clearFileInput();}self._setValidationError('file-input-new');self.$btnUpload.attr('disabled',true);return true;},_noFilesError:function(params){var self=this,label=self.minFileCount>1?self.filePlural:self.fileSingle,msg=self.msgFilesTooLess.replace('{n}',self.minFileCount).replace('{files}',label),$error=self.$errorContainer;self._addError(msg);self.isError=true;self._updateFileDetails(0);$error.fadeIn(800);self._raise('fileerror',[params,msg]);self._clearFileInput();self._setValidationError();},_parseError:function(operation,jqXHR,errorThrown,fileName){var self=this,errMsg=$.trim(errorThrown+''),textPre,text=jqXHR.responseJSON!==undefined&&jqXHR.responseJSON.error!==undefined?jqXHR.responseJSON.error:jqXHR.responseText;if(self.cancelling&&self.msgUploadAborted){errMsg=self.msgUploadAborted;}if(self.showAjaxErrorDetails&&text){text=$.trim(text.replace(/\n\s*\n/g,'\n'));textPre=text.length?'
    '+text+'
    ':'';errMsg+=errMsg?textPre:text;}if(!errMsg){errMsg=self.msgAjaxError.replace('{operation}',operation);}self.cancelling=false;return fileName?''+fileName+': '+errMsg:errMsg;},_parseFileType:function(type,name){var self=this,isValid,vType,cat,i,types=self.allowedPreviewTypes||[];if(type==='application/text-plain'){return'text';}for(i=0;i-1){ext=fname.split('.').pop();if(self.previewFileIconSettings){out=self.previewFileIconSettings[ext]||self.previewFileIconSettings[ext.toLowerCase()]||null;}if(self.previewFileExtSettings){$.each(self.previewFileExtSettings,function(key,func){if(self.previewFileIconSettings[key]&&func(ext)){out=self.previewFileIconSettings[key];return;}});}}return out;},_parseFilePreviewIcon:function(content,fname){var self=this,icn=self._getPreviewIcon(fname)||self.previewFileIcon,out=content;if(out.indexOf('{previewFileIcon}')>-1){out=out.setTokens({'previewFileIconClass':self.previewFileIconClass,'previewFileIcon':icn});}return out;},_raise:function(event,params){var self=this,e=$.Event(event);if(params!==undefined){self.$element.trigger(e,params);}else{self.$element.trigger(e);}if(e.isDefaultPrevented()||e.result===false){return false;}switch(event){case'filebatchuploadcomplete':case'filebatchuploadsuccess':case'fileuploaded':case'fileclear':case'filecleared':case'filereset':case'fileerror':case'filefoldererror':case'fileuploaderror':case'filebatchuploaderror':case'filedeleteerror':case'filecustomerror':case'filesuccessremove':break;default:if(!self.ajaxAborted){self.ajaxAborted=e.result;}break;}return true;},_listenFullScreen:function(isFullScreen){var self=this,$modal=self.$modal,$btnFull,$btnBord;if(!$modal||!$modal.length){return;}$btnFull=$modal&&$modal.find('.btn-fullscreen');$btnBord=$modal&&$modal.find('.btn-borderless');if(!$btnFull.length||!$btnBord.length){return;}$btnFull.removeClass('active').attr('aria-pressed','false');$btnBord.removeClass('active').attr('aria-pressed','false');if(isFullScreen){$btnFull.addClass('active').attr('aria-pressed','true');}else{$btnBord.addClass('active').attr('aria-pressed','true');}if($modal.hasClass('file-zoom-fullscreen')){self._maximizeZoomDialog();}else{if(isFullScreen){self._maximizeZoomDialog();}else{$btnBord.removeClass('active').attr('aria-pressed','false');}}},_listen:function(){var self=this,$el=self.$element,$form=self.$form,$cont=self.$container,fullScreenEvents;self._handler($el,'click',function(e){if($el.hasClass('file-no-browse')){if($el.data('zoneClicked')){$el.data('zoneClicked',false);}else{e.preventDefault();}}});self._handler($el,'change',$.proxy(self._change,self));if(self.showBrowse){self._handler(self.$btnFile,'click',$.proxy(self._browse,self));}self._handler($cont.find('.fileinput-remove:not([disabled])'),'click',$.proxy(self.clear,self));self._handler($cont.find('.fileinput-cancel'),'click',$.proxy(self.cancel,self));self._handler($cont.find('.fileinput-pause'),'click',$.proxy(self.pause,self));self._initDragDrop();self._handler($form,'reset',$.proxy(self.clear,self));if(!self.isAjaxUpload){self._handler($form,'submit',$.proxy(self._submitForm,self));}self._handler(self.$container.find('.fileinput-upload'),'click',$.proxy(self._uploadClick,self));self._handler($(window),'resize',function(){self._listenFullScreen(screen.width===window.innerWidth&&screen.height===window.innerHeight);});fullScreenEvents='webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange';self._handler($(document),fullScreenEvents,function(){self._listenFullScreen($h.checkFullScreen());});self._autoFitContent();self._initClickable();self._refreshPreview();},_autoFitContent:function(){var width=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,self=this,config=width<400?(self.previewSettingsSmall||self.defaults.previewSettingsSmall):(self.previewSettings||self.defaults.previewSettings),sel;$.each(config,function(cat,settings){sel='.file-preview-frame .file-preview-'+cat;self.$preview.find(sel+'.kv-preview-data,'+sel+' .kv-preview-data').css(settings);});},_scanDroppedItems:function(item,files,path){path=path||'';var self=this,i,dirReader,readDir,errorHandler=function(e){self._log($h.logMessages.badDroppedFiles);self._log(e);};if(item.isFile){item.file(function(file){files.push(file);},errorHandler);}else{if(item.isDirectory){dirReader=item.createReader();readDir=function(){dirReader.readEntries(function(entries){if(entries&&entries.length>0){for(i=0;i-1;self._zoneDragDropInit(e);if(self.isDisabled||!hasFiles){e.originalEvent.dataTransfer.effectAllowed='none';e.originalEvent.dataTransfer.dropEffect='none';return;}if(self._raise('fileDragEnter',{'sourceEvent':e,'files':dataTransfer.types.Files})){$h.addCss(self.$dropZone,'file-highlighted');}},_zoneDragLeave:function(e){var self=this;self._zoneDragDropInit(e);if(self.isDisabled){return;}if(self._raise('fileDragLeave',{'sourceEvent':e})){self.$dropZone.removeClass('file-highlighted');}},_zoneDrop:function(e){var self=this,i,$el=self.$element,dataTransfer=e.originalEvent.dataTransfer,files=dataTransfer.files,items=dataTransfer.items,folders=$h.getDragDropFolders(items),processFiles=function(){if(!self.isAjaxUpload){self.changeTriggered=true;$el.get(0).files=files;setTimeout(function(){self.changeTriggered=false;$el.trigger('change'+self.namespace);},self.processDelay);}else{self._change(e,files);}self.$dropZone.removeClass('file-highlighted');};e.preventDefault();if(self.isDisabled||$h.isEmpty(files)){return;}if(!self._raise('fileDragDrop',{'sourceEvent':e,'files':files})){return;}if(folders>0){if(!self.isAjaxUpload){self._showFolderError(folders);return;}files=[];for(i=0;i.kv-file-content img');$zoomImg=self.$preview.find('#zoom-'+id+' >.kv-file-content img');self.setImageOrientation($img,$zoomImg,config.exif.Orientation,$thumb);}i++;});},_initPreview:function(isInit){var self=this,cap=self.initialCaption||'',out;if(!self.previewCache.count(true)){self._clearPreview();if(isInit){self._setCaption(cap);}else{self._initCaption();}return;}out=self.previewCache.out();cap=isInit&&self.initialCaption?self.initialCaption:out.caption;self._setPreviewContent(out.content);self._setInitThumbAttr();self._setCaption(cap);self._initSortable();if(!$h.isEmpty(out.content)){self.$container.removeClass('file-input-new');}self._initPreviewImageOrientations();},_getZoomButton:function(type){var self=this,label=self.previewZoomButtonIcons[type],css=self.previewZoomButtonClasses[type],title=' title="'+(self.previewZoomButtonTitles[type]||'')+'" ',params=title+(type==='close'?' data-dismiss="modal" aria-hidden="true"':'');if(type==='fullscreen'||type==='borderless'||type==='toggleheader'){params+=' data-toggle="button" aria-pressed="false" autocomplete="off"';}return'';},_getModalContent:function(){var self=this;return self._getLayoutTemplate('modal').setTokens({'rtl':self.rtl?' kv-rtl':'','zoomFrameClass':self.frameClass,'heading':self.msgZoomModalHeading,'prev':self._getZoomButton('prev'),'next':self._getZoomButton('next'),'toggleheader':self._getZoomButton('toggleheader'),'fullscreen':self._getZoomButton('fullscreen'),'borderless':self._getZoomButton('borderless'),'close':self._getZoomButton('close')});},_listenModalEvent:function(event){var self=this,$modal=self.$modal,getParams=function(e){return{sourceEvent:e,previewId:$modal.data('previewId'),modal:$modal};};$modal.on(event+'.bs.modal',function(e){var $btnFull=$modal.find('.btn-fullscreen'),$btnBord=$modal.find('.btn-borderless');self._raise('filezoom'+event,getParams(e));if(event==='shown'){$btnBord.removeClass('active').attr('aria-pressed','false');$btnFull.removeClass('active').attr('aria-pressed','false');if($modal.hasClass('file-zoom-fullscreen')){self._maximizeZoomDialog();if($h.checkFullScreen()){$btnFull.addClass('active').attr('aria-pressed','true');}else{$btnBord.addClass('active').attr('aria-pressed','true');}}}});},_initZoom:function(){var self=this,$dialog,modalMain=self._getLayoutTemplate('modalMain'),modalId='#'+$h.MODAL_ID;if(!self.showPreview){return;}self.$modal=$(modalId);if(!self.$modal||!self.$modal.length){$dialog=$(document.createElement('div')).html(modalMain).insertAfter(self.$container);self.$modal=$(modalId).insertBefore($dialog);$dialog.remove();}$h.initModal(self.$modal);self.$modal.html(self._getModalContent());$.each($h.MODAL_EVENTS,function(key,event){self._listenModalEvent(event);});},_initZoomButtons:function(){var self=this,previewId=self.$modal.data('previewId')||'',$first,$last,thumbs=self.getFrames().toArray(),len=thumbs.length,$prev=self.$modal.find('.btn-prev'),$next=self.$modal.find('.btn-next');if(thumbs.length<2){$prev.hide();$next.hide();return;}else{$prev.show();$next.show();}if(!len){return;}$first=$(thumbs[0]);$last=$(thumbs[len-1]);$prev.removeAttr('disabled');$next.removeAttr('disabled');if($first.length&&$first.attr('id')===previewId){$prev.attr('disabled',true);}if($last.length&&$last.attr('id')===previewId){$next.attr('disabled',true);}},_maximizeZoomDialog:function(){var self=this,$modal=self.$modal,$head=$modal.find('.modal-header:visible'),$foot=$modal.find('.modal-footer:visible'),$body=$modal.find('.modal-body'),h=$(window).height(),diff=0;$modal.addClass('file-zoom-fullscreen');if($head&&$head.length){h-=$head.outerHeight(true);}if($foot&&$foot.length){h-=$foot.outerHeight(true);}if($body&&$body.length){diff=$body.outerHeight(true)-$body.height();h-=diff;}$modal.find('.kv-zoom-body').height(h);},_resizeZoomDialog:function(fullScreen){var self=this,$modal=self.$modal,$btnFull=$modal.find('.btn-fullscreen'),$btnBord=$modal.find('.btn-borderless');if($modal.hasClass('file-zoom-fullscreen')){$h.toggleFullScreen(false);if(!fullScreen){if(!$btnFull.hasClass('active')){$modal.removeClass('file-zoom-fullscreen');self.$modal.find('.kv-zoom-body').css('height',self.zoomModalHeight);}else{$btnFull.removeClass('active').attr('aria-pressed','false');}}else{if(!$btnFull.hasClass('active')){$modal.removeClass('file-zoom-fullscreen');self._resizeZoomDialog(true);if($btnBord.hasClass('active')){$btnBord.removeClass('active').attr('aria-pressed','false');}}}}else{if(!fullScreen){self._maximizeZoomDialog();return;}$h.toggleFullScreen(true);}$modal.focus();},_setZoomContent:function($frame,animate){var self=this,$content,tmplt,body,title,$body,$dataEl,config,previewId=$frame.attr('id'),$zoomPreview=self.$preview.find('#zoom-'+previewId),$modal=self.$modal,$tmp,$btnFull=$modal.find('.btn-fullscreen'),$btnBord=$modal.find('.btn-borderless'),cap,size,$btnTogh=$modal.find('.btn-toggleheader');tmplt=$zoomPreview.attr('data-template')||'generic';$content=$zoomPreview.find('.kv-file-content');body=$content.length?$content.html():'';cap=$frame.data('caption')||'';size=$frame.data('size')||'';title=cap+' '+size;$modal.find('.kv-zoom-title').attr('title',$('
    ').html(title).text()).html(title);$body=$modal.find('.kv-zoom-body');$modal.removeClass('kv-single-content');if(animate){$tmp=$body.addClass('file-thumb-loading').clone().insertAfter($body);$body.html(body).hide();$tmp.fadeOut('fast',function(){$body.fadeIn('fast',function(){$body.removeClass('file-thumb-loading');});$tmp.remove();});}else{$body.html(body);}config=self.previewZoomSettings[tmplt];if(config){$dataEl=$body.find('.kv-preview-data');$h.addCss($dataEl,'file-zoom-detail');$.each(config,function(key,value){$dataEl.css(key,value);if(($dataEl.attr('width')&&key==='width')||($dataEl.attr('height')&&key==='height')){$dataEl.removeAttr(key);}});}$modal.data('previewId',previewId);self._handler($modal.find('.btn-prev'),'click',function(){self._zoomSlideShow('prev',previewId);});self._handler($modal.find('.btn-next'),'click',function(){self._zoomSlideShow('next',previewId);});self._handler($btnFull,'click',function(){self._resizeZoomDialog(true);});self._handler($btnBord,'click',function(){self._resizeZoomDialog(false);});self._handler($btnTogh,'click',function(){var $header=$modal.find('.modal-header'),$floatBar=$modal.find('.modal-body .floating-buttons'),ht,$actions=$header.find('.kv-zoom-actions'),resize=function(height){var $body=self.$modal.find('.kv-zoom-body'),h=self.zoomModalHeight;if($modal.hasClass('file-zoom-fullscreen')){h=$body.outerHeight(true);if(!height){h=h-$header.outerHeight(true);}}$body.css('height',height?h+height:h);};if($header.is(':visible')){ht=$header.outerHeight(true);$header.slideUp('slow',function(){$actions.find('.btn').appendTo($floatBar);resize(ht);});}else{$floatBar.find('.btn').appendTo($actions);$header.slideDown('slow',function(){resize();});}$modal.focus();});self._handler($modal,'keydown',function(e){var key=e.which||e.keyCode,$prev=$(this).find('.btn-prev'),$next=$(this).find('.btn-next'),vId=$(this).data('previewId'),vPrevKey=self.rtl?39:37,vNextKey=self.rtl?37:39;if(key===vPrevKey&&$prev.length&&!$prev.attr('disabled')){self._zoomSlideShow('prev',vId);}if(key===vNextKey&&$next.length&&!$next.attr('disabled')){self._zoomSlideShow('next',vId);}});},_zoomPreview:function($btn){var self=this,$frame,$modal=self.$modal;if(!$btn.length){throw'Cannot zoom to detailed preview!';}$h.initModal($modal);$modal.html(self._getModalContent());$frame=$btn.closest($h.FRAMES);self._setZoomContent($frame);$modal.modal('show');self._initZoomButtons();},_zoomSlideShow:function(dir,previewId){var self=this,$btn=self.$modal.find('.kv-zoom-actions .btn-'+dir),$targFrame,i,thumbs=self.getFrames().toArray(),len=thumbs.length,out;if($btn.attr('disabled')){return;}for(i=0;i=len||!thumbs[out]){return;}$targFrame=$(thumbs[out]);if($targFrame.length){self._setZoomContent($targFrame,true);}self._initZoomButtons();self._raise('filezoom'+dir,{'previewId':previewId,modal:self.$modal});},_initZoomButton:function(){var self=this;self.$preview.find('.kv-file-zoom').each(function(){var $el=$(this);self._handler($el,'click',function(){self._zoomPreview($el);});});},_inputFileCount:function(){return this.$element.get(0).files.length;},_refreshPreview:function(){var self=this,files;if((!self._inputFileCount()&&!self.isAjaxUpload)||!self.showPreview||!self.isPreviewable){return;}if(self.isAjaxUpload){if(self.fileManager.count()>0){files=$.extend(true,{},self.fileManager.stack);self.fileManager.clear();self._clearFileInput();}else{files=self.$element.get(0).files;}}else{files=self.$element.get(0).files;}if(files&&files.length){self.readFiles(files);self._setFileDropZoneTitle();}},_clearObjects:function($el){$el.find('video audio').each(function(){this.pause();$(this).remove();});$el.find('img object div').each(function(){$(this).remove();});},_clearFileInput:function(){var self=this,$el=self.$element,$srcFrm,$tmpFrm,$tmpEl;if(!self._inputFileCount()){return;}$srcFrm=$el.closest('form');$tmpFrm=$(document.createElement('form'));$tmpEl=$(document.createElement('div'));$el.before($tmpEl);if($srcFrm.length){$srcFrm.after($tmpFrm);}else{$tmpEl.after($tmpFrm);}$tmpFrm.append($el).trigger('reset');$tmpEl.before($el).remove();$tmpFrm.remove();},_resetUpload:function(){var self=this;self.uploadCache={content:[],config:[],tags:[],append:true};self.$btnUpload.removeAttr('disabled');self._setProgress(0);self.$progress.hide();self._resetErrors(false);self._initAjax();self.fileManager.clearImages();self._resetCanvas();self.cacheInitialPreview={};if(self.overwriteInitial){self.initialPreview=[];self.initialPreviewConfig=[];self.initialPreviewThumbTags=[];self.previewCache.data={content:[],config:[],tags:[]};}},_resetCanvas:function(){var self=this;if(self.canvas&&self.imageCanvasContext){self.imageCanvasContext.clearRect(0,0,self.canvas.width,self.canvas.height);}},_hasInitialPreview:function(){var self=this;return!self.overwriteInitial&&self.previewCache.count(true);},_resetPreview:function(){var self=this,out,cap;if(self.previewCache.count(true)){out=self.previewCache.out();self._setPreviewContent(out.content);self._setInitThumbAttr();cap=self.initialCaption?self.initialCaption:out.caption;self._setCaption(cap);}else{self._clearPreview();self._initCaption();}if(self.showPreview){self._initZoom();self._initSortable();}},_clearDefaultPreview:function(){var self=this;self.$preview.find('.file-default-preview').remove();},_validateDefaultPreview:function(){var self=this;if(!self.showPreview||$h.isEmpty(self.defaultPreviewContent)){return;}self._setPreviewContent('
    '+self.defaultPreviewContent+'
    ');self.$container.removeClass('file-input-new');self._initClickable();},_resetPreviewThumbs:function(isAjax){var self=this,out;if(isAjax){self._clearPreview();self.clearFileStack();return;}if(self._hasInitialPreview()){out=self.previewCache.out();self._setPreviewContent(out.content);self._setInitThumbAttr();self._setCaption(out.caption);self._initPreviewActions();}else{self._clearPreview();}},_getLayoutTemplate:function(t){var self=this,template=self.layoutTemplates[t];if($h.isEmpty(self.customLayoutTags)){return template;}return $h.replaceTags(template,self.customLayoutTags);},_getPreviewTemplate:function(t){var self=this,template=self.previewTemplates[t];if($h.isEmpty(self.customPreviewTags)){return template;}return $h.replaceTags(template,self.customPreviewTags);},_getOutData:function(formdata,jqXHR,responseData,filesData){var self=this;jqXHR=jqXHR||{};responseData=responseData||{};filesData=filesData||self.fileManager.list();return{formdata:formdata,files:filesData,filenames:self.filenames,filescount:self.getFilesCount(),extra:self._getExtraData(),response:responseData,reader:self.reader,jqXHR:jqXHR};},_getMsgSelected:function(n){var self=this,strFiles=n===1?self.fileSingle:self.filePlural;return n>0?self.msgSelected.replace('{n}',n).replace('{files}',strFiles):self.msgNoFilesSelected;},_getFrame:function(id){var self=this,$frame=$('#'+id);if(!$frame.length){self._log($h.logMessages.invalidThumb,{id:id});return null;}return $frame;},_getThumbs:function(css){css=css||'';return this.getFrames(':not(.file-preview-initial)'+css);},_getExtraData:function(fileId,index){var self=this,data=self.uploadExtraData;if(typeof self.uploadExtraData==='function'){data=self.uploadExtraData(fileId,index);}return data;},_initXhr:function(xhrobj,fileId,fileCount){var self=this,fm=self.fileManager,func=function(event){var pct=0,total=event.total,loaded=event.loaded||event.position,stats=fm.getUploadStats(fileId,loaded,total);if(event.lengthComputable&&!self.enableResumableUpload){pct=$h.round(loaded/total*100);}if(fileId){self._setFileUploadStats(fileId,pct,fileCount,stats);}else{self._setProgress(pct,null,null,self._getStats(stats));}self._raise('fileajaxprogress',[stats]);};if(xhrobj.upload){if(self.progressDelay){func=$h.debounce(func,self.progressDelay);}xhrobj.upload.addEventListener('progress',func,false);}return xhrobj;},_initAjaxSettings:function(){var self=this;self._ajaxSettings=$.extend(true,{},self.ajaxSettings);self._ajaxDeleteSettings=$.extend(true,{},self.ajaxDeleteSettings);},_mergeAjaxCallback:function(funcName,srcFunc,type){var self=this,settings=self._ajaxSettings,flag=self.mergeAjaxCallbacks,targFunc;if(type==='delete'){settings=self._ajaxDeleteSettings;flag=self.mergeAjaxDeleteCallbacks;}targFunc=settings[funcName];if(flag&&typeof targFunc==='function'){if(flag==='before'){settings[funcName]=function(){targFunc.apply(this,arguments);srcFunc.apply(this,arguments);};}else{settings[funcName]=function(){srcFunc.apply(this,arguments);targFunc.apply(this,arguments);};}}else{settings[funcName]=srcFunc;}},_ajaxSubmit:function(fnBefore,fnSuccess,fnComplete,fnError,formdata,fileId,index,vUrl){var self=this,settings,defaults,data,processQueue;if(!self._raise('filepreajax',[formdata,fileId,index])){return;}formdata.append('initialPreview',JSON.stringify(self.initialPreview));formdata.append('initialPreviewConfig',JSON.stringify(self.initialPreviewConfig));formdata.append('initialPreviewThumbTags',JSON.stringify(self.initialPreviewThumbTags));self._initAjaxSettings();self._mergeAjaxCallback('beforeSend',fnBefore);self._mergeAjaxCallback('success',fnSuccess);self._mergeAjaxCallback('complete',fnComplete);self._mergeAjaxCallback('error',fnError);vUrl=vUrl||self.uploadUrlThumb||self.uploadUrl;if(typeof vUrl==='function'){vUrl=vUrl();}data=self._getExtraData(fileId,index)||{};if(typeof data==='object'){$.each(data,function(key,value){formdata.append(key,value);});}defaults={xhr:function(){var xhrobj=$.ajaxSettings.xhr();return self._initXhr(xhrobj,fileId,self.fileManager.count());},url:self._encodeURI(vUrl),type:'POST',dataType:'json',data:formdata,cache:false,processData:false,contentType:false};settings=$.extend(true,{},defaults,self._ajaxSettings);self.ajaxQueue.push(settings);processQueue=function(){var config,xhr;if(self.ajaxCurrentThreads0){self.hasInitData=true;content=out.initialPreview||[];config=out.initialPreviewConfig||[];tags=out.initialPreviewThumbTags||[];append=out.append===undefined||out.append;if(content.length>0&&!$h.isArray(content)){content=content.split(self.initialPreviewDelimiter);}if(content.length){self._mergeArray('initialPreview',content);self._mergeArray('initialPreviewConfig',config);self._mergeArray('initialPreviewThumbTags',tags);}if($thumb!==undefined){if(!allFiles){index=self.previewCache.add(content[0],config[0],tags[0],append);data=self.previewCache.get(index,false);$div=$(document.createElement('div')).html(data).hide().insertAfter($thumb);$newCache=$div.find('.kv-zoom-cache');if($newCache&&$newCache.length){$newCache.insertAfter($thumb);}$thumb.fadeOut('slow',function(){var $newThumb=$div.find('.file-preview-frame');if($newThumb&&$newThumb.length){$newThumb.insertBefore($thumb).fadeIn('slow').css('display:inline-block');}self._initPreviewActions();self._clearFileInput();$h.cleanZoomCache(self.$preview.find('#zoom-'+$thumb.attr('id')));$thumb.remove();$div.remove();self._initSortable();});}else{i=$thumb.attr('data-fileindex');self.uploadCache.content[i]=content[0];self.uploadCache.config[i]=config[0]||[];self.uploadCache.tags[i]=tags[0]||[];self.uploadCache.append=append;}}else{self.previewCache.set(content,config,tags,append);self._initPreview();self._initPreviewActions();}}},_initSuccessThumbs:function(){var self=this;if(!self.showPreview){return;}self._getThumbs($h.FRAMES+'.file-preview-success').each(function(){var $thumb=$(this),$preview=self.$preview,$remove=$thumb.find('.kv-file-remove');$remove.removeAttr('disabled');self._handler($remove,'click',function(){var id=$thumb.attr('id'),out=self._raise('filesuccessremove',[id,$thumb.attr('data-fileindex')]);$h.cleanMemory($thumb);if(out===false){return;}$thumb.fadeOut('slow',function(){$h.cleanZoomCache($preview.find('#zoom-'+id));$thumb.remove();if(!self.getFrames().length){self.reset();}});});});},_updateInitialPreview:function(){var self=this,u=self.uploadCache,i,j,len=0,data=self.cacheInitialPreview;if(data&&data.content){len=data.content.length;}if(self.showPreview){self.previewCache.set(u.content,u.config,u.tags,u.append);if(len){for(i=0;i0||!$.isEmptyObject(self.uploadExtraData),uploadFailed,$prog,fnBefore,errMsg,fnSuccess,fnComplete,fnError,updateUploadLog,op=self.ajaxOperations.uploadThumb,fileObj=fm.getFile(id),params={id:previewId,index:i,fileId:id},fileName=self.fileManager.getFileName(id,true);if(self.enableResumableUpload){return;}if(self.showPreview){$thumb=self.fileManager.getThumb(id);$prog=$thumb.find('.file-thumb-progress');$btnUpload=$thumb.find('.kv-file-upload');$btnDelete=$thumb.find('.kv-file-remove');$prog.show();}if(count===0||!hasPostData||(self.showPreview&&$btnUpload&&$btnUpload.hasClass('disabled'))||self._abort(params)){return;}updateUploadLog=function(){if(!uploadFailed){fm.removeFile(id);}else{fm.errors.push(id);}fm.setProcessed(id);if(fm.isProcessed()){self.fileBatchCompleted=true;}};chkComplete=function(){var $initThumbs;if(!self.fileBatchCompleted){return;}setTimeout(function(){var triggerReset=fm.count()===0,errCount=fm.errors.length;self._updateInitialPreview();self.unlock(triggerReset);if(triggerReset){self._clearFileInput();}$initThumbs=self.$preview.find('.file-preview-initial');if(self.uploadAsync&&$initThumbs.length){$h.addCss($initThumbs,$h.SORT_CSS);self._initSortable();}self._raise('filebatchuploadcomplete',[fm.stack,self._getExtraData()]);if(!self.retryErrorUploads||errCount===0){fm.clear();}self._setProgress(101);self.ajaxAborted=false;},self.processDelay);};fnBefore=function(jqXHR){outData=self._getOutData(formdata,jqXHR);fm.initStats(id);self.fileBatchCompleted=false;if(!isBatch){self.ajaxAborted=false;}if(self.showPreview){if(!$thumb.hasClass('file-preview-success')){self._setThumbStatus($thumb,'Loading');$h.addCss($thumb,'file-uploading');}$btnUpload.attr('disabled',true);$btnDelete.attr('disabled',true);}if(!isBatch){self.lock();}if(fm.errors.indexOf(id)!==-1){delete fm.errors[id];}self._raise('filepreupload',[outData,previewId,i]);$.extend(true,params,outData);if(self._abort(params)){jqXHR.abort();if(!isBatch){self._setThumbStatus($thumb,'New');$thumb.removeClass('file-uploading');$btnUpload.removeAttr('disabled');$btnDelete.removeAttr('disabled');self.unlock();}self._setProgressCancelled();}};fnSuccess=function(data,textStatus,jqXHR){var pid=self.showPreview&&$thumb.attr('id')?$thumb.attr('id'):previewId;outData=self._getOutData(formdata,jqXHR,data);$.extend(true,params,outData);setTimeout(function(){if($h.isEmpty(data)||$h.isEmpty(data.error)){if(self.showPreview){self._setThumbStatus($thumb,'Success');$btnUpload.hide();self._initUploadSuccess(data,$thumb,isBatch);self._setProgress(101,$prog);}self._raise('fileuploaded',[outData,pid,i]);if(!isBatch){self.fileManager.remove($thumb);}else{updateUploadLog();}}else{uploadFailed=true;errMsg=self._parseError(op,jqXHR,self.msgUploadError,self.fileManager.getFileName(id));self._showFileError(errMsg,params);self._setPreviewError($thumb,true);if(!self.retryErrorUploads){$btnUpload.hide();}if(isBatch){updateUploadLog();}self._setProgress(101,$('#'+pid).find('.file-thumb-progress'),self.msgUploadError);}},self.processDelay);};fnComplete=function(){setTimeout(function(){if(self.showPreview){$btnUpload.removeAttr('disabled');$btnDelete.removeAttr('disabled');$thumb.removeClass('file-uploading');}if(!isBatch){self.unlock(false);self._clearFileInput();}else{chkComplete();}self._initSuccessThumbs();},self.processDelay);};fnError=function(jqXHR,textStatus,errorThrown){errMsg=self._parseError(op,jqXHR,errorThrown,self.fileManager.getFileName(id));uploadFailed=true;setTimeout(function(){if(isBatch){updateUploadLog();}self.fileManager.setProgress(id,100);self._setPreviewError($thumb,true);if(!self.retryErrorUploads){$btnUpload.hide();}$.extend(true,params,self._getOutData(formdata,jqXHR));self._setProgress(101,$prog,self.msgAjaxProgressError.replace('{operation}',op));self._setProgress(101,$thumb.find('.file-thumb-progress'),self.msgUploadError);self._showFileError(errMsg,params);},self.processDelay);};formdata.append(self.uploadFileAttr,fileObj.file,fileName);self._setUploadData(formdata,{fileId:id});self._ajaxSubmit(fnBefore,fnSuccess,fnComplete,fnError,formdata,id,i);},_uploadBatch:function(){var self=this,fm=self.fileManager,total=fm.total(),params={},fnBefore,fnSuccess,fnError,fnComplete,hasPostData=total>0||!$.isEmptyObject(self.uploadExtraData),errMsg,setAllUploaded,formdata=new FormData(),op=self.ajaxOperations.uploadBatch;if(total===0||!hasPostData||self._abort(params)){return;}setAllUploaded=function(){self.fileManager.clear();self._clearFileInput();};fnBefore=function(jqXHR){self.lock();fm.initStats();var outData=self._getOutData(formdata,jqXHR);self.ajaxAborted=false;if(self.showPreview){self._getThumbs().each(function(){var $thumb=$(this),$btnUpload=$thumb.find('.kv-file-upload'),$btnDelete=$thumb.find('.kv-file-remove');if(!$thumb.hasClass('file-preview-success')){self._setThumbStatus($thumb,'Loading');$h.addCss($thumb,'file-uploading');}$btnUpload.attr('disabled',true);$btnDelete.attr('disabled',true);});}self._raise('filebatchpreupload',[outData]);if(self._abort(outData)){jqXHR.abort();self._getThumbs().each(function(){var $thumb=$(this),$btnUpload=$thumb.find('.kv-file-upload'),$btnDelete=$thumb.find('.kv-file-remove');if($thumb.hasClass('file-preview-loading')){self._setThumbStatus($thumb,'New');$thumb.removeClass('file-uploading');}$btnUpload.removeAttr('disabled');$btnDelete.removeAttr('disabled');});self._setProgressCancelled();}};fnSuccess=function(data,textStatus,jqXHR){var outData=self._getOutData(formdata,jqXHR,data),key=0,$thumbs=self._getThumbs(':not(.file-preview-success)'),keys=$h.isEmpty(data)||$h.isEmpty(data.errorkeys)?[]:data.errorkeys;if($h.isEmpty(data)||$h.isEmpty(data.error)){self._raise('filebatchuploadsuccess',[outData]);setAllUploaded();if(self.showPreview){$thumbs.each(function(){var $thumb=$(this);self._setThumbStatus($thumb,'Success');$thumb.removeClass('file-uploading');$thumb.find('.kv-file-upload').hide().removeAttr('disabled');});self._initUploadSuccess(data);}else{self.reset();}self._setProgress(101);}else{if(self.showPreview){$thumbs.each(function(){var $thumb=$(this);$thumb.removeClass('file-uploading');$thumb.find('.kv-file-upload').removeAttr('disabled');$thumb.find('.kv-file-remove').removeAttr('disabled');if(keys.length===0||$.inArray(key,keys)!==-1){self._setPreviewError($thumb,true);if(!self.retryErrorUploads){$thumb.find('.kv-file-upload').hide();self.fileManager.remove($thumb);}}else{$thumb.find('.kv-file-upload').hide();self._setThumbStatus($thumb,'Success');self.fileManager.remove($thumb);}if(!$thumb.hasClass('file-preview-error')||self.retryErrorUploads){key++;}});self._initUploadSuccess(data);}errMsg=self._parseError(op,jqXHR,self.msgUploadError);self._showFileError(errMsg,outData,'filebatchuploaderror');self._setProgress(101,self.$progress,self.msgUploadError);}};fnComplete=function(){self.unlock();self._initSuccessThumbs();self._clearFileInput();self._raise('filebatchuploadcomplete',[self.fileManager.stack,self._getExtraData()]);};fnError=function(jqXHR,textStatus,errorThrown){var outData=self._getOutData(formdata,jqXHR);errMsg=self._parseError(op,jqXHR,errorThrown);self._showFileError(errMsg,outData,'filebatchuploaderror');self.uploadFileCount=total-1;if(!self.showPreview){return;}self._getThumbs().each(function(){var $thumb=$(this);$thumb.removeClass('file-uploading');if(self.fileManager.getFile($thumb.attr('data-fileid'))){self._setPreviewError($thumb);}});self._getThumbs().removeClass('file-uploading');self._getThumbs(' .kv-file-upload').removeAttr('disabled');self._getThumbs(' .kv-file-delete').removeAttr('disabled');self._setProgress(101,self.$progress,self.msgAjaxProgressError.replace('{operation}',op));};var ctr=0;$.each(self.fileManager.stack,function(key,data){if(!$h.isEmpty(data.file)){formdata.append(self.uploadFileAttr,data.file,(data.nameFmt||('untitled_'+ctr)));}ctr++;});self._ajaxSubmit(fnBefore,fnSuccess,fnComplete,fnError,formdata);},_uploadExtraOnly:function(){var self=this,params={},fnBefore,fnSuccess,fnComplete,fnError,formdata=new FormData(),errMsg,op=self.ajaxOperations.uploadExtra;if(self._abort(params)){return;}fnBefore=function(jqXHR){self.lock();var outData=self._getOutData(formdata,jqXHR);self._raise('filebatchpreupload',[outData]);self._setProgress(50);params.data=outData;params.xhr=jqXHR;if(self._abort(params)){jqXHR.abort();self._setProgressCancelled();}};fnSuccess=function(data,textStatus,jqXHR){var outData=self._getOutData(formdata,jqXHR,data);if($h.isEmpty(data)||$h.isEmpty(data.error)){self._raise('filebatchuploadsuccess',[outData]);self._clearFileInput();self._initUploadSuccess(data);self._setProgress(101);}else{errMsg=self._parseError(op,jqXHR,self.msgUploadError);self._showFileError(errMsg,outData,'filebatchuploaderror');}};fnComplete=function(){self.unlock();self._clearFileInput();self._raise('filebatchuploadcomplete',[self.fileManager.stack,self._getExtraData()]);};fnError=function(jqXHR,textStatus,errorThrown){var outData=self._getOutData(formdata,jqXHR);errMsg=self._parseError(op,jqXHR,errorThrown);params.data=outData;self._showFileError(errMsg,outData,'filebatchuploaderror');self._setProgress(101,self.$progress,self.msgAjaxProgressError.replace('{operation}',op));};self._ajaxSubmit(fnBefore,fnSuccess,fnComplete,fnError,formdata);},_deleteFileIndex:function($frame){var self=this,ind=$frame.attr('data-fileindex'),rev=self.reversePreviewOrder;if(ind.substring(0,5)==='init_'){ind=parseInt(ind.replace('init_',''));self.initialPreview=$h.spliceArray(self.initialPreview,ind,rev);self.initialPreviewConfig=$h.spliceArray(self.initialPreviewConfig,ind,rev);self.initialPreviewThumbTags=$h.spliceArray(self.initialPreviewThumbTags,ind,rev);self.getFrames().each(function(){var $nFrame=$(this),nInd=$nFrame.attr('data-fileindex');if(nInd.substring(0,5)==='init_'){nInd=parseInt(nInd.replace('init_',''));if(nInd>ind){nInd--;$nFrame.attr('data-fileindex','init_'+nInd);}}});if(self.uploadAsync||self.enableResumableUpload){self.cacheInitialPreview=self.getPreview();}}},_initFileActions:function(){var self=this,$preview=self.$preview;if(!self.showPreview){return;}self._initZoomButton();self.getFrames(' .kv-file-remove').each(function(){var $el=$(this),$frame=$el.closest($h.FRAMES),hasError,id=$frame.attr('id'),ind=$frame.attr('data-fileindex'),n,cap,status;self._handler($el,'click',function(){status=self._raise('filepreremove',[id,ind]);if(status===false||!self._validateMinCount()){return false;}hasError=$frame.hasClass('file-preview-error');$h.cleanMemory($frame);$frame.fadeOut('slow',function(){$h.cleanZoomCache($preview.find('#zoom-'+id));self.fileManager.remove($frame);self._clearObjects($frame);$frame.remove();if(id&&hasError){self.$errorContainer.find('li[data-thumb-id="'+id+'"]').fadeOut('fast',function(){$(this).remove();if(!self._errorsExist()){self._resetErrors();}});}self._clearFileInput();var chk=self.previewCache.count(true),len=self.fileManager.count(),file,hasThumb=self.showPreview&&self.getFrames().length;if(len===0&&chk===0&&!hasThumb){self.reset();}else{n=chk+len;if(n>1){cap=self._getMsgSelected(n);}else{file=self.fileManager.getFirstFile();cap=file?file.nameFmt:'_';}self._setCaption(cap);}self._raise('fileremoved',[id,ind]);});});});self.getFrames(' .kv-file-upload').each(function(){var $el=$(this);self._handler($el,'click',function(){var $frame=$el.closest($h.FRAMES),id=$frame.attr('data-fileid');self.$progress.hide();if($frame.hasClass('file-preview-error')&&!self.retryErrorUploads){return;}self._uploadSingle(self.fileManager.getIndex(id),id,false);});});},_initPreviewActions:function(){var self=this,$preview=self.$preview,deleteExtraData=self.deleteExtraData||{},btnRemove=$h.FRAMES+' .kv-file-remove',settings=self.fileActionSettings,origClass=settings.removeClass,errClass=settings.removeErrorClass,resetProgress=function(){var hasFiles=self.isAjaxUpload?self.previewCache.count(true):self._inputFileCount();if(!self.getFrames().length&&!hasFiles){self._setCaption('');self.reset();self.initialCaption='';}};self._initZoomButton();$preview.find(btnRemove).each(function(){var $el=$(this),vUrl=$el.data('url')||self.deleteUrl,vKey=$el.data('key'),errMsg,fnBefore,fnSuccess,fnError,op=self.ajaxOperations.deleteThumb;if($h.isEmpty(vUrl)||vKey===undefined){return;}if(typeof vUrl==='function'){vUrl=vUrl();}var $frame=$el.closest($h.FRAMES),cache=self.previewCache.data,settings,params,config,fileName,extraData,index=$frame.attr('data-fileindex');index=parseInt(index.replace('init_',''));config=$h.isEmpty(cache.config)&&$h.isEmpty(cache.config[index])?null:cache.config[index];extraData=$h.isEmpty(config)||$h.isEmpty(config.extra)?deleteExtraData:config.extra;fileName=config.filename||config.caption||'';if(typeof extraData==='function'){extraData=extraData();}params={id:$el.attr('id'),key:vKey,extra:extraData};fnBefore=function(jqXHR){self.ajaxAborted=false;self._raise('filepredelete',[vKey,jqXHR,extraData]);if(self._abort()){jqXHR.abort();}else{$el.removeClass(errClass);$h.addCss($frame,'file-uploading');$h.addCss($el,'disabled '+origClass);}};fnSuccess=function(data,textStatus,jqXHR){var n,cap;if(!$h.isEmpty(data)&&!$h.isEmpty(data.error)){params.jqXHR=jqXHR;params.response=data;errMsg=self._parseError(op,jqXHR,self.msgDeleteError,fileName);self._showFileError(errMsg,params,'filedeleteerror');$frame.removeClass('file-uploading');$el.removeClass('disabled '+origClass).addClass(errClass);resetProgress();return;}$frame.removeClass('file-uploading').addClass('file-deleted');$frame.fadeOut('slow',function(){index=parseInt(($frame.attr('data-fileindex')).replace('init_',''));self.previewCache.unset(index);self._deleteFileIndex($frame);n=self.previewCache.count(true);cap=n>0?self._getMsgSelected(n):'';self._setCaption(cap);self._raise('filedeleted',[vKey,jqXHR,extraData]);$h.cleanZoomCache($preview.find('#zoom-'+$frame.attr('id')));self._clearObjects($frame);$frame.remove();resetProgress();});};fnError=function(jqXHR,textStatus,errorThrown){var errMsg=self._parseError(op,jqXHR,errorThrown,fileName);params.jqXHR=jqXHR;params.response={};self._showFileError(errMsg,params,'filedeleteerror');$frame.removeClass('file-uploading');$el.removeClass('disabled '+origClass).addClass(errClass);resetProgress();};self._initAjaxSettings();self._mergeAjaxCallback('beforeSend',fnBefore,'delete');self._mergeAjaxCallback('success',fnSuccess,'delete');self._mergeAjaxCallback('error',fnError,'delete');settings=$.extend(true,{},{url:self._encodeURI(vUrl),type:'POST',dataType:'json',data:$.extend(true,{},{key:vKey},extraData)},self._ajaxDeleteSettings);self._handler($el,'click',function(){if(!self._validateMinCount()){return false;}self.ajaxAborted=false;self._raise('filebeforedelete',[vKey,extraData]);if(self.ajaxAborted instanceof Promise){self.ajaxAborted.then(function(result){if(!result){$.ajax(settings);}});}else{if(!self.ajaxAborted){$.ajax(settings);}}});});},_hideFileIcon:function(){var self=this;if(self.overwriteInitial){self.$captionContainer.removeClass('icon-visible');}},_showFileIcon:function(){var self=this;$h.addCss(self.$captionContainer,'icon-visible');},_getSize:function(bytes,sizes){var self=this,size=parseFloat(bytes),i,func=self.fileSizeGetter,out;if(!$.isNumeric(bytes)||!$.isNumeric(size)){return'';}if(typeof func==='function'){out=func(size);}else{if(size===0){out='0.00 B';}else{i=Math.floor(Math.log(size)/Math.log(1024));if(!sizes){sizes=['B','KB','MB','GB','TB','PB','EB','ZB','YB'];}out=(size/Math.pow(1024,i)).toFixed(2)*1+' '+sizes[i];}}return self._getLayoutTemplate('size').replace('{sizeText}',out);},_getFileType:function(ftype){var self=this;return self.mimeTypeAliases[ftype]||ftype;},_generatePreviewTemplate:function(cat,data,fname,ftype,previewId,fileId,isError,size,frameClass,foot,ind,templ,attrs,zoomData){var self=this,caption=self.slug(fname),prevContent,zoomContent='',styleAttribs='',screenW=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,config,newCat=self.preferIconicPreview?'other':cat,title=caption,alt=caption,footer=foot||self._renderFileFooter(cat,caption,size,'auto',isError),hasIconSetting=self._getPreviewIcon(fname),typeCss='type-default',forcePrevIcon=hasIconSetting&&self.preferIconicPreview,forceZoomIcon=hasIconSetting&&self.preferIconicZoomPreview,getContent;config=screenW<400?(self.previewSettingsSmall[newCat]||self.defaults.previewSettingsSmall[newCat]):(self.previewSettings[newCat]||self.defaults.previewSettings[newCat]);if(config){$.each(config,function(key,val){styleAttribs+=key+':'+val+';';});}getContent=function(c,d,zoom,frameCss){var id=zoom?'zoom-'+previewId:previewId,tmplt=self._getPreviewTemplate(c),css=(frameClass||'')+' '+frameCss;if(self.frameClass){css=self.frameClass+' '+css;}if(zoom){css=css.replace(' '+$h.SORT_CSS,'');}tmplt=self._parseFilePreviewIcon(tmplt,fname);if(c==='text'){d=$h.htmlEncode(d);}if(cat==='object'&&!ftype){$.each(self.defaults.fileTypeSettings,function(key,func){if(key==='object'||key==='other'){return;}if(func(fname,ftype)){typeCss='type-'+key;}});}if(!$h.isEmpty(attrs)){if(attrs.title!==undefined&&attrs.title!==null){title=attrs.title;}if(attrs.alt!==undefined&&attrs.alt!==null){title=attrs.alt;}}return tmplt.setTokens({'previewId':id,'caption':caption,'title':title,'alt':alt,'frameClass':css,'type':self._getFileType(ftype),'fileindex':ind,'fileid':fileId||'','typeCss':typeCss,'footer':footer,'data':d,'template':templ||cat,'style':styleAttribs?'style="'+styleAttribs+'"':''});};ind=ind||previewId.slice(previewId.lastIndexOf('-')+1);if(self.fileActionSettings.showZoom){zoomContent=getContent((forceZoomIcon?'other':cat),zoomData?zoomData:data,true,'kv-zoom-thumb');}zoomContent='\n'+self._getLayoutTemplate('zoomCache').replace('{zoomContent}',zoomContent);if(typeof self.sanitizeZoomCache==='function'){zoomContent=self.sanitizeZoomCache(zoomContent);}prevContent=getContent((forcePrevIcon?'other':cat),data,false,'kv-preview-thumb');return prevContent+zoomContent;},_addToPreview:function($preview,content){var self=this;return self.reversePreviewOrder?$preview.prepend(content):$preview.append(content);},_previewDefault:function(file,previewId,isDisabled){var self=this,$preview=self.$preview;if(!self.showPreview){return;}var fname=$h.getFileName(file),ftype=file?file.type:'',content,size=file.size||0,caption=self._getFileName(file,''),isError=isDisabled===true&&!self.isAjaxUpload,data=$h.createObjectURL(file),fileId=self.fileManager.getId(file);self._clearDefaultPreview();content=self._generatePreviewTemplate('other',data,fname,ftype,previewId,fileId,isError,size);self._addToPreview($preview,content);self._setThumbAttr(previewId,caption,size);if(isDisabled===true&&self.isAjaxUpload){self._setThumbStatus($('#'+previewId),'Error');}},canPreview:function(file){var self=this;if(!file||!self.showPreview||!self.$preview||!self.$preview.length){return false;}var name=file.name||'',type=file.type||'',size=(file.size||0)/1000,cat=self._parseFileType(type,name),allowedTypes,allowedMimes,allowedExts,skipPreview,types=self.allowedPreviewTypes,mimes=self.allowedPreviewMimeTypes,exts=self.allowedPreviewExtensions||[],dTypes=self.disabledPreviewTypes,dMimes=self.disabledPreviewMimeTypes,dExts=self.disabledPreviewExtensions||[],maxSize=self.maxFilePreviewSize&&parseFloat(self.maxFilePreviewSize)||0,expAllExt=new RegExp('\\.('+exts.join('|')+')$','i'),expDisExt=new RegExp('\\.('+dExts.join('|')+')$','i');allowedTypes=!types||types.indexOf(cat)!==-1;allowedMimes=!mimes||mimes.indexOf(type)!==-1;allowedExts=!exts.length||$h.compare(name,expAllExt);skipPreview=(dTypes&&dTypes.indexOf(cat)!==-1)||(dMimes&&dMimes.indexOf(type)!==-1)||(dExts.length&&$h.compare(name,expDisExt))||(maxSize&&!isNaN(maxSize)&&size>maxSize);return!skipPreview&&(allowedTypes||allowedMimes||allowedExts);},_previewFile:function(i,file,theFile,previewId,data,fileInfo){if(!this.showPreview){return;}var self=this,fname=$h.getFileName(file),ftype=fileInfo.type,caption=fileInfo.name,cat=self._parseFileType(ftype,fname),content,$preview=self.$preview,fsize=file.size||0,iData=(cat==='text'||cat==='html'||cat==='image')?theFile.target.result:data,fileId=self.fileManager.getId(file);if(cat==='html'&&self.purifyHtml&&window.DOMPurify){iData=window.DOMPurify.sanitize(iData);}content=self._generatePreviewTemplate(cat,iData,fname,ftype,previewId,fileId,false,fsize);self._clearDefaultPreview();self._addToPreview($preview,content);var $thumb=$preview.find('#'+previewId),$img=$thumb.find('img'),id=$thumb.attr('data-fileid');self._validateImageOrientation($img,file,previewId,id,caption,ftype,fsize,iData);self._setThumbAttr(previewId,caption,fsize);self._initSortable();},_setThumbAttr:function(id,caption,size){var self=this,$frame=$('#'+id);if($frame.length){size=size&&size>0?self._getSize(size):'';$frame.data({'caption':caption,'size':size});}},_setInitThumbAttr:function(){var self=this,data=self.previewCache.data,len=self.previewCache.count(true),config,caption,size,previewId;if(len===0){return;}for(var i=0;i&"']/g,'_');},_updateFileDetails:function(numFiles){var self=this,$el=self.$element,label,n,log,nFiles,file,name=($h.isIE(9)&&$h.findFileName($el.val()))||($el[0].files[0]&&$el[0].files[0].name);if(!name&&self.fileManager.count()>0){file=self.fileManager.getFirstFile();label=file.nameFmt;}else{label=name?self.slug(name):'_';}n=self.isAjaxUpload?self.fileManager.count():numFiles;nFiles=self.previewCache.count(true)+n;log=n===1?label:self._getMsgSelected(nFiles);if(self.isError){self.$previewContainer.removeClass('file-thumb-loading');self.$previewStatus.html('');self.$captionContainer.removeClass('icon-visible');}else{self._showFileIcon();}self._setCaption(log,self.isError);self.$container.removeClass('file-input-new file-input-ajax-new');if(arguments.length===1){self._raise('fileselect',[numFiles,label]);}if(self.previewCache.count(true)){self._initPreviewActions();}},_setThumbStatus:function($thumb,status){var self=this;if(!self.showPreview){return;}var icon='indicator'+status,msg=icon+'Title',css='file-preview-'+status.toLowerCase(),$indicator=$thumb.find('.file-upload-indicator'),config=self.fileActionSettings;$thumb.removeClass('file-preview-success file-preview-error file-preview-paused file-preview-loading');if(status==='Success'){$thumb.find('.file-drag-handle').remove();}$indicator.html(config[icon]);$indicator.attr('title',config[msg]);$thumb.addClass(css);if(status==='Error'&&!self.retryErrorUploads){$thumb.find('.kv-file-upload').attr('disabled',true);}},_setProgressCancelled:function(){var self=this;self._setProgress(101,self.$progress,self.msgCancelled);},_setProgress:function(p,$el,error,stats){var self=this;$el=$el||self.$progress;if(!$el.length){return;}var pct=Math.min(p,100),out,pctLimit=self.progressUploadThreshold,t=p<=100?self.progressTemplate:self.progressCompleteTemplate,template=pct<100?self.progressTemplate:(error?(self.paused?self.progressPauseTemplate:self.progressErrorTemplate):t);if(p>=100){stats='';}if(!$h.isEmpty(template)){if(pctLimit&&pct>pctLimit&&p<=100){out=template.setTokens({'percent':pctLimit,'status':self.msgUploadThreshold});}else{out=template.setTokens({'percent':pct,'status':(p>100?self.msgUploadEnd:pct+'%')});}stats=stats||'';out=out.setTokens({stats:stats});$el.html(out);if(error){$el.find('[role="progressbar"]').html(error);}}},_setFileDropZoneTitle:function(){var self=this,$zone=self.$container.find('.file-drop-zone'),title=self.dropZoneTitle,strFiles;if(self.isClickable){strFiles=$h.isEmpty(self.$element.attr('multiple'))?self.fileSingle:self.filePlural;title+=self.dropZoneClickTitle.replace('{files}',strFiles);}$zone.find('.'+self.dropZoneTitleClass).remove();if(!self.showPreview||$zone.length===0||self.fileManager.count()>0||!self.dropZoneEnabled||(!self.isAjaxUpload&&self.$element.files)){return;}if($zone.find($h.FRAMES).length===0&&$h.isEmpty(self.defaultPreviewContent)){$zone.prepend('
    '+title+'
    ');}self.$container.removeClass('file-input-new');$h.addCss(self.$container,'file-input-ajax-new');},_getStats:function(stats){var self=this,pendingTime,t;if(!self.showUploadStats||!stats||!stats.bitrate){return'';}t=self._getLayoutTemplate('stats');pendingTime=(!stats.elapsed||!stats.bps)?self.msgCalculatingTime:self.msgPendingTime.setTokens({time:$h.getElapsed(Math.ceil(stats.pendingBytes/stats.bps))});return t.setTokens({uploadSpeed:stats.bitrate,pendingTime:pendingTime});},_setResumableProgress:function(pct,stats,$thumb){var self=this,rm=self.resumableManager,obj=$thumb?rm:self,$prog=$thumb?$thumb.find('.file-thumb-progress'):null;if(obj.lastProgress===0){obj.lastProgress=pct;}if(pct0&&self._getFileCount(len-1)=limit:dim<=limit;if(isValid){return;}msg=self['msgImage'+type+chk].setTokens({'name':fname,'size':limit});self._showFileError(msg,params);self._setPreviewError($thumb);},_getExifObj:function(data){var self=this,exifObj=null,error=$h.logMessages.exifWarning;if(data.slice(0,23)!=='data:image/jpeg;base64,'&&data.slice(0,22)!=='data:image/jpg;base64,'){exifObj=null;return;}try{exifObj=window.piexif?window.piexif.load(data):null;}catch(err){exifObj=null;error=err&&err.message||'';}if(!exifObj){self._log($h.logMessages.badExifParser,{details:error});}return exifObj;},setImageOrientation:function($img,$zoomImg,value,$thumb){var self=this,invalidImg=!$img||!$img.length,invalidZoomImg=!$zoomImg||!$zoomImg.length,$mark,isHidden=false,$div,zoomOnly=invalidImg&&$thumb&&$thumb.attr('data-template')==='image',ev;if(invalidImg&&invalidZoomImg){return;}ev='load.fileinputimageorient';if(zoomOnly){$img=$zoomImg;$zoomImg=null;$img.css(self.previewSettings.image);$div=$(document.createElement('div')).appendTo($thumb.find('.kv-file-content'));$mark=$(document.createElement('span')).insertBefore($img);$img.css('visibility','hidden').removeClass('file-zoom-detail').appendTo($div);}else{isHidden=!$img.is(':visible');}$img.off(ev).on(ev,function(){if(isHidden){self.$preview.removeClass('hide-content');$thumb.find('.kv-file-content').css('visibility','hidden');}var img=$img.get(0),zoomImg=$zoomImg&&$zoomImg.length?$zoomImg.get(0):null,h=img.offsetHeight,w=img.offsetWidth,r=$h.getRotation(value);if(isHidden){$thumb.find('.kv-file-content').css('visibility','visible');self.$preview.addClass('hide-content');}$img.data('orientation',value);if(zoomImg){$zoomImg.data('orientation',value);}if(value<5){$h.setTransform(img,r);$h.setTransform(zoomImg,r);return;}var offsetAngle=Math.atan(w/h),origFactor=Math.sqrt(Math.pow(h,2)+Math.pow(w,2)),scale=!origFactor?1:(h/Math.cos(Math.PI/2+offsetAngle))/origFactor,s=' scale('+Math.abs(scale)+')';$h.setTransform(img,r+s);$h.setTransform(zoomImg,r+s);if(zoomOnly){$img.css('visibility','visible').insertAfter($mark).addClass('file-zoom-detail');$mark.remove();$div.remove();}});},_validateImageOrientation:function($img,file,previewId,fileId,caption,ftype,fsize,iData){var self=this,exifObj,value,autoOrientImage=self.autoOrientImage;exifObj=autoOrientImage?self._getExifObj(iData):null;value=exifObj?exifObj['0th'][piexif.ImageIFD.Orientation]:null;if(!value){self._validateImage(previewId,fileId,caption,ftype,fsize,iData,exifObj);return;}self.setImageOrientation($img,$('#zoom-'+previewId+' img'),value,$('#'+previewId));self._raise('fileimageoriented',{'$img':$img,'file':file});self._validateImage(previewId,fileId,caption,ftype,fsize,iData,exifObj);},_validateImage:function(previewId,fileId,fname,ftype,fsize,iData,exifObj){var self=this,$preview=self.$preview,params,w1,w2,$thumb=$preview.find('#'+previewId),i=$thumb.attr('data-fileindex'),$img=$thumb.find('img');fname=fname||'Untitled';$img.one('load',function(){w1=$thumb.width();w2=$preview.width();if(w1>w2){$img.css('width','100%');}params={ind:i,id:previewId,fileId:fileId};self._checkDimensions(i,'Small',$img,$thumb,fname,'Width',params);self._checkDimensions(i,'Small',$img,$thumb,fname,'Height',params);if(!self.resizeImage){self._checkDimensions(i,'Large',$img,$thumb,fname,'Width',params);self._checkDimensions(i,'Large',$img,$thumb,fname,'Height',params);}self._raise('fileimageloaded',[previewId]);self.fileManager.addImage(fileId,{ind:i,img:$img,thumb:$thumb,pid:previewId,typ:ftype,siz:fsize,validated:false,imgData:iData,exifObj:exifObj});$thumb.data('exif',exifObj);self._validateAllImages();}).one('error',function(){self._raise('fileimageloaderror',[previewId]);}).each(function(){if(this.complete){$(this).trigger('load');}else{if(this.error){$(this).trigger('error');}}});},_validateAllImages:function(){var self=this,counter={val:0},numImgs=self.fileManager.getImageCount(),fsize,minSize=self.resizeIfSizeMoreThan;if(numImgs!==self.fileManager.totalImages){return;}self._raise('fileimagesloaded');if(!self.resizeImage){return;}$.each(self.fileManager.loadedImages,function(id,config){if(!config.validated){fsize=config.siz;if(fsize&&fsize>minSize*1000){self._getResizedImage(id,config,counter,numImgs);}config.validated=true;}});},_getResizedImage:function(id,config,counter,numImgs){var self=this,img=$(config.img)[0],width=img.naturalWidth,height=img.naturalHeight,blob,ratio=1,maxWidth=self.maxImageWidth||width,maxHeight=self.maxImageHeight||height,isValidImage=!!(width&&height),chkWidth,chkHeight,canvas=self.imageCanvas,dataURI,context=self.imageCanvasContext,type=config.typ,pid=config.pid,ind=config.ind,$thumb=config.thumb,throwError,msg,exifObj=config.exifObj,exifStr,file,params,evParams;throwError=function(msg,params,ev){if(self.isAjaxUpload){self._showFileError(msg,params,ev);}else{self._showError(msg,params,ev);}self._setPreviewError($thumb);};file=self.fileManager.getFile(id);params={id:pid,'index':ind,fileId:id};evParams=[id,pid,ind];if(!file||!isValidImage||(width<=maxWidth&&height<=maxHeight)){if(isValidImage&&file){self._raise('fileimageresized',evParams);}counter.val++;if(counter.val===numImgs){self._raise('fileimagesresized');}if(!isValidImage){throwError(self.msgImageResizeError,params,'fileimageresizeerror');return;}}type=type||self.resizeDefaultImageType;chkWidth=width>maxWidth;chkHeight=height>maxHeight;if(self.resizePreference==='width'){ratio=chkWidth?maxWidth/width:(chkHeight?maxHeight/height:1);}else{ratio=chkHeight?maxHeight/height:(chkWidth?maxWidth/width:1);}self._resetCanvas();width*=ratio;height*=ratio;canvas.width=width;canvas.height=height;try{context.drawImage(img,0,0,width,height);dataURI=canvas.toDataURL(type,self.resizeQuality);if(exifObj){exifStr=window.piexif.dump(exifObj);dataURI=window.piexif.insert(exifStr,dataURI);}blob=$h.dataURI2Blob(dataURI);self.fileManager.setFile(id,blob);self._raise('fileimageresized',evParams);counter.val++;if(counter.val===numImgs){self._raise('fileimagesresized',[undefined,undefined]);}if(!(blob instanceof Blob)){throwError(self.msgImageResizeError,params,'fileimageresizeerror');}}catch(err){counter.val++;if(counter.val===numImgs){self._raise('fileimagesresized',[undefined,undefined]);}msg=self.msgImageResizeException.replace('{errors}',err.message);throwError(msg,params,'fileimageresizeexception');}},_initBrowse:function($container){var self=this,$el=self.$element;if(self.showBrowse){self.$btnFile=$container.find('.btn-file').append($el);}else{$el.appendTo($container).attr('tabindex',-1);$h.addCss($el,'file-no-browse');}},_initClickable:function(){var self=this,$zone,$tmpZone;if(!self.isClickable){return;}$zone=self.$dropZone;if(!self.isAjaxUpload){$tmpZone=self.$preview.find('.file-default-preview');if($tmpZone.length){$zone=$tmpZone;}}$h.addCss($zone,'clickable');$zone.attr('tabindex',-1);self._handler($zone,'click',function(e){var $tar=$(e.target);if(!$(self.elErrorContainer+':visible').length&&(!$tar.parents('.file-preview-thumbnails').length||$tar.parents('.file-default-preview').length)){self.$element.data('zoneClicked',true).trigger('click');$zone.blur();}});},_initCaption:function(){var self=this,cap=self.initialCaption||'';if(self.overwriteInitial||$h.isEmpty(cap)){self.$caption.val('');return false;}self._setCaption(cap);return true;},_setCaption:function(content,isError){var self=this,title,out,icon,n,cap,file;if(!self.$caption.length){return;}self.$captionContainer.removeClass('icon-visible');if(isError){title=$('
    '+self.msgValidationError+'
    ').text();n=self.fileManager.count();if(n){file=self.fileManager.getFirstFile();cap=n===1&&file?file.nameFmt:self._getMsgSelected(n);}else{cap=self._getMsgSelected(self.msgNo);}out=$h.isEmpty(content)?cap:content;icon=''+self.msgValidationErrorIcon+'';}else{if($h.isEmpty(content)){return;}title=$('
    '+content+'
    ').text();out=title;icon=self._getLayoutTemplate('fileIcon');}self.$captionContainer.addClass('icon-visible');self.$caption.attr('title',title).val(out);self.$captionIcon.html(icon);},_createContainer:function(){var self=this,attribs={'class':'file-input file-input-new'+(self.rtl?' kv-rtl':'')},$container=$(document.createElement('div')).attr(attribs).html(self._renderMain());$container.insertBefore(self.$element);self._initBrowse($container);if(self.theme){$container.addClass('theme-'+self.theme);}return $container;},_refreshContainer:function(){var self=this,$container=self.$container,$el=self.$element;$el.insertAfter($container);$container.html(self._renderMain());self._initBrowse($container);self._validateDisabled();},_validateDisabled:function(){var self=this;self.$caption.attr({readonly:self.isDisabled});},_renderMain:function(){var self=this,dropCss=self.dropZoneEnabled?' file-drop-zone':'file-drop-disabled',close=!self.showClose?'':self._getLayoutTemplate('close'),preview=!self.showPreview?'':self._getLayoutTemplate('preview').setTokens({'class':self.previewClass,'dropClass':dropCss}),css=self.isDisabled?self.captionClass+' file-caption-disabled':self.captionClass,caption=self.captionTemplate.setTokens({'class':css+' kv-fileinput-caption'});return self.mainTemplate.setTokens({'class':self.mainClass+(!self.showBrowse&&self.showCaption?' no-browse':''),'preview':preview,'close':close,'caption':caption,'upload':self._renderButton('upload'),'remove':self._renderButton('remove'),'cancel':self._renderButton('cancel'),'pause':self._renderButton('pause'),'browse':self._renderButton('browse')});},_renderButton:function(type){var self=this,tmplt=self._getLayoutTemplate('btnDefault'),css=self[type+'Class'],title=self[type+'Title'],icon=self[type+'Icon'],label=self[type+'Label'],status=self.isDisabled?' disabled':'',btnType='button';switch(type){case'remove':if(!self.showRemove){return'';}break;case'cancel':if(!self.showCancel){return'';}css+=' kv-hidden';break;case'pause':if(!self.showPause){return'';}css+=' kv-hidden';break;case'upload':if(!self.showUpload){return'';}if(self.isAjaxUpload&&!self.isDisabled){tmplt=self._getLayoutTemplate('btnLink').replace('{href}',self.uploadUrl);}else{btnType='submit';}break;case'browse':if(!self.showBrowse){return'';}tmplt=self._getLayoutTemplate('btnBrowse');break;default:return'';}css+=type==='browse'?' btn-file':' fileinput-'+type+' fileinput-'+type+'-button';if(!$h.isEmpty(label)){label=' '+label+'';}return tmplt.setTokens({'type':btnType,'css':css,'title':title,'status':status,'icon':icon,'label':label});},_renderThumbProgress:function(){var self=this;return'
    '+self.progressInfoTemplate.setTokens({percent:101,status:self.msgUploadBegin,stats:''})+'
    ';},_renderFileFooter:function(cat,caption,size,width,isError){var self=this,config=self.fileActionSettings,rem=config.showRemove,drg=config.showDrag,upl=config.showUpload,zoom=config.showZoom,out,params,template=self._getLayoutTemplate('footer'),tInd=self._getLayoutTemplate('indicator'),ind=isError?config.indicatorError:config.indicatorNew,title=isError?config.indicatorErrorTitle:config.indicatorNewTitle,indicator=tInd.setTokens({'indicator':ind,'indicatorTitle':title});size=self._getSize(size);params={type:cat,caption:caption,size:size,width:width,progress:'',indicator:indicator};if(self.isAjaxUpload){params.progress=self._renderThumbProgress();params.actions=self._renderFileActions(params,upl,false,rem,zoom,drg,false,false,false);}else{params.actions=self._renderFileActions(params,false,false,false,zoom,drg,false,false,false);}out=template.setTokens(params);out=$h.replaceTags(out,self.previewThumbTags);return out;},_renderFileActions:function(cfg,showUpl,showDwn,showDel,showZoom,showDrag,disabled,url,key,isInit,dUrl,dFile){var self=this;if(!cfg.type&&isInit){cfg.type='image';}if(self.enableResumableUpload){showUpl=false;}else{if(typeof showUpl==='function'){showUpl=showUpl(cfg);}}if(typeof showDwn==='function'){showDwn=showDwn(cfg);}if(typeof showDel==='function'){showDel=showDel(cfg);}if(typeof showZoom==='function'){showZoom=showZoom(cfg);}if(typeof showDrag==='function'){showDrag=showDrag(cfg);}if(!showUpl&&!showDwn&&!showDel&&!showZoom&&!showDrag){return'';}var vUrl=url===false?'':' data-url="'+url+'"',btnZoom='',btnDrag='',css,vKey=key===false?'':' data-key="'+key+'"',btnDelete='',btnUpload='',btnDownload='',template=self._getLayoutTemplate('actions'),config=self.fileActionSettings,otherButtons=self.otherActionButtons.setTokens({'dataKey':vKey,'key':key}),removeClass=disabled?config.removeClass+' disabled':config.removeClass;if(showDel){btnDelete=self._getLayoutTemplate('actionDelete').setTokens({'removeClass':removeClass,'removeIcon':config.removeIcon,'removeTitle':config.removeTitle,'dataUrl':vUrl,'dataKey':vKey,'key':key});}if(showUpl){btnUpload=self._getLayoutTemplate('actionUpload').setTokens({'uploadClass':config.uploadClass,'uploadIcon':config.uploadIcon,'uploadTitle':config.uploadTitle});}if(showDwn){btnDownload=self._getLayoutTemplate('actionDownload').setTokens({'downloadClass':config.downloadClass,'downloadIcon':config.downloadIcon,'downloadTitle':config.downloadTitle,'downloadUrl':dUrl||self.initialPreviewDownloadUrl});btnDownload=btnDownload.setTokens({'filename':dFile,'key':key});}if(showZoom){btnZoom=self._getLayoutTemplate('actionZoom').setTokens({'zoomClass':config.zoomClass,'zoomIcon':config.zoomIcon,'zoomTitle':config.zoomTitle});}if(showDrag&&isInit){css='drag-handle-init '+config.dragClass;btnDrag=self._getLayoutTemplate('actionDrag').setTokens({'dragClass':css,'dragTitle':config.dragTitle,'dragIcon':config.dragIcon});}return template.setTokens({'delete':btnDelete,'upload':btnUpload,'download':btnDownload,'zoom':btnZoom,'drag':btnDrag,'other':otherButtons});},_browse:function(e){var self=this;if(e&&e.isDefaultPrevented()||!self._raise('filebrowse')){return;}if(self.isError&&!self.isAjaxUpload){self.clear();}self.$captionContainer.focus();},_change:function(e){var self=this;if(self.changeTriggered){return;}var $el=self.$element,isDragDrop=arguments.length>1,isAjaxUpload=self.isAjaxUpload,tfiles,files=isDragDrop?arguments[1]:$el.get(0).files,total,maxCount=!isAjaxUpload&&$h.isEmpty($el.attr('multiple'))?1:self.maxFileCount,len,ctr=self.fileManager.count(),isSingleUpload=$h.isEmpty($el.attr('multiple')),flagSingle=(isSingleUpload&&ctr>0),throwError=function(mesg,file,previewId,index){var p1=$.extend(true,{},self._getOutData(null,{},{},files),{id:previewId,index:index}),p2={id:previewId,index:index,file:file,files:files};return isAjaxUpload?self._showFileError(mesg,p1):self._showError(mesg,p2);},maxCountCheck=function(n,m){var msg=self.msgFilesTooMany.replace('{m}',m).replace('{n}',n);self.isError=throwError(msg,null,null,null);self.$captionContainer.removeClass('icon-visible');self._setCaption('',true);self.$container.removeClass('file-input-new file-input-ajax-new');};self.reader=null;self._resetUpload();self._hideFileIcon();if(self.dropZoneEnabled){self.$container.find('.file-drop-zone .'+self.dropZoneTitleClass).remove();}if(!isAjaxUpload){if(e.target&&e.target.files===undefined){files=e.target.value?[{name:e.target.value.replace(/^.+\\/,'')}]:[];}else{files=e.target.files||{};}}tfiles=files;if($h.isEmpty(tfiles)||tfiles.length===0){if(!isAjaxUpload){self.clear();}self._raise('fileselectnone');return;}self._resetErrors();len=tfiles.length;total=self._getFileCount(isAjaxUpload?(self.fileManager.count()+len):len);if(maxCount>0&&total>maxCount){if(!self.autoReplace||len>maxCount){maxCountCheck((self.autoReplace&&len>maxCount?len:total),maxCount);return;}if(total>maxCount){self._resetPreviewThumbs(isAjaxUpload);}}else{if(!isAjaxUpload||flagSingle){self._resetPreviewThumbs(false);if(flagSingle){self.clearFileStack();}}else{if(isAjaxUpload&&ctr===0&&(!self.previewCache.count(true)||self.overwriteInitial)){self._resetPreviewThumbs(true);}}}self.readFiles(tfiles);},_abort:function(params){var self=this,data;if(self.ajaxAborted&&typeof self.ajaxAborted==='object'&&self.ajaxAborted.message!==undefined){data=$.extend(true,{},self._getOutData(null),params);data.abortData=self.ajaxAborted.data||{};data.abortMessage=self.ajaxAborted.message;self._setProgress(101,self.$progress,self.msgCancelled);self._showFileError(self.ajaxAborted.message,data,'filecustomerror');self.cancel();return true;}return!!self.ajaxAborted;},_resetFileStack:function(){var self=this,i=0;self._getThumbs().each(function(){var $thumb=$(this),ind=$thumb.attr('data-fileindex'),pid=$thumb.attr('id');if(ind==='-1'||ind===-1){return;}if(!self.fileManager.getFile($thumb.attr('data-fileid'))){$thumb.attr({'id':self.previewInitId+'-'+i,'data-fileindex':i});i++;}else{$thumb.attr({'id':'uploaded-'+$h.uniqId(),'data-fileindex':'-1'});}self.$preview.find('#zoom-'+pid).attr({'id':'zoom-'+$thumb.attr('id'),'data-fileindex':$thumb.attr('data-fileindex')});});},_isFileSelectionValid:function(cnt){var self=this;cnt=cnt||0;if(self.required&&!self.getFilesCount()){self.$errorContainer.html('');self._showFileError(self.msgFileRequired);return false;}if(self.minFileCount>0&&self._getFileCount(cnt)=numFiles){if(self.isAjaxUpload&&self.fileManager.count()>0){self._raise('filebatchselected',[self.fileManager.stack]);}else{self._raise('filebatchselected',[files]);}$container.removeClass('file-thumb-loading');$status.html('');return;}var node=ctr+i,previewId=previewInitId+'-'+node,file=files[i],fSizeKB,j,msg,$thumb,fnText=settings.text,fnImage=settings.image,fnHtml=settings.html,typ,chk,typ1,typ2,caption=self._getFileName(file,''),fileSize=(file&&file.size||0)/1000,fileExtExpr='',previewData=$h.createObjectURL(file),fileCount=0,strTypes='',fileId,func,knownTypes=0,isText,isHtml,isImage,txtFlag,processFileLoaded=function(){var msg=msgProgress.setTokens({'index':i+1,'files':numFiles,'percent':50,'name':caption});setTimeout(function(){$status.html(msg);self._updateFileDetails(numFiles);readFile(i+1);},self.processDelay);self._raise('fileloaded',[file,previewId,i,reader]);};if(!file){return;}fileId=self.fileManager.getId(file);if(typLen>0){for(j=0;j0&&fileSize>self.maxFileSize){msg=self.msgSizeTooLarge.setTokens({'name':caption,'size':fSizeKB,'maxSize':self.maxFileSize});throwError(msg,file,previewId,i,fileId);return;}if(self.minFileSize!==null&&fileSize<=$h.getNum(self.minFileSize)){msg=self.msgSizeTooSmall.setTokens({'name':caption,'size':fSizeKB,'minSize':self.minFileSize});throwError(msg,file,previewId,i,fileId);return;}if(!$h.isEmpty(fileTypes)&&$h.isArray(fileTypes)){for(j=0;j0){for(i=0;i0){for(i=0;i0)?self.initialCaption:'';self.$caption.attr('title','').val(cap);$h.addCss(self.$container,'file-input-new');self._validateDefaultPreview();}if(self.$container.find($h.FRAMES).length===0){if(!self._initCaption()){self.$captionContainer.removeClass('icon-visible');}}self._hideFileIcon();self.$captionContainer.focus();self._setFileDropZoneTitle();self._raise('filecleared');return self.$element;},reset:function(){var self=this;if(!self._raise('filereset')){return;}self.lastProgress=0;self._resetPreview();self.$container.find('.fileinput-filename').text('');$h.addCss(self.$container,'file-input-new');if(self.getFrames().length||self.dropZoneEnabled){self.$container.removeClass('file-input-new');}self.clearFileStack();self._setFileDropZoneTitle();return self.$element;},disable:function(){var self=this;self.isDisabled=true;self._raise('filedisabled');self.$element.attr('disabled','disabled');self.$container.find('.kv-fileinput-caption').addClass('file-caption-disabled');self.$container.find('.fileinput-remove, .fileinput-upload, .file-preview-frame button').attr('disabled',true);$h.addCss(self.$container.find('.btn-file'),'disabled');self._initDragDrop();return self.$element;},enable:function(){var self=this;self.isDisabled=false;self._raise('fileenabled');self.$element.removeAttr('disabled');self.$container.find('.kv-fileinput-caption').removeClass('file-caption-disabled');self.$container.find('.fileinput-remove, .fileinput-upload, .file-preview-frame button').removeAttr('disabled');self.$container.find('.btn-file').removeClass('disabled');self._initDragDrop();return self.$element;},upload:function(){var self=this,fm=self.fileManager,totLen=fm.count(),i,outData,len,hasExtraData=!$.isEmptyObject(self._getExtraData());if(!self.isAjaxUpload||self.isDisabled||!self._isFileSelectionValid(totLen)){return;}self.lastProgress=0;self._resetUpload();if(totLen===0&&!hasExtraData){self._showFileError(self.msgUploadEmpty);return;}self.cancelling=false;self.$progress.show();self.lock();len=fm.count();if(totLen===0&&hasExtraData){self._setProgress(2);self._uploadExtraOnly();return;}if(self.enableResumableUpload){return self.resume();}if(self.uploadAsync||self.enableResumableUpload){outData=self._getOutData(null);self._raise('filebatchpreupload',[outData]);self.fileBatchCompleted=false;self.uploadCache={content:[],config:[],tags:[],append:true};for(i=0;i',next:'',toggleheader:'',fullscreen:'',borderless:'',close:''},previewZoomButtonClasses:{prev:'btn btn-navigate',next:'btn btn-navigate',toggleheader:'btn btn-sm btn-kv btn-default btn-outline-secondary',fullscreen:'btn btn-sm btn-kv btn-default btn-outline-secondary',borderless:'btn btn-sm btn-kv btn-default btn-outline-secondary',close:'btn btn-sm btn-kv btn-default btn-outline-secondary'},previewTemplates:{},previewContentTemplates:{},preferIconicPreview:false,preferIconicZoomPreview:false,allowedFileTypes:null,allowedFileExtensions:null,allowedPreviewTypes:undefined,allowedPreviewMimeTypes:null,allowedPreviewExtensions:null,disabledPreviewTypes:undefined,disabledPreviewExtensions:['msi','exe','com','zip','rar','app','vb','scr'],disabledPreviewMimeTypes:null,defaultPreviewContent:null,customLayoutTags:{},customPreviewTags:{},previewFileIcon:'',previewFileIconClass:'file-other-icon',previewFileIconSettings:{},previewFileExtSettings:{},buttonLabelClass:'hidden-xs',browseIcon:' ',browseClass:'btn btn-primary',removeIcon:'',removeClass:'btn btn-default btn-secondary',cancelIcon:'',cancelClass:'btn btn-default btn-secondary',pauseIcon:'',pauseClass:'btn btn-default btn-secondary',uploadIcon:'',uploadClass:'btn btn-default btn-secondary',uploadUrl:null,uploadUrlThumb:null,uploadAsync:true,uploadParamNames:{chunkCount:'chunkCount',chunkIndex:'chunkIndex',chunkSize:'chunkSize',chunkSizeStart:'chunkSizeStart',chunksUploaded:'chunksUploaded',fileBlob:'fileBlob',fileId:'fileId',fileName:'fileName',fileRelativePath:'fileRelativePath',fileSize:'fileSize',retryCount:'retryCount'},maxAjaxThreads:5,processDelay:100,queueDelay:10,progressDelay:0,enableResumableUpload:false,resumableUploadOptions:{fallback:null,testUrl:null,chunkSize:2*1024,maxThreads:4,maxRetries:3,showErrorLog:true},uploadExtraData:{},zoomModalHeight:480,minImageWidth:null,minImageHeight:null,maxImageWidth:null,maxImageHeight:null,resizeImage:false,resizePreference:'width',resizeQuality:0.92,resizeDefaultImageType:'image/jpeg',resizeIfSizeMoreThan:0,minFileSize:0,maxFileSize:0,maxFilePreviewSize:25600,minFileCount:0,maxFileCount:0,validateInitialCount:false,msgValidationErrorClass:'text-danger',msgValidationErrorIcon:' ',msgErrorClass:'file-error-message',progressThumbClass:'progress-bar progress-bar-striped active',progressClass:'progress-bar bg-success progress-bar-success progress-bar-striped active',progressInfoClass:'progress-bar bg-info progress-bar-info progress-bar-striped active',progressCompleteClass:'progress-bar bg-success progress-bar-success',progressPauseClass:'progress-bar bg-primary progress-bar-primary progress-bar-striped active',progressErrorClass:'progress-bar bg-danger progress-bar-danger',progressUploadThreshold:99,previewFileType:'image',elCaptionContainer:null,elCaptionText:null,elPreviewContainer:null,elPreviewImage:null,elPreviewStatus:null,elErrorContainer:null,errorCloseButton:$h.closeButton('kv-error-close'),slugCallback:null,dropZoneEnabled:true,dropZoneTitleClass:'file-drop-zone-title',fileActionSettings:{},otherActionButtons:'',textEncoding:'UTF-8',ajaxSettings:{},ajaxDeleteSettings:{},showAjaxErrorDetails:true,mergeAjaxCallbacks:false,mergeAjaxDeleteCallbacks:false,retryErrorUploads:true,reversePreviewOrder:false,usePdfRenderer:function(){var isIE11=!!window.MSInputMethodContext&&!!document.documentMode;return!!navigator.userAgent.match(/(iPod|iPhone|iPad|Android)/i)||isIE11;},pdfRendererUrl:'',pdfRendererTemplate:''};$.fn.fileinputLocales.en={fileSingle:'file',filePlural:'files',browseLabel:'Browse …',removeLabel:'Remove',removeTitle:'Clear all unprocessed files',cancelLabel:'Cancel',cancelTitle:'Abort ongoing upload',pauseLabel:'Pause',pauseTitle:'Pause ongoing upload',uploadLabel:'Upload',uploadTitle:'Upload selected files',msgNo:'No',msgNoFilesSelected:'No files selected',msgCancelled:'Cancelled',msgPaused:'Paused',msgPlaceholder:'Select {files}...',msgZoomModalHeading:'Detailed Preview',msgFileRequired:'You must select a file to upload.',msgSizeTooSmall:'File "{name}" ({size} KB) is too small and must be larger than {minSize} KB.',msgSizeTooLarge:'File "{name}" ({size} KB) exceeds maximum allowed upload size of {maxSize} KB.',msgFilesTooLess:'You must select at least {n} {files} to upload.',msgFilesTooMany:'Number of files selected for upload ({n}) exceeds maximum allowed limit of {m}.',msgFileNotFound:'File "{name}" not found!',msgFileSecured:'Security restrictions prevent reading the file "{name}".',msgFileNotReadable:'File "{name}" is not readable.',msgFilePreviewAborted:'File preview aborted for "{name}".',msgFilePreviewError:'An error occurred while reading the file "{name}".',msgInvalidFileName:'Invalid or unsupported characters in file name "{name}".',msgInvalidFileType:'Invalid type for file "{name}". Only "{types}" files are supported.',msgInvalidFileExtension:'Invalid extension for file "{name}". Only "{extensions}" files are supported.',msgFileTypes:{'image':'image','html':'HTML','text':'text','video':'video','audio':'audio','flash':'flash','pdf':'PDF','object':'object'},msgUploadAborted:'The file upload was aborted',msgUploadThreshold:'Processing...',msgUploadBegin:'Initializing...',msgUploadEnd:'Done',msgUploadResume:'Resuming upload...',msgUploadEmpty:'No valid data available for upload.',msgUploadError:'Upload Error',msgDeleteError:'Delete Error',msgProgressError:'Error',msgValidationError:'Validation Error',msgLoading:'Loading file {index} of {files} …',msgProgress:'Loading file {index} of {files} - {name} - {percent}% completed.',msgSelected:'{n} {files} selected',msgFoldersNotAllowed:'Drag & drop files only! {n} folder(s) dropped were skipped.',msgImageWidthSmall:'Width of image file "{name}" must be at least {size} px.',msgImageHeightSmall:'Height of image file "{name}" must be at least {size} px.',msgImageWidthLarge:'Width of image file "{name}" cannot exceed {size} px.',msgImageHeightLarge:'Height of image file "{name}" cannot exceed {size} px.',msgImageResizeError:'Could not get the image dimensions to resize.',msgImageResizeException:'Error while resizing the image.
    {errors}
    ',msgAjaxError:'Something went wrong with the {operation} operation. Please try again later!',msgAjaxProgressError:'{operation} failed',msgDuplicateFile:'File "{name}" of same size "{size} KB" has already been selected earlier. Skipping duplicate selection.',msgResumableUploadRetriesExceeded:'Upload aborted beyond {max} retries for file {file}! Error Details:
    {error}
    ',msgPendingTime:'{time} remaining',msgCalculatingTime:'calculating time remaining',ajaxOperations:{deleteThumb:'file delete',uploadThumb:'file upload',uploadBatch:'batch file upload',uploadExtra:'form data upload'},dropZoneTitle:'Drag & drop files here …',dropZoneClickTitle:'
    (or click to select {files})',previewZoomButtonTitles:{prev:'View previous file',next:'View next file',toggleheader:'Toggle header',fullscreen:'Toggle full screen',borderless:'Toggle borderless mode',close:'Close detailed preview'}};$.fn.fileinputLocales.zh={fileSingle:'文件',filePlural:'个文件',browseLabel:'选择 …',removeLabel:'移除',removeTitle:'清除选中文件',cancelLabel:'取消',cancelTitle:'取消进行中的上传',pauseLabel:'Pause',pauseTitle:'Pause ongoing upload',uploadLabel:'上传',uploadTitle:'上传选中文件',msgNo:'没有',msgNoFilesSelected:'未选择文件',msgPaused:'Paused',msgCancelled:'取消',msgPlaceholder:'选择 {files}...',msgZoomModalHeading:'详细预览',msgFileRequired:'必须选择一个文件上传.',msgSizeTooSmall:'文件 "{name}" ({size} KB) 必须大于限定大小 {minSize} KB.',msgSizeTooLarge:'文件 "{name}" ({size} KB) 超过了允许大小 {maxSize} KB.',msgFilesTooLess:'你必须选择最少 {n} {files} 来上传. ',msgFilesTooMany:'选择的上传文件个数 ({n}) 超出最大文件的限制个数 {m}.',msgFileNotFound:'文件 "{name}" 未找到!',msgFileSecured:'安全限制,为了防止读取文件 "{name}".',msgFileNotReadable:'文件 "{name}" 不可读.',msgFilePreviewAborted:'取消 "{name}" 的预览.',msgFilePreviewError:'读取 "{name}" 时出现了一个错误.',msgInvalidFileName:'文件名 "{name}" 包含非法字符.',msgInvalidFileType:'不正确的类型 "{name}". 只支持 "{types}" 类型的文件.',msgInvalidFileExtension:'不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.',msgFileTypes:{'image':'image','html':'HTML','text':'text','video':'video','audio':'audio','flash':'flash','pdf':'PDF','object':'object'},msgUploadAborted:'该文件上传被中止',msgUploadThreshold:'处理中...',msgUploadBegin:'正在初始化...',msgUploadEnd:'完成',msgUploadResume:'Resuming upload...',msgUploadEmpty:'无效的文件上传.',msgUploadError:'Upload Error',msgDeleteError:'Delete Error',msgProgressError:'上传出错',msgValidationError:'验证错误',msgLoading:'加载第 {index} 文件 共 {files} …',msgProgress:'加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.',msgSelected:'{n} {files} 选中',msgFoldersNotAllowed:'只支持拖拽文件! 跳过 {n} 拖拽的文件夹.',msgImageWidthSmall:'图像文件的"{name}"的宽度必须是至少{size}像素.',msgImageHeightSmall:'图像文件的"{name}"的高度必须至少为{size}像素.',msgImageWidthLarge:'图像文件"{name}"的宽度不能超过{size}像素.',msgImageHeightLarge:'图像文件"{name}"的高度不能超过{size}像素.',msgImageResizeError:'无法获取的图像尺寸调整。',msgImageResizeException:'调整图像大小时发生错误。
    {errors}
    ',msgAjaxError:'{operation} 发生错误. 请重试!',msgAjaxProgressError:'{operation} 失败',msgDuplicateFile:'File "{name}" of same size "{size} KB" has already been selected earlier. Skipping duplicate selection.',msgResumableUploadRetriesExceeded:'Upload aborted beyond {max} retries for file {file}! Error Details:
    {error}
    ',msgPendingTime:'{time} remaining',msgCalculatingTime:'calculating time remaining',ajaxOperations:{deleteThumb:'删除文件',uploadThumb:'上传文件',uploadBatch:'批量上传',uploadExtra:'表单数据上传'},dropZoneTitle:'拖拽文件到这里 …
    支持多文件同时上传',dropZoneClickTitle:'
    (或点击{files}按钮选择文件)',fileActionSettings:{removeTitle:'删除文件',uploadTitle:'上传文件',downloadTitle:'下载文件',uploadRetryTitle:'重试',zoomTitle:'查看详情',dragTitle:'移动 / 重置',indicatorNewTitle:'没有上传',indicatorSuccessTitle:'上传',indicatorErrorTitle:'上传错误',indicatorPausedTitle:'Upload Paused',indicatorLoadingTitle:'上传 ...'},previewZoomButtonTitles:{prev:'预览上一个文件',next:'预览下一个文件',toggleheader:'缩放',fullscreen:'全屏',borderless:'无边界模式',close:'关闭当前预览'}};$.fn.fileinput.Constructor=FileInput;$(document).ready(function(){var $input=$('input.file[type=file]');if($input.length){$input.fileinput();}});})); \ No newline at end of file + * bootstrap-fileinput v5.1.3 + * http://plugins.krajee.com/file-input + * + * Author: Kartik Visweswaran + * Copyright: 2014 - 2020, Kartik Visweswaran, Krajee.com + * + * Licensed under the BSD-3-Clause + * https://github.com/kartik-v/bootstrap-fileinput/blob/master/LICENSE.md + */ +!function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&module.exports?module.exports=e(require("jquery")):e(window.jQuery)}(function(e){e.fn.fileinputLocales={},e.fn.fileinputThemes={},String.prototype.setTokens=function(e){var t,i,a=""+this;for(t in e){e.hasOwnProperty(t)&&(i=RegExp("{"+t+"}","g"),a=a.replace(i,e[t]))}return a},Array.prototype.flatMap||(Array.prototype.flatMap=function(e){return[].concat(this.map(e))});var t,i;t={FRAMES:".kv-preview-thumb",SORT_CSS:"file-sortable",INIT_FLAG:"init-",OBJECT_PARAMS:'\n\n\n\n\n\n',DEFAULT_PREVIEW:'
    \n{previewFileIcon}\n
    ',MODAL_ID:"kvFileinputModal",MODAL_EVENTS:["show","shown","hide","hidden","loaded"],logMessages:{ajaxError:"{status}: {error}. Error Details: {text}.",badDroppedFiles:"Error scanning dropped files!",badExifParser:"Error loading the piexif.js library. {details}",badInputType:'The input "type" must be set to "file" for initializing the "bootstrap-fileinput" plugin.',exifWarning:'To avoid this warning, either set "autoOrientImage" to "false" OR ensure you have loaded the "piexif.js" library correctly on your page before the "fileinput.js" script.',invalidChunkSize:'Invalid upload chunk size: "{chunkSize}". Resumable uploads are disabled.',invalidThumb:'Invalid thumb frame with id: "{id}".',noResumableSupport:"The browser does not support resumable or chunk uploads.",noUploadUrl:'The "uploadUrl" is not set. Ajax uploads and resumable uploads have been disabled.',retryStatus:"Retrying upload for chunk # {chunk} for {filename}... retry # {retry}.",chunkQueueError:"Could not push task to ajax pool for chunk index # {index}.",resumableMaxRetriesReached:"Maximum resumable ajax retries ({n}) reached.",resumableRetryError:"Could not retry the resumable request (try # {n})... aborting.",resumableAborting:"Aborting / cancelling the resumable request."},objUrl:window.URL||window.webkitURL,now:function(){return(new Date).getTime()},round:function(e){return e=parseFloat(e),isNaN(e)?0:Math.floor(Math.round(e))},getArray:function(e){var t,i=[],a=e&&e.length||0;for(t=0;a>t;t++){i.push(e[t])}return i},getFileRelativePath:function(e){return(e.newPath||e.relativePath||e.webkitRelativePath||t.getFileName(e)||null)+""},getFileId:function(e,i){var a=t.getFileRelativePath(e);return"function"==typeof i?i(e):e&&a?e.size+"_"+encodeURIComponent(a).replace(/%/g,"_"):null},getFrameSelector:function(e,t){return t=t||"",'[id="'+e+'"]'+t},getZoomSelector:function(e,i){return t.getFrameSelector("zoom-"+e,i)},getFrameElement:function(e,i,a){return e.find(t.getFrameSelector(i,a))},getZoomElement:function(e,i,a){return e.find(t.getZoomSelector(i,a))},getElapsed:function(i){var a=i,r="",n={},o={year:31536000,month:2592000,week:604800,day:86400,hour:3600,minute:60,second:1};return t.getObjectKeys(o).forEach(function(e){n[e]=Math.floor(a/o[e]),a-=n[e]*o[e]}),e.each(n,function(e,t){t>0&&(r+=(r?" ":"")+t+e.substring(0,1))}),r},debounce:function(e,t){var i;return function(){var a=arguments,r=this;clearTimeout(i),i=setTimeout(function(){e.apply(r,a)},t)}},stopEvent:function(e){e.stopPropagation(),e.preventDefault()},getFileName:function(e){return e?e.fileName||e.name||"":""},createObjectURL:function(e){return t.objUrl&&t.objUrl.createObjectURL&&e?t.objUrl.createObjectURL(e):""},revokeObjectURL:function(e){t.objUrl&&t.objUrl.revokeObjectURL&&e&&t.objUrl.revokeObjectURL(e)},compare:function(e,t,i){return void 0!==e&&(i?e===t:e.match(t))},isIE:function(e){var t,i;return"Microsoft Internet Explorer"!==navigator.appName?!1:10===e?RegExp("msie\\s"+e,"i").test(navigator.userAgent):(t=document.createElement("div"),t.innerHTML="",i=t.getElementsByTagName("i").length,document.body.appendChild(t),t.parentNode.removeChild(t),i)},canOrientImage:function(t){var i=e(document.createElement("img")).css({width:"1px",height:"1px"}).insertAfter(t),a=i.css("image-orientation");return i.remove(),!!a},canAssignFilesToInput:function(){var e=document.createElement("input");try{return e.type="file",e.files=null,!0}catch(t){return !1}},getDragDropFolders:function(e){var t,i,a=e?e.length:0,r=0;if(a>0&&e[0].webkitGetAsEntry()){for(t=0;a>t;t++){i=e[t].webkitGetAsEntry(),i&&i.isDirectory&&r++}}return r},initModal:function(t){var i=e("body");i.length&&t.appendTo(i)},isFunction:function(e){return"function"==typeof e},isEmpty:function(i,a){return void 0===i||null===i||!t.isFunction(i)&&(0===i.length||a&&""===e.trim(i))},isArray:function(e){return Array.isArray(e)||"[object Array]"===Object.prototype.toString.call(e)},ifSet:function(e,t,i){return i=i||"",t&&"object"==typeof t&&e in t?t[e]:i},cleanArray:function(e){return e instanceof Array||(e=[]),e.filter(function(e){return void 0!==e&&null!==e})},spliceArray:function(t,i,a){var r,n,o=0,l=[];if(!(t instanceof Array)){return[]}for(n=e.extend(!0,[],t),a&&n.reverse(),r=0;r=0?atob(e.split(",")[1]):decodeURIComponent(e.split(",")[1]),a=new ArrayBuffer(i.length),r=new Uint8Array(a),n=0;nl;){switch(i=n[l++],i>>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:o+=String.fromCharCode(i);break;case 12:case 13:a=n[l++],o+=String.fromCharCode((31&i)<<6|63&a);break;case 14:a=n[l++],r=n[l++],o+=String.fromCharCode((15&i)<<12|(63&a)<<6|(63&r)<<0)}}return o},isHtml:function(e){var t=document.createElement("div");t.innerHTML=e;for(var i=t.childNodes,a=i.length;a--;){if(1===i[a].nodeType){return !0}}return !1},isSvg:function(e){return e.match(/^\s*<\?xml/i)&&(e.match(/"+t+""))},uniqId:function(){return((new Date).getTime()+Math.floor(Math.random()*Math.pow(10,15))).toString(36)},cspBuffer:{CSP_ATTRIB:"data-csp-01928735",domElementsStyles:{},stash:function(i){var a=this,r=e.parseHTML("
    "+i+"
    "),n=e(r);n.find("[style]").each(function(i,r){var n=e(r),o=n.attr("style"),l=t.uniqId(),s={};o&&o.length&&(-1===o.indexOf(";")&&(o+=";"),o.slice(0,o.length-1).split(";").map(function(e){e=e.split(":"),e[0]&&(s[e[0]]=e[1]?e[1]:"")}),a.domElementsStyles[l]=s,n.removeAttr("style").attr(a.CSP_ATTRIB,l))}),n.filter("*").removeAttr("style");var o=Object.values?Object.values(r):Object.keys(r).map(function(e){return r[e]});return o.flatMap(function(e){return e.innerHTML}).join("")},apply:function(t){var i=this,a=e(t);a.find("["+i.CSP_ATTRIB+"]").each(function(t,a){var r=e(a),n=r.attr(i.CSP_ATTRIB),o=i.domElementsStyles[n];o&&r.css(o),r.removeAttr(i.CSP_ATTRIB)}),i.domElementsStyles={}}},setHtml:function(e,i){var a=t.cspBuffer;return e.html(a.stash(i)),a.apply(e),e},htmlEncode:function(e,t){return void 0===e?t||null:e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},replaceTags:function(t,i){var a=t;return i?(e.each(i,function(e,t){"function"==typeof t&&(t=t()),a=a.split(e).join(t)}),a):a},cleanMemory:function(e){var i=e.is("img")?e.attr("src"):e.find("source").attr("src");t.revokeObjectURL(i)},findFileName:function(e){var t=e.lastIndexOf("/");return -1===t&&(t=e.lastIndexOf("\\")),e.split(e.substring(t,t+1)).pop()},checkFullScreen:function(){return document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement},toggleFullScreen:function(e){var i=document,a=i.documentElement,r=t.checkFullScreen();a&&e&&!r?a.requestFullscreen?a.requestFullscreen():a.msRequestFullscreen?a.msRequestFullscreen():a.mozRequestFullScreen?a.mozRequestFullScreen():a.webkitRequestFullscreen&&a.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT):r&&(i.exitFullscreen?i.exitFullscreen():i.msExitFullscreen?i.msExitFullscreen():i.mozCancelFullScreen?i.mozCancelFullScreen():i.webkitExitFullscreen&&i.webkitExitFullscreen())},moveArray:function(t,i,a,r){var n=e.extend(!0,[],t);if(r&&n.reverse(),a>=n.length){for(var o=a-n.length;o--+1;){n.push(void 0)}}return n.splice(a,0,n.splice(i,1)[0]),r&&n.reverse(),n},closeButton:function(e){return e=e?"close "+e:"close",''},getRotation:function(e){switch(e){case 2:return"rotateY(180deg)";case 3:return"rotate(180deg)";case 4:return"rotate(180deg) rotateY(180deg)";case 5:return"rotate(270deg) rotateY(180deg)";case 6:return"rotate(90deg)";case 7:return"rotate(90deg) rotateY(180deg)";case 8:return"rotate(270deg)";default:return""}},setTransform:function(e,t){e&&(e.style.transform=t,e.style.webkitTransform=t,e.style["-moz-transform"]=t,e.style["-ms-transform"]=t,e.style["-o-transform"]=t)},getObjectKeys:function(t){var i=[];return t&&e.each(t,function(e){i.push(e)}),i},getObjectSize:function(e){return t.getObjectKeys(e).length},whenAll:function(i){var a,r,n,o,l,s,d=[].slice,c=1===arguments.length&&t.isArray(i)?i:d.call(arguments),u=e.Deferred(),p=0,f=c.length,g=f;for(n=o=l=Array(f),s=function(e,t,i){return function(){i!==c&&p++,u.notifyWith(t[e]=this,i[e]=d.call(arguments)),--g||u[(p?"reject":"resolve")+"With"](t,i)}},a=0;f>a;a++){(r=c[a])&&e.isFunction(r.promise)?r.promise().done(s(a,l,c)).fail(s(a,n,o)):(u.notifyWith(this,r),--g)}return g||u.resolveWith(l,c),u.promise()}},i=function(i,a){var r=this;r.$element=e(i),r.$parent=r.$element.parent(),r._validate()&&(r.isPreviewable=t.hasFileAPISupport(),r.isIE9=t.isIE(9),r.isIE10=t.isIE(10),(r.isPreviewable||r.isIE9)&&(r._init(a),r._listen()),r.$element.removeClass("file-loading"))},i.prototype={constructor:i,_cleanup:function(){var e=this;e.reader=null,e.clearFileStack(),e.fileBatchCompleted=!0,e.isError=!1,e.isDuplicateError=!1,e.isPersistentError=!1,e.cancelling=!1,e.paused=!1,e.lastProgress=0,e._initAjax()},_isAborted:function(){var e=this;return e.cancelling||e.paused},_initAjax:function(){var i=this,a=i.taskManager={pool:{},addPool:function(e){return a.pool[e]=new a.TasksPool(e)},getPool:function(e){return a.pool[e]},addTask:function(e,t){return new a.Task(e,t)},TasksPool:function(i){var r=this;r.id=i,r.cancelled=!1,r.cancelledDeferrer=e.Deferred(),r.tasks={},r.addTask=function(e,t){return r.tasks[e]=new a.Task(e,t)},r.size=function(){return t.getObjectSize(r.tasks)},r.run=function(i){var a,n,o,l=0,s=!1,d=t.getObjectKeys(r.tasks).map(function(e){return r.tasks[e]}),c=[],u=e.Deferred();if(r.cancelled){return r.cancelledDeferrer.resolve(),u.reject()}if(!i){var p=t.getObjectKeys(r.tasks).map(function(e){return r.tasks[e].deferred});return t.whenAll(p).done(function(){var e=t.getArray(arguments);r.cancelled?(u.reject.apply(null,e),r.cancelledDeferrer.resolve()):(u.resolve.apply(null,e),r.cancelledDeferrer.reject())}).fail(function(){var e=t.getArray(arguments);u.reject.apply(null,e),r.cancelled?r.cancelledDeferrer.resolve():r.cancelledDeferrer.reject()}),e.each(r.tasks,function(e){a=r.tasks[e],a.run()}),u}for(n=function(t){e.when(t.deferred).fail(function(){s=!0,o.apply(null,arguments)}).always(o)},o=function(){var e=t.getArray(arguments);return u.notify(e),c.push(e),r.cancelled?(u.reject.apply(null,c),void r.cancelledDeferrer.resolve()):(c.length===r.size()&&(s?u.reject.apply(null,c):u.resolve.apply(null,c)),void (d.length&&(a=d.shift(),n(a),a.run())))};d.length&&l++0&&s.maxTotalFileCounti.file.size?i.file.size:e},getTotalChunks:function(){var e=parseFloat(i.chunkSize);return !isNaN(e)&&e>0?Math.ceil(i.file.size/e):0},getProgress:function(){var e=i.processedResumables(),t=i.chunkCount;return 0===t?0:Math.ceil(e/t*100)},checkAborted:function(e){a._isAborted()&&(clearInterval(e),a.unlock())},upload:function(){var e,r=o.getIdList(),n="new";e=setInterval(function(){var l;if(i.checkAborted(e),"new"===n&&(a.lock(),n="processing",l=r.shift(),o.initStats(l),o.stack[l]&&(i.init(l,o.stack[l],o.getIndex(l)),i.processUpload())),!o.isPending(l)&&i.completed&&(n="new"),o.isProcessed()){var s=a.$preview.find(".file-preview-initial");s.length&&(t.addCss(s,t.SORT_CSS),a._initSortable()),clearInterval(e),a._clearFileInput(),a.unlock(),setTimeout(function(){var e=a.previewCache.data;e&&(a.initialPreview=e.content,a.initialPreviewConfig=e.config,a.initialPreviewThumbTags=e.tags),a._raise("filebatchuploadcomplete",[a.initialPreview,a.initialPreviewConfig,a.initialPreviewThumbTags,a._getExtraData()])},a.processDelay)}},a.processDelay)},uploadResumable:function(){var e,t,n=a.taskManager,o=i.chunkCount;for(t=n.addPool(i.id),e=0;o>e;e++){i.logs[e]=!(!i.chunksProcessed[i.id]||!i.chunksProcessed[i.id][e]),i.logs[e]||i.pushAjax(e,0)}t.run(r.maxThreads).done(function(){i.setProcessed("success")}).fail(function(){i.setProcessed(t.cancelled?"cancel":"error")})},processUpload:function(){var n,l,s,d,c,u,p,f=i.id;return r.testUrl?(n=new FormData,l=o.stack[f],a._setUploadData(n,{fileId:f,fileName:l.fileName,fileSize:l.size,fileRelativePath:l.relativePath,chunkSize:i.chunkSize,chunkCount:i.chunkCount}),s=function(e){p=a._getOutData(n,e),a._raise("filetestbeforesend",[f,o,i,p])},d=function(r,l,s){p=a._getOutData(n,s,r);var d=a.uploadParamNames,c=d.chunksUploaded||"chunksUploaded",u=[f,o,i,p];r[c]&&t.isArray(r[c])?(i.chunksProcessed[f]||(i.chunksProcessed[f]={}),e.each(r[c],function(e,t){i.logs[t]=!0,i.chunksProcessed[f][t]=!0}),i.chunksProcessed[f].data=r,a._raise("filetestsuccess",u)):a._raise("filetesterror",u),i.uploadResumable()},c=function(e,t,r){p=a._getOutData(n,e),a._raise("filetestajaxerror",[f,o,i,p]),i.setAjaxError(e,t,r,!0),i.uploadResumable()},u=function(){a._raise("filetestcomplete",[f,o,i,a._getOutData(n)])},void a._ajaxSubmit(s,d,u,c,n,f,i.fileIndex,r.testUrl)):void i.uploadResumable()},pushAjax:function(e,t){var r=a.taskManager,o=r.getPool(i.id);o.addTask(o.size()+1,function(e){var t,r=i.stack.shift();t=r[0],i.chunksProcessed[i.id]&&i.chunksProcessed[i.id][t]?a._log(n.chunkQueueError,{index:t}):i.sendAjax(t,r[1],e)}),i.stack.push([e,t])},sendAjax:function(e,l,s){var d,c=i.chunkSize,u=i.id,p=i.file,f=i.$thumb,g=t.logMessages,m=i.$btnDelete,h=function(e,t){t&&(e=e.setTokens(t)),e="Error processing resumable ajax request. "+e,a._log(e),s.reject(e)};if(!i.chunksProcessed[u]||!i.chunksProcessed[u][e]){if(l>r.maxRetries){return h(g.resumableMaxRetriesReached,{n:r.maxRetries}),void i.setProcessed("error")}var v,w,b,_,C,y,x=p.slice?"slice":p.mozSlice?"mozSlice":p.webkitSlice?"webkitSlice":"slice",T=p[x](c*e,c*(e+1));v=new FormData,d=o.stack[u],a._setUploadData(v,{chunkCount:i.chunkCount,chunkIndex:e,chunkSize:c,chunkSizeStart:c*e,fileBlob:[T,i.fileName],fileId:u,fileName:i.fileName,fileRelativePath:d.relativePath,fileSize:p.size,retryCount:l}),i.$progress&&i.$progress.length&&i.$progress.show(),b=function(r){w=a._getOutData(v,r),a.showPreview&&(f.hasClass("file-preview-success")||(a._setThumbStatus(f,"Loading"),t.addCss(f,"file-uploading")),m.attr("disabled",!0)),a._raise("filechunkbeforesend",[u,e,l,o,i,w])},_=function(t,d,c){if(a._isAborted()){return void h(g.resumableAborting)}w=a._getOutData(v,c,t);var p=a.uploadParamNames,f=p.chunkIndex||"chunkIndex",m=[u,e,l,o,i,w];t.error?(r.showErrorLog&&a._log(n.retryStatus,{retry:l+1,filename:i.fileName,chunk:e}),i.pushAjax(e,l+1),i.error=t.error,a._raise("filechunkerror",m)):(i.logs[t[f]]=!0,i.chunksProcessed[u]||(i.chunksProcessed[u]={}),i.chunksProcessed[u][t[f]]=!0,i.chunksProcessed[u].data=t,s.resolve.call(null,t),a._raise("filechunksuccess",m),i.check())},C=function(t,r,n){return a._isAborted()?void h(g.resumableAborting):(w=a._getOutData(v,t),i.setAjaxError(t,r,n),a._raise("filechunkajaxerror",[u,e,l,o,i,w]),i.pushAjax(e,l+1),void h(g.resumableRetryError,{n:l-1}))},y=function(){a._isAborted()||a._raise("filechunkcomplete",[u,e,l,o,i,a._getOutData(v)])},a._ajaxSubmit(b,_,y,C,v,u,i.fileIndex)}}},i.reset()}},_initTemplateDefaults:function(){var i,a,r,n,o,l,s,d,c,u,p,f,g,m,h,v,w,b,_,C,y,x,T,P,F,E,k,S,I,A,D,z,j,U,M,$,R,O,B,L,N,Z,H=this,W=function(e,i){return'\n"+t.DEFAULT_PREVIEW+"\n\n"};i='{preview}\n
    \n
    \n {caption}\n
    \n {remove}\n {cancel}\n {pause}\n {upload}\n {browse}\n
    \n
    ',a='{preview}\n
    \n
    \n{remove}\n{cancel}\n{upload}\n{browse}\n',r='
    \n {close}
    \n
    \n
    \n
    \n
    \n
    \n
    ',o=t.closeButton("fileinput-remove"),n='',l='
    \n \n \n
    ',s='',d='{icon} {label}',c='
    {icon} {label}
    ',Z=t.MODAL_ID+"Label",u='',p='\n',f='
    \n
    \n {status}\n
    \n
    {stats}',N='
    {pendingTime} {uploadSpeed}
    ',g=" ({sizeText})",m='',h='
    \n \n
    \n{drag}\n
    ',v='\n',w='',b='{downloadIcon}',_='',C='{dragIcon}',y='
    {indicator}
    ',x='
    \n',P=x+' title="{caption}">
    \n',F="
    {footer}\n{zoomCache}
    \n",E="{content}\n",O=" {style}",k=W("html","text/html"),I=W("text","text/plain;charset=UTF-8"),$=W("pdf","application/pdf"),S='{alt}\n",A='",D='",z='\n",j='\n",U='\n",M='\n\n'+t.OBJECT_PARAMS+" "+t.DEFAULT_PREVIEW+"\n\n",R='
    \n"+t.DEFAULT_PREVIEW+"\n
    \n",B='
    {zoomContent}
    ',L={width:"100%",height:"100%","min-height":"480px"},H._isPdfRendered()&&($=H.pdfRendererTemplate.replace("{renderer}",H._encodeURI(H.pdfRendererUrl))),H.defaults={layoutTemplates:{main1:i,main2:a,preview:r,close:o,fileIcon:n,caption:l,modalMain:u,modal:p,progress:f,stats:N,size:g,footer:m,indicator:y,actions:h,actionDelete:v,actionUpload:w,actionDownload:b,actionZoom:_,actionDrag:C,btnDefault:s,btnLink:d,btnBrowse:c,zoomCache:B},previewMarkupTags:{tagBefore1:T,tagBefore2:P,tagAfter:F},previewContentTemplates:{generic:E,html:k,image:S,text:I,office:A,gdocs:D,video:z,audio:j,flash:U,object:M,pdf:$,other:R},allowedPreviewTypes:["image","html","text","video","audio","flash","pdf","object"],previewTemplates:{},previewSettings:{image:{width:"auto",height:"auto","max-width":"100%","max-height":"100%"},html:{width:"213px",height:"160px"},text:{width:"213px",height:"160px"},office:{width:"213px",height:"160px"},gdocs:{width:"213px",height:"160px"},video:{width:"213px",height:"160px"},audio:{width:"100%",height:"30px"},flash:{width:"213px",height:"160px"},object:{width:"213px",height:"160px"},pdf:{width:"100%",height:"160px",position:"relative"},other:{width:"213px",height:"160px"}},previewSettingsSmall:{image:{width:"auto",height:"auto","max-width":"100%","max-height":"100%"},html:{width:"100%",height:"160px"},text:{width:"100%",height:"160px"},office:{width:"100%",height:"160px"},gdocs:{width:"100%",height:"160px"},video:{width:"100%",height:"auto"},audio:{width:"100%",height:"30px"},flash:{width:"100%",height:"auto"},object:{width:"100%",height:"auto"},pdf:{width:"100%",height:"160px"},other:{width:"100%",height:"160px"}},previewZoomSettings:{image:{width:"auto",height:"auto","max-width":"100%","max-height":"100%"},html:L,text:L,office:{width:"100%",height:"100%","max-width":"100%","min-height":"480px"},gdocs:{width:"100%",height:"100%","max-width":"100%","min-height":"480px"},video:{width:"auto",height:"100%","max-width":"100%"},audio:{width:"100%",height:"30px"},flash:{width:"auto",height:"480px"},object:{width:"auto",height:"100%","max-width":"100%","min-height":"480px"},pdf:L,other:{width:"auto",height:"100%","min-height":"480px"}},mimeTypeAliases:{"video/quicktime":"video/mp4"},fileTypeSettings:{image:function(e,i){return t.compare(e,"image.*")&&!t.compare(e,/(tiff?|wmf)$/i)||t.compare(i,/\.(gif|png|jpe?g)$/i)},html:function(e,i){return t.compare(e,"text/html")||t.compare(i,/\.(htm|html)$/i)},office:function(e,i){return t.compare(e,/(word|excel|powerpoint|office)$/i)||t.compare(i,/\.(docx?|xlsx?|pptx?|pps|potx?)$/i)},gdocs:function(e,i){return t.compare(e,/(word|excel|powerpoint|office|iwork-pages|tiff?)$/i)||t.compare(i,/\.(docx?|xlsx?|pptx?|pps|potx?|rtf|ods|odt|pages|ai|dxf|ttf|tiff?|wmf|e?ps)$/i)},text:function(e,i){return t.compare(e,"text.*")||t.compare(i,/\.(xml|javascript)$/i)||t.compare(i,/\.(txt|md|nfo|ini|json|php|js|css)$/i)},video:function(e,i){return t.compare(e,"video.*")&&(t.compare(e,/(ogg|mp4|mp?g|mov|webm|3gp)$/i)||t.compare(i,/\.(og?|mp4|webm|mp?g|mov|3gp)$/i))},audio:function(e,i){return t.compare(e,"audio.*")&&(t.compare(i,/(ogg|mp3|mp?g|wav)$/i)||t.compare(i,/\.(og?|mp3|mp?g|wav)$/i))},flash:function(e,i){return t.compare(e,"application/x-shockwave-flash",!0)||t.compare(i,/\.(swf)$/i)},pdf:function(e,i){return t.compare(e,"application/pdf",!0)||t.compare(i,/\.(pdf)$/i)},object:function(){return !0},other:function(){return !0}},fileActionSettings:{showRemove:!0,showUpload:!0,showDownload:!0,showZoom:!0,showDrag:!0,removeIcon:'',removeClass:"btn btn-sm btn-kv btn-default btn-outline-secondary",removeErrorClass:"btn btn-sm btn-kv btn-danger",removeTitle:"Remove file",uploadIcon:'',uploadClass:"btn btn-sm btn-kv btn-default btn-outline-secondary",uploadTitle:"Upload file",uploadRetryIcon:'',uploadRetryTitle:"Retry upload",downloadIcon:'',downloadClass:"btn btn-sm btn-kv btn-default btn-outline-secondary",downloadTitle:"Download file",zoomIcon:'',zoomClass:"btn btn-sm btn-kv btn-default btn-outline-secondary",zoomTitle:"View Details",dragIcon:'',dragClass:"text-info",dragTitle:"Move / Rearrange",dragSettings:{},indicatorNew:'',indicatorSuccess:'',indicatorError:'',indicatorLoading:'',indicatorPaused:'',indicatorNewTitle:"Not uploaded yet",indicatorSuccessTitle:"Uploaded",indicatorErrorTitle:"Upload Error",indicatorLoadingTitle:"Uploading …",indicatorPausedTitle:"Upload Paused"}},e.each(H.defaults,function(t,i){return"allowedPreviewTypes"===t?void (void 0===H.allowedPreviewTypes&&(H.allowedPreviewTypes=i)):void (H[t]=e.extend(!0,{},i,H[t]))}),H._initPreviewTemplates()},_initPreviewTemplates:function(){var i,a=this,r=a.previewMarkupTags,n=r.tagAfter;e.each(a.previewContentTemplates,function(e,o){t.isEmpty(a.previewTemplates[e])&&(i=r.tagBefore2,("generic"===e||"image"===e)&&(i=r.tagBefore1),a._isPdfRendered()&&"pdf"===e&&(i=i.replace("kv-file-content","kv-file-content kv-pdf-rendered")),a.previewTemplates[e]=i+o+n)})},_initPreviewCache:function(){var i=this;i.previewCache={data:{},init:function(){var e=i.initialPreview;e.length>0&&!t.isArray(e)&&(e=e.split(i.initialPreviewDelimiter)),i.previewCache.data={content:e,config:i.initialPreviewConfig,tags:i.initialPreviewThumbTags}},count:function(e){if(!i.previewCache.data||!i.previewCache.data.content){return 0}if(e){var t=i.previewCache.data.content.filter(function(e){return null!==e});return t.length}return i.previewCache.data.content.length},get:function(e,a){var r,n,o,l,s,d,c,u=t.INIT_FLAG+e,p=i.previewCache.data,f=p.config[e],g=p.content[e],m=t.ifSet("previewAsData",f,i.initialPreviewAsData),h=f?{title:f.title||null,alt:f.alt||null}:{title:null,alt:null},v=function(e,a,r,n,o,l,s,d){var c=" file-preview-initial "+t.SORT_CSS+(s?" "+s:""),u=i.previewInitId+"-"+l,p=f&&f.fileId||u;return i._generatePreviewTemplate(e,a,r,n,u,p,!1,null,c,o,l,d,h,f&&f.zoomData||a)};return g&&g.length?(a=void 0===a?!0:a,o=t.ifSet("type",f,i.initialPreviewFileType||"generic"),s=t.ifSet("filename",f,t.ifSet("caption",f)),d=t.ifSet("filetype",f,o),l=i.previewCache.footer(e,a,f&&f.size||null),c=t.ifSet("frameClass",f),r=m?v(o,g,s,d,l,u,c):v("generic",g,s,d,l,u,c,o).setTokens({content:p.content[e]}),p.tags.length&&p.tags[e]&&(r=t.replaceTags(r,p.tags[e])),t.isEmpty(f)||t.isEmpty(f.frameAttr)||(n=t.createElement(r),n.find(".file-preview-initial").attr(f.frameAttr),r=n.html(),n.remove()),r):""},clean:function(e){e.content=t.cleanArray(e.content),e.config=t.cleanArray(e.config),e.tags=t.cleanArray(e.tags),i.previewCache.data=e},add:function(e,a,r,n){var o,l=i.previewCache.data;return e&&e.length?(o=e.length-1,t.isArray(e)||(e=e.split(i.initialPreviewDelimiter)),n&&l.content?(o=l.content.push(e[0])-1,l.config[o]=a,l.tags[o]=r):(l.content=e,l.config=a,l.tags=r),i.previewCache.clean(l),o):0},set:function(e,a,r,n){var o,l,s=i.previewCache.data;if(e&&e.length&&(t.isArray(e)||(e=e.split(i.initialPreviewDelimiter)),l=e.filter(function(e){return null!==e}),l.length)){if(void 0===s.content&&(s.content=[]),void 0===s.config&&(s.config=[]),void 0===s.tags&&(s.tags=[]),n){for(o=0;ot;t++){a=i.previewCache.get(t),r=i.reversePreviewOrder?a+r:r+a}return e=i._getMsgSelected(n),{content:r,caption:e}},footer:function(e,a,r){var n=i.previewCache.data||{};if(t.isEmpty(n.content)){return""}(t.isEmpty(n.config)||t.isEmpty(n.config[e]))&&(n.config[e]={}),a=void 0===a?!0:a;var o,l=n.config[e],s=t.ifSet("caption",l),d=t.ifSet("width",l,"auto"),c=t.ifSet("url",l,!1),u=t.ifSet("key",l,null),p=t.ifSet("fileId",l,null),f=i.fileActionSettings,g=i.initialPreviewShowDelete||!1,m=i.initialPreviewDownloadUrl?i.initialPreviewDownloadUrl+"?key="+u+(p?"&fileId="+p:""):"",h=l.downloadUrl||m,v=l.filename||l.caption||"",w=!!h,b=t.ifSet("showRemove",l,g),_=t.ifSet("showDownload",l,t.ifSet("showDownload",f,w)),C=t.ifSet("showZoom",l,t.ifSet("showZoom",f,!0)),y=t.ifSet("showDrag",l,t.ifSet("showDrag",f,!0)),x=c===!1&&a;return _=_&&l.downloadUrl!==!1&&!!h,o=i._renderFileActions(l,!1,_,b,C,y,x,c,u,!0,h,v),i._getLayoutTemplate("footer").setTokens({progress:i._renderThumbProgress(),actions:o,caption:s,size:i._getSize(r),width:d,indicator:""})}},i.previewCache.init()},_isPdfRendered:function(){var e=this,t=e.usePdfRenderer,i="function"==typeof t?t():!!t;return i&&e.pdfRendererUrl},_handler:function(e,t,i){var a=this,r=a.namespace,n=t.split(" ").join(r+" ")+r;e&&e.length&&e.off(n).on(n,i)},_encodeURI:function(e){var t=this;return t.encodeUrl?encodeURI(e):e},_log:function(e,t){var i=this,a=i.$element.attr("id");i.showConsoleLogs&&(a&&(e='"'+a+'": '+e),e="bootstrap-fileinput: "+e,"object"==typeof t&&(e=e.setTokens(t)),window.console&&void 0!==window.console.log?window.console.log(e):window.alert(e))},_validate:function(){var e=this,i="file"===e.$element.attr("type");return i||e._log(t.logMessages.badInputType),i},_errorsExist:function(){var i,a=this,r=a.$errorContainer.find("li");return r.length?!0:(i=t.createElement(a.$errorContainer.html()),i.find(".kv-error-close").remove(),i.find("ul").remove(),!!e.trim(i.text()).length)},_errorHandler:function(e,t){var i=this,a=e.target.error,r=function(e){i._showError(e.replace("{name}",t))};r(a.code===a.NOT_FOUND_ERR?i.msgFileNotFound:a.code===a.SECURITY_ERR?i.msgFileSecured:a.code===a.NOT_READABLE_ERR?i.msgFileNotReadable:a.code===a.ABORT_ERR?i.msgFilePreviewAborted:i.msgFilePreviewError)},_addError:function(e){var i=this,a=i.$errorContainer;e&&a.length&&(t.setHtml(a,i.errorCloseButton+e),i._handler(a.find(".kv-error-close"),"click",function(){setTimeout(function(){i.showPreview&&!i.getFrames().length&&i.clear(),a.fadeOut("slow")},i.processDelay)}))},_setValidationError:function(e){var i=this;e=(e?e+" ":"")+"has-error",i.$container.removeClass(e).addClass("has-error"),t.addCss(i.$captionContainer,"is-invalid")},_resetErrors:function(e){var t=this,i=t.$errorContainer;t.isPersistentError||(t.isError=!1,t.$container.removeClass("has-error"),t.$captionContainer.removeClass("is-invalid"),i.html(""),e?i.fadeOut("slow"):i.hide())},_showFolderError:function(e){var t,i=this,a=i.$errorContainer;e&&(i.isAjaxUpload||i._clearFileInput(),t=i.msgFoldersNotAllowed.replace("{n}",e),i._addError(t),i._setValidationError(),a.fadeIn(i.fadeDelay),i._raise("filefoldererror",[e,t]))},_showFileError:function(e,t,i){var a=this,r=a.$errorContainer,n=i||"fileuploaderror",o=t&&t.fileId||"",l=t&&t.id?'
  • '+e+"
  • ":"
  • "+e+"
  • ";return 0===r.find("ul").length?a._addError("
      "+l+"
    "):r.find("ul").append(l),r.fadeIn(a.fadeDelay),a._raise(n,[t,e]),a._setValidationError("file-input-new"),!0},_showError:function(e,t,i){var a=this,r=a.$errorContainer,n=i||"fileerror";return t=t||{},t.reader=a.reader,a._addError(e),r.fadeIn(a.fadeDelay),a._raise(n,[t,e]),a.isAjaxUpload||a._clearFileInput(),a._setValidationError("file-input-new"),a.$btnUpload.attr("disabled",!0),!0},_noFilesError:function(e){var t=this,i=t.minFileCount>1?t.filePlural:t.fileSingle,a=t.msgFilesTooLess.replace("{n}",t.minFileCount).replace("{files}",i),r=t.$errorContainer;a="
  • "+a+"
  • ",0===r.find("ul").length?t._addError("
      "+a+"
    "):r.find("ul").append(a),t.isError=!0,t._updateFileDetails(0),r.fadeIn(t.fadeDelay),t._raise("fileerror",[e,a]),t._clearFileInput(),t._setValidationError()},_parseError:function(t,i,a,r){var n,o,l,s=this,d=e.trim(a+"");return o=i.responseJSON&&i.responseJSON.error?""+i.responseJSON.error:"",l=o?o:i.responseText,s.cancelling&&s.msgUploadAborted&&(d=s.msgUploadAborted),s.showAjaxErrorDetails&&l&&(o?d=e.trim(o+""):(l=e.trim(l.replace(/\n\s*\n/g,"\n")),n=l.length?"
    "+l+"
    ":"",d+=d?n:l)),d||(d=s.msgAjaxError.replace("{operation}",t)),s.cancelling=!1,r?""+r+": "+d:d},_parseFileType:function(e,i){var a,r,n,o,l=this,s=l.allowedPreviewTypes||[];if("application/text-plain"===e){return"text"}for(o=0;o-1&&(i=t.split(".").pop(),a.previewFileIconSettings&&(r=a.previewFileIconSettings[i]||a.previewFileIconSettings[i.toLowerCase()]||null),a.previewFileExtSettings&&e.each(a.previewFileExtSettings,function(e,t){return a.previewFileIconSettings[e]&&t(i)?void (r=a.previewFileIconSettings[e]):void 0})),r||a.previewFileIcon},_parseFilePreviewIcon:function(e,t){var i=this,a=i._getPreviewIcon(t),r=e;return r.indexOf("{previewFileIcon}")>-1&&(r=r.setTokens({previewFileIconClass:i.previewFileIconClass,previewFileIcon:a})),r},_raise:function(t,i){var a=this,r=e.Event(t);if(void 0!==i?a.$element.trigger(r,i):a.$element.trigger(r),r.isDefaultPrevented()||r.result===!1){return !1}switch(t){case"filebatchuploadcomplete":case"filebatchuploadsuccess":case"fileuploaded":case"fileclear":case"filecleared":case"filereset":case"fileerror":case"filefoldererror":case"fileuploaderror":case"filebatchuploaderror":case"filedeleteerror":case"filecustomerror":case"filesuccessremove":break;default:a.ajaxAborted||(a.ajaxAborted=r.result)}return !0},_listenFullScreen:function(e){var t,i,a=this,r=a.$modal;r&&r.length&&(t=r&&r.find(".btn-fullscreen"),i=r&&r.find(".btn-borderless"),t.length&&i.length&&(t.removeClass("active").attr("aria-pressed","false"),i.removeClass("active").attr("aria-pressed","false"),e?t.addClass("active").attr("aria-pressed","true"):i.addClass("active").attr("aria-pressed","true"),r.hasClass("file-zoom-fullscreen")?a._maximizeZoomDialog():e?a._maximizeZoomDialog():i.removeClass("active").attr("aria-pressed","false")))},_listen:function(){var i,a,r,n=this,o=n.$element,l=n.$form,s=n.$container;n._handler(o,"click",function(e){o.hasClass("file-no-browse")&&(o.data("zoneClicked")?o.data("zoneClicked",!1):e.preventDefault())}),n._handler(o,"change",e.proxy(n._change,n)),n.showBrowse&&n._handler(n.$btnFile,"click",e.proxy(n._browse,n)),a=s.find(".file-caption-name"),r=function(){return !1},n._handler(s.find(".fileinput-remove:not([disabled])"),"click",e.proxy(n.clear,n)),n._handler(s.find(".fileinput-cancel"),"click",e.proxy(n.cancel,n)),n._handler(s.find(".fileinput-pause"),"click",e.proxy(n.pause,n)),n._handler(a,"keydown",r),n._handler(a,"paste",r),n._initDragDrop(),n._handler(l,"reset",e.proxy(n.clear,n)),n.isAjaxUpload||n._handler(l,"submit",e.proxy(n._submitForm,n)),n._handler(n.$container.find(".fileinput-upload"),"click",e.proxy(n._uploadClick,n)),n._handler(e(window),"resize",function(){n._listenFullScreen(screen.width===window.innerWidth&&screen.height===window.innerHeight)}),i="webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange",n._handler(e(document),i,function(){n._listenFullScreen(t.checkFullScreen())}),n._autoFitContent(),n._initClickable(),n._refreshPreview()},_autoFitContent:function(){var t,i=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,a=this,r=400>i?a.previewSettingsSmall||a.defaults.previewSettingsSmall:a.previewSettings||a.defaults.previewSettings;e.each(r,function(e,i){t=".file-preview-frame .file-preview-"+e,a.$preview.find(t+".kv-preview-data,"+t+" .kv-preview-data").css(i)})},_scanDroppedItems:function(e,i,a){a=a||"";var r,n,o,l=this,s=function(e){l._log(t.logMessages.badDroppedFiles),l._log(e)};e.isFile?e.file(function(e){a&&(e.newPath=a+e.name),i.push(e)},s):e.isDirectory&&(n=e.createReader(),(o=function(){n.readEntries(function(t){if(t&&t.length>0){for(r=0;r-1;return a._zoneDragDropInit(i),a.isDisabled||!n?(r.effectAllowed="none",void (r.dropEffect="none")):(r.dropEffect="copy",void (a._raise("fileDragEnter",{sourceEvent:i,files:r.types.Files})&&t.addCss(a.$dropZone,"file-highlighted")))},_zoneDragLeave:function(e){var t=this;t._zoneDragDropInit(e),t.isDisabled||t._raise("fileDragLeave",{sourceEvent:e})&&t.$dropZone.removeClass("file-highlighted")},_zoneDrop:function(e){var i,a=this,r=a.$element,n=e.originalEvent.dataTransfer,o=n.files,l=n.items,s=t.getDragDropFolders(l),d=function(){a.isAjaxUpload?a._change(e,o):(a.changeTriggered=!0,r.get(0).files=o,setTimeout(function(){a.changeTriggered=!1,r.trigger("change"+a.namespace)},a.processDelay)),a.$dropZone.removeClass("file-highlighted")};if(e.preventDefault(),!a.isDisabled&&!t.isEmpty(o)&&a._raise("fileDragDrop",{sourceEvent:e,files:o})){if(s>0){if(!a.isAjaxUpload){return void a._showFolderError(s)}for(o=[],i=0;i0&&n>=s,c=e(i.item);d&&(n=s-1),o.initialPreview=t.moveArray(o.initialPreview,r,n,u),o.initialPreviewConfig=t.moveArray(o.initialPreviewConfig,r,n,u),o.previewCache.init(),o.getFrames(".file-preview-initial").each(function(){e(this).attr("data-fileindex",t.INIT_FLAG+l),l++}),d&&(a=o.getFrames(":not(.file-preview-initial):first"),a.length&&c.slideUp(function(){c.insertBefore(a).slideDown()})),o._raise("filesorted",{previewId:c.attr("id"),oldIndex:r,newIndex:n,stack:o.initialPreviewConfig})}},e.extend(!0,i,o.fileActionSettings.dragSettings),o.sortable&&o.sortable.destroy(),o.sortable=p.create(l[0],i))},_setPreviewContent:function(e){var i=this;t.setHtml(i.$preview,e),i._autoFitContent()},_initPreviewImageOrientations:function(){var t=this,i=0,a=t.canOrientImage;(t.autoOrientImageInitial||a)&&t.getFrames(".file-preview-initial").each(function(){var r,n,o,l=e(this),s=t.initialPreviewConfig[i];s&&s.exif&&s.exif.Orientation&&(o=l.attr("id"),r=l.find(">.kv-file-content img"),n=t._getZoom(o," >.kv-file-content img"),a?r.css("image-orientation",t.autoOrientImageInitial?"from-image":"none"):t.setImageOrientation(r,n,s.exif.Orientation,l)),i++})},_initPreview:function(e){var i,a=this,r=a.initialCaption||"";return a.previewCache.count(!0)?(i=a.previewCache.out(),r=e&&a.initialCaption?a.initialCaption:i.caption,a._setPreviewContent(i.content),a._setInitThumbAttr(),a._setCaption(r),a._initSortable(),t.isEmpty(i.content)||a.$container.removeClass("file-input-new"),void a._initPreviewImageOrientations()):(a._clearPreview(),void (e?a._setCaption(r):a._initCaption()))},_getZoomButton:function(e){var t=this,i=t.previewZoomButtonIcons[e],a=t.previewZoomButtonClasses[e],r=' title="'+(t.previewZoomButtonTitles[e]||"")+'" ',n=r+("close"===e?' data-dismiss="modal" aria-hidden="true"':"");return("fullscreen"===e||"borderless"===e||"toggleheader"===e)&&(n+=' data-toggle="button" aria-pressed="false" autocomplete="off"'),'"},_getModalContent:function(){var e=this;return e._getLayoutTemplate("modal").setTokens({rtl:e.rtl?" kv-rtl":"",zoomFrameClass:e.frameClass,heading:e.msgZoomModalHeading,prev:e._getZoomButton("prev"),next:e._getZoomButton("next"),toggleheader:e._getZoomButton("toggleheader"),fullscreen:e._getZoomButton("fullscreen"),borderless:e._getZoomButton("borderless"),close:e._getZoomButton("close")})},_listenModalEvent:function(e){var i=this,a=i.$modal,r=function(e){return{sourceEvent:e,previewId:a.data("previewId"),modal:a}};a.on(e+".bs.modal",function(n){var o=a.find(".btn-fullscreen"),l=a.find(".btn-borderless");a.data("fileinputPluginId")===i.$element.attr("id")&&i._raise("filezoom"+e,r(n)),"shown"===e&&(l.removeClass("active").attr("aria-pressed","false"),o.removeClass("active").attr("aria-pressed","false"),a.hasClass("file-zoom-fullscreen")&&(i._maximizeZoomDialog(),t.checkFullScreen()?o.addClass("active").attr("aria-pressed","true"):l.addClass("active").attr("aria-pressed","true")))})},_initZoom:function(){var i,a=this,r=a._getLayoutTemplate("modalMain"),n="#"+t.MODAL_ID;a.showPreview&&(a.$modal=e(n),a.$modal&&a.$modal.length||(i=t.createElement(t.cspBuffer.stash(r)).insertAfter(a.$container),a.$modal=e(n).insertBefore(i),t.cspBuffer.apply(a.$modal),i.remove()),t.initModal(a.$modal),a.$modal.html(t.cspBuffer.stash(a._getModalContent())),t.cspBuffer.apply(a.$modal),e.each(t.MODAL_EVENTS,function(e,t){a._listenModalEvent(t)}))},_initZoomButtons:function(){var t,i,a=this,r=a.$modal.data("previewId")||"",n=a.getFrames().toArray(),o=n.length,l=a.$modal.find(".btn-prev"),s=a.$modal.find(".btn-next");return n.length<2?(l.hide(),void s.hide()):(l.show(),s.show(),void (o&&(t=e(n[0]),i=e(n[o-1]),l.removeAttr("disabled"),s.removeAttr("disabled"),t.length&&t.attr("id")===r&&l.attr("disabled",!0),i.length&&i.attr("id")===r&&s.attr("disabled",!0))))},_maximizeZoomDialog:function(){var t=this,i=t.$modal,a=i.find(".modal-header:visible"),r=i.find(".modal-footer:visible"),n=i.find(".modal-body"),o=e(window).height(),l=0;i.addClass("file-zoom-fullscreen"),a&&a.length&&(o-=a.outerHeight(!0)),r&&r.length&&(o-=r.outerHeight(!0)),n&&n.length&&(l=n.outerHeight(!0)-n.height(),o-=l),i.find(".kv-zoom-body").height(o)},_resizeZoomDialog:function(e){var i=this,a=i.$modal,r=a.find(".btn-fullscreen"),n=a.find(".btn-borderless");if(a.hasClass("file-zoom-fullscreen")){t.toggleFullScreen(!1),e?r.hasClass("active")||(a.removeClass("file-zoom-fullscreen"),i._resizeZoomDialog(!0),n.hasClass("active")&&n.removeClass("active").attr("aria-pressed","false")):r.hasClass("active")?r.removeClass("active").attr("aria-pressed","false"):(a.removeClass("file-zoom-fullscreen"),i.$modal.find(".kv-zoom-body").css("height",i.zoomModalHeight))}else{if(!e){return void i._maximizeZoomDialog()}t.toggleFullScreen(!0)}a.focus()},_setZoomContent:function(i,a){var r,n,o,l,s,d,c,u,p,f,g=this,m=i.attr("id"),h=g._getZoom(m),v=g.$modal,w=v.find(".btn-fullscreen"),b=v.find(".btn-borderless"),_=v.find(".btn-toggleheader");n=h.attr("data-template")||"generic",r=h.find(".kv-file-content"),o=r.length?r.html():"",p=i.data("caption")||"",f=i.data("size")||"",l=p+" "+f,v.find(".kv-zoom-title").attr("title",e("
    ").html(l).text()).html(l),s=v.find(".kv-zoom-body"),v.removeClass("kv-single-content"),a?(u=s.addClass("file-thumb-loading").clone().insertAfter(s),t.setHtml(s,o).hide(),u.fadeOut("fast",function(){s.fadeIn("fast",function(){s.removeClass("file-thumb-loading")}),u.remove()})):t.setHtml(s,o),c=g.previewZoomSettings[n],c&&(d=s.find(".kv-preview-data"),t.addCss(d,"file-zoom-detail"),e.each(c,function(e,t){d.css(e,t),(d.attr("width")&&"width"===e||d.attr("height")&&"height"===e)&&d.removeAttr(e)})),v.data("previewId",m),g._handler(v.find(".btn-prev"),"click",function(){g._zoomSlideShow("prev",m)}),g._handler(v.find(".btn-next"),"click",function(){g._zoomSlideShow("next",m)}),g._handler(w,"click",function(){g._resizeZoomDialog(!0)}),g._handler(b,"click",function(){g._resizeZoomDialog(!1)}),g._handler(_,"click",function(){var e,t=v.find(".modal-header"),i=v.find(".modal-body .floating-buttons"),a=t.find(".kv-zoom-actions"),r=function(e){var i=g.$modal.find(".kv-zoom-body"),a=g.zoomModalHeight;v.hasClass("file-zoom-fullscreen")&&(a=i.outerHeight(!0),e||(a-=t.outerHeight(!0))),i.css("height",e?a+e:a)};t.is(":visible")?(e=t.outerHeight(!0),t.slideUp("slow",function(){a.find(".btn").appendTo(i),r(e)})):(i.find(".btn").appendTo(a),t.slideDown("slow",function(){r()})),v.focus()}),g._handler(v,"keydown",function(t){var i=t.which||t.keyCode,a=e(this).find(".btn-prev"),r=e(this).find(".btn-next"),n=e(this).data("previewId"),o=g.rtl?39:37,l=g.rtl?37:39;i===o&&a.length&&!a.attr("disabled")&&g._zoomSlideShow("prev",n),i===l&&r.length&&!r.attr("disabled")&&g._zoomSlideShow("next",n)})},_showModal:function(e){var i=this,a=i.$modal;e&&e.length&&(t.initModal(a),t.setHtml(a,i._getModalContent()),i._setZoomContent(e),a.data("fileinputPluginId",i.$element.attr("id")),a.modal("show"),i._initZoomButtons())},_zoomPreview:function(e){var i,a=this;if(!e.length){throw"Cannot zoom to detailed preview!"}i=e.closest(t.FRAMES),a._showModal(i)},_zoomSlideShow:function(t,i){var a,r,n,o,l=this,s=l.$modal.find(".kv-zoom-actions .btn-"+t),d=l.getFrames().toArray(),c=[],u=d.length;if(!s.attr("disabled")){for(r=0;u>r;r++){n=e(d[r]),n&&n.length&&n.find(".kv-file-zoom:visible").length&&c.push(d[r])}for(u=c.length,r=0;u>r;r++){if(e(c[r]).attr("id")===i){o="prev"===t?r-1:r+1;break}}0>o||o>=u||!c[o]||(a=e(c[o]),a.length&&l._setZoomContent(a,!0),l._initZoomButtons(),l._raise("filezoom"+t,{previewId:i,modal:l.$modal}))}},_initZoomButton:function(){var t=this;t.$preview.find(".kv-file-zoom").each(function(){var i=e(this);t._handler(i,"click",function(){t._zoomPreview(i)})})},_inputFileCount:function(){return this.$element[0].files.length},_refreshPreview:function(){var t,i=this;(i._inputFileCount()||i.isAjaxUpload)&&i.showPreview&&i.isPreviewable&&(i.isAjaxUpload&&i.fileManager.count()>0?(t=e.extend(!0,{},i.fileManager.stack),i.fileManager.clear(),i._clearFileInput()):t=i.$element[0].files,t&&t.length&&(i.readFiles(t),i._setFileDropZoneTitle()))},_clearObjects:function(t){t.find("video audio").each(function(){this.pause(),e(this).remove()}),t.find("img object div").each(function(){e(this).remove()})},_clearFileInput:function(){var t,i,a,r=this,n=r.$element;r._inputFileCount()&&(t=n.closest("form"),i=e(document.createElement("form")),a=e(document.createElement("div")),n.before(a),t.length?t.after(i):a.after(i),i.append(n).trigger("reset"),a.before(n).remove(),i.remove())},_resetUpload:function(){var e=this;e.uploadStartTime=t.now(),e.uploadCache=[],e.$btnUpload.removeAttr("disabled"),e._setProgress(0),e._hideProgress(),e._resetErrors(!1),e._initAjax(),e.fileManager.clearImages(),e._resetCanvas(),e.overwriteInitial&&(e.initialPreview=[],e.initialPreviewConfig=[],e.initialPreviewThumbTags=[],e.previewCache.data={content:[],config:[],tags:[]})},_resetCanvas:function(){var e=this;e.canvas&&e.imageCanvasContext&&e.imageCanvasContext.clearRect(0,0,e.canvas.width,e.canvas.height)},_hasInitialPreview:function(){var e=this;return !e.overwriteInitial&&e.previewCache.count(!0)},_resetPreview:function(){var i,a,r,n=this,o=n.showUploadedThumbs,l=!n.removeFromPreviewOnError,s=(o||l)&&n.isDuplicateError;n.previewCache.count(!0)?(i=n.previewCache.out(),s&&(r=t.createElement("").insertAfter(n.$container),n.getFrames().each(function(){var t=e(this);(o&&t.hasClass("file-preview-success")||l&&t.hasClass("file-preview-error"))&&r.append(t)})),n._setPreviewContent(i.content),n._setInitThumbAttr(),a=n.initialCaption?n.initialCaption:i.caption,n._setCaption(a),s&&(r.contents().appendTo(n.$preview),r.remove())):(n._clearPreview(),n._initCaption()),n.showPreview&&(n._initZoom(),n._initSortable()),n.isDuplicateError=!1},_clearDefaultPreview:function(){var e=this;e.$preview.find(".file-default-preview").remove()},_validateDefaultPreview:function(){var e=this;e.showPreview&&!t.isEmpty(e.defaultPreviewContent)&&(e._setPreviewContent('
    '+e.defaultPreviewContent+"
    "),e.$container.removeClass("file-input-new"),e._initClickable())},_resetPreviewThumbs:function(e){var t,i=this;return e?(i._clearPreview(),void i.clearFileStack()):void (i._hasInitialPreview()?(t=i.previewCache.out(),i._setPreviewContent(t.content),i._setInitThumbAttr(),i._setCaption(t.caption),i._initPreviewActions()):i._clearPreview())},_getLayoutTemplate:function(e){var i=this,a=i.layoutTemplates[e];return t.isEmpty(i.customLayoutTags)?a:t.replaceTags(a,i.customLayoutTags)},_getPreviewTemplate:function(e){var i=this,a=i.previewTemplates,r=a[e]||a.other;return t.isEmpty(i.customPreviewTags)?r:t.replaceTags(r,i.customPreviewTags)},_getOutData:function(e,t,i,a){var r=this;return t=t||{},i=i||{},a=a||r.fileManager.list(),{formdata:e,files:a,filenames:r.filenames,filescount:r.getFilesCount(),extra:r._getExtraData(),response:i,reader:r.reader,jqXHR:t}},_getMsgSelected:function(e){var t=this,i=1===e?t.fileSingle:t.filePlural;return e>0?t.msgSelected.replace("{n}",e).replace("{files}",i):t.msgNoFilesSelected},_getFrame:function(e,i){var a=this,r=t.getFrameElement(a.$preview,e);return !a.showPreview||i||r.length||a._log(t.logMessages.invalidThumb,{id:e}),r},_getZoom:function(e,i){var a=this,r=t.getZoomElement(a.$preview,e,i);return a.showPreview&&!r.length&&a._log(t.logMessages.invalidThumb,{id:e}),r},_getThumbs:function(e){return e=e||"",this.getFrames(":not(.file-preview-initial)"+e)},_getThumbId:function(e){var t=this;return t.previewInitId+"-"+e},_getExtraData:function(e,t){var i=this,a=i.uploadExtraData;return"function"==typeof i.uploadExtraData&&(a=i.uploadExtraData(e,t)),a},_initXhr:function(e,i){var a=this,r=a.fileManager,n=function(e){var n=0,o=e.total,l=e.loaded||e.position,s=r.getUploadStats(i,l,o);e.lengthComputable&&!a.enableResumableUpload&&(n=t.round(l/o*100)),i?a._setFileUploadStats(i,n,s):a._setProgress(n,null,null,a._getStats(s)),a._raise("fileajaxprogress",[s])};return e.upload&&(a.progressDelay&&(n=t.debounce(n,a.progressDelay)),e.upload.addEventListener("progress",n,!1)),e},_initAjaxSettings:function(){var t=this;t._ajaxSettings=e.extend(!0,{},t.ajaxSettings),t._ajaxDeleteSettings=e.extend(!0,{},t.ajaxDeleteSettings)},_mergeAjaxCallback:function(e,t,i){var a,r=this,n=r._ajaxSettings,o=r.mergeAjaxCallbacks;"delete"===i&&(n=r._ajaxDeleteSettings,o=r.mergeAjaxDeleteCallbacks),a=n[e],o&&"function"==typeof a?"before"===o?n[e]=function(){a.apply(this,arguments),t.apply(this,arguments)}:n[e]=function(){t.apply(this,arguments),a.apply(this,arguments)}:n[e]=t},_ajaxSubmit:function(t,i,a,r,n,o,l,s){var d,c,u,p,f=this;f._raise("filepreajax",[n,o,l])&&(n.append("initialPreview",JSON.stringify(f.initialPreview)),n.append("initialPreviewConfig",JSON.stringify(f.initialPreviewConfig)),n.append("initialPreviewThumbTags",JSON.stringify(f.initialPreviewThumbTags)),f._initAjaxSettings(),f._mergeAjaxCallback("beforeSend",t),f._mergeAjaxCallback("success",i),f._mergeAjaxCallback("complete",a),f._mergeAjaxCallback("error",r),s=s||f.uploadUrlThumb||f.uploadUrl,"function"==typeof s&&(s=s()),u=f._getExtraData(o,l)||{},"object"==typeof u&&e.each(u,function(e,t){n.append(e,t)}),c={xhr:function(){var t=e.ajaxSettings.xhr();return f._initXhr(t,o)},url:f._encodeURI(s),type:"POST",dataType:"json",data:n,cache:!1,processData:!1,contentType:!1},d=e.extend(!0,{},c,f._ajaxSettings),p=f.taskManager.addTask(o+"-"+l,function(){var t,i,a=this.self;t=a.ajaxQueue.shift(),i=e.ajax(t),a.ajaxRequests.push(i)}),f.ajaxQueue.push(d),p.runWithContext({self:f}))},_mergeArray:function(e,i){var a=this,r=t.cleanArray(a[e]),n=t.cleanArray(i);a[e]=r.concat(n)},_initUploadSuccess:function(i,a,r){var n,o,l,s,d,c,u,p,f,g,m=this;return !m.showPreview||"object"!=typeof i||e.isEmptyObject(i)?void m._resetCaption():(void 0!==i.initialPreview&&i.initialPreview.length>0&&(m.hasInitData=!0,c=i.initialPreview||[],u=i.initialPreviewConfig||[],p=i.initialPreviewThumbTags||[],n=void 0===i.append||i.append,c.length>0&&!t.isArray(c)&&(c=c.split(m.initialPreviewDelimiter)),c.length&&(m._mergeArray("initialPreview",c),m._mergeArray("initialPreviewConfig",u),m._mergeArray("initialPreviewThumbTags",p)),void 0!==a?r?(f=a.attr("id"),g=m._getUploadCacheIndex(f),null!==g&&(m.uploadCache[g]={id:f,content:c[0],config:u[0]||[],tags:p[0]||[],append:n})):(l=m.previewCache.add(c[0],u[0],p[0],n),o=m.previewCache.get(l,!1),s=t.createElement(o).hide().appendTo(a),d=s.find(".kv-zoom-cache"),d&&d.length&&d.appendTo(a),a.fadeOut("slow",function(){var e=s.find(".file-preview-frame");e&&e.length&&e.insertBefore(a).fadeIn("slow").css("display:inline-block"),m._initPreviewActions(),m._clearFileInput(),a.remove(),s.remove(),m._initSortable()})):(m.previewCache.set(c,u,p,n),m._initPreview(),m._initPreviewActions())),void m._resetCaption())},_getUploadCacheIndex:function(e){var t,i,a=this,r=a.uploadCache.length;for(t=0;r>t;t++){if(i=a.uploadCache[t],i.id===e){return t}}return null},_initSuccessThumbs:function(){var i=this;i.showPreview&&i._getThumbs(t.FRAMES+".file-preview-success").each(function(){var a=e(this),r=a.find(".kv-file-remove");r.removeAttr("disabled"),i._handler(r,"click",function(){var e=a.attr("id"),r=i._raise("filesuccessremove",[e,a.attr("data-fileindex")]);t.cleanMemory(a),r!==!1&&a.fadeOut("slow",function(){a.remove(),i.getFrames().length||i.reset()})})})},_updateInitialPreview:function(){var t=this,i=t.uploadCache;t.showPreview&&(e.each(i,function(e,i){t.previewCache.add(i.content,i.config,i.tags,i.append)}),t.hasInitData&&(t._initPreview(),t._initPreviewActions()))},_uploadSingle:function(i,a,r){var n,o,l,s,d,c,u,p,f,g,m,h,v,w=this,b=w.fileManager,_=b.count(),C=new FormData,y=w._getThumbId(a),x=_>0||!e.isEmptyObject(w.uploadExtraData),T=w.ajaxOperations.uploadThumb,P=b.getFile(a),F={id:y,index:i,fileId:a},E=w.fileManager.getFileName(a,!0);w.enableResumableUpload||(w.showPreview&&(o=w.fileManager.getThumb(a),u=o.find(".file-thumb-progress"),s=o.find(".kv-file-upload"),d=o.find(".kv-file-remove"),u.show()),0===_||!x||w.showPreview&&s&&s.hasClass("disabled")||w._abort(F)||(v=function(){c?b.errors.push(a):b.removeFile(a),b.setProcessed(a),b.isProcessed()&&(w.fileBatchCompleted=!0,l())},l=function(){var e;w.fileBatchCompleted&&setTimeout(function(){var i=0===b.count(),a=b.errors.length;w._updateInitialPreview(),w.unlock(i),i&&w._clearFileInput(),e=w.$preview.find(".file-preview-initial"),w.uploadAsync&&e.length&&(t.addCss(e,t.SORT_CSS),w._initSortable()),w._raise("filebatchuploadcomplete",[b.stack,w._getExtraData()]),w.retryErrorUploads&&0!==a||b.clear(),w._setProgress(101),w.ajaxAborted=!1},w.processDelay)},p=function(l){n=w._getOutData(C,l),b.initStats(a),w.fileBatchCompleted=!1,r||(w.ajaxAborted=!1),w.showPreview&&(o.hasClass("file-preview-success")||(w._setThumbStatus(o,"Loading"),t.addCss(o,"file-uploading")),s.attr("disabled",!0),d.attr("disabled",!0)),r||w.lock(),-1!==b.errors.indexOf(a)&&delete b.errors[a],w._raise("filepreupload",[n,y,i]),e.extend(!0,F,n),w._abort(F)&&(l.abort(),r||(w._setThumbStatus(o,"New"),o.removeClass("file-uploading"),s.removeAttr("disabled"),d.removeAttr("disabled"),w.unlock()),w._setProgressCancelled())},g=function(l,d,p){var g=w.showPreview&&o.attr("id")?o.attr("id"):y;n=w._getOutData(C,p,l),e.extend(!0,F,n),setTimeout(function(){t.isEmpty(l)||t.isEmpty(l.error)?(w.showPreview&&(w._setThumbStatus(o,"Success"),s.hide(),w._initUploadSuccess(l,o,r),w._setProgress(101,u)),w._raise("fileuploaded",[n,g,i]),r?v():w.fileManager.remove(o)):(c=!0,f=w._parseError(T,p,w.msgUploadError,w.fileManager.getFileName(a)),w._showFileError(f,F),w._setPreviewError(o,!0),w.retryErrorUploads||s.hide(),r&&v(),w._setProgress(101,w._getFrame(g).find(".file-thumb-progress"),w.msgUploadError))},w.processDelay)},m=function(){w.showPreview&&(s.removeAttr("disabled"),d.removeAttr("disabled"),o.removeClass("file-uploading")),r?l():(w.unlock(!1),w._clearFileInput()),w._initSuccessThumbs()},h=function(t,i,n){f=w._parseError(T,t,n,w.fileManager.getFileName(a)),c=!0,setTimeout(function(){var i;r&&v(),w.fileManager.setProgress(a,100),w._setPreviewError(o,!0),w.retryErrorUploads||s.hide(),e.extend(!0,F,w._getOutData(C,t)),w._setProgress(101,w.$progress,w.msgAjaxProgressError.replace("{operation}",T)),i=w.showPreview&&o?o.find(".file-thumb-progress"):"",w._setProgress(101,i,w.msgUploadError),w._showFileError(f,F)},w.processDelay)},w._setFileData(C,P.file,E,a),w._setUploadData(C,{fileId:a}),w._ajaxSubmit(p,g,m,h,C,a,i)))},_setFileData:function(e,t,i,a){var r=this,n=r.preProcessUpload;n&&"function"==typeof n?e.append(r.uploadFileAttr,n(a,t)):e.append(r.uploadFileAttr,t,i)},_uploadBatch:function(){var i,a,r,n,o,l,s=this,d=s.fileManager,c=d.total(),u={},p=c>0||!e.isEmptyObject(s.uploadExtraData),f=new FormData,g=s.ajaxOperations.uploadBatch;if(0!==c&&p&&!s._abort(u)){l=function(){s.fileManager.clear(),s._clearFileInput()},i=function(i){s.lock(),d.initStats();var a=s._getOutData(f,i);s.ajaxAborted=!1,s.showPreview&&s._getThumbs().each(function(){var i=e(this),a=i.find(".kv-file-upload"),r=i.find(".kv-file-remove");i.hasClass("file-preview-success")||(s._setThumbStatus(i,"Loading"),t.addCss(i,"file-uploading")),a.attr("disabled",!0),r.attr("disabled",!0)}),s._raise("filebatchpreupload",[a]),s._abort(a)&&(i.abort(),s._getThumbs().each(function(){var t=e(this),i=t.find(".kv-file-upload"),a=t.find(".kv-file-remove");t.hasClass("file-preview-loading")&&(s._setThumbStatus(t,"New"),t.removeClass("file-uploading")),i.removeAttr("disabled"),a.removeAttr("disabled")}),s._setProgressCancelled())},a=function(i,a,r){var n=s._getOutData(f,r,i),d=0,c=s._getThumbs(":not(.file-preview-success)"),u=t.isEmpty(i)||t.isEmpty(i.errorkeys)?[]:i.errorkeys;t.isEmpty(i)||t.isEmpty(i.error)?(s._raise("filebatchuploadsuccess",[n]),l(),s.showPreview?(c.each(function(){var t=e(this);s._setThumbStatus(t,"Success"),t.removeClass("file-uploading"),t.find(".kv-file-upload").hide().removeAttr("disabled")}),s._initUploadSuccess(i)):s.reset(),s._setProgress(101)):(s.showPreview&&(c.each(function(){var t=e(this);t.removeClass("file-uploading"),t.find(".kv-file-upload").removeAttr("disabled"),t.find(".kv-file-remove").removeAttr("disabled"),0===u.length||-1!==e.inArray(d,u)?(s._setPreviewError(t,!0),s.retryErrorUploads||(t.find(".kv-file-upload").hide(),s.fileManager.remove(t))):(t.find(".kv-file-upload").hide(),s._setThumbStatus(t,"Success"),s.fileManager.remove(t)),(!t.hasClass("file-preview-error")||s.retryErrorUploads)&&d++}),s._initUploadSuccess(i)),o=s._parseError(g,r,s.msgUploadError),s._showFileError(o,n,"filebatchuploaderror"),s._setProgress(101,s.$progress,s.msgUploadError))},n=function(){s.unlock(),s._initSuccessThumbs(),s._clearFileInput(),s._raise("filebatchuploadcomplete",[s.fileManager.stack,s._getExtraData()])},r=function(t,i,a){var r=s._getOutData(f,t);o=s._parseError(g,t,a),s._showFileError(o,r,"filebatchuploaderror"),s.uploadFileCount=c-1,s.showPreview&&(s._getThumbs().each(function(){var t=e(this);t.removeClass("file-uploading"),s.fileManager.getFile(t.attr("data-fileid"))&&s._setPreviewError(t)}),s._getThumbs().removeClass("file-uploading"),s._getThumbs(" .kv-file-upload").removeAttr("disabled"),s._getThumbs(" .kv-file-delete").removeAttr("disabled"),s._setProgress(101,s.$progress,s.msgAjaxProgressError.replace("{operation}",g)))};var m=0;e.each(s.fileManager.stack,function(e,i){t.isEmpty(i.file)||s._setFileData(f,i.file,i.nameFmt||"untitled_"+m,e),m++}),s._ajaxSubmit(i,a,n,r,f)}},_uploadExtraOnly:function(){var e,i,a,r,n,o=this,l={},s=new FormData,d=o.ajaxOperations.uploadExtra;o._abort(l)||(e=function(e){o.lock();var t=o._getOutData(s,e);o._raise("filebatchpreupload",[t]),o._setProgress(50),l.data=t,l.xhr=e,o._abort(l)&&(e.abort(),o._setProgressCancelled())},i=function(e,i,a){var r=o._getOutData(s,a,e);t.isEmpty(e)||t.isEmpty(e.error)?(o._raise("filebatchuploadsuccess",[r]),o._clearFileInput(),o._initUploadSuccess(e),o._setProgress(101)):(n=o._parseError(d,a,o.msgUploadError),o._showFileError(n,r,"filebatchuploaderror"))},a=function(){o.unlock(),o._clearFileInput(),o._raise("filebatchuploadcomplete",[o.fileManager.stack,o._getExtraData()])},r=function(e,t,i){var a=o._getOutData(s,e);n=o._parseError(d,e,i),l.data=a,o._showFileError(n,a,"filebatchuploaderror"),o._setProgress(101,o.$progress,o.msgAjaxProgressError.replace("{operation}",d))},o._ajaxSubmit(e,i,a,r,s))},_deleteFileIndex:function(i){var a=this,r=i.attr("data-fileindex"),n=a.reversePreviewOrder;r.substring(0,5)===t.INIT_FLAG&&(r=parseInt(r.replace(t.INIT_FLAG,"")),a.initialPreview=t.spliceArray(a.initialPreview,r,n),a.initialPreviewConfig=t.spliceArray(a.initialPreviewConfig,r,n),a.initialPreviewThumbTags=t.spliceArray(a.initialPreviewThumbTags,r,n),a.getFrames().each(function(){var i=e(this),a=i.attr("data-fileindex");a.substring(0,5)===t.INIT_FLAG&&(a=parseInt(a.replace(t.INIT_FLAG,"")),a>r&&(a--,i.attr("data-fileindex",t.INIT_FLAG+a)))}))},_resetCaption:function(){var e=this;setTimeout(function(){var t,i,a,r=e.previewCache.count(!0),n=e.fileManager.count(),o=":not(.file-preview-success):not(.file-preview-error)",l=e.showPreview&&e.getFrames(o).length;0!==n||0!==r||l?(i=r+n,i>1?t=e._getMsgSelected(i):(a=e.fileManager.getFirstFile(),t=a?a.nameFmt:"_"),e._setCaption(t)):e.reset()},e.processDelay)},_initFileActions:function(){var i=this;i.showPreview&&(i._initZoomButton(),i.getFrames(" .kv-file-remove").each(function(){var a,r,n=e(this),o=n.closest(t.FRAMES),l=o.attr("id"),s=o.attr("data-fileindex");i._handler(n,"click",function(){return r=i._raise("filepreremove",[l,s]),r!==!1&&i._validateMinCount()?(a=o.hasClass("file-preview-error"),t.cleanMemory(o),void o.fadeOut("slow",function(){i.fileManager.remove(o),i._clearObjects(o),o.remove(),l&&a&&i.$errorContainer.find('li[data-thumb-id="'+l+'"]').fadeOut("fast",function(){e(this).remove(),i._errorsExist()||i._resetErrors()}),i._clearFileInput(),i._resetCaption(),i._raise("fileremoved",[l,s])})):!1})}),i.getFrames(" .kv-file-upload").each(function(){var a=e(this);i._handler(a,"click",function(){var e=a.closest(t.FRAMES),r=e.attr("data-fileid");i._hideProgress(),(!e.hasClass("file-preview-error")||i.retryErrorUploads)&&i._uploadSingle(i.fileManager.getIndex(r),r,!1)})}))},_initPreviewActions:function(){var i=this,a=i.$preview,r=i.deleteExtraData||{},n=t.FRAMES+" .kv-file-remove",o=i.fileActionSettings,l=o.removeClass,s=o.removeErrorClass,d=function(){var e=i.isAjaxUpload?i.previewCache.count(!0):i._inputFileCount();i.getFrames().length||e||(i._setCaption(""),i.reset(),i.initialCaption="")};i._initZoomButton(),a.find(n).each(function(){var a,n,o,c,u=e(this),p=u.data("url")||i.deleteUrl,f=u.data("key"),g=i.ajaxOperations.deleteThumb;if(!t.isEmpty(p)&&void 0!==f){"function"==typeof p&&(p=p());var m,h,v,w,b,_=u.closest(t.FRAMES),C=i.previewCache.data,y=_.attr("data-fileindex");y=parseInt(y.replace(t.INIT_FLAG,"")),v=t.isEmpty(C.config)&&t.isEmpty(C.config[y])?null:C.config[y],b=t.isEmpty(v)||t.isEmpty(v.extra)?r:v.extra,w=v&&(v.filename||v.caption)||"","function"==typeof b&&(b=b()),h={id:u.attr("id"),key:f,extra:b},n=function(e){i.ajaxAborted=!1,i._raise("filepredelete",[f,e,b]),i._abort()?e.abort():(u.removeClass(s),t.addCss(_,"file-uploading"),t.addCss(u,"disabled "+l))},o=function(e,r,n){var o,c;return t.isEmpty(e)||t.isEmpty(e.error)?(_.removeClass("file-uploading").addClass("file-deleted"),void _.fadeOut("slow",function(){y=parseInt(_.attr("data-fileindex").replace(t.INIT_FLAG,"")),i.previewCache.unset(y),i._deleteFileIndex(_),o=i.previewCache.count(!0),c=o>0?i._getMsgSelected(o):"",i._setCaption(c),i._raise("filedeleted",[f,n,b]),i._clearObjects(_),_.remove(),d()})):(h.jqXHR=n,h.response=e,a=i._parseError(g,n,i.msgDeleteError,w),i._showFileError(a,h,"filedeleteerror"),_.removeClass("file-uploading"),u.removeClass("disabled "+l).addClass(s),void d())},c=function(e,t,a){var r=i._parseError(g,e,a,w);h.jqXHR=e,h.response={},i._showFileError(r,h,"filedeleteerror"),_.removeClass("file-uploading"),u.removeClass("disabled "+l).addClass(s),d()},i._initAjaxSettings(),i._mergeAjaxCallback("beforeSend",n,"delete"),i._mergeAjaxCallback("success",o,"delete"),i._mergeAjaxCallback("error",c,"delete"),m=e.extend(!0,{},{url:i._encodeURI(p),type:"POST",dataType:"json",data:e.extend(!0,{},{key:f},b)},i._ajaxDeleteSettings),i._handler(u,"click",function(){return i._validateMinCount()?(i.ajaxAborted=!1,i._raise("filebeforedelete",[f,b]),void (i.ajaxAborted instanceof Promise?i.ajaxAborted.then(function(t){t||e.ajax(m)}):i.ajaxAborted||e.ajax(m))):!1})}})},_hideFileIcon:function(){var e=this;e.overwriteInitial&&e.$captionContainer.removeClass("icon-visible")},_showFileIcon:function(){var e=this;t.addCss(e.$captionContainer,"icon-visible")},_getSize:function(t,i){var a,r,n=this,o=parseFloat(t),l=n.fileSizeGetter;return e.isNumeric(t)&&e.isNumeric(o)?("function"==typeof l?r=l(o):0===o?r="0.00 B":(a=Math.floor(Math.log(o)/Math.log(1024)),i||(i=["B","KB","MB","GB","TB","PB","EB","ZB","YB"]),r=1*(o/Math.pow(1024,a)).toFixed(2)+" "+i[a]),n._getLayoutTemplate("size").replace("{sizeText}",r)):""},_getFileType:function(e){var t=this;return t.mimeTypeAliases[e]||e},_generatePreviewTemplate:function(i,a,r,n,o,l,s,d,c,u,p,f,g,m){var h,v,w,b=this,_=b.slug(r),C="",y="",x=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,T=_,P=_,F="type-default",E=u||b._renderFileFooter(i,_,d,"auto",s),k=b.preferIconicPreview,S=b.preferIconicZoomPreview,I=k?"other":i;return v=400>x?b.previewSettingsSmall[I]||b.defaults.previewSettingsSmall[I]:b.previewSettings[I]||b.defaults.previewSettings[I],v&&e.each(v,function(e,t){y+=e+":"+t+";"}),w=function(a,s,d,u){var m=d?"zoom-"+o:o,h=b._getPreviewTemplate(a),v=(c||"")+" "+u;return b.frameClass&&(v=b.frameClass+" "+v),d&&(v=v.replace(" "+t.SORT_CSS,"")),h=b._parseFilePreviewIcon(h,r),"object"!==i||n||e.each(b.defaults.fileTypeSettings,function(e,t){"object"!==e&&"other"!==e&&t(r,n)&&(F="type-"+e)}),t.isEmpty(g)||(void 0!==g.title&&null!==g.title&&(T=g.title),void 0!==g.alt&&null!==g.alt&&(T=g.alt)),h.setTokens({previewId:m,caption:_,title:T,alt:P,frameClass:v,type:b._getFileType(n),fileindex:p,fileid:l||"",typeCss:F,footer:E,data:s,template:f||i,style:y?'style="'+y+'"':""})},p=p||o.slice(o.lastIndexOf("-")+1),b.fileActionSettings.showZoom&&(C=w(S?"other":i,m?m:a,!0,"kv-zoom-thumb")),C="\n"+b._getLayoutTemplate("zoomCache").replace("{zoomContent}",C),"function"==typeof b.sanitizeZoomCache&&(C=b.sanitizeZoomCache(C)),h=w(k?"other":i,a,!1,"kv-preview-thumb"),h.setTokens({zoomCache:C})},_addToPreview:function(e,i){var a,r=this;return i=t.cspBuffer.stash(i),a=r.reversePreviewOrder?e.prepend(i):e.append(i),t.cspBuffer.apply(e),a},_previewDefault:function(e,i){var a=this,r=a.$preview;if(a.showPreview){var n,o=t.getFileName(e),l=e?e.type:"",s=e.size||0,d=a._getFileName(e,""),c=i===!0&&!a.isAjaxUpload,u=t.createObjectURL(e),p=a.fileManager.getId(e),f=a._getThumbId(p);a._clearDefaultPreview(),n=a._generatePreviewTemplate("other",u,o,l,f,p,c,s),a._addToPreview(r,n),a._setThumbAttr(f,d,s),i===!0&&a.isAjaxUpload&&a._setThumbStatus(a._getFrame(f),"Error")}},_previewFile:function(e,i,a,r,n){if(this.showPreview){var o,l=this,s=t.getFileName(i),d=n.type,c=n.name,u=l._parseFileType(d,s),p=l.$preview,f=i.size||0,g="image"===u?a.target.result:r,m=l.fileManager.getId(i),h=l._getThumbId(m);o=l._generatePreviewTemplate(u,g,s,d,h,m,!1,f),l._clearDefaultPreview(),l._addToPreview(p,o);var v=l._getFrame(h);l._validateImageOrientation(v.find("img"),i,h,m,c,d,f,g),l._setThumbAttr(h,c,f),l._initSortable()}},_setThumbAttr:function(e,t,i){var a=this,r=a._getFrame(e);r.length&&(i=i&&i>0?a._getSize(i):"",r.data({caption:t,size:i}))},_setInitThumbAttr:function(){var e,i,a,r,n=this,o=n.previewCache.data,l=n.previewCache.count(!0);if(0!==l){for(var s=0;l>s;s++){e=o.config[s],r=n.previewInitId+"-"+t.INIT_FLAG+s,i=t.ifSet("caption",e,t.ifSet("filename",e)),a=t.ifSet("size",e),n._setThumbAttr(r,i,a)}}},_slugDefault:function(e){return t.isEmpty(e,!0)?"":(e+"").replace(/[\[\]\/\{}:;#%=\(\)\*\+\?\\\^\$\|<>&"']/g,"_")},_updateFileDetails:function(e,i){var a,r,n,o,l,s=this,d=s.$element,c=t.isIE(9)&&t.findFileName(d.val())||d[0].files[0]&&d[0].files[0].name;!c&&s.fileManager.count()>0?(l=s.fileManager.getFirstFile(),a=l.nameFmt):a=c?s.slug(c):"_",r=s.isAjaxUpload?s.fileManager.count():e,o=s.previewCache.count(!0)+r,n=1===r?a:s._getMsgSelected(o),s.isError?(s.$previewContainer.removeClass("file-thumb-loading"),s.$previewStatus.html(""),s.$captionContainer.removeClass("icon-visible")):s._showFileIcon(),s._setCaption(n,s.isError),s.$container.removeClass("file-input-new file-input-ajax-new"),i||s._raise("fileselect",[e,a]),s.previewCache.count(!0)&&s._initPreviewActions()},_setThumbStatus:function(e,i){var a=this;if(a.showPreview){var r="indicator"+i,n=r+"Title",o="file-preview-"+i.toLowerCase(),l=e.find(".file-upload-indicator"),s=a.fileActionSettings;e.removeClass("file-preview-success file-preview-error file-preview-paused file-preview-loading"),"Success"===i&&e.find(".file-drag-handle").remove(),t.setHtml(l,s[r]),l.attr("title",s[n]),e.addClass(o),"Error"!==i||a.retryErrorUploads||e.find(".kv-file-upload").attr("disabled",!0)}},_setProgressCancelled:function(){var e=this;e._setProgress(101,e.$progress,e.msgCancelled)},_setProgress:function(e,i,a,r){var n=this;if(i=i||n.$progress,i.length){var o,l=Math.min(e,100),s=n.progressUploadThreshold,d=100>=e?n.progressTemplate:n.progressCompleteTemplate,c=100>l?n.progressTemplate:a?n.paused?n.progressPauseTemplate:n.progressErrorTemplate:d;e>=100&&(r=""),t.isEmpty(c)||(o=s&&l>s&&100>=e?c.setTokens({percent:s,status:n.msgUploadThreshold}):c.setTokens({percent:l,status:e>100?n.msgUploadEnd:l+"%"}),r=r||"",o=o.setTokens({stats:r}),t.setHtml(i,o),a&&t.setHtml(i.find('[role="progressbar"]'),a))}},_hasFiles:function(){var e=this.$element[0];return !!(e&&e.files&&e.files.length)},_setFileDropZoneTitle:function(){var e,i=this,a=i.$container.find(".file-drop-zone"),r=i.dropZoneTitle;i.isClickable&&(e=t.isEmpty(i.$element.attr("multiple"))?i.fileSingle:i.filePlural,r+=i.dropZoneClickTitle.replace("{files}",e)),a.find("."+i.dropZoneTitleClass).remove(),!i.showPreview||0===a.length||i.fileManager.count()>0||!i.dropZoneEnabled||i.previewCache.count()>0||!i.isAjaxUpload&&i._hasFiles()||(0===a.find(t.FRAMES).length&&t.isEmpty(i.defaultPreviewContent)&&a.prepend('
    '+r+"
    "),i.$container.removeClass("file-input-new"),t.addCss(i.$container,"file-input-ajax-new"))},_getStats:function(e){var i,a,r=this;return r.showUploadStats&&e&&e.bitrate?(a=r._getLayoutTemplate("stats"),i=e.elapsed&&e.bps?r.msgPendingTime.setTokens({time:t.getElapsed(Math.ceil(e.pendingBytes/e.bps))}):r.msgCalculatingTime,a.setTokens({uploadSpeed:e.bitrate,pendingTime:i})):""},_setResumableProgress:function(e,t,i){var a=this,r=a.resumableManager,n=i?r:a,o=i?i.find(".file-thumb-progress"):null;0===n.lastProgress&&(n.lastProgress=e),e0&&e._getFileCount(t-1)=g:g>=d,u||(s=p["msgImage"+o+i].setTokens({name:n,size:g}),p._showFileError(s,l),p._setPreviewError(r)))},_getExifObj:function(e){var i,a=this,r=t.logMessages.exifWarning;if("data:image/jpeg;base64,"!==e.slice(0,23)&&"data:image/jpg;base64,"!==e.slice(0,22)){return void (i=null)}try{i=window.piexif?window.piexif.load(e):null}catch(n){i=null,r=n&&n.message||""}return i||a._log(t.logMessages.badExifParser,{details:r}),i},setImageOrientation:function(i,a,r,n){var o,l,s,d=this,c=!i||!i.length,u=!a||!a.length,p=!1,f=c&&n&&"image"===n.attr("data-template");c&&u||(s="load.fileinputimageorient",f?(i=a,a=null,i.css(d.previewSettings.image),l=e(document.createElement("div")).appendTo(n.find(".kv-file-content")),o=e(document.createElement("span")).insertBefore(i),i.css("visibility","hidden").removeClass("file-zoom-detail").appendTo(l)):p=!i.is(":visible"),i.off(s).on(s,function(){p&&(d.$preview.removeClass("hide-content"),n.find(".kv-file-content").css("visibility","hidden"));var e=i[0],s=a&&a.length?a[0]:null,c=e.offsetHeight,u=e.offsetWidth,g=t.getRotation(r);if(p&&(n.find(".kv-file-content").css("visibility","visible"),d.$preview.addClass("hide-content")),i.data("orientation",r),s&&a.data("orientation",r),5>r){return t.setTransform(e,g),void t.setTransform(s,g)}var m=Math.atan(u/c),h=Math.sqrt(Math.pow(c,2)+Math.pow(u,2)),v=h?c/Math.cos(Math.PI/2+m)/h:1,w=" scale("+Math.abs(v)+")";t.setTransform(e,g+w),t.setTransform(s,g+w),f&&(i.css("visibility","visible").insertAfter(o).addClass("file-zoom-detail"),o.remove(),l.remove())}))},_validateImageOrientation:function(i,a,r,n,o,l,s,d){var c,u,p,f=this,g=f.autoOrientImage;return f.canOrientImage?void i.css("image-orientation",g?"from-image":"none"):(p=t.getZoomSelector(r," img"),c=g?f._getExifObj(d):null,(u=c?c["0th"][piexif.ImageIFD.Orientation]:null)?(f.setImageOrientation(i,e(p),u,f._getFrame(r)),f._raise("fileimageoriented",{$img:i,file:a}),void f._validateImage(r,n,o,l,s,d,c)):void f._validateImage(r,n,o,l,s,d,c))},_validateImage:function(t,i,a,r,n,o,l){var s,d,c,u=this,p=u.$preview,f=u._getFrame(t),g=f.attr("data-fileindex"),m=f.find("img");a=a||"Untitled",m.one("load",function(){d=f.width(),c=p.width(),d>c&&m.css("width","100%"),s={ind:g,id:t,fileId:i},u._checkDimensions(g,"Small",m,f,a,"Width",s),u._checkDimensions(g,"Small",m,f,a,"Height",s),u.resizeImage||(u._checkDimensions(g,"Large",m,f,a,"Width",s),u._checkDimensions(g,"Large",m,f,a,"Height",s)),u._raise("fileimageloaded",[t]),u.fileManager.addImage(i,{ind:g,img:m,thumb:f,pid:t,typ:r,siz:n,validated:!1,imgData:o,exifObj:l}),f.data("exif",l),u._validateAllImages()}).one("error",function(){u._raise("fileimageloaderror",[t])}).each(function(){this.complete?e(this).trigger("load"):this.error&&e(this).trigger("error")})},_validateAllImages:function(){var t,i=this,a={val:0},r=i.fileManager.getImageCount(),n=i.resizeIfSizeMoreThan;r===i.fileManager.totalImages&&(i._raise("fileimagesloaded"),i.resizeImage&&e.each(i.fileManager.loadedImages,function(e,o){o.validated||(t=o.siz,t&&t>1000*n&&i._getResizedImage(e,o,a,r),o.validated=!0)}))},_getResizedImage:function(i,a,r,n){var o,l,s,d,c,u,p,f,g,m,h=this,v=e(a.img)[0],w=v.naturalWidth,b=v.naturalHeight,_=1,C=h.maxImageWidth||w,y=h.maxImageHeight||b,x=!(!w||!b),T=h.imageCanvas,P=h.imageCanvasContext,F=a.typ,E=a.pid,k=a.ind,S=a.thumb,I=a.exifObj;if(c=function(e,t,i){h.isAjaxUpload?h._showFileError(e,t,i):h._showError(e,t,i),h._setPreviewError(S)},f=h.fileManager.getFile(i),g={id:E,index:k,fileId:i},m=[i,E,k],(!f||!x||C>=w&&y>=b)&&(x&&f&&h._raise("fileimageresized",m),r.val++,r.val===n&&h._raise("fileimagesresized"),!x)){return void c(h.msgImageResizeError,g,"fileimageresizeerror")}F=F||h.resizeDefaultImageType,l=w>C,s=b>y,_="width"===h.resizePreference?l?C/w:s?y/b:1:s?y/b:l?C/w:1,h._resetCanvas(),w*=_,b*=_,T.width=w,T.height=b;try{P.drawImage(v,0,0,w,b),d=T.toDataURL(F,h.resizeQuality),I&&(p=window.piexif.dump(I),d=window.piexif.insert(p,d)),o=t.dataURI2Blob(d),h.fileManager.setFile(i,o),h._raise("fileimageresized",m),r.val++,r.val===n&&h._raise("fileimagesresized",[void 0,void 0]),o instanceof Blob||c(h.msgImageResizeError,g,"fileimageresizeerror")}catch(A){r.val++,r.val===n&&h._raise("fileimagesresized",[void 0,void 0]),u=h.msgImageResizeException.replace("{errors}",A.message),c(u,g,"fileimageresizeexception")}},_showProgress:function(){var e=this;e.$progress&&e.$progress.length&&e.$progress.show()},_hideProgress:function(){var e=this;e.$progress&&e.$progress.length&&e.$progress.hide()},_initBrowse:function(e){var i=this,a=i.$element;i.showBrowse?i.$btnFile=e.find(".btn-file").append(a):(a.appendTo(e).attr("tabindex",-1),t.addCss(a,"file-no-browse"))},_initClickable:function(){var i,a,r=this;r.isClickable&&(i=r.$dropZone,r.isAjaxUpload||(a=r.$preview.find(".file-default-preview"),a.length&&(i=a)),t.addCss(i,"clickable"),i.attr("tabindex",-1),r._handler(i,"click",function(t){var a=e(t.target);e(r.elErrorContainer+":visible").length||a.parents(".file-preview-thumbnails").length&&!a.parents(".file-default-preview").length||(r.$element.data("zoneClicked",!0).trigger("click"),i.blur())}))},_initCaption:function(){var e=this,i=e.initialCaption||"";return e.overwriteInitial||t.isEmpty(i)?(e.$caption.val(""),!1):(e._setCaption(i),!0)},_setCaption:function(i,a){var r,n,o,l,s,d,c=this;if(c.$caption.length){if(c.$captionContainer.removeClass("icon-visible"),a){r=e("
    "+c.msgValidationError+"
    ").text(),l=c.fileManager.count(),l?(d=c.fileManager.getFirstFile(),s=1===l&&d?d.nameFmt:c._getMsgSelected(l)):s=c._getMsgSelected(c.msgNo),n=t.isEmpty(i)?s:i,o=''+c.msgValidationErrorIcon+""}else{if(t.isEmpty(i)){return}r=e("
    "+i+"
    ").text(),n=r,o=c._getLayoutTemplate("fileIcon")}c.$captionContainer.addClass("icon-visible"),c.$caption.attr("title",r).val(n),t.setHtml(c.$captionIcon,o)}},_createContainer:function(){var e=this,i={"class":"file-input file-input-new"+(e.rtl?" kv-rtl":"")},a=t.createElement(t.cspBuffer.stash(e._renderMain()));return t.cspBuffer.apply(a),a.insertBefore(e.$element).attr(i),e._initBrowse(a),e.theme&&a.addClass("theme-"+e.theme),a},_refreshContainer:function(){var e=this,i=e.$container,a=e.$element;a.insertAfter(i),t.setHtml(i,e._renderMain()),e._initBrowse(i),e._validateDisabled()},_validateDisabled:function(){var e=this;e.$caption.attr({readonly:e.isDisabled})},_renderMain:function(){var e=this,t=e.dropZoneEnabled?" file-drop-zone":"file-drop-disabled",i=e.showClose?e._getLayoutTemplate("close"):"",a=e.showPreview?e._getLayoutTemplate("preview").setTokens({"class":e.previewClass,dropClass:t}):"",r=e.isDisabled?e.captionClass+" file-caption-disabled":e.captionClass,n=e.captionTemplate.setTokens({"class":r+" kv-fileinput-caption"});return e.mainTemplate.setTokens({"class":e.mainClass+(!e.showBrowse&&e.showCaption?" no-browse":""),preview:a,close:i,caption:n,upload:e._renderButton("upload"),remove:e._renderButton("remove"),cancel:e._renderButton("cancel"),pause:e._renderButton("pause"),browse:e._renderButton("browse")})},_renderButton:function(e){var i=this,a=i._getLayoutTemplate("btnDefault"),r=i[e+"Class"],n=i[e+"Title"],o=i[e+"Icon"],l=i[e+"Label"],s=i.isDisabled?" disabled":"",d="button";switch(e){case"remove":if(!i.showRemove){return""}break;case"cancel":if(!i.showCancel){return""}r+=" kv-hidden";break;case"pause":if(!i.showPause){return""}r+=" kv-hidden";break;case"upload":if(!i.showUpload){return""}i.isAjaxUpload&&!i.isDisabled?a=i._getLayoutTemplate("btnLink").replace("{href}",i.uploadUrl):d="submit";break;case"browse":if(!i.showBrowse){return""}a=i._getLayoutTemplate("btnBrowse");break;default:return""}return r+="browse"===e?" btn-file":" fileinput-"+e+" fileinput-"+e+"-button",t.isEmpty(l)||(l=' '+l+""),a.setTokens({type:d,css:r,title:n,status:s,icon:o,label:l})},_renderThumbProgress:function(){var e=this;return'
    '+e.progressInfoTemplate.setTokens({percent:101,status:e.msgUploadBegin,stats:""})+"
    "},_renderFileFooter:function(e,i,a,r,n){var o,l,s=this,d=s.fileActionSettings,c=d.showRemove,u=d.showDrag,p=d.showUpload,f=d.showZoom,g=s._getLayoutTemplate("footer"),m=s._getLayoutTemplate("indicator"),h=n?d.indicatorError:d.indicatorNew,v=n?d.indicatorErrorTitle:d.indicatorNewTitle,w=m.setTokens({indicator:h,indicatorTitle:v});return a=s._getSize(a),l={type:e,caption:i,size:a,width:r,progress:"",indicator:w},s.isAjaxUpload?(l.progress=s._renderThumbProgress(),l.actions=s._renderFileActions(l,p,!1,c,f,u,!1,!1,!1)):l.actions=s._renderFileActions(l,!1,!1,!1,f,u,!1,!1,!1),o=g.setTokens(l),o=t.replaceTags(o,s.previewThumbTags)},_renderFileActions:function(e,t,i,a,r,n,o,l,s,d,c,u){var p=this;if(!e.type&&d&&(e.type="image"),p.enableResumableUpload?t=!1:"function"==typeof t&&(t=t(e)),"function"==typeof i&&(i=i(e)),"function"==typeof a&&(a=a(e)),"function"==typeof r&&(r=r(e)),"function"==typeof n&&(n=n(e)),!(t||i||a||r||n)){return""}var f,g=l===!1?"":' data-url="'+l+'"',m="",h="",v=s===!1?"":' data-key="'+s+'"',w="",b="",_="",C=p._getLayoutTemplate("actions"),y=p.fileActionSettings,x=p.otherActionButtons.setTokens({dataKey:v,key:s}),T=o?y.removeClass+" disabled":y.removeClass;return a&&(w=p._getLayoutTemplate("actionDelete").setTokens({removeClass:T,removeIcon:y.removeIcon,removeTitle:y.removeTitle,dataUrl:g,dataKey:v,key:s})),t&&(b=p._getLayoutTemplate("actionUpload").setTokens({uploadClass:y.uploadClass,uploadIcon:y.uploadIcon,uploadTitle:y.uploadTitle})),i&&(_=p._getLayoutTemplate("actionDownload").setTokens({downloadClass:y.downloadClass,downloadIcon:y.downloadIcon,downloadTitle:y.downloadTitle,downloadUrl:c||p.initialPreviewDownloadUrl}),_=_.setTokens({filename:u,key:s})),r&&(m=p._getLayoutTemplate("actionZoom").setTokens({zoomClass:y.zoomClass,zoomIcon:y.zoomIcon,zoomTitle:y.zoomTitle})),n&&d&&(f="drag-handle-init "+y.dragClass,h=p._getLayoutTemplate("actionDrag").setTokens({dragClass:f,dragTitle:y.dragTitle,dragIcon:y.dragIcon})),C.setTokens({"delete":w,upload:b,download:_,zoom:m,drag:h,other:x})},_browse:function(e){var t=this;e&&e.isDefaultPrevented()||!t._raise("filebrowse")||(t.isError&&!t.isAjaxUpload&&t.clear(),t.focusCaptionOnBrowse&&t.$captionContainer.focus())},_change:function(i){var a=this;if(!a.changeTriggered){var r,n,o,l,s=a.$element,d=arguments.length>1,c=a.isAjaxUpload,u=d?arguments[1]:s[0].files,p=a.fileManager.count(),f=t.isEmpty(s.attr("multiple")),g=!c&&f?1:a.maxFileCount,m=a.maxTotalFileCount,h=m>0&&m>g,v=f&&p>0,w=function(t,i,r,n){var o=e.extend(!0,{},a._getOutData(null,{},{},u),{id:r,index:n}),l={id:r,index:n,file:i,files:u};return a.isPersistentError=!0,c?a._showFileError(t,o):a._showError(t,l)},b=function(e,t,i){var r=i?a.msgTotalFilesTooMany:a.msgFilesTooMany;r=r.replace("{m}",t).replace("{n}",e),a.isError=w(r,null,null,null),a.$captionContainer.removeClass("icon-visible"),a._setCaption("",!0),a.$container.removeClass("file-input-new file-input-ajax-new")};if(a.reader=null,a._resetUpload(),a._hideFileIcon(),a.dropZoneEnabled&&a.$container.find(".file-drop-zone ."+a.dropZoneTitleClass).remove(),c||(u=i.target&&void 0===i.target.files?i.target.value?[{name:i.target.value.replace(/^.+\\/,"")}]:[]:i.target.files||{}),r=u,t.isEmpty(r)||0===r.length){return c||a.clear(),void a._raise("fileselectnone")}if(a._resetErrors(),l=r.length,o=c?a.fileManager.count()+l:l,n=a._getFileCount(o,h?!1:void 0),g>0&&n>g){if(!a.autoReplace||l>g){return void b(a.autoReplace&&l>g?l:n,g)}n>g&&a._resetPreviewThumbs(c)}else{if(h&&(n=a._getFileCount(o,!0),m>0&&n>m)){if(!a.autoReplace||l>g){return void b(a.autoReplace&&l>m?l:n,m,!0)}n>g&&a._resetPreviewThumbs(c)}!c||v?(a._resetPreviewThumbs(!1),v&&a.clearFileStack()):!c||0!==p||a.previewCache.count(!0)&&!a.overwriteInitial||a._resetPreviewThumbs(!0)}a.readFiles(r)}},_abort:function(t){var i,a=this;return a.ajaxAborted&&"object"==typeof a.ajaxAborted&&void 0!==a.ajaxAborted.message?(i=e.extend(!0,{},a._getOutData(null),t),i.abortData=a.ajaxAborted.data||{},i.abortMessage=a.ajaxAborted.message,a._setProgress(101,a.$progress,a.msgCancelled),a._showFileError(a.ajaxAborted.message,i,"filecustomerror"),a.cancel(),!0):!!a.ajaxAborted},_resetFileStack:function(){var t=this,i=0;t._getThumbs().each(function(){var a=e(this),r=a.attr("data-fileindex"),n=a.attr("id");"-1"!==r&&-1!==r&&(t.fileManager.getFile(a.attr("data-fileid"))?a.attr({"data-fileindex":"-1"}):(a.attr({"data-fileindex":i}),i++),t._getZoom(n).attr({"data-fileindex":a.attr("data-fileindex")}))})},_isFileSelectionValid:function(e){var t=this;return e=e||0,t.required&&!t.getFilesCount()?(t.$errorContainer.html(""),t._showFileError(t.msgFileRequired),!1):t.minFileCount>0&&t._getFileCount(e)v,!o&&(a||r||n)},addToStack:function(e,t){this.fileManager.add(e,t)},clearFileStack:function(){var e=this;return e.fileManager.clear(),e._initResumableUpload(),e.enableResumableUpload?(null===e.showPause&&(e.showPause=!0),null===e.showCancel&&(e.showCancel=!1)):(e.showPause=!1,null===e.showCancel&&(e.showCancel=!0)),e.$element},getFileStack:function(){return this.fileManager.stack},getFileList:function(){return this.fileManager.list()},getFilesCount:function(e){var t=this,i=t.isAjaxUpload?t.fileManager.count():t._inputFileCount();return e&&(i+=t.previewCache.count(!0)),t._getFileCount(i)},readFiles:function(i){this.reader=new FileReader;var a,r=this,n=r.reader,o=r.$previewContainer,l=r.$previewStatus,s=r.msgLoading,d=r.msgProgress,c=r.previewInitId,u=i.length,p=r.fileTypeSettings,f=r.allowedFileTypes,g=f?f.length:0,m=r.allowedFileExtensions,h=t.isEmpty(m)?"":m.join(", "),v=function(t,n,o,l,s){var d,c=e.extend(!0,{},r._getOutData(null,{},{},i),{id:o,index:l,fileId:s}),p={id:o,index:l,fileId:s,file:n,files:i};r._previewDefault(n,!0),d=r._getFrame(o,!0),r.isAjaxUpload?setTimeout(function(){a(l+1)},r.processDelay):(r.unlock(),u=0),r.removeFromPreviewOnError&&d.length?d.remove():(r._initFileActions(),d.find(".kv-file-upload").remove()),r.isPersistentError=!0,r.isError=r.isAjaxUpload?r._showFileError(t,c):r._showError(t,p),r._updateFileDetails(u)};r.fileManager.clearImages(),e.each(i,function(e,t){var i=r.fileTypeSettings.image;i&&i(t.type)&&r.fileManager.totalImages++}),a=function(w){var b,_=r.$errorContainer,C=r.fileManager;if(w>=u){return r.unlock(),r.duplicateErrors.length&&(b="
  • "+r.duplicateErrors.join("
  • ")+"
  • ",0===_.find("ul").length?t.setHtml(_,r.errorCloseButton+"
      "+b+"
    "):_.find("ul").append(b),_.fadeIn(r.fadeDelay),r._handler(_.find(".kv-error-close"),"click",function(){_.fadeOut(r.fadeDelay)}),r.duplicateErrors=[]),r.isAjaxUpload?(r._raise("filebatchselected",[C.stack]),0!==C.count()||r.isError||r.reset()):r._raise("filebatchselected",[i]),o.removeClass("file-thumb-loading"),void l.html("")}r.lock(!0);var y,x,T,P,F,E,k,S,I,A,D,z,j=i[w],U=r._getFileId(j),M=c+"-"+U,$=(p.text,p.image),R=(p.html,r._getFileName(j,"")),O=(j&&j.size||0)/1000,B="",L=t.createObjectURL(j),N=0,Z="",H=!1,W=0,q=function(){var e=d.setTokens({index:w+1,files:u,percent:50,name:R});setTimeout(function(){l.html(e),r._updateFileDetails(u),a(w+1)},r.processDelay),r._raise("fileloaded",[j,M,U,w,n])&&r.isAjaxUpload&&C.add(j)};if(j){if(S=C.getId(j),g>0){for(x=0;g>x;x++){E=f[x],k=r.msgFileTypes[E]||E,Z+=0===x?k:", "+k}}if(R===!1){return void a(w+1)}if(0===R.length){return T=r.msgInvalidFileName.replace("{name}",t.htmlEncode(t.getFileName(j),"[unknown]")),void v(T,j,M,w,S)}if(t.isEmpty(m)||(B=RegExp("\\.("+m.join("|")+")$","i")),y=O.toFixed(2),r.isAjaxUpload&&C.exists(S)||r._getFrame(M,!0).length){var V={id:M,index:w,fileId:S,file:j,files:i};return T=r.msgDuplicateFile.setTokens({name:R,size:y}),void (r.isAjaxUpload?(r.duplicateErrors.push(T),r.isDuplicateError=!0,r._raise("fileduplicateerror",[j,S,R,y,M,w]),a(w+1),r._updateFileDetails(u)):(r._showError(T,V),r.unlock(),u=0,r._clearFileInput(),r.reset(),r._updateFileDetails(u)))}if(r.maxFileSize>0&&O>r.maxFileSize){return T=r.msgSizeTooLarge.setTokens({name:R,size:y,maxSize:r.maxFileSize}),void v(T,j,M,w,S)}if(null!==r.minFileSize&&O<=t.getNum(r.minFileSize)){return T=r.msgSizeTooSmall.setTokens({name:R,size:y,minSize:r.minFileSize}),void v(T,j,M,w,S)}if(!t.isEmpty(f)&&t.isArray(f)){for(x=0;x0){for(t=0;n>t;t+=1){i.paused=!0,r[t].abort()}}return i.showPreview&&i._getThumbs().each(function(){var t,a=e(this),r=a.attr("data-fileid"),n=i._getLayoutTemplate("stats"),s=a.find(".file-upload-indicator");a.removeClass("file-uploading"),s.attr("title")===l.indicatorLoadingTitle&&(i._setThumbStatus(a,"Paused"),t=n.setTokens({pendingTime:i.msgPaused,uploadSpeed:""}),i.paused=!0,i._setProgress(o,a.find(".file-thumb-progress"),o+"%",t)),i.fileManager.getFile(r)||a.find(".kv-file-remove").removeClass("disabled").removeAttr("disabled")}),i._setProgress(101,i.$progress,i.msgPaused),i.$element},cancel:function(){var t,i=this,a=i.ajaxRequests,r=i.resumableManager,n=i.taskManager,o=r?n.getPool(r.id):void 0,l=a.length;if(i.enableResumableUpload&&o?(o.cancel().done(function(){i._setProgressCancelled()}),r.reset(),i._raise("fileuploadcancelled",[i.fileManager,r])):i._raise("fileuploadcancelled",[i.fileManager]),i._initAjax(),l>0){for(t=0;l>t;t+=1){i.cancelling=!0,a[t].abort()}}return i._getThumbs().each(function(){var t=e(this),a=t.attr("data-fileid"),r=t.find(".file-thumb-progress");t.removeClass("file-uploading"),i._setProgress(0,r),r.hide(),i.fileManager.getFile(a)||(t.find(".kv-file-upload").removeClass("disabled").removeAttr("disabled"),t.find(".kv-file-remove").removeClass("disabled").removeAttr("disabled")),i.unlock()}),setTimeout(function(){i._setProgressCancelled()},i.processDelay),i.$element},clear:function(){var i,a=this;if(a._raise("fileclear")){return a.$btnUpload.removeAttr("disabled"),a._getThumbs().find("video,audio,img").each(function(){t.cleanMemory(e(this))}),a._clearFileInput(),a._resetUpload(),a.clearFileStack(),a.isDuplicateError=!1,a.isPersistentError=!1,a._resetErrors(!0),a._hasInitialPreview()?(a._showFileIcon(),a._resetPreview(),a._initPreviewActions(),a.$container.removeClass("file-input-new")):(a._getThumbs().each(function(){a._clearObjects(e(this))}),a.isAjaxUpload&&(a.previewCache.data={}),a.$preview.html(""),i=!a.overwriteInitial&&a.initialCaption.length>0?a.initialCaption:"",a.$caption.attr("title","").val(i),t.addCss(a.$container,"file-input-new"),a._validateDefaultPreview()),0===a.$container.find(t.FRAMES).length&&(a._initCaption()||a.$captionContainer.removeClass("icon-visible")),a._hideFileIcon(),a.focusCaptionOnClear&&a.$captionContainer.focus(),a._setFileDropZoneTitle(),a._raise("filecleared"),a.$element}},reset:function(){var e=this;if(e._raise("filereset")){return e.lastProgress=0,e._resetPreview(),e.$container.find(".fileinput-filename").text(""),t.addCss(e.$container,"file-input-new"),e.getFrames().length&&e.$container.removeClass("file-input-new"),e.clearFileStack(),e._setFileDropZoneTitle(),e.$element}},disable:function(){var e=this,i=e.$container;return e.isDisabled=!0,e._raise("filedisabled"),e.$element.attr("disabled","disabled"),i.addClass("is-locked"),t.addCss(i.find(".btn-file"),"disabled"),i.find(".kv-fileinput-caption").addClass("file-caption-disabled"),i.find(".fileinput-remove, .fileinput-upload, .file-preview-frame button").attr("disabled",!0),e._initDragDrop(),e.$element},enable:function(){var e=this,t=e.$container;return e.isDisabled=!1,e._raise("fileenabled"),e.$element.removeAttr("disabled"),t.removeClass("is-locked"),t.find(".kv-fileinput-caption").removeClass("file-caption-disabled"),t.find(".fileinput-remove, .fileinput-upload, .file-preview-frame button").removeAttr("disabled"),t.find(".btn-file").removeClass("disabled"),e._initDragDrop(),e.$element},upload:function(){var i,a,r=this,n=r.fileManager,o=n.count(),l=!e.isEmptyObject(r._getExtraData());if(r.isAjaxUpload&&!r.isDisabled&&r._isFileSelectionValid(o)){return r.lastProgress=0,r._resetUpload(),0!==o||l?(r.cancelling=!1,r._showProgress(),r.lock(),0===o&&l?(r._setProgress(2),void r._uploadExtraOnly()):r.enableResumableUpload?r.resume():((r.uploadAsync||r.enableResumableUpload)&&(a=r._getOutData(null),r._raise("filebatchpreupload",[a]),r.fileBatchCompleted=!1,r.uploadCache=[],e.each(r.getFileStack(),function(e){var t=r._getThumbId(e);r.uploadCache.push({id:t,content:null,config:null,tags:null,append:!0})}),r.$preview.find(".file-preview-initial").removeClass(t.SORT_CSS),r._initSortable()),r._setProgress(2),r.hasInitData=!1,r.uploadAsync?(i=0,void e.each(n.stack,function(e){r._uploadSingle(i,e,!0),i++})):(r._uploadBatch(),r.$element))):void r._showFileError(r.msgUploadEmpty)}},destroy:function(){var t=this,i=t.$form,a=t.$container,r=t.$element,n=t.namespace;return e(document).off(n),e(window).off(n),i&&i.length&&i.off(n),t.isAjaxUpload&&t._clearFileInput(),t._cleanup(),t._initPreviewCache(),r.insertBefore(a).off(n).removeData(),a.off().remove(),r},refresh:function(i){var a=this,r=a.$element;return i="object"!=typeof i||t.isEmpty(i)?a.options:e.extend(!0,{},a.options,i),a._init(i,!0),a._listen(),r},zoom:function(e){var t=this,i=t._getFrame(e);t._showModal(i)},getExif:function(e){var t=this,i=t._getFrame(e);return i&&i.data("exif")||null},getFrames:function(i){var a,r=this;return i=i||"",a=r.$preview.find(t.FRAMES+i),r.reversePreviewOrder&&(a=e(a.get().reverse())),a},getPreview:function(){var e=this;return{content:e.initialPreview,config:e.initialPreviewConfig,tags:e.initialPreviewThumbTags}}},e.fn.fileinput=function(a){if(t.hasFileAPISupport()||t.isIE(9)){var r=Array.apply(null,arguments),n=[];switch(r.shift(),this.each(function(){var o,l=e(this),s=l.data("fileinput"),d="object"==typeof a&&a,c=d.theme||l.data("theme"),u={},p={},f=d.language||l.data("language")||e.fn.fileinput.defaults.language||"en";s||(c&&(p=e.fn.fileinputThemes[c]||{}),"en"===f||t.isEmpty(e.fn.fileinputLocales[f])||(u=e.fn.fileinputLocales[f]||{}),o=e.extend(!0,{},e.fn.fileinput.defaults,p,e.fn.fileinputLocales.en,u,d,l.data()),s=new i(this,o),l.data("fileinput",s)),"string"==typeof a&&n.push(s[a].apply(s,r))}),n.length){case 0:return this;case 1:return n[0];default:return n}}};var a='class="kv-preview-data file-preview-pdf" src="{renderer}?file={data}" {style}';e.fn.fileinput.defaults={language:"zh",showCaption:!0,showBrowse:!0,showPreview:!0,showRemove:!0,showUpload:!0,showUploadStats:!0,showCancel:null,showPause:null,showClose:!0,showUploadedThumbs:!0,showConsoleLogs:!1,browseOnZoneClick:!1,autoReplace:!1,autoOrientImage:function(){var e=window.navigator.userAgent,t=!!e.match(/WebKit/i),i=!!e.match(/iP(od|ad|hone)/i),a=i&&t&&!e.match(/CriOS/i);return !a},autoOrientImageInitial:!0,required:!1,rtl:!1,hideThumbnailContent:!1,encodeUrl:!0,focusCaptionOnBrowse:!0,focusCaptionOnClear:!0,generateFileId:null,previewClass:"",captionClass:"",frameClass:"krajee-default",mainClass:"file-caption-main",mainTemplate:null,fileSizeGetter:null,initialCaption:"",initialPreview:[],initialPreviewDelimiter:"*$$*",initialPreviewAsData:!1,initialPreviewFileType:"image",initialPreviewConfig:[],initialPreviewThumbTags:[],previewThumbTags:{},initialPreviewShowDelete:!0,initialPreviewDownloadUrl:"",removeFromPreviewOnError:!1,deleteUrl:"",deleteExtraData:{},overwriteInitial:!0,sanitizeZoomCache:function(e){var i=t.createElement(e);return i.find("input,textarea,select,datalist,form,.file-thumbnail-footer").remove(),i.html()},previewZoomButtonIcons:{prev:'',next:'',toggleheader:'',fullscreen:'',borderless:'',close:''},previewZoomButtonClasses:{prev:"btn btn-navigate",next:"btn btn-navigate",toggleheader:"btn btn-sm btn-kv btn-default btn-outline-secondary",fullscreen:"btn btn-sm btn-kv btn-default btn-outline-secondary",borderless:"btn btn-sm btn-kv btn-default btn-outline-secondary",close:"btn btn-sm btn-kv btn-default btn-outline-secondary"},previewTemplates:{},previewContentTemplates:{},preferIconicPreview:!1,preferIconicZoomPreview:!1,allowedFileTypes:null,allowedFileExtensions:null,allowedPreviewTypes:void 0,allowedPreviewMimeTypes:null,allowedPreviewExtensions:null,disabledPreviewTypes:void 0,disabledPreviewExtensions:["msi","exe","com","zip","rar","app","vb","scr"],disabledPreviewMimeTypes:null,defaultPreviewContent:null,customLayoutTags:{},customPreviewTags:{},previewFileIcon:'',previewFileIconClass:"file-other-icon",previewFileIconSettings:{},previewFileExtSettings:{},buttonLabelClass:"hidden-xs",browseIcon:' ',browseClass:"btn btn-primary",removeIcon:'',removeClass:"btn btn-default btn-secondary",cancelIcon:'',cancelClass:"btn btn-default btn-secondary",pauseIcon:'',pauseClass:"btn btn-default btn-secondary",uploadIcon:'',uploadClass:"btn btn-default btn-secondary",uploadUrl:null,uploadUrlThumb:null,uploadAsync:!0,uploadParamNames:{chunkCount:"chunkCount",chunkIndex:"chunkIndex",chunkSize:"chunkSize",chunkSizeStart:"chunkSizeStart",chunksUploaded:"chunksUploaded",fileBlob:"fileBlob",fileId:"fileId",fileName:"fileName",fileRelativePath:"fileRelativePath",fileSize:"fileSize",retryCount:"retryCount"},maxAjaxThreads:5,fadeDelay:800,processDelay:100,queueDelay:10,progressDelay:0,enableResumableUpload:!1,resumableUploadOptions:{fallback:null,testUrl:null,chunkSize:2048,maxThreads:4,maxRetries:3,showErrorLog:!0},uploadExtraData:{},zoomModalHeight:480,minImageWidth:null,minImageHeight:null,maxImageWidth:null,maxImageHeight:null,resizeImage:!1,resizePreference:"width",resizeQuality:0.92,resizeDefaultImageType:"image/jpeg",resizeIfSizeMoreThan:0,minFileSize:-1,maxFileSize:0,maxFilePreviewSize:25600,minFileCount:0,maxFileCount:0,maxTotalFileCount:0,validateInitialCount:!1,msgValidationErrorClass:"text-danger",msgValidationErrorIcon:' ',msgErrorClass:"file-error-message",progressThumbClass:"progress-bar progress-bar-striped active progress-bar-animated",progressClass:"progress-bar bg-success progress-bar-success progress-bar-striped active progress-bar-animated",progressInfoClass:"progress-bar bg-info progress-bar-info progress-bar-striped active progress-bar-animated",progressCompleteClass:"progress-bar bg-success progress-bar-success",progressPauseClass:"progress-bar bg-primary progress-bar-primary progress-bar-striped active progress-bar-animated",progressErrorClass:"progress-bar bg-danger progress-bar-danger",progressUploadThreshold:99,previewFileType:"image",elCaptionContainer:null,elCaptionText:null,elPreviewContainer:null,elPreviewImage:null,elPreviewStatus:null,elErrorContainer:null,errorCloseButton:t.closeButton("kv-error-close"),slugCallback:null,dropZoneEnabled:!0,dropZoneTitleClass:"file-drop-zone-title",fileActionSettings:{},otherActionButtons:"",textEncoding:"UTF-8",preProcessUpload:null,ajaxSettings:{},ajaxDeleteSettings:{},showAjaxErrorDetails:!0,mergeAjaxCallbacks:!1,mergeAjaxDeleteCallbacks:!1,retryErrorUploads:!0,reversePreviewOrder:!1,usePdfRenderer:function(){var e=!!window.MSInputMethodContext&&!!document.documentMode;return !!navigator.userAgent.match(/(iPod|iPhone|iPad|Android)/i)||e},pdfRendererUrl:"",pdfRendererTemplate:""},e.fn.fileinputLocales.en={fileSingle:"file",filePlural:"files",browseLabel:"Browse …",removeLabel:"Remove",removeTitle:"Clear all unprocessed files",cancelLabel:"Cancel",cancelTitle:"Abort ongoing upload",pauseLabel:"Pause",pauseTitle:"Pause ongoing upload",uploadLabel:"Upload",uploadTitle:"Upload selected files",msgNo:"No",msgNoFilesSelected:"No files selected",msgCancelled:"Cancelled",msgPaused:"Paused",msgPlaceholder:"Select {files} ...",msgZoomModalHeading:"Detailed Preview",msgFileRequired:"You must select a file to upload.",msgSizeTooSmall:'File "{name}" ({size} KB) is too small and must be larger than {minSize} KB.',msgSizeTooLarge:'File "{name}" ({size} KB) exceeds maximum allowed upload size of {maxSize} KB.',msgFilesTooLess:"You must select at least {n} {files} to upload.",msgFilesTooMany:"Number of files selected for upload ({n}) exceeds maximum allowed limit of {m}.",msgTotalFilesTooMany:"You can upload a maximum of {m} files ({n} files detected).",msgFileNotFound:'File "{name}" not found!',msgFileSecured:'Security restrictions prevent reading the file "{name}".',msgFileNotReadable:'File "{name}" is not readable.',msgFilePreviewAborted:'File preview aborted for "{name}".',msgFilePreviewError:'An error occurred while reading the file "{name}".',msgInvalidFileName:'Invalid or unsupported characters in file name "{name}".',msgInvalidFileType:'Invalid type for file "{name}". Only "{types}" files are supported.',msgInvalidFileExtension:'Invalid extension for file "{name}". Only "{extensions}" files are supported.',msgFileTypes:{image:"image",html:"HTML",text:"text",video:"video",audio:"audio",flash:"flash",pdf:"PDF",object:"object"},msgUploadAborted:"The file upload was aborted",msgUploadThreshold:"Processing …",msgUploadBegin:"Initializing …",msgUploadEnd:"Done",msgUploadResume:"Resuming upload …",msgUploadEmpty:"No valid data available for upload.",msgUploadError:"Upload Error",msgDeleteError:"Delete Error",msgProgressError:"Error",msgValidationError:"Validation Error",msgLoading:"Loading file {index} of {files} …",msgProgress:"Loading file {index} of {files} - {name} - {percent}% completed.",msgSelected:"{n} {files} selected",msgFoldersNotAllowed:"Drag & drop files only! {n} folder(s) dropped were skipped.",msgImageWidthSmall:'Width of image file "{name}" must be at least {size} px.',msgImageHeightSmall:'Height of image file "{name}" must be at least {size} px.',msgImageWidthLarge:'Width of image file "{name}" cannot exceed {size} px.',msgImageHeightLarge:'Height of image file "{name}" cannot exceed {size} px.',msgImageResizeError:"Could not get the image dimensions to resize.",msgImageResizeException:"Error while resizing the image.
    {errors}
    ",msgAjaxError:"Something went wrong with the {operation} operation. Please try again later!",msgAjaxProgressError:"{operation} failed",msgDuplicateFile:'File "{name}" of same size "{size} KB" has already been selected earlier. Skipping duplicate selection.',msgResumableUploadRetriesExceeded:"Upload aborted beyond {max} retries for file {file}! Error Details:
    {error}
    ",msgPendingTime:"{time} remaining",msgCalculatingTime:"calculating time remaining",ajaxOperations:{deleteThumb:"file delete",uploadThumb:"file upload",uploadBatch:"batch file upload",uploadExtra:"form data upload"},dropZoneTitle:"Drag & drop files here …",dropZoneClickTitle:"
    (or click to select {files})",previewZoomButtonTitles:{prev:"View previous file",next:"View next file",toggleheader:"Toggle header",fullscreen:"Toggle full screen",borderless:"Toggle borderless mode",close:"Close detailed preview"}},e.fn.fileinputLocales.zh={fileSingle:"文件",filePlural:"个文件",browseLabel:"选择 …",removeLabel:"移除",removeTitle:"清除选中文件",cancelLabel:"取消",cancelTitle:"取消进行中的上传",pauseLabel:"Pause",pauseTitle:"Pause ongoing upload",uploadLabel:"上传",uploadTitle:"上传选中文件",msgNo:"没有",msgNoFilesSelected:"未选择文件",msgPaused:"Paused",msgCancelled:"取消",msgPlaceholder:"选择 {files} ...",msgZoomModalHeading:"详细预览",msgFileRequired:"必须选择一个文件上传.",msgSizeTooSmall:'文件 "{name}" ({size} KB) 必须大于限定大小 {minSize} KB.',msgSizeTooLarge:'文件 "{name}" ({size} KB) 超过了允许大小 {maxSize} KB.',msgFilesTooLess:"你必须选择最少 {n} {files} 来上传. ",msgFilesTooMany:"选择的上传文件个数 ({n}) 超出最大文件的限制个数 {m}.",msgTotalFilesTooMany:"You can upload a maximum of {m} files ({n} files detected).",msgFileNotFound:'文件 "{name}" 未找到!',msgFileSecured:'安全限制,为了防止读取文件 "{name}".',msgFileNotReadable:'文件 "{name}" 不可读.',msgFilePreviewAborted:'取消 "{name}" 的预览.',msgFilePreviewError:'读取 "{name}" 时出现了一个错误.',msgInvalidFileName:'文件名 "{name}" 包含非法字符.',msgInvalidFileType:'不正确的类型 "{name}". 只支持 "{types}" 类型的文件.',msgInvalidFileExtension:'不正确的文件扩展名 "{name}". 只支持 "{extensions}" 的文件扩展名.',msgFileTypes:{image:"image",html:"HTML",text:"text",video:"video",audio:"audio",flash:"flash",pdf:"PDF",object:"object"},msgUploadAborted:"该文件上传被中止",msgUploadThreshold:"处理中 …",msgUploadBegin:"正在初始化 …",msgUploadEnd:"完成",msgUploadResume:"Resuming upload …",msgUploadEmpty:"无效的文件上传.",msgUploadError:"Upload Error",msgDeleteError:"Delete Error",msgProgressError:"上传出错",msgValidationError:"验证错误",msgLoading:"加载第 {index} 文件 共 {files} …",msgProgress:"加载第 {index} 文件 共 {files} - {name} - {percent}% 完成.",msgSelected:"{n} {files} 选中",msgFoldersNotAllowed:"只支持拖拽文件! 跳过 {n} 拖拽的文件夹.",msgImageWidthSmall:'图像文件的"{name}"的宽度必须是至少{size}像素.',msgImageHeightSmall:'图像文件的"{name}"的高度必须至少为{size}像素.',msgImageWidthLarge:'图像文件"{name}"的宽度不能超过{size}像素.',msgImageHeightLarge:'图像文件"{name}"的高度不能超过{size}像素.',msgImageResizeError:"无法获取的图像尺寸调整。",msgImageResizeException:"调整图像大小时发生错误。
    {errors}
    ",msgAjaxError:"{operation} 发生错误. 请重试!",msgAjaxProgressError:"{operation} 失败",msgDuplicateFile:'File "{name}" of same size "{size} KB" has already been selected earlier. Skipping duplicate selection.',msgResumableUploadRetriesExceeded:"Upload aborted beyond {max} retries for file {file}! Error Details:
    {error}
    ",msgPendingTime:"{time} remaining",msgCalculatingTime:"calculating time remaining",ajaxOperations:{deleteThumb:"删除文件",uploadThumb:"上传文件",uploadBatch:"批量上传",uploadExtra:"表单数据上传"},dropZoneTitle:"拖拽文件到这里 …
    支持多文件同时上传",dropZoneClickTitle:"
    (或点击{files}按钮选择文件)",fileActionSettings:{removeTitle:"删除文件",uploadTitle:"上传文件",downloadTitle:"下载文件",uploadRetryTitle:"重试",zoomTitle:"查看详情",dragTitle:"移动 / 重置",indicatorNewTitle:"没有上传",indicatorSuccessTitle:"上传",indicatorErrorTitle:"上传错误",indicatorPausedTitle:"Upload Paused",indicatorLoadingTitle:"上传 …"},previewZoomButtonTitles:{prev:"预览上一个文件",next:"预览下一个文件",toggleheader:"缩放",fullscreen:"全屏",borderless:"无边界模式",close:"关闭当前预览"}},e.fn.fileinput.Constructor=i,e(document).ready(function(){var t=e("input.file[type=file]");t.length&&t.fileinput()})}); \ No newline at end of file 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..b915a5e23 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,9 @@ -.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 - An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation) + * + * @version v1.18.0 + * @homepage https://bootstrap-table.com + * @author wenzhixin (http://wenzhixin.net.cn/) + * @license MIT + */ +.bootstrap-table .fixed-table-toolbar::after{content:"";display:block;clear:both}.bootstrap-table .fixed-table-toolbar .bs-bars,.bootstrap-table .fixed-table-toolbar .columns,.bootstrap-table .fixed-table-toolbar .search{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:400;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 td,.bootstrap-table .fixed-table-container .table th{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,iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAAkElEQVQoz7X QMQ5AQBCF4dWQSJxC5wwax1Cq1e7BAdxD5SL+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.selected td{background-color:rgba(0,0,0,.075)}.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:700;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=checkbox],.bootstrap-table .fixed-table-container .table .bs-checkbox label input[type=radio]{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:flex;justify-content:center;position:absolute;bottom:0;width:100%;z-index:1000;transition:visibility 0s,opacity .15s ease-in-out;opacity:0;visibility:hidden}.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading.open{visibility:visible;opacity:1}.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,.bootstrap-table .fixed-table-pagination>.pagination-detail{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 866a86189..a99c2f0b9 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,8 @@ /** * @author zhixin wen - * version: 1.11.0 + * version: 1.18.0 * 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(".search-collapse").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&&isFirstLoad){isFirstLoad=false;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}if(selectionIds.length>0){selectionIds=[]}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?Tt:Pt)(t)},At=Math.min,$t=function(t){return t>0?At(It(t),9007199254740991):0},Rt=Math.max,Et=Math.min,jt=function(t,e){var i=It(t);return 0>i?Rt(i+e,0):Et(i,e)},_t=function(t){return function(e,i,n){var o,r=R(e),a=$t(r.length),s=jt(n,a);if(t&&i!=i){for(;a>s;){if(o=r[s++],o!=o){return !0}}}else{for(;a>s;s++){if((t||s in r)&&r[s]===i){return t||s||0}}}return !t&&-1}},Nt={includes:_t(!0),indexOf:_t(!1)},Ft=Nt.indexOf,Vt=function(t,e){var i,n=R(t),o=0,r=[];for(i in n){!N(ut,i)&&N(n,i)&&r.push(i)}for(;e.length>o;){N(n,i=e[o++])&&(~Ft(r,i)||r.push(i))}return r},Dt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],Bt=Dt.concat("length","prototype"),Lt=Object.getOwnPropertyNames||function(t){return Vt(t,Bt)},Ht={f:Lt},Mt=Object.getOwnPropertySymbols,Ut={f:Mt},qt=Ct("Reflect","ownKeys")||function(t){var e=Ht.f(U(t)),i=Ut.f;return i?e.concat(i(t)):e},zt=function(t,e){for(var i=qt(e),n=W.f,o=M.f,r=0;rr;){W.f(t,i=n[r++],e[i])}return t},se=Ct("document","documentElement"),le=">",ce="<",he="prototype",ue="script",de=ht("IE_PROTO"),pe=function(){},fe=function(t){return ce+ue+le+t+ce+"/"+ue+le},ge=function(t){t.write(fe("")),t.close();var e=t.parentWindow.Object;return t=null,e},ve=function(){var t,e=D("iframe"),i="java"+ue+":";return e.style.display="none",se.appendChild(e),e.src=i+"",t=e.contentWindow.document,t.open(),t.write(fe("document.F=Object")),t.close(),t.F},be=function(){try{wt=document.domain&&new ActiveXObject("htmlfile")}catch(t){}be=wt?ge(wt):ve();for(var e=Dt.length;e--;){delete be[he][Dt[e]]}return be()};ut[de]=!0;var me=Object.create||function(t,e){var i;return null!==t?(pe[he]=U(t),i=new pe,pe[he]=null,i[de]=t):i=be(),void 0===e?i:ae(i,e)},ye=Ht.f,we={}.toString,Se="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],xe=function(t){try{return ye(t)}catch(e){return Se.slice()}},ke=function(t){return Se&&"[object Window]"==we.call(t)?xe(t):ye(R(t))},Oe={f:ke},Ce=rt("wks"),Pe=b.Symbol,Te=ie?Pe:lt,Ie=function(t){return N(Ce,t)||(ee&&N(Pe,t)?Ce[t]=Pe[t]:Ce[t]=Te("Symbol."+t)),Ce[t]},Ae=Ie,$e={f:Ae},Re=W.f,Ee=function(t){var e=kt.Symbol||(kt.Symbol={});N(e,t)||Re(e,t,{value:$e.f(t)})},je=W.f,_e=Ie("toStringTag"),Ne=function(t,e,i){t&&!N(t=i?t:t.prototype,_e)&&je(t,_e,{configurable:!0,value:e})},Fe=function(t){if("function"!=typeof t){throw TypeError(t+" is not a function")}return t},Ve=function(t,e,i){if(Fe(t),void 0===e){return t}switch(i){case 0:return function(){return t.call(e)};case 1:return function(i){return t.call(e,i)};case 2:return function(i,n){return t.call(e,i,n)};case 3:return function(i,n,o){return t.call(e,i,n,o)}}return function(){return t.apply(e,arguments)}},De=Ie("species"),Be=function(t,e){var i;return ne(t)&&(i=t.constructor,"function"!=typeof i||i!==Array&&!ne(i.prototype)?E(i)&&(i=i[De],null===i&&(i=void 0)):i=void 0),new (void 0===i?Array:i)(0===e?0:e)},Le=[].push,He=function(t){var e=1==t,i=2==t,n=3==t,o=4==t,r=6==t,a=5==t||r;return function(s,l,c,h){for(var u,d,p=oe(s),f=A(p),g=Ve(l,c,3),v=$t(f.length),b=0,m=h||Be,y=e?m(s,v):i?m(s,0):void 0;v>b;b++){if((a||b in f)&&(u=f[b],d=g(u,b,p),t)){if(e){y[b]=d}else{if(d){switch(t){case 3:return !0;case 5:return u;case 6:return b;case 2:Le.call(y,u)}}else{if(o){return !1}}}}}return r?-1:n||o?o:y}},Me={forEach:He(0),map:He(1),filter:He(2),some:He(3),every:He(4),find:He(5),findIndex:He(6)},Ue=Me.forEach,qe=ht("hidden"),ze="Symbol",We="prototype",Ge=Ie("toPrimitive"),Ke=St.set,Ye=St.getterFor(ze),Je=Object[We],Xe=b.Symbol,Qe=Ct("JSON","stringify"),Ze=M.f,ti=W.f,ei=Oe.f,ii=O.f,ni=rt("symbols"),oi=rt("op-symbols"),ri=rt("string-to-symbol-registry"),ai=rt("symbol-to-string-registry"),si=rt("wks"),li=b.QObject,ci=!li||!li[We]||!li[We].findChild,hi=y&&m(function(){return 7!=me(ti({},"a",{get:function(){return ti(this,"a",{value:7}).a}})).a})?function(t,e,i){var n=Ze(Je,e);n&&delete Je[e],ti(t,e,i),n&&t!==Je&&ti(Je,e,n)}:ti,ui=function(t,e){var i=ni[t]=me(Xe[We]);return Ke(i,{type:ze,tag:t,description:e}),y||(i.description=e),i},di=ee&&"symbol"==typeof Xe.iterator?function(t){return"symbol"==typeof t}:function(t){return Object(t) instanceof Xe},pi=function(t,e,i){t===Je&&pi(oi,e,i),U(t);var n=j(e,!0);return U(i),N(ni,n)?(i.enumerable?(N(t,qe)&&t[qe][n]&&(t[qe][n]=!1),i=me(i,{enumerable:C(0,!1)})):(N(t,qe)||ti(t,qe,C(1,{})),t[qe][n]=!0),hi(t,n,i)):ti(t,n,i)},fi=function(t,e){U(t);var i=R(e),n=re(i).concat(yi(i));return Ue(n,function(e){(!y||vi.call(i,e))&&pi(t,e,i[e])}),t},gi=function(t,e){return void 0===e?me(t):fi(me(t),e)},vi=function(t){var e=j(t,!0),i=ii.call(this,e);return this===Je&&N(ni,e)&&!N(oi,e)?!1:i||!N(this,e)||!N(ni,e)||N(this,qe)&&this[qe][e]?i:!0},bi=function(t,e){var i=R(t),n=j(e,!0);if(i!==Je||!N(ni,n)||N(oi,n)){var o=Ze(i,n);return !o||!N(ni,n)||N(i,qe)&&i[qe][n]||(o.enumerable=!0),o}},mi=function(t){var e=ei(R(t)),i=[];return Ue(e,function(t){N(ni,t)||N(ut,t)||i.push(t)}),i},yi=function(t){var e=t===Je,i=ei(e?oi:R(t)),n=[];return Ue(i,function(t){!N(ni,t)||e&&!N(Je,t)||n.push(ni[t])}),n};if(ee||(Xe=function(){if(this instanceof Xe){throw TypeError("Symbol is not a constructor")}var t=arguments.length&&void 0!==arguments[0]?arguments[0]+"":void 0,e=lt(t),i=function(t){this===Je&&i.call(oi,t),N(this,qe)&&N(this[qe],e)&&(this[qe][e]=!1),hi(this,e,C(1,t))};return y&&ci&&hi(Je,e,{configurable:!0,set:i}),ui(e,t)},xt(Xe[We],"toString",function(){return Ye(this).tag}),O.f=vi,W.f=pi,M.f=bi,Ht.f=Oe.f=mi,Ut.f=yi,y&&(ti(Xe[We],"description",{configurable:!0,get:function(){return Ye(this).description}}),xt(Je,"propertyIsEnumerable",vi,{unsafe:!0}))),ie||($e.f=function(t){return ui(Ie(t),t)}),te({global:!0,wrap:!0,forced:!ee,sham:!ee},{Symbol:Xe}),Ue(re(si),function(t){Ee(t)}),te({target:ze,stat:!0,forced:!ee},{"for":function(t){var e=t+"";if(N(ri,e)){return ri[e]}var i=Xe(e);return ri[e]=i,ai[i]=e,i},keyFor:function(t){if(!di(t)){throw TypeError(t+" is not a symbol")}return N(ai,t)?ai[t]:void 0},useSetter:function(){ci=!0},useSimple:function(){ci=!1}}),te({target:"Object",stat:!0,forced:!ee,sham:!y},{create:gi,defineProperty:pi,defineProperties:fi,getOwnPropertyDescriptor:bi}),te({target:"Object",stat:!0,forced:!ee},{getOwnPropertyNames:mi,getOwnPropertySymbols:yi}),te({target:"Object",stat:!0,forced:m(function(){Ut.f(1)})},{getOwnPropertySymbols:function(t){return Ut.f(oe(t))}}),Qe){var wi=!ee||m(function(){var t=Xe();return"[null]"!=Qe([t])||"{}"!=Qe({a:t})||"{}"!=Qe(Object(t))});te({target:"JSON",stat:!0,forced:wi},{stringify:function(t,e,i){for(var n,o=[t],r=1;arguments.length>r;){o.push(arguments[r++])}return n=e,!E(e)&&void 0===t||di(t)?void 0:(ne(e)||(e=function(t,e){return"function"==typeof n&&(e=n.call(this,t,e)),di(e)?void 0:e}),o[1]=e,Qe.apply(null,o))}})}Xe[We][Ge]||G(Xe[We],Ge,Xe[We].valueOf),Ne(Xe,ze),ut[qe]=!0;var Si=W.f,xi=b.Symbol;if(y&&"function"==typeof xi&&(!("description" in xi.prototype)||void 0!==xi().description)){var ki={},Oi=function(){var t=arguments.length<1||void 0===arguments[0]?void 0:arguments[0]+"",e=this instanceof Oi?new xi(t):void 0===t?xi():xi(t);return""===t&&(ki[e]=!0),e};zt(Oi,xi);var Ci=Oi.prototype=xi.prototype;Ci.constructor=Oi;var Pi=Ci.toString,Ti=xi("test")+""=="Symbol(test)",Ii=/^Symbol\((.*)\)[^)]+$/;Si(Ci,"description",{configurable:!0,get:function(){var t=E(this)?this.valueOf():this,e=Pi.call(t);if(N(ki,t)){return""}var i=Ti?e.slice(7,-1):e.replace(Ii,"$1");return""===i?void 0:i}}),te({global:!0,forced:!0},{Symbol:Oi})}Ee("iterator");var Ai,$i,Ri=function(t,e,i){var n=j(e);n in t?W.f(t,n,C(0,i)):t[n]=i},Ei=Ct("navigator","userAgent")||"",ji=b.process,_i=ji&&ji.versions,Ni=_i&&_i.v8;Ni?(Ai=Ni.split("."),$i=Ai[0]+Ai[1]):Ei&&(Ai=Ei.match(/Edge\/(\d+)/),(!Ai||Ai[1]>=74)&&(Ai=Ei.match(/Chrome\/(\d+)/),Ai&&($i=Ai[1])));var Fi=$i&&+$i,Vi=Ie("species"),Di=function(t){return Fi>=51||!m(function(){var e=[],i=e.constructor={};return i[Vi]=function(){return{foo:1}},1!==e[t](Boolean).foo})},Bi=Ie("isConcatSpreadable"),Li=9007199254740991,Hi="Maximum allowed index exceeded",Mi=Fi>=51||!m(function(){var t=[];return t[Bi]=!1,t.concat()[0]!==t}),Ui=Di("concat"),qi=function(t){if(!E(t)){return !1}var e=t[Bi];return void 0!==e?!!e:ne(t)},zi=!Mi||!Ui;te({target:"Array",proto:!0,forced:zi},{concat:function(t){var e,i,n,o,r,a=oe(this),s=Be(a,0),l=0;for(e=-1,n=arguments.length;n>e;e++){if(r=-1===e?a:arguments[e],qi(r)){if(o=$t(r.length),l+o>Li){throw TypeError(Hi)}for(i=0;o>i;i++,l++){i in r&&Ri(s,l,r[i])}}else{if(l>=Li){throw TypeError(Hi)}Ri(s,l++,r)}}return s.length=l,s}});var Wi=Me.filter,Gi=Di("filter"),Ki=Gi&&!m(function(){[].filter.call({length:-1,0:1},function(t){throw t})});te({target:"Array",proto:!0,forced:!Gi||!Ki},{filter:function(t){return Wi(this,t,arguments.length>1?arguments[1]:void 0)}});var Yi=Ie("unscopables"),Ji=Array.prototype;void 0==Ji[Yi]&&W.f(Ji,Yi,{configurable:!0,value:me(null)});var Xi=function(t){Ji[Yi][t]=!0},Qi=Me.find,Zi="find",tn=!0;Zi in []&&Array(1)[Zi](function(){tn=!1}),te({target:"Array",proto:!0,forced:tn},{find:function(t){return Qi(this,t,arguments.length>1?arguments[1]:void 0)}}),Xi(Zi);var en=Me.findIndex,nn="findIndex",on=!0;nn in []&&Array(1)[nn](function(){on=!1}),te({target:"Array",proto:!0,forced:on},{findIndex:function(t){return en(this,t,arguments.length>1?arguments[1]:void 0)}}),Xi(nn);var rn=Nt.includes;te({target:"Array",proto:!0},{includes:function(t){return rn(this,t,arguments.length>1?arguments[1]:void 0)}}),Xi("includes");var an=function(t,e){var i=[][t];return !i||!m(function(){i.call(null,e||function(){throw 1},1)})},sn=Nt.indexOf,ln=[].indexOf,cn=!!ln&&1/[1].indexOf(1,-0)<0,hn=an("indexOf");te({target:"Array",proto:!0,forced:cn||hn},{indexOf:function(t){return cn?ln.apply(this,arguments)||0:sn(this,t,arguments.length>1?arguments[1]:void 0)}});var un,dn,pn,fn=!m(function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}),gn=ht("IE_PROTO"),vn=Object.prototype,bn=fn?Object.getPrototypeOf:function(t){return t=oe(t),N(t,gn)?t[gn]:"function"==typeof t.constructor&&t instanceof t.constructor?t.constructor.prototype:t instanceof Object?vn:null},mn=Ie("iterator"),yn=!1,wn=function(){return this};[].keys&&(pn=[].keys(),"next" in pn?(dn=bn(bn(pn)),dn!==Object.prototype&&(un=dn)):yn=!0),void 0==un&&(un={}),N(un,mn)||G(un,mn,wn);var Sn={IteratorPrototype:un,BUGGY_SAFARI_ITERATORS:yn},xn=Sn.IteratorPrototype,kn=function(t,e,i){var n=e+" Iterator";return t.prototype=me(xn,{next:C(1,i)}),Ne(t,n,!1),t},On=function(t){if(!E(t)&&null!==t){throw TypeError("Can't set "+(t+"")+" as a prototype")}return t},Cn=Object.setPrototypeOf||("__proto__" in {}?function(){var t,e=!1,i={};try{t=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set,t.call(i,[]),e=i instanceof Array}catch(n){}return function(i,n){return U(i),On(n),e?t.call(i,n):i.__proto__=n,i}}():void 0),Pn=Sn.IteratorPrototype,Tn=Sn.BUGGY_SAFARI_ITERATORS,In=Ie("iterator"),An="keys",$n="values",Rn="entries",En=function(){return this},jn=function(t,e,i,n,o,r,a){kn(i,e,n);var s,l,c,h=function(t){if(t===o&&g){return g}if(!Tn&&t in p){return p[t]}switch(t){case An:return function(){return new i(this,t)};case $n:return function(){return new i(this,t)};case Rn:return function(){return new i(this,t)}}return function(){return new i(this)}},u=e+" Iterator",d=!1,p=t.prototype,f=p[In]||p["@@iterator"]||o&&p[o],g=!Tn&&f||h(o),v="Array"==e?p.entries||f:f;if(v&&(s=bn(v.call(new t)),Pn!==Object.prototype&&s.next&&(bn(s)!==Pn&&(Cn?Cn(s,Pn):"function"!=typeof s[In]&&G(s,In,En)),Ne(s,u,!0))),o==$n&&f&&f.name!==$n&&(d=!0,g=function(){return f.call(this)}),p[In]!==g&&G(p,In,g),o){if(l={values:h($n),keys:r?g:h(An),entries:h(Rn)},a){for(c in l){!Tn&&!d&&c in p||xt(p,c,l[c])}}else{te({target:e,proto:!0,forced:Tn||d},l)}}return l},_n="Array Iterator",Nn=St.set,Fn=St.getterFor(_n),Vn=jn(Array,"Array",function(t,e){Nn(this,{type:_n,target:R(t),index:0,kind:e})},function(){var t=Fn(this),e=t.target,i=t.kind,n=t.index++;return !e||n>=e.length?(t.target=void 0,{value:void 0,done:!0}):"keys"==i?{value:n,done:!1}:"values"==i?{value:e[n],done:!1}:{value:[n,e[n]],done:!1}},"values");Xi("keys"),Xi("values"),Xi("entries");var Dn=[].join,Bn=A!=Object,Ln=an("join",",");te({target:"Array",proto:!0,forced:Bn||Ln},{join:function(t){return Dn.call(R(this),void 0===t?",":t)}});var Hn=Me.map,Mn=Di("map"),Un=Mn&&!m(function(){[].map.call({length:-1,0:1},function(t){throw t})});te({target:"Array",proto:!0,forced:!Mn||!Un},{map:function(t){return Hn(this,t,arguments.length>1?arguments[1]:void 0)}});var qn=[].reverse,zn=[1,2];te({target:"Array",proto:!0,forced:zn+""==zn.reverse()+""},{reverse:function(){return ne(this)&&(this.length=this.length),qn.call(this)}});var Wn=Ie("species"),Gn=[].slice,Kn=Math.max;te({target:"Array",proto:!0,forced:!Di("slice")},{slice:function(t,e){var i,n,o,r=R(this),a=$t(r.length),s=jt(t,a),l=jt(void 0===e?a:e,a);if(ne(r)&&(i=r.constructor,"function"!=typeof i||i!==Array&&!ne(i.prototype)?E(i)&&(i=i[Wn],null===i&&(i=void 0)):i=void 0,i===Array||void 0===i)){return Gn.call(r,s,l)}for(n=new (void 0===i?Array:i)(Kn(l-s,0)),o=0;l>s;s++,o++){s in r&&Ri(n,o,r[s])}return n.length=o,n}});var Yn=[],Jn=Yn.sort,Xn=m(function(){Yn.sort(void 0)}),Qn=m(function(){Yn.sort(null)}),Zn=an("sort"),to=Xn||!Qn||Zn;te({target:"Array",proto:!0,forced:to},{sort:function(t){return void 0===t?Jn.call(oe(this)):Jn.call(oe(this),Fe(t))}});var eo=Math.max,io=Math.min,no=9007199254740991,oo="Maximum allowed length exceeded";te({target:"Array",proto:!0,forced:!Di("splice")},{splice:function(t,e){var i,n,o,r,a,s,l=oe(this),c=$t(l.length),h=jt(t,c),u=arguments.length;if(0===u?i=n=0:1===u?(i=0,n=c-h):(i=u-2,n=io(eo(It(e),0),c-h)),c+i-n>no){throw TypeError(oo)}for(o=Be(l,n),r=0;n>r;r++){a=h+r,a in l&&Ri(o,r,l[a])}if(o.length=n,n>i){for(r=h;c-n>r;r++){a=r+n,s=r+i,a in l?l[s]=l[a]:delete l[s]}for(r=c;r>c-n+i;r--){delete l[r-1]}}else{if(i>n){for(r=c-n;r>h;r--){a=r+n-1,s=r+i-1,a in l?l[s]=l[a]:delete l[s]}}}for(r=0;i>r;r++){l[r+h]=arguments[r+2]}return l.length=c-n+i,o}});var ro=function(t,e,i){var n,o;return Cn&&"function"==typeof(n=e.constructor)&&n!==i&&E(o=n.prototype)&&o!==i.prototype&&Cn(t,o),t},ao=" \n\x0B\f\r                 \u2028\u2029\ufeff",so="["+ao+"]",lo=RegExp("^"+so+so+"*"),co=RegExp(so+so+"*$"),ho=function(t){return function(e){var i=$(e)+"";return 1&t&&(i=i.replace(lo,"")),2&t&&(i=i.replace(co,"")),i}},uo={start:ho(1),end:ho(2),trim:ho(3)},po=Ht.f,fo=M.f,go=W.f,vo=uo.trim,bo="Number",mo=b[bo],yo=mo.prototype,wo=T(me(yo))==bo,So=function(t){var e,i,n,o,r,a,s,l,c=j(t,!1);if("string"==typeof c&&c.length>2){if(c=vo(c),e=c.charCodeAt(0),43===e||45===e){if(i=c.charCodeAt(2),88===i||120===i){return NaN}}else{if(48===e){switch(c.charCodeAt(1)){case 66:case 98:n=2,o=49;break;case 79:case 111:n=8,o=55;break;default:return +c}for(r=c.slice(2),a=r.length,s=0;a>s;s++){if(l=r.charCodeAt(s),48>l||l>o){return NaN}}return parseInt(r,n)}}}return +c};if(Qt(bo,!mo(" 0o1")||!mo("0b1")||mo("+0x1"))){for(var xo,ko=function(t){var e=arguments.length<1?0:t,i=this;return i instanceof ko&&(wo?m(function(){yo.valueOf.call(i)}):T(i)!=bo)?ro(new mo(So(e)),i,ko):So(e)},Oo=y?po(mo):"MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger".split(","),Co=0;Oo.length>Co;Co++){N(mo,xo=Oo[Co])&&!N(ko,xo)&&go(ko,xo,fo(mo,xo))}ko.prototype=yo,yo.constructor=ko,xt(b,bo,ko)}var Po=Object.assign,To=Object.defineProperty,Io=!Po||m(function(){if(y&&1!==Po({b:1},Po(To({},"a",{enumerable:!0,get:function(){To(this,"b",{value:3,enumerable:!1})}}),{b:2})).b){return !0}var t={},e={},i=Symbol(),n="abcdefghijklmnopqrst";return t[i]=7,n.split("").forEach(function(t){e[t]=t}),7!=Po({},t)[i]||re(Po({},e)).join("")!=n})?function(t,e){for(var i=oe(t),n=arguments.length,o=1,r=Ut.f,a=O.f;n>o;){for(var s,l=A(arguments[o++]),c=r?re(l).concat(r(l)):re(l),h=c.length,u=0;h>u;){s=c[u++],(!y||a.call(l,s))&&(i[s]=l[s])}}return i}:Po;te({target:"Object",stat:!0,forced:Object.assign!==Io},{assign:Io});var Ao=O.f,$o=function(t){return function(e){for(var i,n=R(e),o=re(n),r=o.length,a=0,s=[];r>a;){i=o[a++],(!y||Ao.call(n,i))&&s.push(t?[i,n[i]]:n[i])}return s}},Ro={entries:$o(!0),values:$o(!1)},Eo=Ro.entries;te({target:"Object",stat:!0},{entries:function(t){return Eo(t)}});var jo=Ie("toStringTag"),_o={};_o[jo]="z";var No=_o+""=="[object z]",Fo=Ie("toStringTag"),Vo="Arguments"==T(function(){return arguments}()),Do=function(t,e){try{return t[e]}catch(i){}},Bo=No?T:function(t){var e,i,n;return void 0===t?"Undefined":null===t?"Null":"string"==typeof(i=Do(e=Object(t),Fo))?i:Vo?T(e):"Object"==(n=T(e))&&"function"==typeof e.callee?"Arguments":n},Lo=No?{}.toString:function(){return"[object "+Bo(this)+"]"};No||xt(Object.prototype,"toString",Lo,{unsafe:!0});var Ho=uo.trim,Mo=b.parseFloat,Uo=1/Mo(ao+"-0")!==-(1/0),qo=Uo?function(t){var e=Ho(t+""),i=Mo(e);return 0===i&&"-"==e.charAt(0)?-0:i}:Mo;te({global:!0,forced:parseFloat!=qo},{parseFloat:qo});var zo=uo.trim,Wo=b.parseInt,Go=/^[+-]?0[Xx]/,Ko=8!==Wo(ao+"08")||22!==Wo(ao+"0x16"),Yo=Ko?function(t,e){var i=zo(t+"");return Wo(i,e>>>0||(Go.test(i)?16:10))}:Wo;te({global:!0,forced:parseInt!=Yo},{parseInt:Yo});var Jo=Ie("match"),Xo=function(t){var e;return E(t)&&(void 0!==(e=t[Jo])?!!e:"RegExp"==T(t))},Qo=function(){var t=U(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.dotAll&&(e+="s"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e},Zo=m(function(){var t=i("a","y");return t.lastIndex=2,null!=t.exec("abcd")}),tr=m(function(){var t=i("^r","gy");return t.lastIndex=2,null!=t.exec("str")}),er={UNSUPPORTED_Y:Zo,BROKEN_CARET:tr},ir=Ie("species"),nr=function(t){var e=Ct(t),i=W.f;y&&e&&!e[ir]&&i(e,ir,{configurable:!0,get:function(){return this}})},or=W.f,rr=Ht.f,ar=St.set,sr=Ie("match"),lr=b.RegExp,cr=lr.prototype,hr=/a/g,ur=/a/g,dr=new lr(hr)!==hr,pr=er.UNSUPPORTED_Y,fr=y&&Qt("RegExp",!dr||pr||m(function(){return ur[sr]=!1,lr(hr)!=hr||lr(ur)==ur||"/a/i"!=lr(hr,"i")}));if(fr){for(var gr=function(t,e){var i,n=this instanceof gr,o=Xo(t),r=void 0===e;if(!n&&o&&t.constructor===gr&&r){return t}dr?o&&!r&&(t=t.source):t instanceof gr&&(r&&(e=Qo.call(t)),t=t.source),pr&&(i=!!e&&e.indexOf("y")>-1,i&&(e=e.replace(/y/g,"")));var a=ro(dr?new lr(t,e):lr(t,e),n?this:cr,gr);return pr&&i&&ar(a,{sticky:i}),a},vr=(function(t){t in gr||or(gr,t,{configurable:!0,get:function(){return lr[t]},set:function(e){lr[t]=e}})}),br=rr(lr),mr=0;br.length>mr;){vr(br[mr++])}cr.constructor=gr,gr.prototype=cr,xt(b,"RegExp",gr)}nr("RegExp");var yr=RegExp.prototype.exec,wr=String.prototype.replace,Sr=yr,xr=function(){var t=/a/,e=/b*/g;return yr.call(t,"a"),yr.call(e,"a"),0!==t.lastIndex||0!==e.lastIndex}(),kr=er.UNSUPPORTED_Y||er.BROKEN_CARET,Or=void 0!==/()??/.exec("")[1],Cr=xr||Or||kr;Cr&&(Sr=function(t){var e,i,n,o,r=this,a=kr&&r.sticky,s=Qo.call(r),l=r.source,c=0,h=t;return a&&(s=s.replace("y",""),-1===s.indexOf("g")&&(s+="g"),h=(t+"").slice(r.lastIndex),r.lastIndex>0&&(!r.multiline||r.multiline&&"\n"!==t[r.lastIndex-1])&&(l="(?: "+l+")",h=" "+h,c++),i=RegExp("^(?:"+l+")",s)),Or&&(i=RegExp("^"+l+"$(?!\\s)",s)),xr&&(e=r.lastIndex),n=yr.call(a?i:r,h),a?n?(n.input=n.input.slice(c),n[0]=n[0].slice(c),n.index=r.lastIndex,r.lastIndex+=n[0].length):r.lastIndex=0:xr&&n&&(r.lastIndex=r.global?n.index+n[0].length:e),Or&&n&&n.length>1&&wr.call(n[0],i,function(){for(o=1;o1?arguments[1]:void 0)}});var Nr=function(t){return function(e,i){var n,o,r=$(e)+"",a=It(i),s=r.length;return 0>a||a>=s?t?"":void 0:(n=r.charCodeAt(a),55296>n||n>56319||a+1===s||(o=r.charCodeAt(a+1))<56320||o>57343?t?r.charAt(a):n:t?r.slice(a,a+2):(n-55296<<10)+(o-56320)+65536)}},Fr={codeAt:Nr(!1),charAt:Nr(!0)},Vr=Fr.charAt,Dr="String Iterator",Br=St.set,Lr=St.getterFor(Dr);jn(String,"String",function(t){Br(this,{type:Dr,string:t+"",index:0})},function(){var t,e=Lr(this),i=e.string,n=e.index;return n>=i.length?{value:void 0,done:!0}:(t=Vr(i,n),e.index+=t.length,{value:t,done:!1})});var Hr=Ie("species"),Mr=!m(function(){var t=/./;return t.exec=function(){var t=[];return t.groups={a:"7"},t},"7"!=="".replace(t,"$")}),Ur=function(){return"$0"==="a".replace(/./,"$0")}(),qr=!m(function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var i="ab".split(t);return 2!==i.length||"a"!==i[0]||"b"!==i[1]}),zr=function(t,e,i,n){var o=Ie(t),r=!m(function(){var e={};return e[o]=function(){return 7},7!=""[t](e)}),a=r&&!m(function(){var e=!1,i=/a/;return"split"===t&&(i={},i.constructor={},i.constructor[Hr]=function(){return i},i.flags="",i[o]=/./[o]),i.exec=function(){return e=!0,null},i[o](""),!e});if(!r||!a||"replace"===t&&(!Mr||!Ur)||"split"===t&&!qr){var s=/./[o],l=i(o,""[t],function(t,e,i,n,o){return e.exec===Pr?r&&!o?{done:!0,value:s.call(e,i,n)}:{done:!0,value:t.call(i,e,n)}:{done:!1}},{REPLACE_KEEPS_$0:Ur}),c=l[0],h=l[1];xt(String.prototype,t,c),xt(RegExp.prototype,o,2==e?function(t,e){return h.call(t,this,e)}:function(t){return h.call(t,this)})}n&&G(RegExp.prototype[o],"sham",!0)},Wr=Fr.charAt,Gr=function(t,e,i){return e+(i?Wr(t,e).length:1)},Kr=function(t,e){var i=t.exec;if("function"==typeof i){var n=i.call(t,e);if("object"!=typeof n){throw TypeError("RegExp exec method returned something other than an Object or null")}return n}if("RegExp"!==T(t)){throw TypeError("RegExp#exec called on incompatible receiver")}return Pr.call(t,e)},Yr=Math.max,Jr=Math.min,Xr=Math.floor,Qr=/\$([$&'`]|\d\d?|<[^>]*>)/g,Zr=/\$([$&'`]|\d\d?)/g,ta=function(t){return void 0===t?t:t+""};zr("replace",2,function(t,e,i,n){function o(t,i,n,o,r,a){var s=n+t.length,l=o.length,c=Zr;return void 0!==r&&(r=oe(r),c=Qr),e.call(a,c,function(e,a){var c;switch(a.charAt(0)){case"$":return"$";case"&":return t;case"`":return i.slice(0,n);case"'":return i.slice(s);case"<":c=r[a.slice(1,-1)];break;default:var h=+a;if(0===h){return e}if(h>l){var u=Xr(h/10);return 0===u?e:l>=u?void 0===o[u-1]?a.charAt(1):o[u-1]+a.charAt(1):e}c=o[h-1]}return void 0===c?"":c})}return[function(i,n){var o=$(this),r=void 0==i?void 0:i[t];return void 0!==r?r.call(i,o,n):e.call(o+"",i,n)},function(t,r){if(n.REPLACE_KEEPS_$0||"string"==typeof r&&-1===r.indexOf("$0")){var a=i(e,t,this,r);if(a.done){return a.value}}var s=U(t),l=this+"",c="function"==typeof r;c||(r+="");var h=s.global;if(h){var u=s.unicode;s.lastIndex=0}for(var d=[];;){var p=Kr(s,l);if(null===p){break}if(d.push(p),!h){break}var f=p[0]+"";""===f&&(s.lastIndex=Gr(l,$t(s.lastIndex),u))}for(var g="",v=0,b=0;b=v&&(g+=l.slice(v,y)+O,v=y+m.length)}return g+l.slice(v)}]});var ea=Object.is||function(t,e){return t===e?0!==t||1/t===1/e:t!=t&&e!=e};zr("search",1,function(t,e,i){return[function(e){var i=$(this),n=void 0==e?void 0:e[t];return void 0!==n?n.call(e,i):RegExp(e)[t](i+"")},function(t){var n=i(e,t,this);if(n.done){return n.value}var o=U(t),r=this+"",a=o.lastIndex;ea(a,0)||(o.lastIndex=0);var s=Kr(o,r);return ea(o.lastIndex,a)||(o.lastIndex=a),null===s?-1:s.index}]});var ia=Ie("species"),na=function(t,e){var i,n=U(t).constructor;return void 0===n||void 0==(i=U(n)[ia])?e:Fe(i)},oa=[].push,ra=Math.min,aa=4294967295,sa=!m(function(){return !RegExp(aa,"y")});zr("split",2,function(t,e,i){var n;return n="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,i){var n=$(this)+"",o=void 0===i?aa:i>>>0;if(0===o){return[]}if(void 0===t){return[n]}if(!Xo(t)){return e.call(n,t,o)}for(var r,a,s,l=[],c=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),h=0,u=RegExp(t.source,c+"g");(r=Pr.call(u,n))&&(a=u.lastIndex,!(a>h&&(l.push(n.slice(h,r.index)),r.length>1&&r.index=o)));){u.lastIndex===r.index&&u.lastIndex++}return h===n.length?(s||!u.test(""))&&l.push(""):l.push(n.slice(h)),l.length>o?l.slice(0,o):l}:"0".split(void 0,0).length?function(t,i){return void 0===t&&0===i?[]:e.call(this,t,i)}:e,[function(e,i){var o=$(this),r=void 0==e?void 0:e[t];return void 0!==r?r.call(e,o,i):n.call(o+"",e,i)},function(t,o){var r=i(n,t,this,o,n!==e);if(r.done){return r.value}var a=U(t),s=this+"",l=na(a,RegExp),c=a.unicode,h=(a.ignoreCase?"i":"")+(a.multiline?"m":"")+(a.unicode?"u":"")+(sa?"y":"g"),u=new l(sa?a:"^(?:"+a.source+")",h),d=void 0===o?aa:o>>>0;if(0===d){return[]}if(0===s.length){return null===Kr(u,s)?[s]:[]}for(var p=0,f=0,g=[];f1?arguments[1]:void 0)}:[].forEach;for(var fa in ua){var ga=b[fa],va=ga&&ga.prototype;if(va&&va.forEach!==pa){try{G(va,"forEach",pa)}catch(ba){va.forEach=pa}}}var ma=Ie("iterator"),ya=Ie("toStringTag"),wa=Vn.values;for(var Sa in ua){var xa=b[Sa],ka=xa&&xa.prototype;if(ka){if(ka[ma]!==wa){try{G(ka,ma,wa)}catch(ba){ka[ma]=wa}}if(ka[ya]||G(ka,ya,Sa),ua[Sa]){for(var Oa in Vn){if(ka[Oa]!==Vn[Oa]){try{G(ka,Oa,Vn[Oa])}catch(ba){ka[Oa]=Vn[Oa]}}}}}}var Ca="1.18.0",Pa=4;try{var Ta=t.fn.dropdown.Constructor.VERSION;void 0!==Ta&&(Pa=parseInt(Ta,10))}catch(Ia){}try{var Aa=bootstrap.Tooltip.VERSION;void 0!==Aa&&(Pa=parseInt(Aa,10))}catch(Ia){}var $a={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:''}}}[Pa],Ra={id:void 0,firstLoad:!0,height:void 0,classes:"table table-bordered table-hover",buttons:{},theadClasses:"",striped:!1,headerStyle:function(t){return{}},rowStyle:function(t,e){return{}},rowAttributes:function(t,e){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(t){return t},queryParamsType:"limit",responseHandler:function(t){return t},totalField:"total",totalNotFilteredField:"totalNotFiltered",dataField:"rows",footerField:"footer",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,searchHighlight:!1,searchOnEnterKey:!1,strictSearch:!1,searchSelector:!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(t){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(t){var e=t.tagName;return["A","BUTTON"].includes(e)},singleSelect:!1,checkboxHeader:!0,maintainMetaData:!1,multipleSelectRow:!1,uniqueId:void 0,cardView:!1,detailView:!1,detailViewIcon:!0,detailViewByClick:!1,detailViewAlign:"left",detailFormatter:function(t,e){return""},detailFilter:function(t,e){return !0},toolbar:void 0,toolbarAlign:"left",buttonsToolbar:void 0,buttonsAlign:"right",buttonsOrder:["search","paginationSwitch","refresh","toggle","fullscreen","columns"],buttonsPrefix:$a.classes.buttonsPrefix,buttonsClass:$a.classes.buttons,icons:$a.icons,iconSize:void 0,iconsPrefix:$a.iconsPrefix,loadingFontSize:"auto",loadingTemplate:function(t){return'\n '.concat(t,'\n \n \n ')},onAll:function(t,e){return !1},onClickCell:function(t,e,i,n){return !1},onDblClickCell:function(t,e,i,n){return !1},onClickRow:function(t,e){return !1},onDblClickRow:function(t,e){return !1},onSort:function(t,e){return !1},onCheck:function(t){return !1},onUncheck:function(t){return !1},onCheckAll:function(t){return !1},onUncheckAll:function(t){return !1},onCheckSome:function(t){return !1},onUncheckSome:function(t){return !1},onLoadSuccess:function(t){return !1},onLoadError:function(t){return !1},onColumnSwitch:function(t,e){return !1},onPageChange:function(t,e){return !1},onSearch:function(t){return !1},onShowSearch:function(){return !1},onToggle:function(t){return !1},onPreBody:function(t){return !1},onPostBody:function(){return !1},onPostHeader:function(){return !1},onPostFooter:function(){return !1},onExpandRow:function(t,e,i){return !1},onCollapseRow:function(t,e){return !1},onRefreshOptions:function(t){return !1},onRefresh:function(t){return !1},onResetView:function(){return !1},onScrollBody:function(){return !1}},Ea={formatLoadingMessage:function(){return"Loading, please wait"},formatRecordsPerPage:function(t){return"".concat(t," rows per page")},formatShowingRows:function(t,e,i,n){return void 0!==n&&n>0&&n>i?"Showing ".concat(t," to ").concat(e," of ").concat(i," rows (filtered from ").concat(n," total rows)"):"Showing ".concat(t," to ").concat(e," of ").concat(i," rows")},formatSRPaginationPreText:function(){return"previous page"},formatSRPaginationPageText:function(t){return"to page ".concat(t)},formatSRPaginationNextText:function(){return"next page"},formatDetailPagination:function(t){return"Showing ".concat(t," rows")},formatSearch:function(){return"Search"},formatShowSearch:function(){return"Show Search"},formatPageGo:function(){return"Go"},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"}},ja={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,searchHighlightFormatter:!1,escape:!1,events:void 0},_a=["getOptions","refreshOptions","getData","getSelections","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"],Na={"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(Ra,Ea);var Fa={VERSION:Ca,THEME:"bootstrap".concat(Pa),CONSTANTS:$a,DEFAULTS:Ra,COLUMN_DEFAULTS:ja,METHODS:_a,EVENTS:Na,LOCALES:{en:Ea,"en-US":Ea}},Va=m(function(){re(1)});te({target:"Object",stat:!0,forced:Va},{keys:function(t){return re(oe(t))}});var Da=M.f,Ba="".endsWith,La=Math.min,Ha=_r("endsWith"),Ma=!Ha&&!!function(){var t=Da(String.prototype,"endsWith");return t&&!t.writable}();te({target:"String",proto:!0,forced:!Ma&&!Ha},{endsWith:function(t){var e=$(this)+"";Er(t);var i=arguments.length>1?arguments[1]:void 0,n=$t(e.length),o=void 0===i?n:La($t(i),n),r=t+"";return Ba?Ba.call(e,r,o):e.slice(o-r.length,o)===r}});var Ua=M.f,qa="".startsWith,za=Math.min,Wa=_r("startsWith"),Ga=!Wa&&!!function(){var t=Ua(String.prototype,"startsWith");return t&&!t.writable}();te({target:"String",proto:!0,forced:!Ga&&!Wa},{startsWith:function(t){var e=$(this)+"";Er(t);var i=$t(za(arguments.length>1?arguments[1]:void 0,e.length)),n=t+"";return qa?qa.call(e,n,i):e.slice(i,i+n.length)===n}});var Ka={getSearchInput:function(e){return"string"==typeof e.options.searchSelector?t(e.options.searchSelector):e.$toolbar.find(".search input")},sprintf:function(t){for(var e=arguments.length,i=Array(e>1?e-1:0),n=1;e>n;n++){i[n-1]=arguments[n]}var o=!0,r=0,a=t.replace(/%s/g,function(){var t=i[r++];return void 0===t?(o=!1,""):t});return o?a:""},isObject:function(t){return t instanceof Object&&!Array.isArray(t)},isEmptyObject:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return 0===Object.entries(t).length&&t.constructor===Object},isNumeric:function(t){return !isNaN(parseFloat(t))&&isFinite(t)},getFieldTitle:function(t,e){var i=!0,n=!1,o=void 0;try{for(var r,a=t[Symbol.iterator]();!(i=(r=a.next()).done);i=!0){var s=r.value;if(s.field===e){return s.title}}}catch(l){n=!0,o=l}finally{try{i||null==a["return"]||a["return"]()}finally{if(n){throw o}}}return""},setFieldIndex:function(t){var e=0,i=[],n=!0,o=!1,r=void 0;try{for(var a,s=t[0][Symbol.iterator]();!(n=(a=s.next()).done);n=!0){var l=a.value;e+=l.colspan||1}}catch(c){o=!0,r=c}finally{try{n||null==s["return"]||s["return"]()}finally{if(o){throw r}}}for(var h=0;hu;u++){i[h][u]=!1}}for(var d=0;dx;x++){for(var k=0;w>k;k++){i[d+x][S+k]=!0}}}}catch(c){f=!0,g=c}finally{try{p||null==b["return"]||b["return"]()}finally{if(f){throw g}}}}},normalizeAccent:function(t){return"string"!=typeof t?t:t.normalize("NFD").replace(/[\u0300-\u036f]/g,"")},updateFieldGroup:function(t){var e,i=(e=[]).concat.apply(e,l(t)),n=!0,o=!1,r=void 0;try{for(var a,s=t[Symbol.iterator]();!(n=(a=s.next()).done);n=!0){var c=a.value,h=!0,u=!1,d=void 0;try{for(var p,f=c[Symbol.iterator]();!(h=(p=f.next()).done);h=!0){var g=p.value;if(g.colspanGroup>1){for(var v=0,b=function(t){var e=i.find(function(e){return e.fieldIndex===t +});e.visible&&v++},m=g.colspanIndex;m0}}}catch(y){u=!0,d=y}finally{try{h||null==f["return"]||f["return"]()}finally{if(u){throw d}}}}}catch(y){o=!0,r=y}finally{try{n||null==s["return"]||s["return"]()}finally{if(o){throw r}}}},getScrollBarWidth:function(){if(void 0===this.cachedWidth){var e=t("
    ").addClass("fixed-table-scroll-inner"),i=t("
    ").addClass("fixed-table-scroll-outer");i.append(e),t("body").append(i);var n=e[0].offsetWidth;i.css("overflow","scroll");var o=e[0].offsetWidth;n===o&&(o=i[0].clientWidth),i.remove(),this.cachedWidth=n-o}return this.cachedWidth},calculateObjectValue:function(t,e){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3?arguments[3]:void 0,r=e;if("string"==typeof e){var a=e.split(".");if(a.length>1){r=window;var s=!0,c=!1,h=void 0;try{for(var u,d=a[Symbol.iterator]();!(s=(u=d.next()).done);s=!0){var p=u.value;r=r[p]}}catch(f){c=!0,h=f}finally{try{s||null==d["return"]||d["return"]()}finally{if(c){throw h}}}}else{r=window[e]}}return null!==r&&"object"===n(r)?r:"function"==typeof r?r.apply(t,i||[]):!r&&"string"==typeof e&&this.sprintf.apply(this,[e].concat(l(i)))?this.sprintf.apply(this,[e].concat(l(i))):o},compareObjects:function(t,e,i){var n=Object.keys(t),o=Object.keys(e);if(i&&n.length!==o.length){return !1}for(var r=0,a=n;r/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/`/g,"`"):t},unescapeHTML:function(t){return"string"==typeof t?t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/`/g,"`"):t},getRealDataAttr:function(t){for(var e=0,i=Object.entries(t);etd,>th").each(function(o,a){for(var s=t(a),c=+s.attr("colspan")||1,h=+s.attr("rowspan")||1,u=o;r[i]&&r[i][u];u++){}for(var d=u;u+c>d;d++){for(var p=i;i+h>p;p++){r[p]||(r[p]=[]),r[p][d]=!0}}var f=e[u].field;l[f]=s.html().trim(),l["_".concat(f,"_id")]=s.attr("id"),l["_".concat(f,"_class")]=s.attr("class"),l["_".concat(f,"_rowspan")]=s.attr("rowspan"),l["_".concat(f,"_colspan")]=s.attr("colspan"),l["_".concat(f,"_title")]=s.attr("title"),l["_".concat(f,"_data")]=n.getRealDataAttr(s.data()),l["_".concat(f,"_style")]=s.attr("style")}),o.push(l)}),o},sort:function(t,e,i,n,o,r){return(void 0===t||null===t)&&(t=""),(void 0===e||null===e)&&(e=""),n&&t===e&&(t=o,e=r),this.isNumeric(t)&&this.isNumeric(e)?(t=parseFloat(t),e=parseFloat(e),e>t?-1*i:t>e?i:0):t===e?0:("string"!=typeof t&&(t=""+t),-1===t.localeCompare(e)?-1*i:i)},getEventName:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=e||"".concat(+new Date).concat(~~(1000000*Math.random())),"".concat(t,"-").concat(e)},hasDetailViewIcon:function(t){return t.detailView&&t.detailViewIcon&&!t.cardView},getDetailViewIndexOffset:function(t){return this.hasDetailViewIcon(t)&&"right"!==t.detailViewAlign?1:0},checkAutoMergeCells:function(t){var e=!0,i=!1,n=void 0;try{for(var o,r=t[Symbol.iterator]();!(e=(o=r.next()).done);e=!0){for(var a=o.value,s=0,l=Object.keys(a);so&&s++;for(var l=i;n>l;l++){t[l]&&a.push(t[l])}return{topOffset:o,bottomOffset:r,rowsAbove:s,rows:a}}},{key:"checkChanges",value:function(t,e){var i=e!==this.cache[t];return this.cache[t]=e,i}},{key:"getExtra",value:function(t,e){var i=document.createElement("tr");return i.className="virtual-scroll-".concat(t),e&&(i.style.height="".concat(e,"px")),i.outerHTML}}]),t}(),Qa=function(){function e(i,n){o(this,e),this.options=n,this.$el=t(i),this.$el_=this.$el.clone(),this.timeoutId_=0,this.timeoutFooter_=0}return a(e,[{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 e=this.options;this.constants=Fa.CONSTANTS,this.constants.theme=t.fn.bootstrapTable.theme;var i=e.buttonsPrefix?"".concat(e.buttonsPrefix,"-"):"";this.constants.buttonsClass=[e.buttonsPrefix,i+e.buttonsClass,Ka.sprintf("".concat(i,"%s"),e.iconSize)].join(" ").trim(),this.buttons=Ka.calculateObjectValue(this,e.buttons,[],[])}},{key:"initLocale",value:function(){if(this.options.locale){var e=t.fn.bootstrapTable.locales,i=this.options.locale.split(/-|_/);i[0]=i[0].toLowerCase(),i[1]&&(i[1]=i[1].toUpperCase()),e[this.options.locale]?t.extend(this.options,e[this.options.locale]):e[i.join("-")]?t.extend(this.options,e[i.join("-")]):e[i[0]]&&t.extend(this.options,e[i[0]])}}},{key:"initContainer",value:function(){var e=["top","both"].includes(this.options.paginationVAlign)?'
    ':"",i=["bottom","both"].includes(this.options.paginationVAlign)?'
    ':"",n=Ka.calculateObjectValue(this.options,this.options.loadingTemplate,[this.options.formatLoadingMessage()]);this.$container=t('\n
    \n
    \n ').concat(e,'\n
    \n
    \n
    \n
    \n ').concat(n,'\n
    \n
    \n \n
    \n ').concat(i,"\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.options.buttonsToolbar?this.$toolbar=t("body").find(this.options.buttonsToolbar):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),this.$tableLoading.addClass(this.options.classes),this.options.striped&&this.$el.addClass("table-striped"),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 i=this,n=[];if(this.$header=this.$el.find(">thead"),this.$header.length?this.options.theadClasses&&this.$header.addClass(this.options.theadClasses):this.$header=t('')).appendTo(this.$el),this._headerTrClasses=[],this._headerTrStyles=[],this.$header.find("tr").each(function(e,o){var r=t(o),a=[];r.find("th").each(function(e,i){var n=t(i);void 0!==n.data("field")&&n.data("field","".concat(n.data("field"))),a.push(t.extend({},{title:n.html(),"class":n.attr("class"),titleTooltip:n.attr("title"),rowspan:n.attr("rowspan")?+n.attr("rowspan"):void 0,colspan:n.attr("colspan")?+n.attr("colspan"):void 0},n.data()))}),n.push(a),r.attr("class")&&i._headerTrClasses.push(r.attr("class")),r.attr("style")&&i._headerTrStyles.push(r.attr("style"))}),Array.isArray(this.options.columns[0])||(this.options.columns=[this.options.columns]),this.options.columns=t.extend(!0,[],n,this.options.columns),this.columns=[],this.fieldsColumnsIndex=[],Ka.setFieldIndex(this.options.columns),this.options.columns.forEach(function(n,o){n.forEach(function(n,r){var a=t.extend({},e.COLUMN_DEFAULTS,n);void 0!==a.fieldIndex&&(i.columns[a.fieldIndex]=a,i.fieldsColumnsIndex[a.field]=a.fieldIndex),i.options.columns[o][r]=a})}),!this.options.data.length){var o=Ka.trToData(this.columns,this.$el.find(">tbody>tr"));o.length&&(this.options.data=o,this.fromHtml=!0)}this.options.pagination&&"server"!==this.options.sidePagination||(this.footerData=Ka.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 e=this,i={},n=[];this.header={fields:[],styles:[],classes:[],formatters:[],detailFormatters:[],events:[],sorters:[],sortNames:[],cellStyles:[],searchables:[]},Ka.updateFieldGroup(this.options.columns),this.options.columns.forEach(function(t,o){n.push(""));var r="";0===o&&Ka.hasDetailViewIcon(e.options)&&(r='\n
    \n ')),r&&"right"!==e.options.detailViewAlign&&n.push(r),t.forEach(function(t,r){var a=Ka.sprintf(' class="%s"',t["class"]),l=t.widthUnit,c=parseFloat(t.width),h=Ka.sprintf("text-align: %s; ",t.halign?t.halign:t.align),u=Ka.sprintf("text-align: %s; ",t.align),d=Ka.sprintf("vertical-align: %s; ",t.valign);if(d+=Ka.sprintf("width: %s; ",!t.checkbox&&!t.radio||c?c?c+l:void 0:t.showSelectTitle?void 0:"36px"),void 0!==t.fieldIndex||t.visible){var p=Ka.calculateObjectValue(null,e.options.headerStyle,[t]),f=[],g="";if(p&&p.css){for(var v=0,b=Object.entries(p.css);v0?" data-not-first-th":"",">"),n.push(Ka.sprintf('
    ',e.options.sortable&&t.sortable?"sortable both":""));var S=e.options.escape?Ka.escapeHTML(t.title):t.title,x=S;t.checkbox&&(S="",!e.options.singleSelect&&e.options.checkboxHeader&&(S=''),e.header.stateField=t.field),t.radio&&(S="",e.header.stateField=t.field),!S&&t.showSelectTitle&&(S+=x),n.push(S),n.push("
    "),n.push('
    '),n.push("
    "),n.push("")}}),r&&"right"===e.options.detailViewAlign&&n.push(r),n.push("")}),this.$header.html(n.join("")),this.$header.find("th[data-field]").each(function(e,n){t(n).data(i[t(n).data("field")])}),this.$container.off("click",".th-inner").on("click",".th-inner",function(i){var n=t(i.currentTarget);return e.options.detailView&&!n.parent().hasClass("bs-checkbox")&&n.closest(".bootstrap-table")[0]!==e.$container[0]?!1:void (e.options.sortable&&n.parent().data().sortable&&e.onSort(i))}),this.$header.children().children().off("keypress").on("keypress",function(i){if(e.options.sortable&&t(i.currentTarget).data().sortable){var n=i.keyCode||i.which;13===n&&e.onSort(i)}});var o=Ka.getEventName("resize.bootstrap-table",this.$el.attr("id"));t(window).off(o),!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(),t(window).on(o,function(){return e.resetView()})),this.$selectAll=this.$header.find('[name="btSelectAll"]'),this.$selectAll.off("click").on("click",function(i){i.stopPropagation();var n=t(i.currentTarget).prop("checked");e[n?"checkAll":"uncheckAll"](),e.updateSelected()})}},{key:"initData",value:function(t,e){"append"===e?this.options.data=this.options.data.concat(t):"prepend"===e?this.options.data=[].concat(t).concat(this.options.data):(t=t||Ka.deepCopy(this.options.data),this.options.data=Array.isArray(t)?t:t[this.options.dataField]),this.data=l(this.options.data),this.options.sortReset&&(this.unsortedData=l(this.data)),"server"!==this.options.sidePagination&&this.initSort()}},{key:"initSort",value:function(){var t=this,e=this.options.sortName,i="desc"===this.options.sortOrder?-1:1,n=this.header.fields.indexOf(this.options.sortName),o=0;-1!==n?(this.options.sortStable&&this.data.forEach(function(t,e){t.hasOwnProperty("_position")||(t._position=e)}),this.options.customSort?Ka.calculateObjectValue(this.options,this.options.customSort,[this.options.sortName,this.options.sortOrder,this.data]):this.data.sort(function(o,r){t.header.sortNames[n]&&(e=t.header.sortNames[n]);var a=Ka.getItemField(o,e,t.options.escape),s=Ka.getItemField(r,e,t.options.escape),l=Ka.calculateObjectValue(t.header,t.header.sorters[n],[a,s,o,r]);return void 0!==l?t.options.sortStable&&0===l?i*(o._position-r._position):i*l:Ka.sort(a,s,i,t.options.sortStable,o._position,r._position)}),void 0!==this.options.sortClass&&(clearTimeout(o),o=setTimeout(function(){t.$el.removeClass(t.options.sortClass);var e=t.$header.find('[data-field="'.concat(t.options.sortName,'"]')).index();t.$el.find("tr td:nth-child(".concat(e+1,")")).addClass(t.options.sortClass)},250))):this.options.sortReset&&(this.data=l(this.unsortedData))}},{key:"onSort",value:function(e){var i=e.type,n=e.currentTarget,o="keypress"===i?t(n):t(n).parent(),r=this.$header.find("th").eq(o.index());if(this.$header.add(this.$header_).find("span.order").remove(),this.options.sortName===o.data("field")){var a=this.options.sortOrder;void 0===a?this.options.sortOrder="asc":"asc"===a?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)}else{this.options.sortName=o.data("field"),this.options.rememberOrder?this.options.sortOrder="asc"===o.data("order")?"desc":"asc":this.options.sortOrder=this.columns[this.fieldsColumnsIndex[o.data("field")]].sortOrder||this.columns[this.fieldsColumnsIndex[o.data("field")]].order}return this.trigger("sort",this.options.sortName,this.options.sortOrder),o.add(r).data("order",this.options.sortOrder),this.getCaret(),"server"===this.options.sidePagination&&this.options.serverSort?(this.options.pageNumber=1,void this.initServer(this.options.silentSort)):(this.initSort(),void this.initBody())}},{key:"initToolbar",value:function(){var e,i=this,o=this.options,r=[],a=0,l=0;this.$toolbar.find(".bs-bars").children().length&&t("body").append(t(o.toolbar)),this.$toolbar.html(""),("string"==typeof o.toolbar||"object"===n(o.toolbar))&&t(Ka.sprintf('
    ',this.constants.classes.pull,o.toolbarAlign)).appendTo(this.$toolbar).append(t(o.toolbar)),r=['
    ')],"string"==typeof o.icons&&(o.icons=Ka.calculateObjectValue(null,o.icons)),"string"==typeof o.buttonsOrder&&(o.buttonsOrder=o.buttonsOrder.replace(/\[|\]| |'/g,"").toLowerCase().split(",")),this.buttons=Object.assign(this.buttons,{search:{text:o.formatSearch(),icon:o.icons.search,render:!1,event:this.toggleShowSearch,attributes:{"aria-label":o.formatShowSearch(),title:o.formatShowSearch()}},paginationSwitch:{text:o.pagination?o.formatPaginationSwitchUp():o.formatPaginationSwitchDown(),icon:o.pagination?o.icons.paginationSwitchDown:o.icons.paginationSwitchUp,render:!1,event:this.togglePagination,attributes:{"aria-label":o.formatPaginationSwitch(),title:o.formatPaginationSwitch()}},refresh:{text:o.formatRefresh(),icon:o.icons.refresh,render:!1,event:this.refresh,attributes:{"aria-label":o.formatRefresh(),title:o.formatRefresh()}},toggle:{text:o.formatToggle(),icon:o.icons.toggleOff,render:!1,event:this.toggleView,attributes:{"aria-label":o.formatToggleOn(),title:o.formatToggleOn()}},fullscreen:{text:o.formatFullscreen(),icon:o.icons.fullscreen,render:!1,event:this.toggleFullscreen,attributes:{"aria-label":o.formatFullscreen(),title:o.formatFullscreen()}},columns:{render:!1,html:function Z(){var Z=[];if(Z.push('
    \n \n ").concat(i.constants.html.toolbarDropdown[0])),o.showColumnsSearch&&(Z.push(Ka.sprintf(i.constants.html.toolbarDropdownItem,Ka.sprintf('',i.constants.classes.input,o.formatSearch()))),Z.push(i.constants.html.toolbarDropdownSeparator)),o.showColumnsToggleAll){var t=i.getVisibleColumns().length===i.columns.filter(function(t){return !i.isSelectionColumn(t)}).length;Z.push(Ka.sprintf(i.constants.html.toolbarDropdownItem,Ka.sprintf(' %s',t?'checked="checked"':"",o.formatColumnsToggleAll()))),Z.push(i.constants.html.toolbarDropdownSeparator)}var e=0;return i.columns.forEach(function(t,i){t.visible&&e++}),i.columns.forEach(function(t,n){if(!i.isSelectionColumn(t)&&(!o.cardView||t.cardVisible)&&!t.ignore){var r=t.visible?' checked="checked"':"",a=e<=o.minimumCountColumns&&r?' disabled="disabled"':"";t.switchable&&(Z.push(Ka.sprintf(i.constants.html.toolbarDropdownItem,Ka.sprintf(' %s',t.field,n,r,a,t.title))),l++)}}),Z.push(i.constants.html.toolbarDropdown[1],"
    "),Z.join("")}}});for(var c={},h=0,u=Object.entries(this.buttons);h"}c[p]=g;var x="show".concat(p.charAt(0).toUpperCase()).concat(p.substring(1)),k=o[x];!(!f.hasOwnProperty("render")||f.hasOwnProperty("render")&&f.render)||void 0!==k&&k!==!0||(o[x]=!0),o.buttonsOrder.includes(p)||o.buttonsOrder.push(p)}var O=!0,C=!1,P=void 0;try{for(var T,I=o.buttonsOrder[Symbol.iterator]();!(O=(T=I.next()).done);O=!0){var A=T.value,$=o["show".concat(A.charAt(0).toUpperCase()).concat(A.substring(1))];$&&r.push(c[A])}}catch(R){C=!0,P=R}finally{try{O||null==I["return"]||I["return"]()}finally{if(C){throw P}}}r.push("
    "),(this.showToolbar||r.length>2)&&this.$toolbar.append(r.join("")),o.showSearch&&this.$toolbar.find('button[name="showSearch"]').off("click").on("click",function(){return i.toggleShowSearch()});for(var E=0,j=Object.entries(this.buttons);E'),Y=K;if(o.showSearchButton||o.showSearchClearButton){var J=(o.showSearchButton?W:"")+(o.showSearchClearButton?G:"");Y=o.search?Ka.sprintf(this.constants.html.inputGroup,K,J):J}r.push(Ka.sprintf('\n
    \n %s\n
    \n '),Y)),this.$toolbar.append(r.join(""));var X=Ka.getSearchInput(this);o.showSearchButton?(this.$toolbar.find(".search button[name=search]").off("click").on("click",function(t){clearTimeout(a),a=setTimeout(function(){i.onSearch({currentTarget:X})},o.searchTimeOut)}),o.searchOnEnterKey&&z(X)):z(X),o.showSearchClearButton&&this.$toolbar.find(".search button[name=clearSearch]").click(function(){i.resetSearch()})}else{if("string"==typeof o.searchSelector){var Q=Ka.getSearchInput(this);z(Q)}}}},{key:"onSearch",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},i=e.currentTarget,n=e.firedByInitSearchText,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:!0;if(void 0!==i&&t(i).length&&o){var r=t(i).val().trim();if(this.options.trimOnSearch&&t(i).val()!==r&&t(i).val(r),this.searchText===r){return}(i===Ka.getSearchInput(this)[0]||t(i).hasClass("search-input"))&&(this.searchText=r,this.options.searchText=r)}n||(this.options.pageNumber=1),this.initSearch(),n?"client"===this.options.sidePagination&&this.updatePagination():this.updatePagination(),this.trigger("search",this.searchText)}},{key:"initSearch",value:function(){var t=this;if(this.filterOptions=this.filterOptions||this.options.filterOptions,"server"!==this.options.sidePagination){if(this.options.customSearch){return this.data=Ka.calculateObjectValue(this.options,this.options.customSearch,[this.options.data,this.searchText,this.filterColumns]),void (this.options.sortReset&&(this.unsortedData=l(this.data)))}var e=this.searchText&&(this.fromHtml?Ka.escapeHTML(this.searchText):this.searchText).toLowerCase(),i=Ka.isEmptyObject(this.filterColumns)?null:this.filterColumns;"function"==typeof this.filterOptions.filterAlgorithm?this.data=this.options.data.filter(function(e,n){return t.filterOptions.filterAlgorithm.apply(null,[e,i])}):"string"==typeof this.filterOptions.filterAlgorithm&&(this.data=i?this.options.data.filter(function(e,n){var o=t.filterOptions.filterAlgorithm;if("and"===o){for(var r in i){if(Array.isArray(i[r])&&!i[r].includes(e[r])||!Array.isArray(i[r])&&e[r]!==i[r]){return !1}}}else{if("or"===o){var a=!1;for(var s in i){(Array.isArray(i[s])&&i[s].includes(e[s])||!Array.isArray(i[s])&&e[s]===i[s])&&(a=!0)}return a}}return !0}):l(this.options.data));var n=this.getVisibleFields();this.data=e?this.data.filter(function(i,o){for(var r=0;r|=<|>=|>|<)(?:\s+)?(\d+)?|(\d+)?(\s+)?(<=|=>|=<|>=|>|<))/gm,d=u.exec(e),p=!1;if(d){var f=d[1]||"".concat(d[5],"l"),g=d[2]||d[3],v=parseInt(l,10),b=parseInt(g,10);switch(f){case">":case"b;break;case"<":case">l":p=b>v;break;case"<=":case"=<":case">=l":case"=>l":p=b>=v;break;case">=":case"=>":case"<=l":case"==b}}if(p||"".concat(l).toLowerCase().includes(e)){return !0}}}}}return !1}):this.data,this.options.sortReset&&(this.unsortedData=l(this.data)),this.initSort()}}},{key:"initPagination",value:function(){var e=this,i=this.options;if(!i.pagination){return void this.$pagination.hide()}this.$pagination.show();var n,o,r,a,s,l,c,h=[],u=!1,d=this.getData({includeHiddenRows:!1}),p=i.pageList;if("string"==typeof p&&(p=p.replace(/\[|\]| /g,"").toLowerCase().split(",")),p=p.map(function(t){return"string"==typeof t?t.toLowerCase()===i.formatAllRows().toLowerCase()||["all","unlimited"].includes(t.toLowerCase())?i.formatAllRows():+t:t}),this.paginationParts=i.paginationParts,"string"==typeof this.paginationParts&&(this.paginationParts=this.paginationParts.replace(/\[|\]| |'/g,"").split(",")),"server"!==i.sidePagination&&(i.totalRows=d.length),this.totalPages=0,i.totalRows&&(i.pageSize===i.formatAllRows()&&(i.pageSize=i.totalRows,u=!0),this.totalPages=~~((i.totalRows-1)/i.pageSize)+1,i.totalPages=this.totalPages),this.totalPages>0&&i.pageNumber>this.totalPages&&(i.pageNumber=this.totalPages),this.pageFrom=(i.pageNumber-1)*i.pageSize+1,this.pageTo=i.pageNumber*i.pageSize,this.pageTo>i.totalRows&&(this.pageTo=i.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"))&&h.push('
    ')),this.paginationParts.includes("pageInfo")||this.paginationParts.includes("pageInfoShort")){var f=this.paginationParts.includes("pageInfoShort")?i.formatDetailPagination(i.totalRows):i.formatShowingRows(this.pageFrom,this.pageTo,i.totalRows,i.totalNotFiltered);h.push('\n '.concat(f,"\n "))}if(this.paginationParts.includes("pageSize")){h.push('');var g=['\n \n ").concat(this.constants.html.pageDropdown[0])];p.forEach(function(t,n){if(!i.smartDisplay||0===n||p[n-1]")),h.push(i.formatRecordsPerPage(g.join("")))}if((this.paginationParts.includes("pageInfo")||this.paginationParts.includes("pageInfoShort")||this.paginationParts.includes("pageSize"))&&h.push("
    "),this.paginationParts.includes("pageList")){h.push('
    '),Ka.sprintf(this.constants.html.pagination[0],Ka.sprintf(" pagination-%s",i.iconSize)),Ka.sprintf(this.constants.html.paginationItem," page-pre",i.formatSRPaginationPreText(),i.paginationPreText)),this.totalPagesthis.totalPages-o&&(o=o-(i.paginationSuccessivelySize-(this.totalPages-o))+1),1>o&&(o=1),r>this.totalPages&&(r=this.totalPages);var v=Math.round(i.paginationPagesBySide/2),b=function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return Ka.sprintf(e.constants.html.paginationItem,n+(t===i.pageNumber?" ".concat(e.constants.classes.paginationActive):""),i.formatSRPaginationPageText(t),t)};if(o>1){var m=i.paginationPagesBySide;for(m>=o&&(m=o-1),n=1;m>=n;n++){h.push(b(n))}o-1===m+1?(n=o-1,h.push(b(n))):o-1>m&&(o-2*i.paginationPagesBySide>i.paginationPagesBySide&&i.paginationUseIntermediate?(n=Math.round((o-v)/2+v),h.push(b(n," page-intermediate"))):h.push(Ka.sprintf(this.constants.html.paginationItem," page-first-separator disabled","","...")))}for(n=o;r>=n;n++){h.push(b(n))}if(this.totalPages>r){var y=this.totalPages-(i.paginationPagesBySide-1);for(r>=y&&(y=r+1),r+1===y-1?(n=r+1,h.push(b(n))):y>r+1&&(this.totalPages-r>2*i.paginationPagesBySide&&i.paginationUseIntermediate?(n=Math.round((this.totalPages-v-r)/2+r),h.push(b(n," page-intermediate"))):h.push(Ka.sprintf(this.constants.html.paginationItem," page-last-separator disabled","","..."))),n=y;n<=this.totalPages;n++){h.push(b(n))}}h.push(Ka.sprintf(this.constants.html.paginationItem," page-next",i.formatSRPaginationNextText(),i.paginationNextText)),h.push(this.constants.html.pagination[1],"
    ")}this.$pagination.html(h.join(""));var w=["bottom","both"].includes(i.paginationVAlign)?" ".concat(this.constants.classes.dropup):"";if(this.$pagination.last().find(".page-list > span").addClass(w),!i.onlyInfoPagination&&(a=this.$pagination.find(".page-list a"),s=this.$pagination.find(".page-pre"),l=this.$pagination.find(".page-next"),c=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(),i.smartDisplay&&(p.length<2||i.totalRows<=p[0])&&this.$pagination.find("span.page-list").hide(),this.$pagination[this.getData().length?"show":"hide"](),i.paginationLoop||(1===i.pageNumber&&s.addClass("disabled"),i.pageNumber===this.totalPages&&l.addClass("disabled")),u&&(i.pageSize=i.formatAllRows()),a.off("click").on("click",function(t){return e.onPageListChange(t)}),s.off("click").on("click",function(t){return e.onPagePre(t)}),l.off("click").on("click",function(t){return e.onPageNext(t)}),c.off("click").on("click",function(t){return e.onPageNumber(t)}),this.options.showPageGo)){var S=this,x=this.$pagination.find("ul.pagination"),k=x.find("li.pageGo");k.length||(k=t('
  • '+Ka.sprintf('',this.options.pageNumber)+('
  • ").appendTo(x),k.find("button").click(function(){var t=parseInt(k.find("input").val())||1;(1>t||t>S.options.totalPages)&&(t=1),S.selectPage(t)}))}}},{key:"updatePagination",value:function(e){e&&t(e.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(e){e.preventDefault();var i=t(e.currentTarget);return i.parent().addClass(this.constants.classes.dropdownActive).siblings().removeClass(this.constants.classes.dropdownActive),this.options.pageSize=i.text().toUpperCase()===this.options.formatAllRows().toUpperCase()?this.options.formatAllRows():+i.text(),this.$toolbar.find(".page-size").text(this.options.pageSize),this.updatePagination(e),!1}},{key:"onPagePre",value:function(t){return t.preventDefault(),this.options.pageNumber-1===0?this.options.pageNumber=this.options.totalPages:this.options.pageNumber--,this.updatePagination(t),!1}},{key:"onPageNext",value:function(t){return t.preventDefault(),this.options.pageNumber+1>this.options.totalPages?this.options.pageNumber=1:this.options.pageNumber++,this.updatePagination(t),!1}},{key:"onPageNumber",value:function(e){return e.preventDefault(),this.options.pageNumber!==+t(e.currentTarget).text()?(this.options.pageNumber=+t(e.currentTarget).text(),this.updatePagination(e),!1):void 0}},{key:"initRow",value:function(t,e,i,o){var r=this,a=[],l={},c=[],h="",u={},d=[];if(!(Ka.findIndex(this.hiddenRows,t)>-1)){if(l=Ka.calculateObjectValue(this.options,this.options.rowStyle,[t,e],l),l&&l.css){for(var p=0,f=Object.entries(l.css);p"),this.options.cardView&&a.push('
    '));var I="";return Ka.hasDetailViewIcon(this.options)&&(I="",Ka.calculateObjectValue(null,this.options.detailFilter,[e,t])&&(I+='\n \n '.concat(Ka.sprintf(this.constants.html.icon,this.options.iconsPrefix,this.options.icons.detailOpen),"\n \n ")),I+=""),I&&"right"!==this.options.detailViewAlign&&a.push(I),this.header.fields.forEach(function(i,n){var o="",l=Ka.getItemField(t,i,r.options.escape),h="",u="",d={},p="",f=r.header.classes[n],g="",v="",b="",m="",y="",w="",S=r.columns[n];if((!r.fromHtml&&!r.autoMergeCells||void 0!==l||S.checkbox||S.radio)&&S.visible&&(!r.options.cardView||S.cardVisible)){if(S.escape&&(l=Ka.escapeHTML(l)),c.concat([r.header.styles[n]]).length&&(v+="".concat(c.concat([r.header.styles[n]]).join("; "))),t["_".concat(i,"_style")]&&(v+="".concat(t["_".concat(i,"_style")])),v&&(g=' style="'.concat(v,'"')),t["_".concat(i,"_id")]&&(p=Ka.sprintf(' id="%s"',t["_".concat(i,"_id")])),t["_".concat(i,"_class")]&&(f=Ka.sprintf(' class="%s"',t["_".concat(i,"_class")])),t["_".concat(i,"_rowspan")]&&(m=Ka.sprintf(' rowspan="%s"',t["_".concat(i,"_rowspan")])),t["_".concat(i,"_colspan")]&&(y=Ka.sprintf(' colspan="%s"',t["_".concat(i,"_colspan")])),t["_".concat(i,"_title")]&&(w=Ka.sprintf(' title="%s"',t["_".concat(i,"_title")])),d=Ka.calculateObjectValue(r.header,r.header.cellStyles[n],[l,t,e,i],d),d.classes&&(f=' class="'.concat(d.classes,'"')),d.css){for(var x=[],k=0,O=Object.entries(d.css);k$1"))),t["_".concat(i,"_data")]&&!Ka.isEmptyObject(t["_".concat(i,"_data")])){for(var I=0,A=Object.entries(t["_".concat(i,"_data")]);I'):'"))+'")+(r.header.formatters[n]&&"string"==typeof h?h:"")+(r.options.cardView?"
    ":""),t[r.header.stateField]=h===!0||!!l||h&&h.checked}else{if(h=void 0===h||null===h?r.options.undefinedText:h,r.options.cardView){var F=r.options.showHeader?'").concat(Ka.getFieldTitle(r.columns,i),""):"";o='
    '.concat(F,'').concat(h,"
    "),r.options.smartDisplay&&""===h&&(o='
    ')}else{o="").concat(h,"")}}a.push(o)}}),I&&"right"===this.options.detailViewAlign&&a.push(I),this.options.cardView&&a.push("
    "),a.push(""),a.join("")}}},{key:"initBody",value:function(e){var i=this,n=this.getData();this.trigger("pre-body",n),this.$body=this.$el.find(">tbody"),this.$body.length||(this.$body=t("").appendTo(this.$el)),this.options.pagination&&"server"!==this.options.sidePagination||(this.pageFrom=1,this.pageTo=n.length);var o=[],r=t(document.createDocumentFragment()),a=!1;this.autoMergeCells=Ka.checkAutoMergeCells(n.slice(this.pageFrom-1,this.pageTo));for(var s=this.pageFrom-1;s'.concat(Ka.sprintf('%s',this.getVisibleFields().length+Ka.getDetailViewIndexOffset(this.options),this.options.formatNoMatches()),"")),e||this.scrollTo(0),this.initBodyEvent(),this.updateSelected(),this.initFooter(),this.resetView(),"server"!==this.options.sidePagination&&(this.options.totalRows=n.length),this.trigger("post-body",n)}},{key:"initBodyEvent",value:function(){var e=this;this.$body.find("> tr[data-index] > td").off("click dblclick").on("click dblclick",function(i){var n=t(i.currentTarget),o=n.parent(),r=t(i.target).parents(".card-views").children(),a=t(i.target).parents(".card-view"),s=o.data("index"),l=e.data[s],c=e.options.cardView?r.index(a):n[0].cellIndex,h=e.getVisibleFields(),u=h[c-Ka.getDetailViewIndexOffset(e.options)],d=e.columns[e.fieldsColumnsIndex[u]],p=Ka.getItemField(l,u,e.options.escape);if(!n.find(".detail-icon").length){if(e.trigger("click"===i.type?"click-cell":"dbl-click-cell",u,p,l,n),e.trigger("click"===i.type?"click-row":"dbl-click-row",l,o,u),"click"===i.type&&e.options.clickToSelect&&d.clickToSelect&&!Ka.calculateObjectValue(e.options,e.options.ignoreClickToSelectOn,[i.target])){var f=o.find(Ka.sprintf('[name="%s"]',e.options.selectItemName));f.length&&f[0].click()}"click"===i.type&&e.options.detailViewByClick&&e.toggleDetailView(s,e.header.detailFormatters[e.fieldsColumnsIndex[u]])}}).off("mousedown").on("mousedown",function(t){e.multipleSelectRowCtrlKey=t.ctrlKey||t.metaKey,e.multipleSelectRowShiftKey=t.shiftKey}),this.$body.find("> tr[data-index] > td > .detail-icon").off("click").on("click",function(i){return i.preventDefault(),e.toggleDetailView(t(i.currentTarget).parent().parent().data("index")),!1}),this.$selectItem=this.$body.find(Ka.sprintf('[name="%s"]',this.options.selectItemName)),this.$selectItem.off("click").on("click",function(i){i.stopImmediatePropagation();var n=t(i.currentTarget);e._toggleCheck(n.prop("checked"),n.data("index"))}),this.header.events.forEach(function(i,n){var o=i;if(o){"string"==typeof o&&(o=Ka.calculateObjectValue(null,o));var r=e.header.fields[n],a=e.getVisibleFields().indexOf(r);if(-1!==a){a+=Ka.getDetailViewIndexOffset(e.options);var s=function(i){if(!o.hasOwnProperty(i)){return"continue"}var n=o[i];e.$body.find(">tr:not(.no-records-found)").each(function(o,s){var l=t(s),c=l.find(e.options.cardView?".card-views>.card-view":">td").eq(a),h=i.indexOf(" "),u=i.substring(0,h),d=i.substring(h+1);c.find(d).off(u).on(u,function(t){var i=l.data("index"),o=e.data[i],a=o[r];n.apply(e,[t,a,o,i])})})};for(var l in o){s(l)}}}})}},{key:"initServer",value:function(e,i,n){var o=this,r={},a=this.header.fields.indexOf(this.options.sortName),s={searchText:this.searchText,sortName:this.options.sortName,sortOrder:this.options.sortOrder};if(this.header.sortNames[a]&&(s.sortName=this.header.sortNames[a]),this.options.pagination&&"server"===this.options.sidePagination&&(s.pageSize=this.options.pageSize===this.options.formatAllRows()?this.options.totalRows:this.options.pageSize,s.pageNumber=this.options.pageNumber),!this.options.firstLoad&&!firstLoadTable.includes(this.options.id)){return void firstLoadTable.push(this.options.id)}if(n||this.options.url||this.options.ajax){if("limit"===this.options.queryParamsType&&(s={search:s.searchText,sort:s.sortName,order:s.sortOrder},this.options.pagination&&"server"===this.options.sidePagination&&(s.offset=this.options.pageSize===this.options.formatAllRows()?0:this.options.pageSize*(this.options.pageNumber-1),s.limit=this.options.pageSize===this.options.formatAllRows()?this.options.totalRows:this.options.pageSize,0===s.limit&&delete s.limit)),this.options.search&&"server"===this.options.sidePagination&&this.columns.filter(function(t){return !t.searchable}).length){s.searchable=[];var l=!0,c=!1,h=void 0;try{for(var u,d=this.columns[Symbol.iterator]();!(l=(u=d.next()).done);l=!0){var p=u.value;!p.checkbox&&p.searchable&&(this.options.visibleSearch&&p.visible||!this.options.visibleSearch)&&s.searchable.push(p.field)}}catch(f){c=!0,h=f}finally{try{l||null==d["return"]||d["return"]()}finally{if(c){throw h}}}}if(Ka.isEmptyObject(this.filterColumnsPartial)||(s.filter=JSON.stringify(this.filterColumnsPartial,null)),t.extend(s,i||{}),r=Ka.calculateObjectValue(this.options,this.options.queryParams,[s],r),r!==!1){e||this.showLoading();var g=t.extend({},Ka.calculateObjectValue(null,this.options.ajaxOptions),{type:this.options.method,url:n||this.options.url,data:"application/json"===this.options.contentType&&"post"===this.options.method?JSON.stringify(r):r,cache:this.options.cache,contentType:this.options.contentType,dataType:this.options.dataType,success:function(t,i,n){var r=Ka.calculateObjectValue(o.options,o.options.responseHandler,[t,n],t);o.load(r),o.trigger("load-success",r,n&&n.status,n),e||o.hideLoading(),"server"===o.options.sidePagination&&r[o.options.totalField]>0&&!r[o.options.dataField].length&&o.updatePagination()},error:function(t){var i=[];"server"===o.options.sidePagination&&(i={},i[o.options.totalField]=0,i[o.options.dataField]=[]),o.load(i),o.trigger("load-error",t&&t.status,t),e||o.$tableLoading.hide()}});return this.options.ajax?Ka.calculateObjectValue(this,this.options.ajax,[g],null):(this._xhr&&4!==this._xhr.readyState&&this._xhr.abort(),this._xhr=t.ajax(g)),r}}}},{key:"initSearchText",value:function(){if(this.options.search&&(this.searchText="",""!==this.options.searchText)){var t=Ka.getSearchInput(this);t.val(this.options.searchText),this.onSearch({currentTarget:t,firedByInitSearchText:!0})}}},{key:"getCaret",value:function(){var e=this;this.$header.find("th").each(function(i,n){t(n).find(".sortable").removeClass("desc asc").addClass(t(n).data("field")===e.options.sortName?e.options.sortOrder:"both")})}},{key:"updateSelected",value:function(){var e=this.$selectItem.filter(":enabled").length&&this.$selectItem.filter(":enabled").length===this.$selectItem.filter(":enabled").filter(":checked").length;this.$selectAll.add(this.$selectAll_).prop("checked",e),this.$selectItem.each(function(e,i){t(i).closest("tr")[t(i).prop("checked")?"addClass":"removeClass"]("selected") +})}},{key:"updateRows",value:function(){var e=this;this.$selectItem.each(function(i,n){e.data[t(n).data("index")][e.header.stateField]=t(n).prop("checked")})}},{key:"resetRows",value:function(){var t=!0,e=!1,i=void 0;try{for(var n,o=this.data[Symbol.iterator]();!(t=(n=o.next()).done);t=!0){var r=n.value;this.$selectAll.prop("checked",!1),this.$selectItem.prop("checked",!1),this.header.stateField&&(r[this.header.stateField]=!1)}}catch(a){e=!0,i=a}finally{try{t||null==o["return"]||o["return"]()}finally{if(e){throw i}}}this.initHiddenRows()}},{key:"trigger",value:function(i){for(var n,o,r="".concat(i,".bs.table"),a=arguments.length,s=Array(a>1?a-1:0),l=1;a>l;l++){s[l-1]=arguments[l]}(n=this.options)[e.EVENTS[r]].apply(n,[].concat(s,[this])),this.$el.trigger(t.Event(r,{sender:this}),s),(o=this.options).onAll.apply(o,[r].concat([].concat(s,[this]))),this.$el.trigger(t.Event("all.bs.table",{sender:this}),[r,s])}},{key:"resetHeader",value:function(){var t=this;clearTimeout(this.timeoutId_),this.timeoutId_=setTimeout(function(){return t.fitHeader()},this.$el.is(":hidden")?100:0)}},{key:"fitHeader",value:function(){var e=this;if(this.$el.is(":hidden")){return void (this.timeoutId_=setTimeout(function(){return e.fitHeader()},100))}var i=this.$tableBody.get(0),n=i.scrollWidth>i.clientWidth&&i.scrollHeight>i.clientHeight+this.$header.outerHeight()?Ka.getScrollBarWidth():0;this.$el.css("margin-top",-this.$header.outerHeight());var o=t(":focus");if(o.length>0){var r=o.parents("th");if(r.length>0){var a=r.attr("data-field");if(void 0!==a){var s=this.$header.find("[data-field='".concat(a,"']"));s.length>0&&s.find(":input").addClass("focus-temp")}}}this.$header_=this.$header.clone(!0,!0),this.$selectAll_=this.$header_.find('[name="btSelectAll"]'),this.$tableHeader.css("margin-right",n).find("table").css("width",this.$el.outerWidth()).html("").attr("class",this.$el.attr("class")).append(this.$header_),this.$tableLoading.css("width",this.$el.outerWidth());var l=t(".focus-temp:visible:eq(0)");l.length>0&&(l.focus(),this.$header.find(".focus-temp").removeClass("focus-temp")),this.$header.find("th[data-field]").each(function(i,n){e.$header_.find(Ka.sprintf('th[data-field="%s"]',t(n).data("field"))).data(t(n).data())});for(var c=this.getVisibleFields(),h=this.$header_.find("th"),u=this.$body.find(">tr:not(.no-records-found,.virtual-scroll-top)").eq(0);u.length&&u.find('>td[colspan]:not([colspan="1"])').length;){u=u.next()}var d=u.find("> *").length;u.find("> *").each(function(i,n){var o=t(n);if(Ka.hasDetailViewIcon(e.options)&&(0===i&&"right"!==e.options.detailViewAlign||i===d-1&&"right"===e.options.detailViewAlign)){var r=h.filter(".detail"),a=r.innerWidth()-r.find(".fht-cell").width();return void r.find(".fht-cell").width(o.innerWidth()-a)}var s=i-Ka.getDetailViewIndexOffset(e.options),l=e.$header_.find(Ka.sprintf('th[data-field="%s"]',c[s]));l.length>1&&(l=t(h[o[0].cellIndex]));var u=l.innerWidth()-l.find(".fht-cell").width();l.find(".fht-cell").width(o.innerWidth()-u)}),this.horizontalScroll(),this.trigger("post-header")}},{key:"initFooter",value:function(){if(this.options.showFooter&&!this.options.cardView){var t=this.getData(),e=[],i="";Ka.hasDetailViewIcon(this.options)&&(i='
    '),i&&"right"!==this.options.detailViewAlign&&e.push(i);var n=!0,o=!1,r=void 0;try{for(var a,l=this.columns[Symbol.iterator]();!(n=(a=l.next()).done);n=!0){var c=a.value,h="",u="",d=[],p={},f=Ka.sprintf(' class="%s"',c["class"]);if(c.visible&&(!(this.footerData&&this.footerData.length>0)||c.field in this.footerData[0])){if(this.options.cardView&&!c.cardVisible){return}if(h=Ka.sprintf("text-align: %s; ",c.falign?c.falign:c.align),u=Ka.sprintf("vertical-align: %s; ",c.valign),p=Ka.calculateObjectValue(null,this.options.footerStyle,[c]),p&&p.css){for(var g=0,v=Object.entries(p.css);g0&&(w=this.footerData[0]["_"+c.field+"_colspan"]||0),w&&e.push(' colspan="'.concat(w,'" ')),e.push(">"),e.push('
    ');var S="";this.footerData&&this.footerData.length>0&&(S=this.footerData[0][c.field]||""),e.push(Ka.calculateObjectValue(c,c.footerFormatter,[t,S],S)),e.push("
    "),e.push('
    '),e.push("
    "),e.push("")}}}catch(x){o=!0,r=x}finally{try{n||null==l["return"]||l["return"]()}finally{if(o){throw r}}}i&&"right"===this.options.detailViewAlign&&e.push(i),this.options.height||this.$tableFooter.length||(this.$el.append(""),this.$tableFooter=this.$el.find("tfoot")),this.$tableFooter.find("tr").html(e.join("")),this.trigger("post-footer",this.$tableFooter)}}},{key:"fitFooter",value:function(){var e=this;if(this.$el.is(":hidden")){return void setTimeout(function(){return e.fitFooter()},100)}var i=this.$tableBody.get(0),n=i.scrollWidth>i.clientWidth&&i.scrollHeight>i.clientHeight+this.$header.outerHeight()?Ka.getScrollBarWidth():0;this.$tableFooter.css("margin-right",n).find("table").css("width",this.$el.outerWidth()).attr("class",this.$el.attr("class"));var o=(this.getVisibleFields(),this.$tableFooter.find("th")),r=this.$body.find(">tr:first-child:not(.no-records-found)");for(o.find(".fht-cell").width("auto");r.length&&r.find('>td[colspan]:not([colspan="1"])').length;){r=r.next()}var a=r.find("> *").length;r.find("> *").each(function(i,n){var r=t(n);if(Ka.hasDetailViewIcon(e.options)&&(0===i&&"left"===e.options.detailViewAlign||i===a-1&&"right"===e.options.detailViewAlign)){var s=o.filter(".detail"),l=s.innerWidth()-s.find(".fht-cell").width();return void s.find(".fht-cell").width(r.innerWidth()-l)}var c=o.eq(i),h=c.innerWidth()-c.find(".fht-cell").width();c.find(".fht-cell").width(r.innerWidth()-h)}),this.horizontalScroll()}},{key:"horizontalScroll",value:function(){var t=this;this.$tableBody.off("scroll").on("scroll",function(){var e=t.$tableBody.scrollLeft();t.options.showHeader&&t.options.height&&t.$tableHeader.scrollLeft(e),t.options.showFooter&&!t.options.cardView&&t.$tableFooter.scrollLeft(e),t.trigger("scroll-body",t.$tableBody)})}},{key:"getVisibleFields",value:function(){var t=[],e=!0,i=!1,n=void 0;try{for(var o,r=this.header.fields[Symbol.iterator]();!(e=(o=r.next()).done);e=!0){var a=o.value,s=this.columns[this.fieldsColumnsIndex[a]];s&&s.visible&&t.push(a)}}catch(l){i=!0,n=l}finally{try{e||null==r["return"]||r["return"]()}finally{if(i){throw n}}}return t}},{key:"initHiddenRows",value:function(){this.hiddenRows=[]}},{key:"getOptions",value:function(){var e=t.extend({},this.options);return delete e.data,t.extend(!0,{},e)}},{key:"refreshOptions",value:function(e){Ka.compareObjects(this.options,e,!0)||(this.options=t.extend(this.options,e),this.trigger("refresh-options",this.options),this.destroy(),this.init())}},{key:"getData",value:function(t){var e=this,i=this.options.data;if(!this.searchText&&!this.options.customSearch&&void 0===this.options.sortName&&Ka.isEmptyObject(this.filterColumns)&&Ka.isEmptyObject(this.filterColumnsPartial)||t&&t.unfiltered||(i=this.data),t&&t.useCurrentPage&&(i=i.slice(this.pageFrom-1,this.pageTo)),t&&!t.includeHiddenRows){var n=this.getHiddenRows();i=i.filter(function(t){return -1===Ka.findIndex(n,t)})}return t&&t.formatted&&i.forEach(function(t){for(var i=0,n=Object.entries(t);i=0;e--){var o=!1;i=this.options.data[e],(i.hasOwnProperty(t.field)||"$index"===t.field)&&(o=i.hasOwnProperty(t.field)||"$index"!==t.field?t.values.includes(i[t.field]):t.values.includes(e),o&&(this.options.data.splice(e,1),"server"===this.options.sidePagination&&(this.options.totalRows-=1)))}n!==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(t){t.hasOwnProperty("index")&&t.hasOwnProperty("row")&&(this.options.data.splice(t.index,0,t.row),this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0))}},{key:"updateRow",value:function(e){var i=Array.isArray(e)?e:[e],n=!0,o=!1,r=void 0;try{for(var a,s=i[Symbol.iterator]();!(n=(a=s.next()).done);n=!0){var l=a.value;l.hasOwnProperty("index")&&l.hasOwnProperty("row")&&(l.hasOwnProperty("replace")&&l.replace?this.options.data[l.index]=l.row:t.extend(this.options.data[l.index],l.row))}}catch(c){o=!0,r=c}finally{try{n||null==s["return"]||s["return"]()}finally{if(o){throw r}}}this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0)}},{key:"getRowByUniqueId",value:function(t){var e,i,n,o=this.options.uniqueId,r=this.options.data.length,a=t,s=null;for(e=r-1;e>=0;e--){if(i=this.options.data[e],i.hasOwnProperty(o)){n=i[o]}else{if(!i._data||!i._data.hasOwnProperty(o)){continue}n=i._data[o]}if("string"==typeof n?a=""+a:"number"==typeof n&&(+n===n&&n%1===0?a=parseInt(a):n===+n&&0!==n&&(a=parseFloat(a))),n===a){s=i;break}}return s}},{key:"updateByUniqueId",value:function(e){var i=Array.isArray(e)?e:[e],n=!0,o=!1,r=void 0;try{for(var a,s=i[Symbol.iterator]();!(n=(a=s.next()).done);n=!0){var l=a.value;if(l.hasOwnProperty("id")&&l.hasOwnProperty("row")){var c=this.options.data.indexOf(this.getRowByUniqueId(l.id));-1!==c&&(l.hasOwnProperty("replace")&&l.replace?this.options.data[c]=l.row:t.extend(this.options.data[c],l.row))}}}catch(h){o=!0,r=h}finally{try{n||null==s["return"]||s["return"]()}finally{if(o){throw r}}}this.initSearch(),this.initPagination(),this.initSort(),this.initBody(!0)}},{key:"removeByUniqueId",value:function(t){var e=this.options.data.length,i=this.getRowByUniqueId(t);i&&this.options.data.splice(this.options.data.indexOf(i),1),e!==this.options.data.length&&(this.initSearch(),this.initPagination(),this.initBody(!0))}},{key:"updateCell",value:function(t){t.hasOwnProperty("index")&&t.hasOwnProperty("field")&&t.hasOwnProperty("value")&&(this.data[t.index][t.field]=t.value,t.reinit!==!1&&(this.initSort(),this.initBody(!0)))}},{key:"updateCellByUniqueId",value:function(t){var e=this,i=Array.isArray(t)?t:[t];i.forEach(function(t){var i=t.id,n=t.field,o=t.value,r=e.options.data.indexOf(e.getRowByUniqueId(i));-1!==r&&(e.options.data[r][n]=o)}),t.reinit!==!1&&(this.initSort(),this.initBody(!0))}},{key:"showRow",value:function(t){this._toggleRow(t,!0)}},{key:"hideRow",value:function(t){this._toggleRow(t,!1)}},{key:"_toggleRow",value:function(t,e){var i;if(t.hasOwnProperty("index")?i=this.getData()[t.index]:t.hasOwnProperty("uniqueId")&&(i=this.getRowByUniqueId(t.uniqueId)),i){var n=Ka.findIndex(this.hiddenRows,i);e||-1!==n?e&&n>-1&&this.hiddenRows.splice(n,1):this.hiddenRows.push(i),this.initBody(!0),this.initPagination()}}},{key:"getHiddenRows",value:function(t){if(t){return this.initHiddenRows(),this.initBody(!0),void this.initPagination()}var e=this.getData(),i=[],n=!0,o=!1,r=void 0;try{for(var a,s=e[Symbol.iterator]();!(n=(a=s.next()).done);n=!0){var l=a.value;this.hiddenRows.includes(l)&&i.push(l)}}catch(c){o=!0,r=c}finally{try{n||null==s["return"]||s["return"]()}finally{if(o){throw r}}}return this.hiddenRows=i,i}},{key:"showColumn",value:function(t){var e=this,i=Array.isArray(t)?t:[t];i.forEach(function(t){e._toggleColumn(e.fieldsColumnsIndex[t],!0,!0)})}},{key:"hideColumn",value:function(t){var e=this,i=Array.isArray(t)?t:[t];i.forEach(function(t){e._toggleColumn(e.fieldsColumnsIndex[t],!1,!0)})}},{key:"_toggleColumn",value:function(t,e,i){if(-1!==t&&this.columns[t].visible!==e&&(this.columns[t].visible=e,this.initHeader(),this.initSearch(),this.initPagination(),this.initBody(),this.options.showColumns)){var n=this.$toolbar.find('.keep-open input:not(".toggle-all")').prop("disabled",!1);i&&n.filter(Ka.sprintf('[value="%s"]',t)).prop("checked",e),n.filter(":checked").length<=this.options.minimumCountColumns&&n.filter(":checked").prop("disabled",!0)}}},{key:"getVisibleColumns",value:function(){var t=this;return this.columns.filter(function(e){return e.visible&&!t.isSelectionColumn(e)})}},{key:"getHiddenColumns",value:function(){return this.columns.filter(function(t){var e=t.visible;return !e})}},{key:"isSelectionColumn",value:function(t){return t.radio||t.checkbox}},{key:"showAllColumns",value:function(){this._toggleAllColumns(!0)}},{key:"hideAllColumns",value:function(){this._toggleAllColumns(!1)}},{key:"_toggleAllColumns",value:function(e){var i=this,n=!0,o=!1,r=void 0;try{for(var a,s=this.columns.slice().reverse()[Symbol.iterator]();!(n=(a=s.next()).done);n=!0){var l=a.value;if(l.switchable){if(!e&&this.options.showColumns&&this.getVisibleColumns().length===this.options.minimumCountColumns){continue}l.visible=e}}}catch(c){o=!0,r=c}finally{try{n||null==s["return"]||s["return"]()}finally{if(o){throw r}}}if(this.initHeader(),this.initSearch(),this.initPagination(),this.initBody(),this.options.showColumns){var h=this.$toolbar.find('.keep-open input[type="checkbox"]:not(".toggle-all")').prop("disabled",!1);e?h.prop("checked",e):h.get().reverse().forEach(function(n){h.filter(":checked").length>i.options.minimumCountColumns&&t(n).prop("checked",e)}),h.filter(":checked").length<=this.options.minimumCountColumns&&h.filter(":checked").prop("disabled",!0)}}},{key:"mergeCells",value:function(t){var e,i,n=t.index,o=this.getVisibleFields().indexOf(t.field),r=t.rowspan||1,a=t.colspan||1,s=this.$body.find(">tr");o+=Ka.getDetailViewIndexOffset(this.options);var l=s.eq(n).find(">td").eq(o);if(!(0>n||0>o||n>=this.data.length)){for(e=n;n+r>e;e++){for(i=o;o+a>i;i++){s.eq(e).find(">td").eq(i).hide()}}l.attr("rowspan",r).attr("colspan",a).show()}}},{key:"checkAll",value:function(){this._toggleCheckAll(!0)}},{key:"uncheckAll",value:function(){this._toggleCheckAll(!1)}},{key:"_toggleCheckAll",value:function(t){var e=this.getSelections();this.$selectAll.add(this.$selectAll_).prop("checked",t),this.$selectItem.filter(":enabled").prop("checked",t),this.updateRows(),this.updateSelected();var i=this.getSelections();return t?void this.trigger("check-all",i,e):void this.trigger("uncheck-all",i,e)}},{key:"checkInvert",value:function(){var e=this.$selectItem.filter(":enabled"),i=e.filter(":checked");e.each(function(e,i){t(i).prop("checked",!t(i).prop("checked"))}),this.updateRows(),this.updateSelected(),this.trigger("uncheck-some",i),i=this.getSelections(),this.trigger("check-some",i)}},{key:"check",value:function(t){this._toggleCheck(!0,t)}},{key:"uncheck",value:function(t){this._toggleCheck(!1,t)}},{key:"_toggleCheck",value:function(t,e){var i=this.$selectItem.filter('[data-index="'.concat(e,'"]')),n=this.options.data[e];if(i.is(":radio")||this.options.singleSelect||this.options.multipleSelectRow&&!this.multipleSelectRowCtrlKey&&!this.multipleSelectRowShiftKey){var o=!0,r=!1,a=void 0;try{for(var s,l=this.options.data[Symbol.iterator]();!(o=(s=l.next()).done);o=!0){var c=s.value;c[this.header.stateField]=!1}}catch(h){r=!0,a=h}finally{try{o||null==l["return"]||l["return"]()}finally{if(r){throw a}}}this.$selectItem.filter(":checked").not(i).prop("checked",!1)}if(n[this.header.stateField]=t,this.options.multipleSelectRow){if(this.multipleSelectRowShiftKey&&this.multipleSelectRowLastSelectedIndex>=0){for(var u=[this.multipleSelectRowLastSelectedIndex,e].sort(),d=u[0]+1;d0&&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(),e+=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&&(e+=this.$tableFooter.outerHeight(!0))),this.$container.hasClass("fullscreen")){this.$tableContainer.css("height",""),this.$tableContainer.css("width","")}else{if(this.options.height){this.$tableBorder&&(this.$tableBorder.css("width",""),this.$tableBorder.css("height",""));var i=this.$toolbar.outerHeight(!0),n=this.$pagination.outerHeight(!0),o=this.options.height-i-n,r=this.$tableBody.find(">table"),a=r.outerHeight();if(this.$tableContainer.css("height","".concat(o,"px")),this.$tableBorder&&r.is(":visible")){var s=o-a-2;this.$tableBody[0].scrollWidth-this.$tableBody.innerWidth()&&(s-=Ka.getScrollBarWidth()),this.$tableBorder.css("width","".concat(r.outerWidth(),"px")),this.$tableBorder.css("height","".concat(s,"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(e,"px"))),this.trigger("reset-view")}},{key:"showLoading",value:function(){this.$tableLoading.toggleClass("open",!0);var t=this.options.loadingFontSize;"auto"===this.options.loadingFontSize&&(t=0.04*this.$tableLoading.width(),t=Math.max(12,t),t=Math.min(32,t),t="".concat(t,"px")),this.$tableLoading.find(".loading-text").css("font-size",t)}},{key:"hideLoading",value:function(){this.$tableLoading.toggleClass("open",!1)}},{key:"toggleShowSearch",value:function(){this.$el.parents(".select-table").siblings().slideToggle()}},{key:"togglePagination",value:function(){this.options.pagination=!this.options.pagination;var t=this.options.showButtonIcons?this.options.pagination?this.options.icons.paginationSwitchDown:this.options.icons.paginationSwitchUp:"",e=this.options.showButtonText?this.options.pagination?this.options.formatPaginationSwitchUp():this.options.formatPaginationSwitchDown():"";this.$toolbar.find('button[name="paginationSwitch"]').html(Ka.sprintf(this.constants.html.icon,this.options.iconsPrefix,t)+" "+e),this.updatePagination()}},{key:"toggleFullscreen",value:function(){this.$el.closest(".bootstrap-table").toggleClass("fullscreen"),this.resetView()}},{key:"toggleView",value:function(){this.options.cardView=!this.options.cardView,this.initHeader();var t=this.options.showButtonIcons?this.options.cardView?this.options.icons.toggleOn:this.options.icons.toggleOff:"",e=this.options.showButtonText?this.options.cardView?this.options.formatToggleOff():this.options.formatToggleOn():"";this.$toolbar.find('button[name="toggle"]').html(Ka.sprintf(this.constants.html.icon,this.options.iconsPrefix,t)+" "+e),this.initBody(),this.trigger("toggle",this.options.cardView)}},{key:"resetSearch",value:function(t){var e=Ka.getSearchInput(this);e.val(t||""),this.onSearch({currentTarget:e})}},{key:"filterBy",value:function(e,i){this.filterOptions=Ka.isEmptyObject(i)?this.options.filterOptions:t.extend(this.options.filterOptions,i),this.filterColumns=Ka.isEmptyObject(e)?{}:e,this.options.pageNumber=1,this.initSearch(),this.updatePagination()}},{key:"scrollTo",value:function i(e){var o={unit:"px",value:0};"object"===n(e)?o=Object.assign(o,e):"string"==typeof e&&"bottom"===e?o.value=this.$tableBody[0].scrollHeight:("string"==typeof e||"number"==typeof e)&&(o.value=e);var i=o.value;"rows"===o.unit&&(i=0,this.$body.find("> tr:lt(".concat(o.value,")")).each(function(e,n){i+=t(n).outerHeight(!0)})),this.$tableBody.scrollTop(i)}},{key:"getScrollPosition",value:function(){return this.$tableBody.scrollTop()}},{key:"selectPage",value:function(t){t>0&&t<=this.options.totalPages&&(this.options.pageNumber=t,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"]',t));i.next().is("tr.detail-view")?this.collapseRow(t):this.expandRow(t,e),this.resetView()}},{key:"expandRow",value:function(t,e){var i=this.data[t],n=this.$body.find(Ka.sprintf('> tr[data-index="%s"][data-has-detail-view]',t));if(!n.next().is("tr.detail-view")){this.options.detailViewIcon&&n.find("a.detail-icon").html(Ka.sprintf(this.constants.html.icon,this.options.iconsPrefix,this.options.icons.detailClose)),n.after(Ka.sprintf('',n.children("td").length));var o=n.next().find("td"),r=e||this.options.detailFormatter,a=Ka.calculateObjectValue(this.options,r,[t,i,o],"");1===o.length&&o.append(a),this.trigger("expand-row",t,i,o)}}},{key:"expandRowByUniqueId",value:function(t){var e=this.getRowByUniqueId(t);e&&this.expandRow(this.data.indexOf(e))}},{key:"collapseRow",value:function(t){var e=this.data[t],i=this.$body.find(Ka.sprintf('> tr[data-index="%s"][data-has-detail-view]',t));i.next().is("tr.detail-view")&&(this.options.detailViewIcon&&i.find("a.detail-icon").html(Ka.sprintf(this.constants.html.icon,this.options.iconsPrefix,this.options.icons.detailOpen)),this.trigger("collapse-row",t,e,i.next()),i.next().remove())}},{key:"collapseRowByUniqueId",value:function(t){var e=this.getRowByUniqueId(t);e&&this.collapseRow(this.data.indexOf(e))}},{key:"expandAllRows",value:function(){for(var e=this.$body.find("> tr[data-index][data-has-detail-view]"),i=0;i tr[data-index][data-has-detail-view]"),i=0;i1?i-1:0),r=1;i>r;r++){o[r-1]=arguments[r]}var a;return this.each(function(i,r){var s=t(r).data("bootstrap.table"),l=t.extend({},Qa.DEFAULTS,t(r).data(),"object"===n(e)&&e);if("string"==typeof e){var c;if(!Fa.METHODS.includes(e)){throw Error("Unknown method: ".concat(e))}if(!s){return}a=(c=s)[e].apply(c,o),"destroy"===e&&t(r).removeData("bootstrap.table")}s||(s=new t.BootstrapTable(r,l),t(r).data("bootstrap.table",s),s.init())}),void 0===a?this:a},t.fn.bootstrapTable.Constructor=Qa,t.fn.bootstrapTable.theme=Fa.THEME,t.fn.bootstrapTable.VERSION=Fa.VERSION,t.fn.bootstrapTable.defaults=Qa.DEFAULTS,t.fn.bootstrapTable.columnDefaults=Qa.COLUMN_DEFAULTS,t.fn.bootstrapTable.events=Qa.EVENTS,t.fn.bootstrapTable.locales=Qa.LOCALES,t.fn.bootstrapTable.methods=Qa.METHODS,t.fn.bootstrapTable.utils=Ka,t(function(){t('[data-toggle="table"]').bootstrapTable()}),Qa});var 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(t,e){return $.isPlainObject(e)?addRememberRow(t,e):$.isArray(e)?$.each(e,function(e,i){$.isPlainObject(i)?addRememberRow(t,i):-1==$.inArray(i,t)&&(t[t.length]=i)}):-1==$.inArray(e,t)&&(t[t.length]=e),t},difference=function(t,e){if($.isPlainObject(e)){removeRememberRow(t,e)}else{if($.isArray(e)){$.each(e,function(e,i){if($.isPlainObject(i)){removeRememberRow(t,i)}else{var n=$.inArray(i,t);-1!=n&&t.splice(n,1)}})}else{var i=$.inArray(e,t);-1!=i&&t.splice(i,1)}}return t},_={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..7f2781ccb --- /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.18.0 + * @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,a=Object.getOwnPropertyDescriptor,f={f:a&&!c.call({1:2},1)?function(t){var e=a(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,b=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t},v=function(t){return y(b(t))},d=function(t){return"object"==typeof t?null!==t:"function"==typeof t},g=function(t,e){if(!d(t))return t;var n,r;if(e&&"function"==typeof(n=t.toString)&&!d(r=n.call(t)))return r;if("function"==typeof(n=t.valueOf)&&!d(r=n.call(t)))return r;if(!e&&"function"==typeof(n=t.toString)&&!d(r=n.call(t)))return r;throw TypeError("Can't convert object to primitive value")},m={}.hasOwnProperty,O=function(t,e){return m.call(t,e)},w=o.document,j=d(w)&&d(w.createElement),S=function(t){return j?w.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=v(t),e=g(e,!0),R)try{return T(t,e)}catch(t){}if(O(t,e))return s(!f.f.call(t,e),t[e])}},A=function(t){if(!d(t))throw TypeError(String(t)+" is not an object");return t},E=Object.defineProperty,x={f:u?E:function(t,e,n){if(A(t),e=g(e,!0),A(n),R)try{return E(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 x.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="__core-js_shared__",F=o[k]||I(k,{}),M=Function.toString;"function"!=typeof F.inspectSource&&(F.inspectSource=function(t){return M.call(t)});var C,q,B,L=F.inspectSource,N=o.WeakMap,z="function"==typeof N&&/native code/.test(L(N)),D=n((function(t){(t.exports=function(t,e){return F[t]||(F[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.0",mode:"global",copyright:"© 2019 Denis Pushkarev (zloirock.ru)"})})),W=0,G=Math.random(),$=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++W+G).toString(36)},K=D("keys"),Q=function(t){return K[t]||(K[t]=$(t))},V={},X=o.WeakMap;if(z){var Y=new X,H=Y.get,J=Y.has,U=Y.set;C=function(t,e){return U.call(Y,t,e),e},q=function(t){return H.call(Y,t)||{}},B=function(t){return J.call(Y,t)}}else{var Z=Q("state");V[Z]=!0,C=function(t,e){return _(t,Z,e),e},q=function(t){return O(t,Z)?t[Z]:{}},B=function(t){return O(t,Z)}}var tt,et,nt={set:C,get:q,has:B,enforce:function(t){return B(t)?q(t):C(t,{})},getterFor:function(t){return function(e){var n;if(!d(e)||(n=q(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}},rt=n((function(t){var e=nt.get,n=nt.enforce,r=String(String).split("String");(t.exports=function(t,e,i,u){var c=!!u&&!!u.unsafe,a=!!u&&!!u.enumerable,f=!!u&&!!u.noTargetGet;"function"==typeof i&&("string"!=typeof e||O(i,"name")||_(i,"name",e),n(i).source=r.join("string"==typeof e?e:"")),t!==o?(c?!f&&t[e]&&(a=!0):delete t[e],a?t[e]=i:_(t,e,i)):a?t[e]=i:I(e,i)})(Function.prototype,"toString",(function(){return"function"==typeof this&&e(this).source||L(this)}))})),ot=o,it=function(t){return"function"==typeof t?t:void 0},ut=function(t,e){return arguments.length<2?it(ot[t])||it(o[t]):ot[t]&&ot[t][e]||o[t]&&o[t][e]},ct=Math.ceil,at=Math.floor,ft=function(t){return isNaN(t=+t)?0:(t>0?at:ct)(t)},st=Math.min,lt=function(t){return t>0?st(ft(t),9007199254740991):0},pt=Math.max,ht=Math.min,yt=function(t){return function(e,n,r){var o,i=v(e),u=lt(i.length),c=function(t,e){var n=ft(t);return n<0?pt(n+e,0):ht(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}},bt={includes:yt(!0),indexOf:yt(!1)}.indexOf,vt=function(t,e){var n,r=v(t),o=0,i=[];for(n in r)!O(V,n)&&O(r,n)&&i.push(n);for(;e.length>o;)O(r,n=e[o++])&&(~bt(i,n)||i.push(n));return i},dt=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],gt=dt.concat("length","prototype"),mt={f:Object.getOwnPropertyNames||function(t){return vt(t,gt)}},Ot={f:Object.getOwnPropertySymbols},wt=ut("Reflect","ownKeys")||function(t){var e=mt.f(A(t)),n=Ot.f;return n?e.concat(n(t)):e},jt=function(t,e){for(var n=wt(e),r=x.f,o=P.f,i=0;i=74)&&(tt=Gt.match(/Chrome\/(\d+)/))&&(et=tt[1]);var Vt,Xt=et&&+et,Yt=zt("species"),Ht=zt("isConcatSpreadable"),Jt=9007199254740991,Ut="Maximum allowed index exceeded",Zt=Xt>=51||!i((function(){var t=[];return t[Ht]=!1,t.concat()[0]!==t})),te=(Vt="concat",Xt>=51||!i((function(){var t=[];return(t.constructor={})[Yt]=function(){return{foo:1}},1!==t[Vt](Boolean).foo}))),ee=function(t){if(!d(t))return!1;var e=t[Ht];return void 0!==e?!!e:kt(t)};It({target:"Array",proto:!0,forced:!Zt||!te},{concat:function(t){var e,n,r,o,i,u=Ft(this),c=Wt(u,0),a=0;for(e=-1,r=arguments.length;eJt)throw TypeError(Ut);for(n=0;n=Jt)throw TypeError(Ut);Mt(c,a++,i)}return c.length=a,c}});var ne,re=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)}},oe=[].push,ie=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,a,f,s){for(var l,p,h=Ft(c),b=y(h),v=re(a,f,3),d=lt(b.length),g=0,m=s||Wt,O=e?m(c,d):n?m(c,0):void 0;d>g;g++)if((u||g in b)&&(p=v(l=b[g],g,h),t))if(e)O[g]=p;else if(p)switch(t){case 3:return!0;case 5:return l;case 6:return g;case 2:oe.call(O,l)}else if(o)return!1;return i?-1:r||o?o:O}},ue={forEach:ie(0),map:ie(1),filter:ie(2),some:ie(3),every:ie(4),find:ie(5),findIndex:ie(6)},ce=Object.keys||function(t){return vt(t,dt)},ae=u?Object.defineProperties:function(t,e){A(t);for(var n,r=ce(e),o=r.length,i=0;o>i;)x.f(t,n=r[i++],e[n]);return t},fe=ut("document","documentElement"),se=Q("IE_PROTO"),le=function(){},pe=function(t){return" + + diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/datetime.html b/ruoyi-admin/src/main/resources/templates/demo/form/datetime.html index f159f3d88..591ba101b 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/datetime.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/datetime.html @@ -57,7 +57,7 @@
    @@ -111,7 +111,7 @@
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/duallistbox.html b/ruoyi-admin/src/main/resources/templates/demo/form/duallistbox.html index a8a55ddf1..ef80a3dec 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/duallistbox.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/duallistbox.html @@ -33,6 +33,11 @@ +
    + 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/invoice.html b/ruoyi-admin/src/main/resources/templates/demo/form/invoice.html new file mode 100644 index 000000000..d3e2974ee --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/form/invoice.html @@ -0,0 +1,121 @@ + + + + + + +
    + +
    +
    +
    +
    +
    +
    + 北京百度在线网络技术有限公司
    + 北京市海淀区上地十街10号
    + 总机: (+86 10) 5992 8888 +
    +
    + +
    +

    单据编号:

    +

    H+-000567F7-00

    +
    + 阿里巴巴集团
    + 中国杭州市华星路99号东部软件园创业大厦6层(310099)
    + 总机: (86) 571-8502-2088 +
    +

    + 日期: 2014-11-11 +

    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    清单数量单价税率总价
    +
    尚都比拉2013冬装新款女装 韩版修身呢子大衣 秋冬气质羊毛呢外套 +
    +
    1¥26.00¥1.20¥31,98
    +
    11*11夏娜 新款斗篷毛呢外套 女秋冬呢子大衣 韩版大码宽松呢大衣 +
    + 双十一特价 + +
    2¥80.00¥1.20¥196.80
    +
    2013秋装 新款女装韩版学生秋冬加厚加绒保暖开衫卫衣 百搭女外套 +
    +
    3¥420.00¥1.20¥1033.20
    +
    + + + + + + + + + + + + + + + + + +
    总价: + ¥1026.00
    税: + ¥235.98
    总计 + ¥1261.98
    +
    + +
    + +
    注意: 请在30日内完成付款,否则订单会自动取消。 +
    +
    +
    +
    +
    + + + + diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/jasny.html b/ruoyi-admin/src/main/resources/templates/demo/form/jasny.html index 25aefb835..e581fc9ca 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/jasny.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/jasny.html @@ -62,7 +62,7 @@
    @@ -105,7 +105,7 @@
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/labels_tips.html b/ruoyi-admin/src/main/resources/templates/demo/form/labels_tips.html new file mode 100644 index 000000000..02622e679 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/form/labels_tips.html @@ -0,0 +1,237 @@ + + + + + + +
    +
    +
    +
    +
    +
    徽章 (Badges)
    +
    + + + + + + + + + + +
    +
    +
    +

    + 要添加徽章,只需要在元素上添加.badge即可,改变徽章的颜色可使用如下class,如.badge-primary。 +

    +

    +

    +

    badge-primary +

    +

    badge-info +

    +

    badge-success +

    +

    badge-warning +

    +

    badge-danger +

    +
    +
    +
    + +
    +
    +
    +
    标签 (Labels)
    +
    + + + + + + + + + + +
    +
    +
    +

    + 要添加徽章,只需要在元素上添加class.label即可,如果需要修改颜色,添加如下class,如.label-primary +

    +

    +

    +

    label-primary +

    +

    label-info +

    +

    label-success +

    +

    label-warning +

    +

    label-danger +

    +
    +
    +
    +
    + +
    +
    +
    +
    +
    通知样式
    +
    + + + + + + + + + + +
    +
    +
    +
    + RuoYi是一个很棒的后台UI框架 了解更多. +
    +
    + RuoYi是一个很棒的后台UI框架 了解更多. +
    +
    + RuoYi是一个很棒的后台UI框架 了解更多. +
    +
    + RuoYi是一个很棒的后台UI框架 了解更多. +
    +
    +
    +
    +
    +
    +
    +
    带关闭按钮的通知样式
    +
    + + + + + + + + + + +
    +
    +
    +
    + + RuoYi是一个很棒的后台UI框架 了解更多. +
    +
    + + RuoYi是一个很棒的后台UI框架 了解更多. +
    +
    + + RuoYi是一个很棒的后台UI框架 了解更多. +
    +
    + + RuoYi是一个很棒的后台UI框架 了解更多. +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    工具提示
    +
    + + + + + + + + + + +
    +
    +
    +

    工具提示示例 深色背景

    +
    + + + + +
    +
    +

    工具提示 - 单击提示

    +
    + + + + +
    +
    +
    +
    + +
    + +
    + + + + 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/select.html b/ruoyi-admin/src/main/resources/templates/demo/form/select.html index 383c31e0f..070a53174 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/select.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/select.html @@ -69,7 +69,7 @@
    @@ -133,7 +133,7 @@
    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 7d6820fdb..2ed3ff875 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.0.0 + 当前版本:v4.5.1

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

    你好,若依

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

    - 当前版本:v4.0.0 + 当前版本:v4.5.1

    开源免费 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..d8cdf2a31 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 @@
    @@ -334,7 +334,7 @@

    超大屏幕

    -

    Bootstrap 支持的另一个特性,超大屏幕(Jumbotron)。顾名思义该组件可以增加标题的大小,并为登陆页面内容添加更多的外边距(margin)。使用超大屏幕(Jumbotron)的步骤如下:

    +

    Bootstrap 支持的另一个特性,超大屏幕(Jumbotron)。顾名思义该组件可以增加标题的大小,并为登录页面内容添加更多的外边距(margin)。使用超大屏幕(Jumbotron)的步骤如下:

    1. 创建一个带有 class .jumbotron. 的容器
    2. diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/timeline.html b/ruoyi-admin/src/main/resources/templates/demo/form/timeline.html new file mode 100644 index 000000000..0b0239e14 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/form/timeline.html @@ -0,0 +1,113 @@ + + + + + + 时间轴 + + + + + + +
      +
      +
      + 打开/关闭颜色/背景或方向版本: + 轻型版本 + 黑色版本 +
      +
      +
      +
      + + +
      +

      会议

      +

      上一年的销售业绩发布会。总结产品营销和销售趋势及销售的现状。 +

      + 更多信息 + + 今天
      + 2月3日 +
      +
      +
      + +
      +
      + +
      + +
      +

      给张三发送文档

      +

      发送上年度《销售业绩报告》

      + 下载文档 + + 今天
      + 2月3日 +
      +
      +
      + +
      +
      + +
      + +
      +

      喝咖啡休息

      +

      喝咖啡啦,啦啦啦~~

      + 更多 + 昨天
      2月2日
      +
      +
      + +
      +
      + +
      + +
      +

      给李四打电话

      +

      给李四打电话分配本月工作任务

      + 昨天
      2月2日
      +
      +
      + +
      +
      + +
      + +
      +

      公司年会

      +

      发年终奖啦,啦啦啦~~

      + 前天
      2月1日
      +
      +
      +
      +
      +
      +
      + + + + diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/upload.html b/ruoyi-admin/src/main/resources/templates/demo/form/upload.html index 7c78daa34..4292d2329 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/upload.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/upload.html @@ -29,7 +29,7 @@
    @@ -49,6 +49,14 @@ "/img/profile.jpg" ] }); + + $("#fileinput-demo-1").on("fileuploaded", function(event, data, proviewId, index) { + console.info(event); + console.info(data); + console.info(proviewId); + console.info(index); + }); + }); diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/validate.html b/ruoyi-admin/src/main/resources/templates/demo/form/validate.html index 35f48fa48..8fb68d729 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/validate.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/validate.html @@ -71,7 +71,7 @@

    更多示例请访问官方示例页面:查看

    -

    中文API可参考:http://doc.ruoyi.vip/#/standard/zjwd?id=jquery-validate +

    中文API可参考:http://doc.ruoyi.vip/ruoyi/document/zjwd.html#jquery-validate

    diff --git a/ruoyi-admin/src/main/resources/templates/demo/form/wizard.html b/ruoyi-admin/src/main/resources/templates/demo/form/wizard.html index 428f330ec..ffcdde1fc 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/form/wizard.html +++ b/ruoyi-admin/src/main/resources/templates/demo/form/wizard.html @@ -1,192 +1,332 @@ - - + + + -
    -
    -
    -
    -

    表单向导

    -

    Smart UI 部件允许您快速创建表单向导接口。

    -

    了解 jQuery Steps -

    -
    -
    -
    -
    -
    -
    基础表单向导
    -
    -
    -

    - 这是一个简单的表单向导示例 -

    -
    -

    第一步

    -
    -
    -

    第一步

    -

    - 这是第一步的内容 -

    -
    -
    +
    +
    +
    +
    +
    +
    + 表单向导 + https://github.com/techlab/jquery-smartwizard +
    +
    +
    +
    + -

    第二步

    -
    -
    -

    第二步

    -

    - 这是第二步的内容 -

    -
    -
    +
    +
    + +
    +
    +
    +
    +
    + +
    + + + + 这里写点提示的内容 + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + + + + 请再次输入您的密码 + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +

    1、如果需要工具栏在页面底部显示, 将style中下面的部分取消注释

    .sw>.toolbar-bottom

    +

    2、如果设置了自动调节高度为false, 将style中下面的部分取消注释

    .sw>.tab-content

    +

    3、工具栏的按钮样式会被表单插件中.btn样式覆盖导致bootstrap中的按钮样式无效, 如果需要改变按钮样式可以自己定义并提高优先级

    +
    +
    +
    +
    +

    测试多行显示

    +
    +$('#smartwizard').smartWizard({
    +  selected: 0, // Initial selected step, 0 = first step
    +  theme: 'default', // theme for the wizard, related css need to include for other than default theme
    +  justified: true, // Nav menu justification. true/false
    +  darkMode:false, // Enable/disable Dark Mode if the theme supports. true/false
    +  autoAdjustHeight: true, // Automatically adjust content height
    +  cycleSteps: false, // Allows to cycle the navigation of steps
    +  backButtonSupport: true, // Enable the back button support
    +  enableURLhash: true, // Enable selection of the step based on url hash
    +  transition: {
    +      animation: 'none', // Effect on navigation, none/fade/slide-horizontal/slide-vertical/slide-swing
    +      speed: '400', // Transion animation speed
    +      easing:'' // Transition animation easing. Not supported without a jQuery easing plugin
    +  },
    +  toolbarSettings: {
    +      toolbarPosition: 'bottom', // none, top, bottom, both
    +      toolbarButtonPosition: 'right', // left, right, center
    +      showNextButton: true, // show/hide a Next button
    +      showPreviousButton: true, // show/hide a Previous button
    +      toolbarExtraButtons: [] // Extra buttons to show on toolbar, array of jQuery input/buttons elements
    +  },
    +  anchorSettings: {
    +      anchorClickable: true, // Enable/Disable anchor navigation
    +      enableAllAnchors: false, // Activates all anchors clickable all times
    +      markDoneStep: true, // Add done state on navigation
    +      markAllPreviousStepsAsDone: true, // When a step selected by url hash, all previous steps are marked done
    +      removeDoneStepOnNavigateBack: false, // While navigate back done step after active step will be cleared
    +      enableAnchorOnDoneStep: true // Enable/Disable the done steps navigation
    +  },
    +  keyboardSettings: {
    +      keyNavigation: true, // Enable/Disable keyboard navigation(left and right keys are used if enabled)
    +      keyLeft: [37], // Left key code
    +      keyRight: [39] // Right key code
    +  },
    +  lang: { // Language variables for button
    +      next: 'Next',
    +      previous: 'Previous'
    +  },
    +  disabledSteps: [], // Array Steps disabled
    +  errorSteps: [], // Highlight step with errors
    +  hiddenSteps: [] // Hidden steps
    +});
    +										
    +
    +
    +
    +
    +
    +
    +
    -

    第三步

    -
    -
    -

    第三步

    -

    - 这是第三步的内容 -

    -
    -
    -
    +
    +
    + + + 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/modal/table/check.html b/ruoyi-admin/src/main/resources/templates/demo/modal/table/check.html index cf8d178d1..80365d6ef 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/modal/table/check.html +++ b/ruoyi-admin/src/main/resources/templates/demo/modal/table/check.html @@ -7,7 +7,7 @@
    -
    +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/modal/table/parent.html b/ruoyi-admin/src/main/resources/templates/demo/modal/table/parent.html index 14f59dcc7..40019c7a9 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/modal/table/parent.html +++ b/ruoyi-admin/src/main/resources/templates/demo/modal/table/parent.html @@ -7,7 +7,7 @@
    -
    +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/modal/table/radio.html b/ruoyi-admin/src/main/resources/templates/demo/modal/table/radio.html index 4c9607dfc..88c60d682 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/modal/table/radio.html +++ b/ruoyi-admin/src/main/resources/templates/demo/modal/table/radio.html @@ -7,7 +7,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..ca302663d 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/operate/detail.html +++ b/ruoyi-admin/src/main/resources/templates/demo/operate/detail.html @@ -8,10 +8,12 @@
    -
    +
    +
    +
    - +
    @@ -45,7 +47,7 @@ + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/curd.html b/ruoyi-admin/src/main/resources/templates/demo/table/curd.html index 529ae3209..ee7617729 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/curd.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/curd.html @@ -15,7 +15,7 @@ 根据值删除行 -
    + 删除所有行 @@ -36,7 +36,7 @@
    -
    +
    @@ -88,7 +88,7 @@ /* 新增表格行 */ function insertRow(){ var randomId = 100 + ~~(Math.random() * 100) - $.btTable.bootstrapTable('insertRow', { + $("#" + table.options.id).bootstrapTable('insertRow', { index: 0, // 你想插入到哪,0表示第一行 row: { userId: randomId, @@ -108,7 +108,7 @@ $.modal.alertWarning("请至少选择一条记录"); return; } - $.btTable.bootstrapTable('remove', { + $("#" + table.options.id).bootstrapTable('remove', { field: 'userId', values: ids }) @@ -116,18 +116,18 @@ /* 删除行ID值为1的数据 */ function removeRowByUniqueId(){ - $.btTable.bootstrapTable('removeByUniqueId', 1) + $("#" + table.options.id).bootstrapTable('removeByUniqueId', 1) } /* 删除所有表格行 */ function removeRowAll(){ - $.btTable.bootstrapTable('removeAll') + $("#" + table.options.id).bootstrapTable('removeAll') } /* 修改表格行 */ function updateRow(){ var randomId = 100 + ~~(Math.random() * 100) - $.btTable.bootstrapTable('updateRow', { + $("#" + table.options.id).bootstrapTable('updateRow', { index: 0, // 你想修改哪行,0表示第一行 row: { userId: randomId, @@ -143,7 +143,7 @@ /* 修改行ID值为1的数据 */ function updateRowByUniqueId(){ var randomId = 100 + ~~(Math.random() * 100) - $.btTable.bootstrapTable('updateByUniqueId', { + $("#" + table.options.id).bootstrapTable('updateByUniqueId', { id: 1, row: { userId: randomId, @@ -158,19 +158,19 @@ /* 查询表格所有数据值 */ function getData(){ - var data = $.btTable.bootstrapTable('getData'); + var data = $("#" + table.options.id).bootstrapTable('getData'); alert(JSON.stringify(data)) } /* 查询行ID值为1的数据 */ function getRowByUniqueId(){ - var data = $.btTable.bootstrapTable('getRowByUniqueId', 1); + var data = $("#" + table.options.id).bootstrapTable('getRowByUniqueId', 1); alert(JSON.stringify(data)) } /* 查询表格选择行数据值 */ function getSelections(){ - var data = $.btTable.bootstrapTable('getSelections'); + var data = $("#" + table.options.id).bootstrapTable('getSelections'); alert(JSON.stringify(data)) } 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/detail.html b/ruoyi-admin/src/main/resources/templates/demo/table/detail.html index a51c634be..de12dbd8d 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/detail.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/detail.html @@ -1,13 +1,13 @@ - +
    -
    +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/editable.html b/ruoyi-admin/src/main/resources/templates/demo/table/editable.html new file mode 100644 index 000000000..3395e6d4e --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/editable.html @@ -0,0 +1,128 @@ + + + + + + + +
    + + + + + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/event.html b/ruoyi-admin/src/main/resources/templates/demo/table/event.html index 89f7f2a86..372b4c916 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/event.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/event.html @@ -8,7 +8,7 @@

    自定义触发事件(点击某行/双击某行/单击某格/双击某格/服务器发送数据前触发/数据被加载时触发)

    -
    +
    @@ -24,6 +24,10 @@ showRefresh: false, showToggle: false, showColumns: false, + onCheck: onCheck, + onUncheck: onUncheck, + onCheckAll: onCheckAll, + onUncheckAll: onUncheckAll, onClickRow: onClickRow, onDblClickRow: onDblClickRow, onClickCell: onClickCell, @@ -95,6 +99,28 @@ alert("双击格name:" + field + " value:" + value); } + function onCheck(row, $element){ + alert("选中行userId:" + row.userId + " userName:" + row.userName); + } + + function onUncheck(row, $element){ + alert("取消行userId:" + row.userId + " userName:" + row.userName); + } + + function onCheckAll(rowsAfter, rowsBefore){ + var rows = $.map(rowsAfter, function(row) { + return $.common.getItemField(row, "userId"); + }); + alert("全选行:" + rows); + } + + function onUncheckAll(rowsAfter, rowsBefore){ + var rows = $.map(rowsBefore, function(row) { + return $.common.getItemField(row, "userId"); + }); + alert("取消行:" + rows); + } + function responseHandler(res){ alert("请求获取数据后处理回调函数"); } 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 85ba38d30..82be299a5 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/export.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/export.html @@ -7,11 +7,12 @@
    -
    +
    + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/groupHeader.html b/ruoyi-admin/src/main/resources/templates/demo/table/groupHeader.html index b7b3903ec..27d2b8d60 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/groupHeader.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/groupHeader.html @@ -7,7 +7,7 @@
    -
    +
    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/image.html b/ruoyi-admin/src/main/resources/templates/demo/table/image.html index 4aaf51eb4..32a1e0505 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/image.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/image.html @@ -7,7 +7,7 @@
    -
    +
    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 43331e02b..a503ec95d 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/multi.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/multi.html @@ -4,35 +4,94 @@ -
    -
    -
    -
    +
    +
    +
    + +
    + +
    + +
    + +
    +
    -
    -
    -
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    + + +
    +
    \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/other.html b/ruoyi-admin/src/main/resources/templates/demo/table/other.html index e9ed0ac49..d0f791b7f 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/other.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/other.html @@ -27,7 +27,7 @@
    -
    +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/pageGo.html b/ruoyi-admin/src/main/resources/templates/demo/table/pageGo.html index 9eab0de97..32a95817c 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/pageGo.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/pageGo.html @@ -7,7 +7,7 @@
    -
    +
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/params.html b/ruoyi-admin/src/main/resources/templates/demo/table/params.html index 7193af190..ba852f100 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/params.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/params.html @@ -8,7 +8,7 @@

    通过queryParams方法设置

    -
    +
    @@ -24,7 +24,7 @@

    通过form自动填充

    -
    +
    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..85c0c4096 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/print.html @@ -0,0 +1,130 @@ + + + + + + +
    +
    +
    + +
    +
    +
    +
    +
    + + + + \ 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/remember.html b/ruoyi-admin/src/main/resources/templates/demo/table/remember.html index ca175863f..4c0b9ec7e 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/remember.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/remember.html @@ -12,7 +12,7 @@
    -
    +
    @@ -24,10 +24,6 @@ $(function() { var options = { url: prefix + "/list", - showSearch: false, - showRefresh: false, - showToggle: false, - showColumns: false, rememberSelected: true, columns: [{ field: 'state', @@ -81,7 +77,8 @@ // 选中数据 function checkItem(){ - var arrays = $.table.selectColumns("userId"); + // var arrays = $.table.selectColumns("userId"); + var arrays = $.table.selectColumns("userCode"); alert(arrays); } diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/reorder.html b/ruoyi-admin/src/main/resources/templates/demo/table/reorder.html index 9e5f3a091..8c40c4da9 100644 --- a/ruoyi-admin/src/main/resources/templates/demo/table/reorder.html +++ b/ruoyi-admin/src/main/resources/templates/demo/table/reorder.html @@ -8,7 +8,7 @@

    按住表格拖拽

    -
    diff --git a/ruoyi-admin/src/main/resources/templates/demo/table/resizable.html b/ruoyi-admin/src/main/resources/templates/demo/table/resizable.html new file mode 100644 index 000000000..40f92f51a --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/resizable.html @@ -0,0 +1,78 @@ + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    + + + + + \ 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 210b58b0b..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..f55e87533 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/demo/table/subdata.html @@ -0,0 +1,199 @@ + + + + + + + +
    + + +

    客户信息

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

    商品数据

    +
    +
    + + +
    +
    +
    +
    +
    + +
    + +
    +
    +   + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/templates/error/404.html b/ruoyi-admin/src/main/resources/templates/error/404.html index 774a58dfd..9d2eee875 100644 --- a/ruoyi-admin/src/main/resources/templates/error/404.html +++ b/ruoyi-admin/src/main/resources/templates/error/404.html @@ -4,9 +4,9 @@ RuoYi - 404 - - - + + +
    @@ -14,8 +14,14 @@

    找不到网页!

    对不起,您正在寻找的页面不存在。尝试检查URL的错误,然后按浏览器上的刷新按钮或尝试在我们的应用程序中找到其他内容。 - 主页 + 主页
    + diff --git a/ruoyi-admin/src/main/resources/templates/error/500.html b/ruoyi-admin/src/main/resources/templates/error/500.html index f59b91b93..aa0941af5 100644 --- a/ruoyi-admin/src/main/resources/templates/error/500.html +++ b/ruoyi-admin/src/main/resources/templates/error/500.html @@ -4,9 +4,9 @@ RuoYi - 500 - - - + + +
    @@ -15,8 +15,14 @@
    服务器遇到意外事件,不允许完成请求。我们抱歉。您可以返回主页面。 - 主页 + 主页
    + diff --git a/ruoyi-admin/src/main/resources/templates/error/business.html b/ruoyi-admin/src/main/resources/templates/error/business.html index f47cde785..1faf08c0b 100644 --- a/ruoyi-admin/src/main/resources/templates/error/business.html +++ b/ruoyi-admin/src/main/resources/templates/error/business.html @@ -4,9 +4,9 @@ RuoYi - 403 - - - + + +
    diff --git a/ruoyi-admin/src/main/resources/templates/error/unauth.html b/ruoyi-admin/src/main/resources/templates/error/unauth.html index ca14e5526..e4826433c 100644 --- a/ruoyi-admin/src/main/resources/templates/error/unauth.html +++ b/ruoyi-admin/src/main/resources/templates/error/unauth.html @@ -4,9 +4,9 @@ RuoYi - 403 - - - + + +
    @@ -15,8 +15,14 @@
    对不起,您没有访问权限,请不要进行非法操作!您可以返回主页面 - 返回主页 + 返回主页
    + diff --git a/ruoyi-admin/src/main/resources/templates/include.html b/ruoyi-admin/src/main/resources/templates/include.html index c761349a7..815414e2f 100644 --- a/ruoyi-admin/src/main/resources/templates/include.html +++ b/ruoyi-admin/src/main/resources/templates/include.html @@ -2,6 +2,7 @@ + @@ -9,39 +10,35 @@ - + - - + +
    + + - - - - - + + + - - - - - - + +
    @@ -74,7 +71,7 @@
    - +
    @@ -95,12 +92,12 @@
    - -
    - + +
    +
    -
    - +
    +
    @@ -113,10 +110,10 @@
    - +
    - +
    @@ -137,6 +134,11 @@
    + +
    + +
    +
    @@ -145,12 +147,12 @@
    - -
    - + +
    +
    -
    - +
    +
    @@ -172,4 +174,40 @@
    -
    \ 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..16af01cc5 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/index-topnav.html @@ -0,0 +1,431 @@ + + + + + + + 若依系统首页 + + + + + + + + + + + + +
    + + + + + + +
    + +
    + + + + 刷新 +
    + + + +
    + +
    + + +
    + +
    + + + + + + + + + + + + + + + + diff --git a/ruoyi-admin/src/main/resources/templates/index.html b/ruoyi-admin/src/main/resources/templates/index.html index 768bb573c..bcd9a8769 100644 --- a/ruoyi-admin/src/main/resources/templates/index.html +++ b/ruoyi-admin/src/main/resources/templates/index.html @@ -5,19 +5,18 @@ 若依系统首页 - - + + + - + - +
    @@ -25,17 +24,19 @@ + + + - + - + - -
    -
    - @@ -232,16 +258,112 @@ - - + + + - diff --git a/ruoyi-admin/src/main/resources/templates/lock.html b/ruoyi-admin/src/main/resources/templates/lock.html new file mode 100644 index 000000000..2b8b42c08 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/lock.html @@ -0,0 +1,208 @@ + + + + + + + 锁定屏幕 + + + + + + +
    +
    +
    [[ ${user.loginName} ]] / [[${#strings.defaultString(user.userName, '-')}]]
    + +
    +
    + User Image +
    +
    +
    + +
    + +
    +
    +
    +
    + +
    系统锁屏,请输入密码登陆!
    + +
    + + + + + + + + diff --git a/ruoyi-admin/src/main/resources/templates/login.html b/ruoyi-admin/src/main/resources/templates/login.html index 5b4caf87f..68d531197 100644 --- a/ruoyi-admin/src/main/resources/templates/login.html +++ b/ruoyi-admin/src/main/resources/templates/login.html @@ -3,26 +3,24 @@ - 登录若依系统 - - + + + + + - -
    @@ -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 eb1bb3da5..568565ed1 100644 --- a/ruoyi-admin/src/main/resources/templates/main.html +++ b/ruoyi-admin/src/main/resources/templates/main.html @@ -17,11 +17,10 @@
    领取阿里云通用云产品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
    - 阿里云Hi拼购 限量爆款 低至199元/年 -
    https://www.aliyun.com/acts/hi-group-buying?userCode=brki8iof + 阿里云服务器折扣区 ☛☛点我进入☚☚     腾讯云服务器秒杀区 ☛☛点我进入☚☚

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

    @@ -81,7 +80,7 @@

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

    -

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

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

    微信:/ *若依

    @@ -98,13 +97,355 @@
    +
    +
    +
    + v4.5.12020.11.18 +
    +
    +
    +
    +
      +
    1. 阻止任意文件下载漏洞
    2. +
    3. 升级shiro到最新版1.7.0 阻止权限绕过漏洞
    4. +
    5. 升级druid到最新版本v1.2.2
    6. +
    7. 新增表格行触发事件(onCheck、onUncheck、onCheckAll、onUncheckAll)
    8. +
    9. 修复多页签关闭非当前选项出现空白问题
    10. +
    11. 代码生成预览支持高亮显示
    12. +
    13. mapperLocations配置支持分隔符
    14. +
    15. 权限信息调整
    16. +
    17. 个人中心头像和上传头像增加默认图片
    18. +
    19. 全局配置类保持和其他应用命名相同
    20. +
    +
    +
    +
    +
    +
    +
    + v4.5.02020.10.20 +
    +
    +
    +
    +
      +
    1. 新增菜单导航显示风格(default为左侧导航菜单,topnav为顶部导航菜单)
    2. +
    3. 菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)
    4. +
    5. 账号密码支持自定义更新周期
    6. +
    7. 初始密码支持自定义修改策略
    8. +
    9. 新增校验用户修改新密码不能与旧密码相同
    10. +
    11. 添加检查密码范围支持的特殊字符包括:~!@#$%^&*()-=_+
    12. +
    13. 注册账号设置默认用户名称及密码最后更新时间
    14. +
    15. 去除用户手机邮箱部门必填验证
    16. +
    17. 新增日期格式化方法
    18. +
    19. 代码生成添加bit类型
    20. +
    21. 树结构加载添加callBack回调方法
    22. +
    23. 修复用户管理页面滚动返回顶部条失效
    24. +
    25. 修复代码生成模板文件上传组件缺少ctx的问题
    26. +
    27. 限制系统内置参数不允许删除
    28. +
    29. 新增表格列宽拖动插件
    30. +
    31. 新增Ajax局部刷新demo
    32. +
    33. 新增是否开启页脚功能
    34. +
    35. 新增表格参数(通过自定义函数设置标题样式headerStyle)
    36. +
    37. 新增表格参数(通过自定义函数设置页脚样式footerStyle)
    38. +
    39. 修复窗体大小改变后浮动提示框失效问题
    40. +
    41. 生成代码补充必填样式
    42. +
    43. 生成页面时不忽略remark属性
    44. +
    45. 字典数据列表页添加关闭按钮
    46. +
    47. Excel注解支持自动统计数据总和
    48. +
    49. 升级springboot到2.1.17 提升安全性
    50. +
    51. 升级pagehelper到最新版1.3.0
    52. +
    53. 升级druid到最新版本v1.2.1
    54. +
    55. 升级fastjson到最新版1.2.74
    56. +
    57. 升级bootstrap-fileinput到最新版本5.1.2
    58. +
    59. 升级oshi到最新版本v5.2.5
    60. +
    61. 表单向导插件更换为jquery-smartwizard
    62. +
    63. 修改主子表提交示例代码防止渲染失效
    64. +
    65. 添加导入数据弹出窗体自定义宽高
    66. +
    67. 用户信息参数返回忽略掉密码字段
    68. +
    69. 优化关闭窗体添加index参数
    70. +
    71. 回显数据字典(字符串数组)增加空值判断
    72. +
    73. 修改前端密码长度校验和错误提示不符问题
    74. +
    75. AjaxResult重写put方法,以方便链式调用
    76. +
    77. 增强验证码校验的语义,更易懂
    78. +
    79. 导入excel整形值校验优化
    80. +
    81. Excel导出类型NUMERIC支持精度浮点类型
    82. +
    83. 导出Excel调整targetAttr获取值方法,防止get方法不规范
    84. +
    85. 输入框组验证错误后置图标提示颜色
    86. +
    87. 上传媒体类型添加视频格式
    88. +
    89. 数据权限判断参数类型
    90. +
    91. 修正数据库字符串类型nvarchar
    92. +
    93. 优化递归子节点
    94. +
    95. 修复多表格搜索formId无效
    96. +
    97. 其他细节优化
    98. +
    +
    +
    +
    +
    +
    +
    + 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. +
    3. 浮动提示方法tooltip支持弹窗
    4. +
    5. 代码生成&字典数据支持模糊条件查询
    6. +
    7. 增加页签全屏方法
    8. +
    9. 增加清除表单验证错误信息方法
    10. +
    11. 支持iframe局部刷新页面
    12. +
    13. 支持在线切换主题
    14. +
    15. 修改图片预览设置的高宽参数颠倒问题
    16. +
    17. 操作日志新增解锁账户功能
    18. +
    19. 管理员用户&角色不允许操作
    20. +
    21. 去掉jsoup包调用自定义转义工具
    22. +
    23. 添加时间轴示例
    24. +
    25. 修复翻页记住选择时获取指定列值的问题
    26. +
    27. 代码生成sql脚本添加导出按钮
    28. +
    29. 添加表格父子视图示例
    30. +
    31. 添加表格行内编辑示例
    32. +
    33. 升级fastjson到最新版1.2.60 阻止漏洞攻击
    34. +
    35. 升级echarts到最新版4.2.1
    36. +
    37. 操作日志新增返回参数
    38. +
    39. 支持mybatis通配符扫描任意多个包
    40. +
    41. 权限验证多种情况处理
    42. +
    43. 修复树形类型的代码生成的部分必要属性无法显示
    44. +
    45. 修复非表格插件情况下重置出现异常
    46. +
    47. 修复富文本编辑器有序列表冲突
    48. +
    49. 代码生成表前缀配置支持多个
    50. +
    51. 修复自动去除表前缀配置无效问题
    52. +
    53. 菜单列表按钮数据可见不显示(权限标识控制)
    54. +
    55. 修复设置会话超时时间无效问题
    56. +
    57. 新增本地资源通用下载方法
    58. +
    59. 操作日志记录新增请求方式
    60. +
    61. 代码生成单选按钮属性重名修复
    62. +
    63. 优化select2下拉框宽度不会随浏览器改变
    64. +
    65. 修复代码生成树表异常
    66. +
    67. 其他细节优化
    68. +
    +
    +
    +
    v4.0.02019.08.08
    -
    +
    1. 代码生成支持预览、编辑,保存方案
    2. @@ -158,8 +499,8 @@
    3. 其他细节优化
    -
    -
    +
    +
    @@ -452,7 +793,7 @@
      -
    1. 新增登陆超时提醒
    2. +
    3. 新增登录超时提醒
    4. 修复定时器热部署转换问题
    5. 修复登录验证码校验无效问题
    6. 定时任务新增立即执行一次
    7. @@ -523,7 +864,7 @@
      1. 优化登录失败刷新验证码
      2. -
      3. 新增用户登陆地址时间
      4. +
      5. 新增用户登录地址时间
      6. 修复ajax超时退出问题
      7. 新增html调用数据字典(若依首创)
      8. 调整系统部分样式
      9. @@ -823,7 +1164,7 @@ type: 1, closeBtn:false, shadeClose:true, - area: ['600px', 'auto'], + area: ['600px', '360px'], content: html }); }); diff --git a/ruoyi-admin/src/main/resources/templates/monitor/cache/cache.html b/ruoyi-admin/src/main/resources/templates/monitor/cache/cache.html new file mode 100644 index 000000000..ae3749b08 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/monitor/cache/cache.html @@ -0,0 +1,184 @@ + + + + + + +
        + +
        +
        +
        +
        +
        +
        缓存列表
        +
        + +
        +
        +
        + + + + + + + + + + + + + + + +
        缓存名称操作
        [[${stat.index + 1}]][[${cacheName}]]
        +
        +
        +
        +
        +
        +
        +
        键名列表
        +
        + +
        +
        +
        + + + + + + + + + + + + + + + + +
        缓存键名操作
        [[${stat.index + 1}]][[${cacheKey}]]
        +
        +
        +
        +
        +
        +
        +
        缓存内容
        + +
        +
        +
        +
        +
        + + +
        +
        + + +
        +
        + + +
        +
        +
        +
        +
        +
        +
        +
        +
        + + + + diff --git a/ruoyi-admin/src/main/resources/templates/monitor/logininfor/logininfor.html b/ruoyi-admin/src/main/resources/templates/monitor/logininfor/logininfor.html index 0be36dcaf..0c0a392bb 100644 --- a/ruoyi-admin/src/main/resources/templates/monitor/logininfor/logininfor.html +++ b/ruoyi-admin/src/main/resources/templates/monitor/logininfor/logininfor.html @@ -44,13 +44,16 @@ 清空 + + 解锁 + 导出
      -
      +
    @@ -121,6 +124,10 @@ }; $.table.init(options); }); + + function unlock() { + $.operate.post(prefix + "/unlock?loginName=" + $.table.selectColumns("loginName")); + } \ No newline at end of file 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 573b19156..88e5a543f 100644 --- a/ruoyi-admin/src/main/resources/templates/monitor/online/online.html +++ b/ruoyi-admin/src/main/resources/templates/monitor/online/online.html @@ -14,7 +14,7 @@ 登录地址:
  • - 操作人员: + 登录名称:
  •  搜索 @@ -32,11 +32,12 @@
  • -
    +
    + diff --git a/ruoyi-admin/src/main/resources/templates/monitor/operlog/operlog.html b/ruoyi-admin/src/main/resources/templates/monitor/operlog/operlog.html index 3cef2bb7b..a8b932a24 100644 --- a/ruoyi-admin/src/main/resources/templates/monitor/operlog/operlog.html +++ b/ruoyi-admin/src/main/resources/templates/monitor/operlog/operlog.html @@ -56,7 +56,7 @@
    -
    +
    @@ -75,6 +75,7 @@ detailUrl: prefix + "/detail/{id}", removeUrl: prefix + "/remove", exportUrl: prefix + "/export", + queryParams: queryParams, sortName: "operTime", sortOrder: "desc", modalName: "操作日志", @@ -148,15 +149,20 @@ $.table.init(options); }); + function queryParams(params) { + var search = $.table.queryParams(params); + search.businessTypes = $.common.join($('#businessTypes').selectpicker('val')); + return search; + } + function searchPre() { - var data = {}; - data.businessTypes = $.common.join($('#businessTypes').selectpicker('val')); - $.table.search('operlog-form', data); + $.table.search('operlog-form', 'bootstrap-table'); } function resetPre() { - $.form.reset(); + $("#operlog-form")[0].reset(); $("#businessTypes").selectpicker('refresh'); + $.table.search('operlog-form', 'bootstrap-table'); } 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..e07637299 --- /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 new file mode 100644 index 000000000..c2e992a9c --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/skin.html @@ -0,0 +1,165 @@ + + + + + + + 主题选择 + + + + + + + + + + + + + diff --git a/ruoyi-admin/src/main/resources/templates/system/config/add.html b/ruoyi-admin/src/main/resources/templates/system/config/add.html index 68b6dee33..d93aacb6a 100644 --- a/ruoyi-admin/src/main/resources/templates/system/config/add.html +++ b/ruoyi-admin/src/main/resources/templates/system/config/add.html @@ -7,19 +7,19 @@
    - +
    - +
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/config/config.html b/ruoyi-admin/src/main/resources/templates/system/config/config.html index 14be0fcbb..b11267d6b 100644 --- a/ruoyi-admin/src/main/resources/templates/system/config/config.html +++ b/ruoyi-admin/src/main/resources/templates/system/config/config.html @@ -50,9 +50,12 @@ 导出 + + 清理缓存 +
    -
    +
    @@ -70,8 +73,8 @@ updateUrl: prefix + "/edit/{id}", removeUrl: prefix + "/remove", exportUrl: prefix + "/export", - sortName: "createTime", - sortOrder: "desc", + sortName: "configId", + sortOrder: "asc", modalName: "参数", columns: [{ checkbox: true @@ -82,11 +85,17 @@ }, { field: 'configName', - title: '参数名称' + title: '参数名称', + formatter: function(value, row, index) { + return $.table.tooltip(value); + } }, { field: 'configKey', - title: '参数键名' + title: '参数键名', + formatter: function(value, row, index) { + return $.table.tooltip(value); + } }, { field: 'configValue', @@ -105,7 +114,7 @@ title: '备注', align: 'center', formatter: function(value, row, index) { - return $.table.tooltip(value); + return $.table.tooltip(value, 10, "open"); } }, { @@ -125,6 +134,11 @@ }; $.table.init(options); }); + + /** 清理参数缓存 */ + function clearCache() { + $.operate.get(prefix + "/clearCache"); + } \ 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 3ce6aae14..fe11d1fad 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 f21db0843..eda6f21be 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/dict/data/edit.html b/ruoyi-admin/src/main/resources/templates/system/dict/data/edit.html index bdb2bd2a2..a1a55531f 100644 --- a/ruoyi-admin/src/main/resources/templates/system/dict/data/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/dict/data/edit.html @@ -8,13 +8,13 @@
    - +
    - +
    @@ -32,7 +32,7 @@
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/dict/type/add.html b/ruoyi-admin/src/main/resources/templates/system/dict/type/add.html index 31756c56c..2ae428f02 100644 --- a/ruoyi-admin/src/main/resources/templates/system/dict/type/add.html +++ b/ruoyi-admin/src/main/resources/templates/system/dict/type/add.html @@ -7,13 +7,13 @@
    - +
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/dict/type/edit.html b/ruoyi-admin/src/main/resources/templates/system/dict/type/edit.html index 2bcb15f82..abb35330d 100644 --- a/ruoyi-admin/src/main/resources/templates/system/dict/type/edit.html +++ b/ruoyi-admin/src/main/resources/templates/system/dict/type/edit.html @@ -8,13 +8,13 @@
    - +
    - +
    diff --git a/ruoyi-admin/src/main/resources/templates/system/dict/type/type.html b/ruoyi-admin/src/main/resources/templates/system/dict/type/type.html index ac51b5e2a..cf6e53c46 100644 --- a/ruoyi-admin/src/main/resources/templates/system/dict/type/type.html +++ b/ruoyi-admin/src/main/resources/templates/system/dict/type/type.html @@ -50,10 +50,13 @@ 导出 + + 清理缓存 +
    -
    +
    @@ -72,8 +75,8 @@ updateUrl: prefix + "/edit/{id}", removeUrl: prefix + "/remove", exportUrl: prefix + "/export", - sortName: "createTime", - sortOrder: "desc", + sortName: "dictId", + sortOrder: "asc", modalName: "类型", columns: [{ checkbox: true @@ -105,7 +108,10 @@ }, { field: 'remark', - title: '备注' + title: '备注', + formatter: function(value, row, index) { + return $.table.tooltip(value); + } }, { field: 'createTime', @@ -132,6 +138,11 @@ var url = prefix + '/detail/' + dictId; $.modal.openTab("字典数据", url); } + + /** 清理字典缓存 */ + function clearCache() { + $.operate.get(prefix + "/clearCache"); + } \ 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..151a844ae 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 @@
    - +
    @@ -71,12 +71,23 @@
    -
    +
    + +
    +
    + + +
    +
    + + +
    +
    @@ -147,18 +158,21 @@ $("#icon").parents(".form-group").show(); $("#target").parents(".form-group").hide(); $("input[name='visible']").parents(".form-group").show(); + $(".is-refresh").hide(); } else if (menuType == "C") { $("#url").parents(".form-group").show(); $("#perms").parents(".form-group").show(); $("#icon").parents(".form-group").show(); $("#target").parents(".form-group").show(); $("input[name='visible']").parents(".form-group").show(); + $(".is-refresh").show(); } else if (menuType == "F") { $("#url").parents(".form-group").hide(); $("#perms").parents(".form-group").show(); $("#icon").parents(".form-group").hide(); $("#target").parents(".form-group").hide(); $("input[name='visible']").parents(".form-group").hide(); + $(".is-refresh").hide(); } }); }); 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..fd1950cce 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 @@
    - +
    @@ -72,12 +72,23 @@
    -
    +
    + +
    +
    + + +
    +
    + + +
    +
    @@ -163,18 +174,21 @@ $("#icon").parents(".form-group").show(); $("#target").parents(".form-group").hide(); $("input[name='visible']").parents(".form-group").show(); + $(".is-refresh").hide(); } else if (menuType == "C") { $("#url").parents(".form-group").show(); $("#perms").parents(".form-group").show(); $("#icon").parents(".form-group").show(); $("#target").parents(".form-group").show(); $("input[name='visible']").parents(".form-group").show(); + $(".is-refresh").show(); } else if (menuType == "F") { $("#url").parents(".form-group").hide(); $("#perms").parents(".form-group").show(); $("#icon").parents(".form-group").hide(); $("#target").parents(".form-group").hide(); $("input[name='visible']").parents(".form-group").hide(); + $(".is-refresh").hide(); } } 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 a5ee47679..45baba914 100644 --- a/ruoyi-admin/src/main/resources/templates/system/menu/menu.html +++ b/ruoyi-admin/src/main/resources/templates/system/menu/menu.html @@ -72,7 +72,8 @@ { title: '菜单名称', field: 'menuName', - width: '20%', + width: '20', + widthUnit: '%', formatter: function(value, row, index) { if ($.common.isEmpty(row.icon)) { return row.menuName; @@ -84,19 +85,25 @@ { field: 'orderNum', title: '排序', - width: '10%', + width: '10', + widthUnit: '%', align: "left" }, { field: 'url', title: '请求地址', - width: '15%', - align: "left" + width: '15', + widthUnit: '%', + align: "left", + formatter: function(value, row, index) { + return $.table.tooltip(value); + } }, { title: '类型', field: 'menuType', - width: '10%', + width: '10', + widthUnit: '%', align: "left", formatter: function(value, item, index) { if (item.menuType == 'M') { @@ -113,21 +120,30 @@ { field: 'visible', title: '可见', - width: '10%', + width: '10', + widthUnit: '%', align: "left", formatter: function(value, row, index) { + if (row.menuType == 'F') { + return '-'; + } return $.table.selectDictLabel(datas, row.visible); } }, { field: 'perms', title: '权限标识', - width: '15%', + width: '15', + widthUnit: '%', align: "left", + formatter: function(value, row, index) { + return $.table.tooltip(value); + } }, { title: '操作', - width: '20%', + width: '20', + widthUnit: '%', align: "left", formatter: function(value, row, index) { var actions = []; 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/notice/notice.html b/ruoyi-admin/src/main/resources/templates/system/notice/notice.html index ab117fad5..eb7d30dd2 100644 --- a/ruoyi-admin/src/main/resources/templates/system/notice/notice.html +++ b/ruoyi-admin/src/main/resources/templates/system/notice/notice.html @@ -44,7 +44,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/post/post.html b/ruoyi-admin/src/main/resources/templates/system/post/post.html index 6166546c5..52700770f 100644 --- a/ruoyi-admin/src/main/resources/templates/system/post/post.html +++ b/ruoyi-admin/src/main/resources/templates/system/post/post.html @@ -47,7 +47,7 @@
    -
    +
    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..82d3f439b 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("")
    - +
    @@ -42,9 +42,15 @@
    - +
    - + + + +
    @@ -111,6 +117,30 @@ focusCleanup: true }); + $('input').on('ifChanged', function(obj){ + var type = $(this).val(); + var checked = obj.currentTarget.checked; + if (type == 1) { + if (checked) { + $._tree.expandAll(true); + } else { + $._tree.expandAll(false); + } + } else if (type == "2") { + if (checked) { + $._tree.checkAllNodes(true); + } else { + $._tree.checkAllNodes(false); + } + } else if (type == "3") { + if (checked) { + $._tree.setting.check.chkboxType = { "Y": "ps", "N": "ps" }; + } else { + $._tree.setting.check.chkboxType = { "Y": "", "N": "" }; + } + } + }) + function submitHandler() { if ($.validate.form()) { add(); 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 f474d901d..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 @@ - +
    @@ -39,7 +39,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..d3b5513a9 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 @@
    - +
    @@ -34,9 +34,15 @@
    - +
    -
    + + + +
    @@ -55,6 +61,30 @@ }; $.tree.init(options); }); + + $('input').on('ifChanged', function(obj){ + var type = $(this).val(); + var checked = obj.currentTarget.checked; + if (type == 1) { + if (checked) { + $._tree.expandAll(true); + } else { + $._tree.expandAll(false); + } + } else if (type == "2") { + if (checked) { + $._tree.checkAllNodes(true); + } else { + $._tree.checkAllNodes(false); + } + } else if (type == "3") { + if (checked) { + $._tree.setting.check.chkboxType = { "Y": "ps", "N": "ps" }; + } else { + $._tree.setting.check.chkboxType = { "Y": "", "N": "" }; + } + } + }) function submitHandler() { if ($.validate.form()) { 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 063968e32..354380d16 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("")
    - +
    @@ -43,9 +43,15 @@
    - +
    - + + + +
    @@ -117,6 +123,30 @@ }, focusCleanup: true }); + + $('input').on('ifChanged', function(obj){ + var type = $(this).val(); + var checked = obj.currentTarget.checked; + if (type == 1) { + if (checked) { + $._tree.expandAll(true); + } else { + $._tree.expandAll(false); + } + } else if (type == "2") { + if (checked) { + $._tree.checkAllNodes(true); + } else { + $._tree.checkAllNodes(false); + } + } else if (type == "3") { + if (checked) { + $._tree.setting.check.chkboxType = { "Y": "ps", "N": "ps" }; + } else { + $._tree.setting.check.chkboxType = { "Y": "", "N": "" }; + } + } + }) function edit() { var roleId = $("input[name='roleId']").val(); 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 61a3f1197..18628819e 100644 --- a/ruoyi-admin/src/main/resources/templates/system/role/role.html +++ b/ruoyi-admin/src/main/resources/templates/system/role/role.html @@ -53,7 +53,7 @@
    -
    +
    @@ -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/role/selectUser.html b/ruoyi-admin/src/main/resources/templates/system/role/selectUser.html index 8bafb7460..25b50675d 100644 --- a/ruoyi-admin/src/main/resources/templates/system/role/selectUser.html +++ b/ruoyi-admin/src/main/resources/templates/system/role/selectUser.html @@ -28,7 +28,7 @@
    -
    +
    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 0d5e97716..c7f25c5ad 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,10 +20,10 @@
    - +
    - +
    @@ -33,17 +33,23 @@
    - +
    - +
    + + +
    - +
    - +
    + + +
    @@ -51,17 +57,22 @@
    - +
    - +
    - +
    - +
    + + +
    @@ -149,7 +160,7 @@ type: "post", dataType: "json", data: { - name : function() { + "loginName": function() { return $.common.trim($("#loginName").val()); } }, @@ -169,7 +180,7 @@ type: "post", dataType: "json", data: { - name: function () { + "email": function () { return $.common.trim($("#email").val()); } }, @@ -185,7 +196,7 @@ type: "post", dataType: "json", data: { - name: function () { + "phonenumber": function () { return $.common.trim($("#phonenumber").val()); } }, @@ -210,7 +221,9 @@ }); 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"); @@ -222,7 +235,7 @@ } } - /*用户管理-新增-选择部门树*/ + /* 用户管理-新增-选择部门树 */ function selectDeptTree() { var treeId = $("#treeId").val(); var deptId = $.common.isEmpty(treeId) ? "100" : $("#treeId").val(); @@ -238,20 +251,18 @@ function doSubmit(index, layero){ var tree = layero.find("iframe")[0].contentWindow.$._tree; - if ($.tree.notAllowParents(tree)) { - var body = layer.getChildFrame('body', index); - $("#treeId").val(body.find('#treeId').val()); - $("#treeName").val(body.find('#treeName').val()); - layer.close(index); - } + var body = layer.getChildFrame('body', index); + $("#treeId").val(body.find('#treeId').val()); + $("#treeName").val(body.find('#treeName').val()); + layer.close(index); } $(function() { $('#post').select2({ - placeholder:"请选择岗位", + placeholder: "请选择岗位", allowClear: true }); }) - + \ No newline at end of file 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 d7a0c31b4..3d598dbd4 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,10 +21,10 @@
    - +
    - +
    @@ -34,17 +34,23 @@
    - +
    - +
    + + +
    - +
    - +
    + + +
    @@ -52,7 +58,7 @@
    - +
    @@ -194,7 +200,7 @@ } } - /*用户管理-修改-选择部门树*/ + /* 用户管理-修改-选择部门树 */ function selectDeptTree() { var deptId = $.common.isEmpty($("#treeId").val()) ? "100" : $("#treeId").val(); var url = ctx + "system/dept/selectDeptTree/" + deptId; @@ -209,17 +215,15 @@ function doSubmit(index, layero){ var tree = layero.find("iframe")[0].contentWindow.$._tree; - if ($.tree.notAllowParents(tree)) { - var body = layer.getChildFrame('body', index); - $("#treeId").val(body.find('#treeId').val()); - $("#treeName").val(body.find('#treeName').val()); - layer.close(index); - } + var body = layer.getChildFrame('body', index); + $("#treeId").val(body.find('#treeId').val()); + $("#treeName").val(body.find('#treeName').val()); + layer.close(index); } $(function() { $('#post').select2({ - placeholder:"请选择岗位", + placeholder: "请选择岗位", allowClear: true }); }) 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..1951aadd2 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..78c0b5102 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 @@
    - +
    @@ -114,6 +115,16 @@
    + + + + 密码只能为0-9数字 + 密码只能为a-z和A-Z字母 + 密码必须包含(字母,数字) + 密码必须包含(字母,数字,特殊字符!@#$%^&*()-=_+) + + +
    @@ -143,9 +154,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, @@ -250,7 +280,7 @@ }, newPassword: { required: "请输入新密码", - minlength: "密码不能小于6个字符", + minlength: "密码不能小于5个字符", maxlength: "密码不能大于20个字符" }, confirmPassword: { @@ -263,7 +293,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..32b5ffbb4 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 @@ -1,92 +1,104 @@ - + -
    -
    - -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - - 请再次输入您的密码 -
    -
    -
    -
    - +
    +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + + + + + 密码只能为0-9数字 + 密码只能为a-z和A-Z字母 + 密码必须包含(字母,数字) + 密码必须包含(字母,数字,特殊字符!@#$%^&*()-=_+) + + + +
    +
    +
    + +
    + + 请再次输入您的密码 +
    +
    +
    +
    + - + }, + focusCleanup: true + }); + + function submitHandler() { + 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 b261e35af..21d506c37 100644 --- a/ruoyi-admin/src/main/resources/templates/system/user/user.html +++ b/ruoyi-admin/src/main/resources/templates/system/user/user.html @@ -80,7 +80,7 @@
    -
    +
    @@ -101,6 +101,14 @@ panehHidden = true; } $('body').layout({ initClosed: panehHidden, west__size: 185 }); + // 回到顶部绑定 + if ($.fn.toTop !== undefined) { + var opt = { + win:$('.ui-layout-center'), + doc:$('.ui-layout-center') + }; + $('#scroll-up').toTop(opt); + } queryUserList(); queryDeptTree(); }); @@ -166,7 +174,10 @@ var actions = []; actions.push('编辑 '); actions.push('删除 '); - actions.push('重置'); + var more = []; + more.push("重置密码 "); + more.push("分配角色"); + actions.push('更多操作'); return actions.join(''); } }] @@ -219,6 +230,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 435fe9ff6..daa8b44a9 100644 --- a/ruoyi-admin/src/main/resources/templates/tool/build/build.html +++ b/ruoyi-admin/src/main/resources/templates/tool/build/build.html @@ -111,12 +111,10 @@
    -
    -
    - - -
    -
    +
    + + +
    @@ -164,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 fe5fc81cf..b5e84fabc 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -5,102 +5,102 @@ ruoyi com.ruoyi - 4.0.0 + 4.5.1 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 - - - - - com.github.pagehelper - pagehelper-spring-boot-starter - - - - 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.jsoup - jsoup - - - - - org.apache.poi - poi-ooxml - - - - - org.yaml - snakeyaml - - - + + - javax.servlet - javax.servlet-api - - + org.apache.shiro + shiro-ehcache + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + + + + + 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/DataSource.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java index a272a5b7b..6b41ee739 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java @@ -10,7 +10,9 @@ import com.ruoyi.common.enums.DataSourceType; /** * 自定义多数据源切换注解 - * + * + * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 + * * @author ruoyi */ @Target({ ElementType.METHOD, ElementType.TYPE }) 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 2112128a8..bfe119e46 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,6 +4,7 @@ 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数据注解 @@ -14,6 +15,11 @@ import java.lang.annotation.Target; @Target(ElementType.FIELD) public @interface Excel { + /** + * 导出时在excel中排序 + */ + public int sort() default Integer.MAX_VALUE; + /** * 导出到Excel中的名字. */ @@ -24,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字符串) */ @@ -74,6 +100,32 @@ public @interface Excel */ public String targetAttr() default ""; + /** + * 是否自动统计数据,在最后追加一行统计数据总和 + */ + public boolean isStatistics() default false; + + /** + * 导出字段对齐方式(0:默认;1:靠左;2:居中;3:靠右) + */ + Align align() default Align.AUTO; + + public enum Align + { + AUTO(0), LEFT(1), CENTER(2), RIGHT(3); + private final int value; + + Align(int value) + { + this.value = value; + } + + public int value() + { + return this.value; + } + } + /** * 字段类型(0:导出导入;1:仅导出;2:仅导入) */ 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 72ac2ecca..4f91b0b6c 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; @@ -13,7 +12,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/config/Global.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/Global.java deleted file mode 100644 index 7509d3ae7..000000000 --- a/ruoyi-common/src/main/java/com/ruoyi/common/config/Global.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.ruoyi.common.config; - -import java.io.FileNotFoundException; -import java.util.HashMap; -import java.util.Map; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.common.utils.YamlUtil; - -/** - * 全局配置类 - * - * @author ruoyi - */ -public class Global -{ - private static final Logger log = LoggerFactory.getLogger(Global.class); - - private static String NAME = "application.yml"; - - /** - * 当前对象实例 - */ - private static Global global; - - /** - * 保存全局属性值 - */ - private static Map map = new HashMap(); - - private Global() - { - } - - /** - * 静态工厂方法 - */ - public static synchronized Global getInstance() - { - if (global == null) - { - global = new Global(); - } - return global; - } - - /** - * 获取配置 - */ - public static String getConfig(String key) - { - String value = map.get(key); - if (value == null) - { - Map yamlMap = null; - try - { - yamlMap = YamlUtil.loadYaml(NAME); - value = String.valueOf(YamlUtil.getProperty(yamlMap, key)); - map.put(key, value != null ? value : StringUtils.EMPTY); - } - catch (FileNotFoundException e) - { - log.error("获取全局配置异常 {}", key); - } - } - return value; - } - - /** - * 获取项目名称 - */ - public static String getName() - { - return StringUtils.nvl(getConfig("ruoyi.name"), "RuoYi"); - } - - /** - * 获取项目版本 - */ - public static String getVersion() - { - return StringUtils.nvl(getConfig("ruoyi.version"), "4.0.0"); - } - - /** - * 获取版权年份 - */ - public static String getCopyrightYear() - { - return StringUtils.nvl(getConfig("ruoyi.copyrightYear"), "2019"); - } - - /** - * 实例演示开关 - */ - public static String isDemoEnabled() - { - return StringUtils.nvl(getConfig("ruoyi.demoEnabled"), "true"); - } - - /** - * 获取ip地址开关 - */ - public static Boolean isAddressEnabled() - { - return Boolean.valueOf(getConfig("ruoyi.addressEnabled")); - } - - /** - * 获取文件上传路径 - */ - public static String getProfile() - { - return getConfig("ruoyi.profile"); - } - - /** - * 获取头像上传路径 - */ - public static String getAvatarPath() - { - return getProfile() + "/avatar"; - } - - /** - * 获取下载路径 - */ - public static String getDownloadPath() - { - return getProfile() + "/download"; - } - - /** - * 获取上传路径 - */ - public static String getUploadPath() - { - return getProfile() + "/upload"; - } -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java new file mode 100644 index 000000000..10f5ca797 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java @@ -0,0 +1,116 @@ +package com.ruoyi.common.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 全局配置类 + * + * @author ruoyi + */ +@Component +@ConfigurationProperties(prefix = "ruoyi") +public class RuoYiConfig +{ + /** 项目名称 */ + private static String name; + + /** 版本 */ + private static String version; + + /** 版权年份 */ + private static String copyrightYear; + + /** 实例演示开关 */ + private static boolean demoEnabled; + + /** 上传路径 */ + private static String profile; + + /** 获取地址开关 */ + private static boolean addressEnabled; + + public static String getName() + { + return name; + } + + public void setName(String name) + { + RuoYiConfig.name = name; + } + + public static String getVersion() + { + return version; + } + + public void setVersion(String version) + { + RuoYiConfig.version = version; + } + + public static String getCopyrightYear() + { + return copyrightYear; + } + + public void setCopyrightYear(String copyrightYear) + { + RuoYiConfig.copyrightYear = copyrightYear; + } + + public static boolean isDemoEnabled() + { + return demoEnabled; + } + + public void setDemoEnabled(boolean demoEnabled) + { + RuoYiConfig.demoEnabled = demoEnabled; + } + + public static String getProfile() + { + return profile; + } + + public void setProfile(String profile) + { + RuoYiConfig.profile = profile; + } + + public static boolean isAddressEnabled() + { + return addressEnabled; + } + + public void setAddressEnabled(boolean addressEnabled) + { + RuoYiConfig.addressEnabled = addressEnabled; + } + + /** + * 获取头像上传路径 + */ + public static String getAvatarPath() + { + return getProfile() + "/avatar"; + } + + /** + * 获取下载路径 + */ + public static String getDownloadPath() + { + return getProfile() + "/download/"; + } + + /** + * 获取上传路径 + */ + public static String getUploadPath() + { + return getProfile() + "/upload"; + } +} 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 1a52c1f7f..3c6554582 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 @@ -12,6 +12,11 @@ public class Constants */ public static final String UTF8 = "UTF-8"; + /** + * GBK 字符集 + */ + public static final String GBK = "GBK"; + /** * 通用成功标识 */ @@ -32,16 +37,16 @@ public class Constants */ public static final String LOGOUT = "Logout"; + /** + * 注册 + */ + public static final String REGISTER = "Register"; + /** * 登录失败 */ public static final String LOGIN_FAIL = "Error"; - /** - * 自动去除表前缀 - */ - public static final String AUTO_REOMVE_PRE = "true"; - /** * 当前记录起始索引 */ @@ -61,4 +66,34 @@ public class Constants * 排序的方向 "desc" 或者 "asc". */ public static final String IS_ASC = "isAsc"; + + /** + * 系统用户授权缓存 + */ + public static final String SYS_AUTH_CACHE = "sys-authCache"; + + /** + * 参数管理 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:"; + + /** + * 资源映射路径 前缀 + */ + public static final String RESOURCE_PREFIX = "/profile"; } 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 5a55c29d4..c6b8339db 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 @@ -13,6 +13,9 @@ public class GenConstants /** 树表(增删改查) */ public static final String TPL_TREE = "tree"; + /** 主子表(增删改查) */ + public static final String TPL_SUB = "sub"; + /** 树编码字段 */ public static final String TREE_CODE = "treeCode"; @@ -22,8 +25,14 @@ public class GenConstants /** 树名称字段 */ public static final String TREE_NAME = "treeName"; + /** 上级菜单ID字段 */ + public static final String PARENT_MENU_ID = "parentMenuId"; + + /** 上级菜单名称字段 */ + public static final String PARENT_MENU_NAME = "parentMenuName"; + /** 数据库字符串类型 */ - public static final String[] COLUMNTYPE_STR = { "char", "varchar", "narchar", "varchar2", "tinytext", "text", + public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2", "tinytext", "text", "mediumtext", "longtext" }; /** 数据库时间类型 */ @@ -31,7 +40,7 @@ public class GenConstants /** 数据库数字类型 */ public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer", - "bigint", "float", "float", "double", "decimal" }; + "bit", "bigint", "float", "double", "decimal" }; /** 页面不需要编辑字段 */ public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" }; @@ -44,6 +53,12 @@ public class GenConstants 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"; @@ -62,6 +77,12 @@ public class GenConstants /** 日期控件 */ 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"; @@ -81,7 +102,7 @@ public class GenConstants public static final String TYPE_DATE = "Date"; /** 模糊查询 */ - public static final String QUERY_LIKE = "Like"; + 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 b82036666..8318b8f5f 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 @@ -5,7 +5,7 @@ package com.ruoyi.common.constant; * * @author ruoyi */ -public interface ScheduleConstants +public class ScheduleConstants { public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME"; 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 c5027c240..dfa57dbfb 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 @@ -5,7 +5,7 @@ package com.ruoyi.common.constant; * * @author ruoyi */ -public interface ShiroConstants +public class ShiroConstants { /** * 当前登录的用户 @@ -13,29 +13,34 @@ public interface ShiroConstants public static final String CURRENT_USER = "currentUser"; /** - * 用户名 + * 用户名字段 */ public static final String CURRENT_USERNAME = "username"; + /** + * 锁定屏幕字段 + */ + public static final String LOCK_SCREEN = "lockscreen"; + /** * 消息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 a51ba3bfd..336652481 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 @@ -19,14 +19,17 @@ public class UserConstants 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"; @@ -89,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 a6c350d13..87e91b26f 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 @@ -81,6 +81,19 @@ public class BaseController } + /* + * 设置请求排序数据 + */ + 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/AjaxResult.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java index 5463547aa..ebd301ea5 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java @@ -1,23 +1,24 @@ package com.ruoyi.common.core.domain; import java.util.HashMap; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.utils.StringUtils; /** * 操作消息提醒 - * + * * @author ruoyi */ public class AjaxResult extends HashMap { private static final long serialVersionUID = 1L; + /** 状态码 */ public static final String CODE_TAG = "code"; + /** 返回内容 */ public static final String MSG_TAG = "msg"; + /** 数据对象 */ public static final String DATA_TAG = "data"; /** @@ -44,18 +45,6 @@ public class AjaxResult extends HashMap } } - /** 状态类型 */ - private Type type; - - /** 状态码 */ - private int code; - - /** 返回内容 */ - private String msg; - - /** 数据对象 */ - private Object data; - /** * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 */ @@ -65,7 +54,7 @@ public class AjaxResult extends HashMap /** * 初始化一个新创建的 AjaxResult 对象 - * + * * @param type 状态类型 * @param msg 返回内容 */ @@ -77,7 +66,7 @@ public class AjaxResult extends HashMap /** * 初始化一个新创建的 AjaxResult 对象 - * + * * @param type 状态类型 * @param msg 返回内容 * @param data 数据对象 @@ -92,9 +81,23 @@ public class AjaxResult extends HashMap } } + /** + * 方便链式调用 + * + * @param key 键 + * @param value 值 + * @return 数据对象 + */ + @Override + public AjaxResult put(String key, Object value) + { + super.put(key, value); + return this; + } + /** * 返回成功消息 - * + * * @return 成功消息 */ public static AjaxResult success() @@ -104,7 +107,7 @@ public class AjaxResult extends HashMap /** * 返回成功数据 - * + * * @return 成功消息 */ public static AjaxResult success(Object data) @@ -114,7 +117,7 @@ public class AjaxResult extends HashMap /** * 返回成功消息 - * + * * @param msg 返回内容 * @return 成功消息 */ @@ -125,7 +128,7 @@ public class AjaxResult extends HashMap /** * 返回成功消息 - * + * * @param msg 返回内容 * @param data 数据对象 * @return 成功消息 @@ -137,7 +140,7 @@ public class AjaxResult extends HashMap /** * 返回警告消息 - * + * * @param msg 返回内容 * @return 警告消息 */ @@ -148,7 +151,7 @@ public class AjaxResult extends HashMap /** * 返回警告消息 - * + * * @param msg 返回内容 * @param data 数据对象 * @return 警告消息 @@ -160,7 +163,7 @@ public class AjaxResult extends HashMap /** * 返回错误消息 - * + * * @return */ public static AjaxResult error() @@ -170,7 +173,7 @@ public class AjaxResult extends HashMap /** * 返回错误消息 - * + * * @param msg 返回内容 * @return 警告消息 */ @@ -181,7 +184,7 @@ public class AjaxResult extends HashMap /** * 返回错误消息 - * + * * @param msg 返回内容 * @param data 数据对象 * @return 警告消息 @@ -190,53 +193,4 @@ public class AjaxResult extends HashMap { return new AjaxResult(Type.ERROR, msg, data); } - - public Type getType() - { - return type; - } - - public void setType(Type type) - { - this.type = type; - } - - public int getCode() - { - return code; - } - - public void setCode(int code) - { - this.code = code; - } - - public String getMsg() - { - return msg; - } - - public void setMsg(String msg) - { - this.msg = msg; - } - - public Object getData() - { - return data; - } - - public void setData(Object data) - { - this.data = data; - } - - @Override - public String toString() { - return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) - .append("code", getCode()) - .append("msg", getMsg()) - .append("data", getData()) - .toString(); - } } 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/domain/TreeEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java index d580f027b..7a0efe62a 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java @@ -18,6 +18,9 @@ public class TreeEntity extends BaseEntity /** 显示顺序 */ private Integer orderNum; + /** 祖级列表 */ + private String ancestors; + public String getParentName() { return parentName; @@ -47,4 +50,14 @@ public class TreeEntity extends BaseEntity { this.orderNum = orderNum; } + + public String getAncestors() + { + return ancestors; + } + + public void setAncestors(String ancestors) + { + this.ancestors = ancestors; + } } \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java similarity index 94% rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDept.java rename to ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java index 4d86400d1..e8530a9cf 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDept.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java @@ -1,4 +1,4 @@ -package com.ruoyi.system.domain; +package com.ruoyi.common.core.domain.entity; import javax.validation.constraints.*; import org.apache.commons.lang3.builder.ToStringBuilder; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictData.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java similarity index 95% rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictData.java rename to ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java index 4b8146a72..c1d357400 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictData.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java @@ -1,4 +1,4 @@ -package com.ruoyi.system.domain; +package com.ruoyi.common.core.domain.entity; import javax.validation.constraints.*; import org.apache.commons.lang3.builder.ToStringBuilder; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictType.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java similarity index 93% rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictType.java rename to ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java index 11de732e0..ad7c5320a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysDictType.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java @@ -1,4 +1,4 @@ -package com.ruoyi.system.domain; +package com.ruoyi.common.core.domain.entity; import javax.validation.constraints.*; import org.apache.commons.lang3.builder.ToStringBuilder; @@ -25,7 +25,7 @@ public class SysDictType extends BaseEntity private String dictName; /** 字典类型 */ - @Excel(name = "字典类型 ") + @Excel(name = "字典类型") private String dictType; /** 状态(0正常 1停用) */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java similarity index 86% rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java rename to ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java index 8a0f83f44..da1869a5c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysMenu.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java @@ -1,4 +1,4 @@ -package com.ruoyi.system.domain; +package com.ruoyi.common.core.domain.entity; import java.util.List; import java.util.ArrayList; @@ -34,15 +34,18 @@ public class SysMenu extends BaseEntity /** 菜单URL */ private String url; - /** 打开方式:menuItem页签 menuBlank新窗口 */ + /** 打开方式(menuItem页签 menuBlank新窗口) */ private String target; - /** 类型:0目录,1菜单,2按钮 */ + /** 类型(M目录 C菜单 F按钮) */ private String menuType; - /** 菜单状态:0显示,1隐藏 */ + /** 菜单状态(0显示 1隐藏) */ private String visible; + /** 是否刷新(0刷新 1不刷新) */ + private String isRefresh; + /** 权限字符串 */ private String perms; @@ -147,6 +150,16 @@ public class SysMenu extends BaseEntity this.visible = visible; } + public String getIsRefresh() + { + return isRefresh; + } + + public void setIsRefresh(String isRefresh) + { + this.isRefresh = isRefresh; + } + @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符") public String getPerms() { diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRole.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java similarity index 88% rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRole.java rename to ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java index a639621dc..e8ea03a31 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRole.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java @@ -1,4 +1,4 @@ -package com.ruoyi.system.domain; +package com.ruoyi.common.core.domain.entity; import javax.validation.constraints.*; import org.apache.commons.lang3.builder.ToStringBuilder; @@ -52,6 +52,16 @@ public class SysRole extends BaseEntity /** 部门组(数据权限) */ private Long[] deptIds; + public SysRole() + { + + } + + public SysRole(Long roleId) + { + this.roleId = roleId; + } + public Long getRoleId() { return roleId; @@ -62,6 +72,16 @@ public class SysRole extends BaseEntity this.roleId = roleId; } + public boolean isAdmin() + { + return isAdmin(this.roleId); + } + + public static boolean isAdmin(Long roleId) + { + return roleId != null && 1L == roleId; + } + public String getDataScope() { return dataScope; @@ -157,6 +177,7 @@ public class SysRole extends BaseEntity this.deptIds = deptIds; } + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) .append("roleId", getRoleId()) diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java similarity index 84% rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java rename to ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java index c1e5ac969..f3ff4d9f3 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUser.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java @@ -1,10 +1,11 @@ -package com.ruoyi.system.domain; +package com.ruoyi.common.core.domain.entity; import java.util.Date; import java.util.List; import javax.validation.constraints.*; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.ruoyi.common.annotation.Excel; import com.ruoyi.common.annotation.Excel.ColumnType; import com.ruoyi.common.annotation.Excel.Type; @@ -42,6 +43,9 @@ public class SysUser extends BaseEntity @Excel(name = "用户名称") private String userName; + /** 用户类型 */ + private String userType; + /** 用户邮箱 */ @Excel(name = "用户邮箱") private String email; @@ -70,14 +74,17 @@ public class SysUser extends BaseEntity /** 删除标志(0代表存在 2代表删除) */ private String delFlag; - /** 最后登陆IP */ - @Excel(name = "最后登陆IP", type = Type.EXPORT) + /** 最后登录IP */ + @Excel(name = "最后登录IP", type = Type.EXPORT) private String loginIp; - /** 最后登陆时间 */ - @Excel(name = "最后登陆时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) + /** 最后登录时间 */ + @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) private Date loginDate; + /** 密码最后更新时间 */ + private Date pwdUpdateDate; + /** 部门对象 */ @Excels({ @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), @@ -93,6 +100,16 @@ public class SysUser extends BaseEntity /** 岗位组 */ private Long[] postIds; + public SysUser() + { + + } + + public SysUser(Long userId) + { + this.userId = userId; + } + public Long getUserId() { return userId; @@ -166,6 +183,16 @@ public class SysUser extends BaseEntity this.userName = userName; } + public String getUserType() + { + return userType; + } + + public void setUserType(String userType) + { + this.userType = userType; + } + @Email(message = "邮箱格式不正确") @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") public String getEmail() @@ -209,6 +236,7 @@ public class SysUser extends BaseEntity this.avatar = avatar; } + @JsonIgnore public String getPassword() { return password; @@ -269,6 +297,16 @@ public class SysUser extends BaseEntity this.loginDate = loginDate; } + public Date getPwdUpdateDate() + { + return pwdUpdateDate; + } + + public void setPwdUpdateDate(Date pwdUpdateDate) + { + this.pwdUpdateDate = pwdUpdateDate; + } + public SysDept getDept() { if (dept == null) @@ -320,6 +358,7 @@ public class SysUser extends BaseEntity .append("deptId", getDeptId()) .append("loginName", getLoginName()) .append("userName", getUserName()) + .append("userType", getUserType()) .append("email", getEmail()) .append("phonenumber", getPhonenumber()) .append("sex", getSex()) @@ -336,6 +375,7 @@ public class SysUser extends BaseEntity .append("updateTime", getUpdateTime()) .append("remark", getRemark()) .append("dept", getDept()) + .append("roles", getRoles()) .toString(); } } 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 7fccaf46e..23f1f8bd5 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 @@ -11,12 +11,15 @@ public class PageDomain { /** 当前记录起始索引 */ private Integer pageNum; + /** 每页显示记录数 */ private Integer pageSize; + /** 排序列 */ private String orderByColumn; - /** 排序的方向 "desc" 或者 "asc". */ - private String isAsc; + + /** 排序的方向desc或者asc */ + private String isAsc = "asc"; public String getOrderBy() { 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 82dca3716..29f60e7fc 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 @@ -22,7 +22,7 @@ public class TableDataInfo implements Serializable private int code; /** 消息内容 */ - private int msg; + private String msg; /** * 表格数据对象 @@ -73,12 +73,12 @@ public class TableDataInfo implements Serializable this.code = code; } - public int getMsg() + public String getMsg() { return msg; } - public void setMsg(int msg) + public void setMsg(String msg) { this.msg = msg; } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java index 8297661af..4fa575ce1 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java @@ -66,7 +66,7 @@ public class CharsetKit if (null == destCharset) { - srcCharset = StandardCharsets.UTF_8; + destCharset = StandardCharsets.UTF_8; } if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) 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 81cd78b81..8954bbb10 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 @@ -68,4 +68,14 @@ public class InvalidExtensionException extends FileUploadException 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 437137dea..913ebb176 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,9 +2,9 @@ package com.ruoyi.common.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ruoyi.common.config.Global; -import com.ruoyi.common.json.JSON; -import com.ruoyi.common.json.JSONObject; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.http.HttpUtils; /** @@ -16,37 +16,38 @@ 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 final String UNKNOWN = "XX XX"; public static String getRealAddressByIP(String ip) { - String address = "XX XX"; - + String address = UNKNOWN; // 内网不查询 if (IpUtils.internalIp(ip)) { return "内网IP"; } - if (Global.isAddressEnabled()) + if (RuoYiConfig.isAddressEnabled()) { - String rspStr = HttpUtils.sendPost(IP_URL, "ip=" + ip); - if (StringUtils.isEmpty(rspStr)) - { - log.error("获取地理位置异常 {}", ip); - return address; - } - 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; + 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); } catch (Exception e) { - log.error("获取地理位置异常 {}", ip); + 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..ae27682de --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/CacheUtils.java @@ -0,0 +1,197 @@ +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.apache.shiro.cache.ehcache.EhCacheManager; +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 + */ + public static Cache getCache(String cacheName) + { + Cache cache = cacheManager.getCache(cacheName); + if (cache == null) + { + throw new RuntimeException("当前系统中没有定义“" + cacheName + "”这个缓存。"); + } + return cache; + } + + /** + * 获取所有缓存 + * + * @return 缓存组 + */ + public static String[] getCacheNames() + { + return ((EhCacheManager) cacheManager).getCacheManager().getCacheNames(); + } +} 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/DateUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java index 8ff95f1b7..4b45f35bd 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java @@ -131,6 +131,14 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils return new Date(time); } + /** + * 计算相差天数 + */ + public static int differentDaysByMillisecond(Date date1, Date date2) + { + return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24))); + } + /** * 计算两个时间差 */ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java new file mode 100644 index 000000000..d5c324fc9 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java @@ -0,0 +1,181 @@ +package com.ruoyi.common.utils; + +import java.util.List; +import org.springframework.stereotype.Component; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.core.domain.entity.SysDictData; + +/** + * 字典工具类 + * + * @author ruoyi + */ +@Component +public class DictUtils +{ + /** + * 分隔符 + */ + public static final String SEPARATOR = ","; + + /** + * 设置字典缓存 + * + * @param key 参数键 + * @param dictDatas 字典数据列表 + */ + public static void setDictCache(String key, List dictDatas) + { + CacheUtils.put(getCacheName(), getCacheKey(key), dictDatas); + } + + /** + * 获取字典缓存 + * + * @param key 参数键 + * @return dictDatas 字典数据列表 + */ + public static List getDictCache(String key) + { + Object cacheObj = CacheUtils.get(getCacheName(), getCacheKey(key)); + if (StringUtils.isNotNull(cacheObj)) + { + List DictDatas = StringUtils.cast(cacheObj); + return DictDatas; + } + return null; + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @return 字典标签 + */ + public static String getDictLabel(String dictType, String dictValue) + { + return getDictLabel(dictType, dictValue, SEPARATOR); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @return 字典值 + */ + public static String getDictValue(String dictType, String dictLabel) + { + return getDictValue(dictType, dictLabel, SEPARATOR); + } + + /** + * 根据字典类型和字典值获取字典标签 + * + * @param dictType 字典类型 + * @param dictValue 字典值 + * @param separator 分隔符 + * @return 字典标签 + */ + public static String getDictLabel(String dictType, String dictValue, String separator) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + + if (StringUtils.containsAny(separator, dictValue) && StringUtils.isNotEmpty(datas)) + { + for (SysDictData dict : datas) + { + for (String value : dictValue.split(separator)) + { + if (value.equals(dict.getDictValue())) + { + propertyString.append(dict.getDictLabel() + separator); + break; + } + } + } + } + else + { + for (SysDictData dict : datas) + { + if (dictValue.equals(dict.getDictValue())) + { + return dict.getDictLabel(); + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 根据字典类型和字典标签获取字典值 + * + * @param dictType 字典类型 + * @param dictLabel 字典标签 + * @param separator 分隔符 + * @return 字典值 + */ + public static String getDictValue(String dictType, String dictLabel, String separator) + { + StringBuilder propertyString = new StringBuilder(); + List datas = getDictCache(dictType); + + if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas)) + { + for (SysDictData dict : datas) + { + for (String label : dictLabel.split(separator)) + { + if (label.equals(dict.getDictLabel())) + { + propertyString.append(dict.getDictValue() + separator); + break; + } + } + } + } + else + { + for (SysDictData dict : datas) + { + if (dictLabel.equals(dict.getDictLabel())) + { + return dict.getDictValue(); + } + } + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 清空字典缓存 + */ + public static void clearDictCache() + { + CacheUtils.removeAll(getCacheName()); + } + + /** + * 获取cache name + * + * @return 缓存名 + */ + public static String getCacheName() + { + return Constants.SYS_DICT_CACHE; + } + + /** + * 设置cache key + * + * @param configKey 参数键 + * @return 缓存键key + */ + public static String getCacheKey(String configKey) + { + return Constants.SYS_DICT_KEY + configKey; + } +} 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 a2a7011b0..d699215a2 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 @@ -109,8 +109,9 @@ public class IpUtils { 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); @@ -118,12 +119,14 @@ 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); @@ -132,13 +135,15 @@ public class IpUtils 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; @@ -146,8 +151,9 @@ public class IpUtils 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; diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/util/LogUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java similarity index 95% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/util/LogUtils.java rename to ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java index 96a38eb55..d5a357c53 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/util/LogUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java @@ -1,4 +1,4 @@ -package com.ruoyi.framework.util; +package com.ruoyi.common.utils; import java.io.PrintWriter; import java.io.StringWriter; @@ -8,7 +8,6 @@ import org.apache.shiro.SecurityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ruoyi.common.json.JSON; -import com.ruoyi.common.utils.IpUtils; /** * 处理并记录日志文件 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 451b180fe..a5a190cdd 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 @@ -16,6 +16,11 @@ import com.ruoyi.common.core.text.Convert; */ public class ServletUtils { + /** + * 定义移动端请求的所有可能类型 + */ + private final static String[] agent = { "Android", "iPhone", "iPod", "iPad", "Windows Phone", "MQQBrowser" }; + /** * 获取String参数 */ @@ -132,4 +137,28 @@ public class ServletUtils } 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-framework/src/main/java/com/ruoyi/framework/util/ShiroUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ShiroUtils.java similarity index 78% rename from ruoyi-framework/src/main/java/com/ruoyi/framework/util/ShiroUtils.java rename to ruoyi-common/src/main/java/com/ruoyi/common/utils/ShiroUtils.java index a57f1197b..f0c894322 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/util/ShiroUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ShiroUtils.java @@ -1,17 +1,13 @@ -package com.ruoyi.framework.util; +package com.ruoyi.common.utils; import org.apache.shiro.SecurityUtils; import org.apache.shiro.crypto.SecureRandomNumberGenerator; -import org.apache.shiro.mgt.RealmSecurityManager; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.SimplePrincipalCollection; - -import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.utils.bean.BeanUtils; -import com.ruoyi.framework.shiro.realm.UserRealm; -import com.ruoyi.system.domain.SysUser; /** * shiro 工具类 @@ -57,13 +53,6 @@ public class ShiroUtils subject.runAs(newPrincipalCollection); } - public static void clearCachedAuthorizationInfo() - { - RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager(); - UserRealm realm = (UserRealm) rsm.getRealms().iterator().next(); - realm.clearCachedAuthorizationInfo(); - } - public static Long getUserId() { return getSysUser().getUserId().longValue(); 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 86dee8a8a..51174f1ea 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 @@ -301,7 +301,6 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } sb.append(Character.toLowerCase(c)); } - return sb.toString(); } @@ -364,7 +363,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } /** - * 驼峰式命名法 例如:user_name->userName + * 驼峰式命名法 + * 例如:user_name->userName */ public static String toCamelCase(String s) { @@ -372,6 +372,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { return null; } + if (s.indexOf(SEPARATOR) == -1) + { + return s; + } s = s.toLowerCase(); StringBuilder sb = new StringBuilder(s.length()); boolean upperCase = false; @@ -395,4 +399,10 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils } 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/FileTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java new file mode 100644 index 000000000..65be65b4a --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java @@ -0,0 +1,47 @@ +package com.ruoyi.common.utils.file; + +import java.io.File; +import org.apache.commons.lang3.StringUtils; + +/** + * 文件类型工具类 + * + * @author ruoyi + */ +public class FileTypeUtils +{ + /** + * 获取文件类型 + *

    + * 例如: ruoyi.txt, 返回: txt + * + * @param file 文件名 + * @return 后缀(不含".") + */ + public static String getFileType(File file) + { + if (null == file) + { + return StringUtils.EMPTY; + } + return getFileType(file.getName()); + } + + /** + * 获取文件类型 + *

    + * 例如: ruoyi.txt, 返回: txt + * + * @param fileName 文件名 + * @return 后缀(不含".") + */ + public static String getFileType(String fileName) + { + int separatorIndex = fileName.lastIndexOf("."); + if (separatorIndex < 0) + { + return ""; + } + return fileName.substring(separatorIndex + 1).toLowerCase(); + } +} \ No newline at end of file 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 6190a566b..52fdcdcd6 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 @@ -4,13 +4,14 @@ 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; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.constant.Constants; import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; 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; /** * 文件上传工具类 @@ -32,9 +33,7 @@ public class FileUploadUtils /** * 默认上传的地址 */ - private static String defaultBaseDir = Global.getProfile(); - - private static int counter = 0; + private static String defaultBaseDir = RuoYiConfig.getProfile(); public static void setDefaultBaseDir(String defaultBaseDir) { @@ -90,7 +89,7 @@ public class FileUploadUtils * * @param baseDir 相对应用的基目录 * @param file 上传的文件 - * @param extension 上传文件类型 + * @param allowedExtension 上传文件类型 * @return 返回上传成功的文件名 * @throws FileSizeLimitExceededException 如果超出最大大小 * @throws FileNameLengthLimitExceededException 文件名太长 @@ -124,7 +123,7 @@ public class FileUploadUtils { String fileName = file.getOriginalFilename(); String extension = getExtension(file); - fileName = DateUtils.datePath() + "/" + encodingFilename(fileName) + "." + extension; + fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension; return fileName; } @@ -132,35 +131,24 @@ public class FileUploadUtils { File desc = new File(uploadDir + File.separator + fileName); - if (!desc.getParentFile().exists()) - { - desc.getParentFile().mkdirs(); - } if (!desc.exists()) { - desc.createNewFile(); + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } } return desc; } private static final String getPathFileName(String uploadDir, String fileName) throws IOException { - int dirLastIndex = uploadDir.lastIndexOf("/") + 1; + int dirLastIndex = RuoYiConfig.getProfile().length() + 1; String currentDir = StringUtils.substring(uploadDir, dirLastIndex); - String pathFileName = "/profile/" + currentDir + "/" + fileName; + 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; - } - /** * 文件大小校验 * @@ -197,12 +185,16 @@ public class FileUploadUtils throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension, fileName); } + else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) + { + throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension, + fileName); + } else { throw new InvalidExtensionException(allowedExtension, extension, fileName); } } - } /** 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 03f5aa2a2..6bc2ce63c 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,14 +7,18 @@ 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; +import org.apache.commons.lang3.ArrayUtils; +import com.ruoyi.common.utils.StringUtils; /** * 文件处理工具类 * * @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]+"; @@ -104,6 +108,30 @@ public class FileUtils return filename.matches(FILENAME_PATTERN); } + /** + * 检查文件是否可下载 + * + * @param resource 需要下载的文件 + * @return true 正常 false 非法 + */ + public static boolean checkAllowDownload(String resource) + { + // 禁止目录上跳级别 + if (StringUtils.contains(resource, "..")) + { + return false; + } + + // 检查允许下载的文件规则 + if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource))) + { + return true; + } + + // 不在允许下载的文件规则 + return false; + } + /** * 下载文件名重新编码 * @@ -111,8 +139,7 @@ public class FileUtils * @param fileName 文件名 * @return 编码后的文件名 */ - public static String setFileDownloadHeader(HttpServletRequest request, String fileName) - throws UnsupportedEncodingException + public static String setFileDownloadHeader(HttpServletRequest request, String fileName) throws UnsupportedEncodingException { final String agent = request.getHeader("USER-AGENT"); String filename = fileName; @@ -139,4 +166,38 @@ public class FileUtils } 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 698464128..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 @@ -16,7 +16,7 @@ public class MimeTypeUtils public static final String IMAGE_BMP = "image/bmp"; public static final String IMAGE_GIF = "image/gif"; - + public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" }; public static final String[] FLASH_EXTENSION = { "swf", "flv" }; @@ -24,6 +24,8 @@ public class MimeTypeUtils 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 = { // 图片 "bmp", "gif", "jpg", "jpeg", "png", @@ -31,6 +33,8 @@ public class MimeTypeUtils "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt", // 压缩文件 "rar", "zip", "gz", "bz2", + // 视频格式 + "mp4", "avi", "rmvb", // pdf "pdf" }; 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 new file mode 100644 index 000000000..bf9980a36 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java @@ -0,0 +1,155 @@ +package com.ruoyi.common.utils.html; + +import com.ruoyi.common.utils.StringUtils; + +/** + * 转义和反转义工具类 + * + * @author ruoyi + */ +public class EscapeUtil +{ + public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)"; + + private static final char[][] TEXT = new char[64][]; + + static + { + for (int i = 0; i < 64; i++) + { + TEXT[i] = new char[] { (char) i }; + } + + // special HTML characters + TEXT['\''] = "'".toCharArray(); // 单引号 + TEXT['"'] = """.toCharArray(); // 单引号 + TEXT['&'] = "&".toCharArray(); // &符 + TEXT['<'] = "<".toCharArray(); // 小于号 + TEXT['>'] = ">".toCharArray(); // 大于号 + } + + /** + * 转义文本中的HTML字符为安全的字符 + * + * @param text 被转义的文本 + * @return 转义后的文本 + */ + public static String escape(String text) + { + return encode(text); + } + + /** + * 还原被转义的HTML特殊字符 + * + * @param content 包含转义符的HTML内容 + * @return 转换后的字符串 + */ + public static String unescape(String content) + { + return decode(content); + } + + /** + * 清除所有HTML标签,但是不删除标签内的内容 + * + * @param content 文本 + * @return 清除标签后的文本 + */ + public static String clean(String content) + { + return new HTMLFilter().filter(content); + } + + /** + * Escape编码 + * + * @param text 被编码的文本 + * @return 编码后的字符 + */ + private static String encode(String text) + { + int len; + if ((text == null) || ((len = text.length()) == 0)) + { + return StringUtils.EMPTY; + } + StringBuilder buffer = new StringBuilder(len + (len >> 2)); + char c; + for (int i = 0; i < len; i++) + { + c = text.charAt(i); + if (c < 64) + { + buffer.append(TEXT[c]); + } + else + { + buffer.append(c); + } + } + return buffer.toString(); + } + + /** + * Escape解码 + * + * @param content 被转义的内容 + * @return 解码后的字符串 + */ + public static String decode(String content) + { + if (StringUtils.isEmpty(content)) + { + return content; + } + + StringBuilder tmp = new StringBuilder(content.length()); + int lastPos = 0, pos = 0; + char ch; + while (lastPos < content.length()) + { + pos = content.indexOf("%", lastPos); + if (pos == lastPos) + { + if (content.charAt(pos + 1) == 'u') + { + ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16); + tmp.append(ch); + lastPos = pos + 6; + } + else + { + ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16); + tmp.append(ch); + lastPos = pos + 3; + } + } + else + { + if (pos == -1) + { + tmp.append(content.substring(lastPos)); + lastPos = content.length(); + } + else + { + tmp.append(content.substring(lastPos, pos)); + lastPos = pos; + } + } + } + return tmp.toString(); + } + + 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 new file mode 100644 index 000000000..cd8cd4ff8 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java @@ -0,0 +1,570 @@ +package com.ruoyi.common.utils.html; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * HTML过滤器,用于去除XSS漏洞隐患。 + * + * @author ruoyi + */ +public final class HTMLFilter +{ + /** + * regex flag union representing /si modifiers in php + **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("\""); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>(); + + /** + * set of allowed html elements, along with allowed attributes for each element + **/ + private final Map> vAllowed; + /** + * counts of open tags for each (allowable) html element + **/ + private final Map vTagCounts = new HashMap<>(); + + /** + * html elements which must always be self-closing (e.g. "") + **/ + private final String[] vSelfClosingTags; + /** + * html elements which must always have separate opening and closing tags (e.g. "") + **/ + private final String[] vNeedClosingTags; + /** + * set of disallowed html elements + **/ + private final String[] vDisallowed; + /** + * attributes which should be checked for valid protocols + **/ + private final String[] vProtocolAtts; + /** + * allowed protocols + **/ + private final String[] vAllowedProtocols; + /** + * tags which should be removed if they contain no content (e.g. "" or "") + **/ + private final String[] vRemoveBlanks; + /** + * entities allowed within html markup + **/ + private final String[] vAllowedEntities; + /** + * flag determining whether comments are allowed in input String. + */ + private final boolean stripComment; + private final boolean encodeQuotes; + /** + * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "" + * becomes " text "). If set to false, unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** + * Default constructor. + */ + public HTMLFilter() + { + vAllowed = new HashMap<>(); + + final ArrayList a_atts = new ArrayList<>(); + a_atts.add("href"); + a_atts.add("target"); + vAllowed.put("a", a_atts); + + final ArrayList img_atts = new ArrayList<>(); + img_atts.add("src"); + img_atts.add("width"); + img_atts.add("height"); + img_atts.add("alt"); + vAllowed.put("img", img_atts); + + final ArrayList no_atts = new ArrayList<>(); + vAllowed.put("b", no_atts); + vAllowed.put("strong", no_atts); + vAllowed.put("i", no_atts); + vAllowed.put("em", no_atts); + + vSelfClosingTags = new String[] { "img" }; + vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" }; + vDisallowed = new String[] {}; + vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp. + vProtocolAtts = new String[] { "src", "href" }; + vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" }; + vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" }; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = false; + } + + /** + * Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + @SuppressWarnings("unchecked") + public HTMLFilter(final Map conf) + { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + private void reset() + { + vTagCounts.clear(); + } + + // --------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr(final int decimal) + { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars(final String s) + { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + // --------------------------------------------------------------- + + /** + * given a user submitted input String, filter out any invalid or restricted html. + * + * @param input text (i.e. submitted by a user) than may contain html + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter(final String input) + { + reset(); + String s = input; + + s = escapeComments(s); + + s = balanceHTML(s); + + s = checkTags(s); + + s = processRemoveBlanks(s); + + // s = validateEntities(s); + + return s; + } + + public boolean isAlwaysMakeTags() + { + return alwaysMakeTags; + } + + public boolean isStripComments() + { + return stripComment; + } + + private String escapeComments(final String s) + { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) + { + final String match = m.group(1); // (.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHTML(String s) + { + if (alwaysMakeTags) + { + // + // 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); + + } + else + { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags(String s) + { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) + { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + final StringBuilder sBuilder = new StringBuilder(buf.toString()); + for (String key : vTagCounts.keySet()) + { + for (int ii = 0; ii < vTagCounts.get(key); ii++) + { + sBuilder.append(""); + } + } + s = sBuilder.toString(); + + return s; + } + + private String processRemoveBlanks(final String s) + { + String result = s; + for (String tag : vRemoveBlanks) + { + if (!P_REMOVE_PAIR_BLANKS.containsKey(tag)) + { + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if (!P_REMOVE_SELF_BLANKS.containsKey(tag)) + { + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) + { + Matcher m = regex_pattern.matcher(s); + return m.replaceAll(replacement); + } + + private String processTag(final String s) + { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) + { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) + { + if (false == inArray(name, vSelfClosingTags)) + { + if (vTagCounts.containsKey(name)) + { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return ""; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) + { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) + { + final StringBuilder params = new StringBuilder(); + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List paramNames = new ArrayList<>(); + final List paramValues = new ArrayList<>(); + while (m2.find()) + { + paramNames.add(m2.group(1)); // ([a-z0-9]+) + paramValues.add(m2.group(3)); // (.*?) + } + while (m3.find()) + { + paramNames.add(m3.group(1)); // ([a-z0-9]+) + paramValues.add(m3.group(3)); // ([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0; ii < paramNames.size(); ii++) + { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + + // debug( "paramName='" + paramName + "'" ); + // debug( "paramValue='" + paramValue + "'" ); + // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); + + if (allowedAttribute(name, paramName)) + { + if (inArray(paramName, vProtocolAtts)) + { + paramValue = processParamProtocol(paramValue); + } + params.append(' ').append(paramName).append("=\"").append(paramValue).append("\""); + } + } + + if (inArray(name, vSelfClosingTags)) + { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) + { + ending = ""; + } + + if (ending == null || ending.length() < 1) + { + if (vTagCounts.containsKey(name)) + { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } + else + { + vTagCounts.put(name, 1); + } + } + else + { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } + else + { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) + { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol(String s) + { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) + { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) + { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1); + if (s.startsWith("#//")) + { + s = "#" + s.substring(3); + } + } + } + + return s; + } + + private String decodeEntities(String s) + { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.decode(match).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) + { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities(final String s) + { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) + { + final String one = m.group(1); // ([^&;]*) + final String two = m.group(2); // (?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes(final String s) + { + if (encodeQuotes) + { + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) + { + final String one = m.group(1); // (>|^) + final String two = m.group(2); // ([^<]+?) + final String three = m.group(3); // (<|$) + // 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, two) + m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three)); + } + m.appendTail(buf); + return buf.toString(); + } + else + { + return s; + } + } + + private String checkEntity(final String preamble, final String term) + { + + return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble; + } + + private boolean isValidEntity(final String entity) + { + return inArray(entity, vAllowedEntities); + } + + private static boolean inArray(final String s, final String[] array) + { + for (String item : array) + { + if (item != null && item.equals(s)) + { + return true; + } + } + return false; + } + + private boolean allowed(final String name) + { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute(final String name, final String paramName) + { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +} \ No newline at end of file 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 323dbc1a3..5e92cde8f 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 @@ -18,6 +18,7 @@ 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发送方法 @@ -36,6 +37,19 @@ public class HttpUtils * @return 所代表远程资源的响应结果 */ 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; @@ -49,7 +63,7 @@ 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) { @@ -104,7 +118,7 @@ public class HttpUtils StringBuilder result = new StringBuilder(); try { - String urlNameString = url + "?" + param; + String urlNameString = url; log.info("sendPost - {}", urlNameString); URL realUrl = new URL(urlNameString); URLConnection conn = realUrl.openConnection(); 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 75264d4f3..8fbc8b00f 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 @@ -1,874 +1,1034 @@ -package com.ruoyi.common.utils.poi; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import org.apache.poi.hssf.usermodel.HSSFDateUtil; -import org.apache.poi.ss.usermodel.BorderStyle; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.CellType; -import org.apache.poi.ss.usermodel.DataValidation; -import org.apache.poi.ss.usermodel.DataValidationConstraint; -import org.apache.poi.ss.usermodel.DataValidationHelper; -import org.apache.poi.ss.usermodel.DateUtil; -import org.apache.poi.ss.usermodel.FillPatternType; -import org.apache.poi.ss.usermodel.Font; -import org.apache.poi.ss.usermodel.HorizontalAlignment; -import org.apache.poi.ss.usermodel.IndexedColors; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.VerticalAlignment; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.usermodel.WorkbookFactory; -import org.apache.poi.ss.util.CellRangeAddressList; -import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.apache.poi.xssf.usermodel.XSSFDataValidation; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.ruoyi.common.annotation.Excel; -import com.ruoyi.common.annotation.Excel.ColumnType; -import com.ruoyi.common.annotation.Excel.Type; -import com.ruoyi.common.annotation.Excels; -import com.ruoyi.common.config.Global; -import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.core.text.Convert; -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; - -/** - * Excel相关处理 - * - * @author ruoyi - */ -public class ExcelUtil -{ - private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); - - /** - * Excel sheet最大行数,默认65536 - */ - public static final int sheetSize = 65536; - - /** - * 工作表名称 - */ - private String sheetName; - - /** - * 导出类型(EXPORT:导出数据;IMPORT:导入模板) - */ - private Type type; - - /** - * 工作薄对象 - */ - private Workbook wb; - - /** - * 工作表对象 - */ - private Sheet sheet; - - /** - * 样式列表 - */ - private Map styles; - - /** - * 导入导出数据列表 - */ - private List list; - - /** - * 注解列表 - */ - private List fields; - - /** - * 实体对象 - */ - public Class clazz; - - public ExcelUtil(Class clazz) - { - this.clazz = clazz; - } - - public void init(List list, String sheetName, Type type) - { - if (list == null) - { - list = new ArrayList(); - } - this.list = list; - this.sheetName = sheetName; - this.type = type; - createExcelField(); - createWorkbook(); - } - - /** - * 对excel表单默认第一个索引名转换成list - * - * @param input 输入流 - * @return 转换后集合 - */ - public List importExcel(InputStream is) throws Exception - { - return importExcel(StringUtils.EMPTY, is); - } - - /** - * 对excel表单指定表格索引名转换成list - * - * @param sheetName 表格索引名 - * @param input 输入流 - * @return 转换后集合 - */ - 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)) - { - // 如果指定sheet名,则取指定sheet中的内容. - sheet = wb.getSheet(sheetName); - } - else - { - // 如果传入的sheet名不存在则默认指向第1个sheet. - sheet = wb.getSheetAt(0); - } - - if (sheet == null) - { - throw new IOException("文件sheet不存在"); - } - - int rows = sheet.getPhysicalNumberOfRows(); - - if (rows > 0) - { - // 定义一个map用于存放excel列的序号和field. - Map cellMap = new HashMap(); - // 获取表头 - Row heard = sheet.getRow(0); - for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) - { - Cell cell = heard.getCell(i); - if (StringUtils.isNotNull(cell != null)) - { - String value = this.getCellValue(heard, i).toString(); - cellMap.put(value, i); - } - else - { - cellMap.put(null, i); - } - } - // 有数据时才处理 得到类的所有field. - Field[] allFields = clazz.getDeclaredFields(); - // 定义一个map用于存放列的序号和field. - Map fieldsMap = new HashMap(); - 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)) - { - // 设置类的私有字段属性可访问. - field.setAccessible(true); - Integer column = cellMap.get(attr.name()); - fieldsMap.put(column, field); - } - } - for (int i = 1; i < rows; i++) - { - // 从第2行开始取数据,默认第一行是表头. - Row row = sheet.getRow(i); - T entity = null; - for (Map.Entry entry : fieldsMap.entrySet()) - { - Object val = this.getCellValue(row, entry.getKey()); - - // 如果不存在实例则新建. - entity = (entity == null ? clazz.newInstance() : entity); - // 从map中得到对应列的field. - Field field = fieldsMap.get(entry.getKey()); - // 取得类型,并根据对象类型设置值. - Class fieldType = field.getType(); - if (String.class == fieldType) - { - String s = Convert.toStr(val); - if (StringUtils.endsWith(s, ".0")) - { - val = StringUtils.substringBefore(s, ".0"); - } - else - { - val = Convert.toStr(val); - } - } - else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) - { - val = Convert.toInt(val); - } - else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) - { - val = Convert.toLong(val); - } - else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) - { - val = Convert.toDouble(val); - } - else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) - { - val = Convert.toFloat(val); - } - else if (BigDecimal.class == fieldType) - { - val = Convert.toBigDecimal(val); - } - else if (Date.class == fieldType) - { - if (val instanceof String) - { - val = DateUtils.parseDate(val); - } - else if (val instanceof Double) - { - val = DateUtil.getJavaDate((Double) val); - } - } - if (StringUtils.isNotNull(fieldType)) - { - Excel attr = field.getAnnotation(Excel.class); - String propertyName = field.getName(); - if (StringUtils.isNotEmpty(attr.targetAttr())) - { - propertyName = field.getName() + "." + attr.targetAttr(); - } - else if (StringUtils.isNotEmpty(attr.readConverterExp())) - { - val = reverseByExp(String.valueOf(val), attr.readConverterExp()); - } - ReflectUtils.invokeSetter(entity, propertyName, val); - } - } - list.add(entity); - } - } - return list; - } - - /** - * 对list数据源将其里面的数据导入到excel表单 - * - * @param list 导出数据集合 - * @param sheetName 工作表的名称 - * @return 结果 - */ - 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) - { - this.init(null, sheetName, Type.IMPORT); - return exportExcel(); - } - - /** - * 对list数据源将其里面的数据导入到excel表单 - * - * @return 结果 - */ - public AjaxResult exportExcel() - { - OutputStream out = null; - try - { - // 取出一共有多少个sheet. - double sheetNo = Math.ceil(list.size() / sheetSize); - for (int index = 0; index <= sheetNo; index++) - { - createSheet(sheetNo, index); - - // 产生一行 - Row row = sheet.createRow(0); - int column = 0; - // 写入各个字段的列头名称 - for (Object[] os : fields) - { - Excel excel = (Excel) os[1]; - this.createCell(excel, row, column++); - } - if (Type.EXPORT.equals(type)) - { - fillExcelData(index, row); - } - } - String filename = encodingFilename(sheetName); - out = new FileOutputStream(getAbsoluteFile(filename)); - wb.write(out); - return AjaxResult.success(filename); - } - catch (Exception e) - { - log.error("导出Excel异常{}", e.getMessage()); - throw new BusinessException("导出Excel失败,请联系网站管理员!"); - } - finally - { - if (wb != null) - { - try - { - wb.close(); - } - catch (IOException e1) - { - e1.printStackTrace(); - } - } - if (out != null) - { - try - { - out.close(); - } - catch (IOException e1) - { - e1.printStackTrace(); - } - } - } - } - - /** - * 填充excel数据 - * - * @param index 序号 - * @param row 单元格行 - * @param cell 类型单元格 - */ - 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++) - { - row = sheet.createRow(i + 1 - startNo); - // 得到导出对象. - T vo = (T) list.get(i); - int column = 0; - for (Object[] os : fields) - { - Field field = (Field) os[0]; - Excel excel = (Excel) os[1]; - // 设置实体类私有属性可访问 - field.setAccessible(true); - this.addCell(excel, row, vo, field, column++); - } - } - } - - /** - * 创建表格样式 - * - * @param wb 工作薄对象 - * @return 样式列表 - */ - private Map createStyles(Workbook wb) - { - // 写入各条记录,每条记录对应excel表中的一行 - Map styles = new HashMap(); - CellStyle style = wb.createCellStyle(); - style.setAlignment(HorizontalAlignment.CENTER); - style.setVerticalAlignment(VerticalAlignment.CENTER); - style.setBorderRight(BorderStyle.THIN); - style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderLeft(BorderStyle.THIN); - style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderTop(BorderStyle.THIN); - style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderBottom(BorderStyle.THIN); - style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - Font dataFont = wb.createFont(); - dataFont.setFontName("Arial"); - dataFont.setFontHeightInPoints((short) 10); - style.setFont(dataFont); - styles.put("data", style); - - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(HorizontalAlignment.CENTER); - style.setVerticalAlignment(VerticalAlignment.CENTER); - style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setFillPattern(FillPatternType.SOLID_FOREGROUND); - Font headerFont = wb.createFont(); - headerFont.setFontName("Arial"); - headerFont.setFontHeightInPoints((short) 10); - headerFont.setBold(true); - headerFont.setColor(IndexedColors.WHITE.getIndex()); - style.setFont(headerFont); - styles.put("header", style); - - return styles; - } - - /** - * 创建单元格 - */ - public Cell createCell(Excel attr, Row row, int column) - { - // 创建列 - Cell cell = row.createCell(column); - // 写入列信息 - cell.setCellValue(attr.name()); - setDataValidation(attr, row, column); - cell.setCellStyle(styles.get("header")); - return cell; - } - - /** - * 设置单元格信息 - * - * @param value 单元格值 - * @param attr 注解相关 - * @param cell 单元格信息 - */ - public void setCellVo(Object value, Excel attr, Cell cell) - { - if (ColumnType.STRING == attr.cellType()) - { - cell.setCellType(CellType.NUMERIC); - cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); - } - else if (ColumnType.NUMERIC == attr.cellType()) - { - cell.setCellType(CellType.NUMERIC); - cell.setCellValue(Integer.parseInt(value + "")); - } - } - - /** - * 创建表格样式 - */ - public void setDataValidation(Excel attr, Row row, int column) - { - if (attr.name().indexOf("注:") >= 0) - { - sheet.setColumnWidth(column, 6000); - } - else - { - // 设置列宽 - sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); - row.setHeight((short) (attr.height() * 20)); - } - // 如果设置了提示信息则鼠标放上去提示. - if (StringUtils.isNotEmpty(attr.prompt())) - { - // 这里默认设了2-101列提示. - setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); - } - // 如果设置了combo属性则本列只能选择不能输入 - if (attr.combo().length > 0) - { - // 这里默认设了2-101列只能选择不能输入. - setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); - } - } - - /** - * 添加单元格 - */ - public Cell addCell(Excel attr, Row row, T vo, Field field, int column) - { - Cell cell = null; - try - { - // 设置行高 - row.setHeight((short) (attr.height() * 20)); - // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. - if (attr.isExport()) - { - // 创建cell - cell = row.createCell(column); - cell.setCellStyle(styles.get("data")); - - // 用于读取对象中的属性 - Object value = getTargetValue(vo, field, attr); - String dateFormat = attr.dateFormat(); - String readConverterExp = attr.readConverterExp(); - 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 - { - // 设置列类型 - setCellVo(value, attr, cell); - } - } - } - catch (Exception e) - { - log.error("导出Excel失败{}", e); - } - return cell; - } - - /** - * 设置 POI XSSFSheet 单元格提示 - * - * @param sheet 表单 - * @param promptTitle 提示标题 - * @param promptContent 提示内容 - * @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) - { - DataValidationHelper helper = sheet.getDataValidationHelper(); - DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); - CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); - DataValidation dataValidation = helper.createValidation(constraint, regions); - dataValidation.createPromptBox(promptTitle, promptContent); - dataValidation.setShowPromptBox(true); - sheet.addValidationData(dataValidation); - } - - /** - * 设置某些列的值只能输入预制的数据,显示下拉框. - * - * @param sheet 要设置的sheet. - * @param textlist 下拉框显示的内容 - * @param firstRow 开始行 - * @param endRow 结束行 - * @param firstCol 开始列 - * @param endCol 结束列 - * @return 设置好的sheet. - */ - public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) - { - DataValidationHelper helper = sheet.getDataValidationHelper(); - // 加载下拉列表内容 - DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); - // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 - CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); - // 数据有效性对象 - DataValidation dataValidation = helper.createValidation(constraint, regions); - // 处理Excel兼容性问题 - if (dataValidation instanceof XSSFDataValidation) - { - dataValidation.setSuppressDropDownArrow(true); - dataValidation.setShowErrorBox(true); - } - else - { - dataValidation.setSuppressDropDownArrow(false); - } - - sheet.addValidationData(dataValidation); - } - - /** - * 解析导出值 0=男,1=女,2=未知 - * - * @param propertyValue 参数值 - * @param converterExp 翻译注解 - * @return 解析后值 - * @throws Exception - */ - public static String convertByExp(String propertyValue, String converterExp) throws Exception - { - try - { - String[] convertSource = converterExp.split(","); - for (String item : convertSource) - { - String[] itemArray = item.split("="); - if (itemArray[0].equals(propertyValue)) - { - return itemArray[1]; - } - } - } - catch (Exception e) - { - throw e; - } - return propertyValue; - } - - /** - * 反向解析值 男=0,女=1,未知=2 - * - * @param propertyValue 参数值 - * @param converterExp 翻译注解 - * @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)) - { - return itemArray[0]; - } - } - } - catch (Exception e) - { - throw e; - } - return propertyValue; - } - - /** - * 编码文件名 - */ - public String encodingFilename(String filename) - { - filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; - return filename; - } - - /** - * 获取下载路径 - * - * @param filename 文件名称 - */ - public String getAbsoluteFile(String filename) - { - String downloadPath = Global.getDownloadPath() + filename; - File desc = new File(downloadPath); - if (!desc.getParentFile().exists()) - { - desc.getParentFile().mkdirs(); - } - return downloadPath; - } - - /** - * 获取bean中的属性值 - * - * @param vo 实体对象 - * @param field 字段 - * @param excel 注解 - * @return 最终的属性值 - * @throws Exception - */ - private Object getTargetValue(T vo, Field field, Excel excel) throws Exception - { - Object o = field.get(vo); - if (StringUtils.isNotEmpty(excel.targetAttr())) - { - String target = excel.targetAttr(); - if (target.indexOf(".") > -1) - { - String[] targets = target.split("[.]"); - for (String name : targets) - { - o = getValue(o, name); - } - } - else - { - o = getValue(o, target); - } - } - return o; - } - - /** - * 以类的属性的get方法方法形式获取值 - * - * @param o - * @param name - * @return value - * @throws Exception - */ - 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); - } - return o; - } - - /** - * 得到所有定义字段 - */ - 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) - { - // 单注解 - if (field.isAnnotationPresent(Excel.class)) - { - putToField(field, field.getAnnotation(Excel.class)); - } - - // 多注解 - if (field.isAnnotationPresent(Excels.class)) - { - Excels attrs = field.getAnnotation(Excels.class); - Excel[] excels = attrs.value(); - for (Excel excel : excels) - { - putToField(field, excel); - } - } - } - } - - /** - * 放到字段集合中 - */ - private void putToField(Field field, Excel attr) - { - if (attr != null && (attr.type() == Type.ALL || attr.type() == type)) - { - this.fields.add(new Object[] { field, attr }); - } - } - - /** - * 创建一个工作簿 - */ - public void createWorkbook() - { - this.wb = new SXSSFWorkbook(500); - } - - /** - * 创建工作表 - * - * @param sheetName,指定Sheet名称 - * @param sheetNo sheet数量 - * @param index 序号 - */ - public void createSheet(double sheetNo, int index) - { - this.sheet = wb.createSheet(); - this.styles = createStyles(wb); - // 设置工作表的名称. - if (sheetNo == 0) - { - wb.setSheetName(index, sheetName); - } - else - { - wb.setSheetName(index, sheetName + index); - } - } - - /** - * 获取单元格值 - * - * @param row 获取的行 - * @param column 获取单元格列号 - * @return 单元格值 - */ - public Object getCellValue(Row row, int column) - { - if (row == null) - { - return row; - } - Object val = ""; - try - { - Cell cell = row.getCell(column); - if (cell != null) - { - if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA) - { - val = cell.getNumericCellValue(); - 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 - { - val = new DecimalFormat("0").format(val); - } - } - } - else if (cell.getCellTypeEnum() == CellType.STRING) - { - val = cell.getStringCellValue(); - } - else if (cell.getCellTypeEnum() == CellType.BOOLEAN) - { - val = cell.getBooleanCellValue(); - } - else if (cell.getCellTypeEnum() == CellType.ERROR) - { - val = cell.getErrorCellValue(); - } - - } - } - catch (Exception e) - { - return val; - } - return val; - } +package com.ruoyi.common.utils.poi; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +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.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.DataValidation; +import org.apache.poi.ss.usermodel.DataValidationConstraint; +import org.apache.poi.ss.usermodel.DataValidationHelper; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.ss.util.CellRangeAddressList; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFDataValidation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.annotation.Excel.ColumnType; +import com.ruoyi.common.annotation.Excel.Type; +import com.ruoyi.common.annotation.Excels; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.exception.BusinessException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.DictUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.reflect.ReflectUtils; + +/** + * Excel相关处理 + * + * @author ruoyi + */ +public class ExcelUtil +{ + private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); + + /** + * Excel sheet最大行数,默认65536 + */ + public static final int sheetSize = 65536; + + /** + * 工作表名称 + */ + private String sheetName; + + /** + * 导出类型(EXPORT:导出数据;IMPORT:导入模板) + */ + private Type type; + + /** + * 工作薄对象 + */ + private Workbook wb; + + /** + * 工作表对象 + */ + private Sheet sheet; + + /** + * 样式列表 + */ + private Map styles; + + /** + * 导入导出数据列表 + */ + private List list; + + /** + * 注解列表 + */ + 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) + { + this.clazz = clazz; + } + + public void init(List list, String sheetName, Type type) + { + if (list == null) + { + list = new ArrayList(); + } + this.list = list; + this.sheetName = sheetName; + this.type = type; + createExcelField(); + createWorkbook(); + } + + /** + * 对excel表单默认第一个索引名转换成list + * + * @param is 输入流 + * @return 转换后集合 + */ + public List importExcel(InputStream is) throws Exception + { + return importExcel(StringUtils.EMPTY, is); + } + + /** + * 对excel表单指定表格索引名转换成list + * + * @param sheetName 表格索引名 + * @param is 输入流 + * @return 转换后集合 + */ + 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)) + { + // 如果指定sheet名,则取指定sheet中的内容. + sheet = wb.getSheet(sheetName); + } + else + { + // 如果传入的sheet名不存在则默认指向第1个sheet. + sheet = wb.getSheetAt(0); + } + + if (sheet == null) + { + throw new IOException("文件sheet不存在"); + } + + int rows = sheet.getPhysicalNumberOfRows(); + + if (rows > 0) + { + // 定义一个map用于存放excel列的序号和field. + Map cellMap = new HashMap(); + // 获取表头 + Row heard = sheet.getRow(0); + for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++) + { + Cell cell = heard.getCell(i); + if (StringUtils.isNotNull(cell)) + { + String value = this.getCellValue(heard, i).toString(); + cellMap.put(value, i); + } + else + { + cellMap.put(null, i); + } + } + // 有数据时才处理 得到类的所有field. + Field[] allFields = clazz.getDeclaredFields(); + // 定义一个map用于存放列的序号和field. + Map fieldsMap = new HashMap(); + 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)) + { + // 设置类的私有字段属性可访问. + field.setAccessible(true); + Integer column = cellMap.get(attr.name()); + fieldsMap.put(column, field); + } + } + for (int i = 1; i < rows; i++) + { + // 从第2行开始取数据,默认第一行是表头. + Row row = sheet.getRow(i); + T entity = null; + for (Map.Entry entry : fieldsMap.entrySet()) + { + Object val = this.getCellValue(row, entry.getKey()); + + // 如果不存在实例则新建. + entity = (entity == null ? clazz.newInstance() : entity); + // 从map中得到对应列的field. + Field field = fieldsMap.get(entry.getKey()); + // 取得类型,并根据对象类型设置值. + Class fieldType = field.getType(); + if (String.class == fieldType) + { + String s = Convert.toStr(val); + if (StringUtils.endsWith(s, ".0")) + { + val = StringUtils.substringBefore(s, ".0"); + } + else + { + String dateFormat = field.getAnnotation(Excel.class).dateFormat(); + if (StringUtils.isNotEmpty(dateFormat)) + { + val = DateUtils.parseDateToStr(dateFormat, (Date) val); + } + else + { + val = Convert.toStr(val); + } + } + } + else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val))) + { + val = Convert.toInt(val); + } + else if (Long.TYPE == fieldType || Long.class == fieldType) + { + val = Convert.toLong(val); + } + else if (Double.TYPE == fieldType || Double.class == fieldType) + { + val = Convert.toDouble(val); + } + else if (Float.TYPE == fieldType || Float.class == fieldType) + { + val = Convert.toFloat(val); + } + else if (BigDecimal.class == fieldType) + { + val = Convert.toBigDecimal(val); + } + else if (Date.class == fieldType) + { + if (val instanceof String) + { + val = DateUtils.parseDate(val); + } + else if (val instanceof Double) + { + val = DateUtil.getJavaDate((Double) val); + } + } + else if (Boolean.TYPE == fieldType || Boolean.class == fieldType) + { + val = Convert.toBool(val, false); + } + if (StringUtils.isNotNull(fieldType)) + { + Excel attr = field.getAnnotation(Excel.class); + String propertyName = field.getName(); + if (StringUtils.isNotEmpty(attr.targetAttr())) + { + propertyName = field.getName() + "." + attr.targetAttr(); + } + 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); + } + } + list.add(entity); + } + } + return list; + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @param list 导出数据集合 + * @param sheetName 工作表的名称 + * @return 结果 + */ + 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) + { + this.init(null, sheetName, Type.IMPORT); + return exportExcel(); + } + + /** + * 对list数据源将其里面的数据导入到excel表单 + * + * @return 结果 + */ + public AjaxResult exportExcel() + { + OutputStream out = null; + try + { + // 取出一共有多少个sheet. + double sheetNo = Math.ceil(list.size() / sheetSize); + for (int index = 0; index <= sheetNo; index++) + { + createSheet(sheetNo, index); + + // 产生一行 + Row row = sheet.createRow(0); + int column = 0; + // 写入各个字段的列头名称 + for (Object[] os : fields) + { + Excel excel = (Excel) os[1]; + this.createCell(excel, row, column++); + } + 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) + { + log.error("导出Excel异常{}", e.getMessage()); + throw new BusinessException("导出Excel失败,请联系网站管理员!"); + } + finally + { + if (wb != null) + { + try + { + wb.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + if (out != null) + { + try + { + out.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + } + } + } + + /** + * 填充excel数据 + * + * @param index 序号 + * @param 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++) + { + row = sheet.createRow(i + 1 - startNo); + // 得到导出对象. + T vo = (T) list.get(i); + int column = 0; + for (Object[] os : fields) + { + Field field = (Field) os[0]; + Excel excel = (Excel) os[1]; + // 设置实体类私有属性可访问 + field.setAccessible(true); + this.addCell(excel, row, vo, field, column++); + } + } + } + + /** + * 创建表格样式 + * + * @param wb 工作薄对象 + * @return 样式列表 + */ + private Map createStyles(Workbook wb) + { + // 写入各条记录,每条记录对应excel表中的一行 + Map styles = new HashMap(); + CellStyle style = wb.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setBorderRight(BorderStyle.THIN); + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderLeft(BorderStyle.THIN); + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderTop(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setBorderBottom(BorderStyle.THIN); + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); + Font dataFont = wb.createFont(); + dataFont.setFontName("Arial"); + dataFont.setFontHeightInPoints((short) 10); + style.setFont(dataFont); + styles.put("data", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + Font headerFont = wb.createFont(); + headerFont.setFontName("Arial"); + headerFont.setFontHeightInPoints((short) 10); + headerFont.setBold(true); + 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); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.LEFT); + styles.put("data1", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.CENTER); + styles.put("data2", style); + + style = wb.createCellStyle(); + style.cloneStyleFrom(styles.get("data")); + style.setAlignment(HorizontalAlignment.RIGHT); + styles.put("data3", style); + + return styles; + } + + /** + * 创建单元格 + */ + public Cell createCell(Excel attr, Row row, int column) + { + // 创建列 + Cell cell = row.createCell(column); + // 写入列信息 + cell.setCellValue(attr.name()); + setDataValidation(attr, row, column); + cell.setCellStyle(styles.get("header")); + return cell; + } + + /** + * 设置单元格信息 + * + * @param value 单元格值 + * @param attr 注解相关 + * @param cell 单元格信息 + */ + public void setCellVo(Object value, Excel attr, Cell cell) + { + if (ColumnType.STRING == attr.cellType()) + { + cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix()); + } + else if (ColumnType.NUMERIC == attr.cellType()) + { + 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) + { + sheet.setColumnWidth(column, 6000); + } + else + { + // 设置列宽 + sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256)); + row.setHeight((short) (attr.height() * 20)); + } + // 如果设置了提示信息则鼠标放上去提示. + if (StringUtils.isNotEmpty(attr.prompt())) + { + // 这里默认设了2-101列提示. + setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column); + } + // 如果设置了combo属性则本列只能选择不能输入 + if (attr.combo().length > 0) + { + // 这里默认设了2-101列只能选择不能输入. + setXSSFValidation(sheet, attr.combo(), 1, 100, column, column); + } + } + + /** + * 添加单元格 + */ + public Cell addCell(Excel attr, Row row, T vo, Field field, int column) + { + Cell cell = null; + try + { + // 设置行高 + row.setHeight((short) (attr.height() * 20)); + // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. + if (attr.isExport()) + { + // 创建cell + cell = row.createCell(column); + int align = attr.align().value(); + cell.setCellStyle(styles.get("data" + (align >= 1 && align <= 3 ? align : ""))); + + // 用于读取对象中的属性 + Object value = getTargetValue(vo, field, attr); + String dateFormat = attr.dateFormat(); + String readConverterExp = attr.readConverterExp(); + 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(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) + { + log.error("导出Excel失败{}", e); + } + return cell; + } + + /** + * 设置 POI XSSFSheet 单元格提示 + * + * @param sheet 表单 + * @param promptTitle 提示标题 + * @param promptContent 提示内容 + * @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) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + DataValidationConstraint constraint = helper.createCustomConstraint("DD1"); + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + DataValidation dataValidation = helper.createValidation(constraint, regions); + dataValidation.createPromptBox(promptTitle, promptContent); + dataValidation.setShowPromptBox(true); + sheet.addValidationData(dataValidation); + } + + /** + * 设置某些列的值只能输入预制的数据,显示下拉框. + * + * @param sheet 要设置的sheet. + * @param textlist 下拉框显示的内容 + * @param firstRow 开始行 + * @param endRow 结束行 + * @param firstCol 开始列 + * @param endCol 结束列 + * @return 设置好的sheet. + */ + public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol) + { + DataValidationHelper helper = sheet.getDataValidationHelper(); + // 加载下拉列表内容 + DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist); + // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列 + CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol); + // 数据有效性对象 + DataValidation dataValidation = helper.createValidation(constraint, regions); + // 处理Excel兼容性问题 + if (dataValidation instanceof XSSFDataValidation) + { + dataValidation.setSuppressDropDownArrow(true); + dataValidation.setShowErrorBox(true); + } + else + { + dataValidation.setSuppressDropDownArrow(false); + } + + sheet.addValidationData(dataValidation); + } + + /** + * 解析导出值 0=男,1=女,2=未知 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + * @throws Exception + */ + 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) + { + String[] itemArray = item.split("="); + 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) + { + throw e; + } + return StringUtils.stripEnd(propertyString.toString(), separator); + } + + /** + * 反向解析值 男=0,女=1,未知=2 + * + * @param propertyValue 参数值 + * @param converterExp 翻译注解 + * @param separator 分隔符 + * @return 解析后值 + * @throws Exception + */ + 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]; + } + } + } + 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 + { + return DictUtils.getDictLabel(dictType, dictValue, separator); + } + + /** + * 反向解析值字典值 + * + * @param dictLabel 字典标签 + * @param dictType 字典类型 + * @param separator 分隔符 + * @return 字典值 + */ + public static String reverseDictByExp(String dictLabel, String dictType, String separator) throws Exception + { + return DictUtils.getDictValue(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) + { + filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx"; + return filename; + } + + /** + * 获取下载路径 + * + * @param filename 文件名称 + */ + public String getAbsoluteFile(String filename) + { + String downloadPath = RuoYiConfig.getDownloadPath() + filename; + File desc = new File(downloadPath); + if (!desc.getParentFile().exists()) + { + desc.getParentFile().mkdirs(); + } + return downloadPath; + } + + /** + * 获取bean中的属性值 + * + * @param vo 实体对象 + * @param field 字段 + * @param excel 注解 + * @return 最终的属性值 + * @throws Exception + */ + private Object getTargetValue(T vo, Field field, Excel excel) throws Exception + { + Object o = field.get(vo); + if (StringUtils.isNotEmpty(excel.targetAttr())) + { + String target = excel.targetAttr(); + if (target.indexOf(".") > -1) + { + String[] targets = target.split("[.]"); + for (String name : targets) + { + o = getValue(o, name); + } + } + else + { + o = getValue(o, target); + } + } + return o; + } + + /** + * 以类的属性的get方法方法形式获取值 + * + * @param o + * @param name + * @return value + * @throws Exception + */ + private Object getValue(Object o, String name) throws Exception + { + if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) + { + Class clazz = o.getClass(); + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + o = field.get(o); + } + return o; + } + + /** + * 得到所有定义字段 + */ + 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) + { + // 单注解 + if (field.isAnnotationPresent(Excel.class)) + { + putToField(field, field.getAnnotation(Excel.class)); + } + + // 多注解 + if (field.isAnnotationPresent(Excels.class)) + { + Excels attrs = field.getAnnotation(Excels.class); + Excel[] excels = attrs.value(); + 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 }); + } + } + + /** + * 创建一个工作簿 + */ + public void createWorkbook() + { + this.wb = new SXSSFWorkbook(500); + } + + /** + * 创建工作表 + * + * @param sheetNo sheet数量 + * @param index 序号 + */ + public void createSheet(double sheetNo, int index) + { + this.sheet = wb.createSheet(); + this.styles = createStyles(wb); + // 设置工作表的名称. + if (sheetNo == 0) + { + wb.setSheetName(index, sheetName); + } + else + { + wb.setSheetName(index, sheetName + index); + } + } + + /** + * 获取单元格值 + * + * @param row 获取的行 + * @param column 获取单元格列号 + * @return 单元格值 + */ + public Object getCellValue(Row row, int column) + { + if (row == null) + { + return row; + } + Object val = ""; + try + { + Cell cell = row.getCell(column); + if (StringUtils.isNotNull(cell)) + { + if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA) + { + val = cell.getNumericCellValue(); + if (DateUtil.isCellDateFormatted(cell)) + { + val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换 + } + else + { + if ((Double) val % 1 > 0) + { + val = new BigDecimal(val.toString()); + } + else + { + val = new DecimalFormat("0").format(val); + } + } + } + else if (cell.getCellType() == CellType.STRING) + { + val = cell.getStringCellValue(); + } + else if (cell.getCellType() == CellType.BOOLEAN) + { + val = cell.getBooleanCellValue(); + } + else if (cell.getCellType() == CellType.ERROR) + { + val = cell.getErrorCellValue(); + } + + } + } + catch (Exception e) + { + return val; + } + return val; + } } \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java index b78e53e10..b19953e06 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java @@ -204,6 +204,10 @@ public class ReflectUtils args[i] = DateUtil.getJavaDate((Double) args[i]); } } + else if (cs[i] == boolean.class || cs[i] == Boolean.class) + { + args[i] = Convert.toBool(args[i]); + } } } return (E) method.invoke(obj, args); 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 e0311595a..99293ee41 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,7 +5,10 @@ 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 @@ -13,17 +16,25 @@ import org.springframework.stereotype.Component; * @author ruoyi */ @Component -public final class SpringUtils implements BeanFactoryPostProcessor +public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware { /** Spring应用上下文环境 */ private static ConfigurableListableBeanFactory beanFactory; + private static ApplicationContext applicationContext; + @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { SpringUtils.beanFactory = beanFactory; } + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException + { + SpringUtils.applicationContext = applicationContext; + } + /** * 获取对象 * @@ -111,4 +122,25 @@ public final class SpringUtils implements BeanFactoryPostProcessor { 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 b31804b67..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,5 +1,6 @@ package com.ruoyi.common.utils.sql; +import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.StringUtils; /** @@ -10,9 +11,9 @@ import com.ruoyi.common.utils.StringUtils; public class SqlUtil { /** - * 仅支持字母、数字、下划线、空格、逗号(支持多个字段排序) + * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) */ - public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,]+"; + public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+"; /** * 检查字符,防止注入绕过 @@ -21,7 +22,7 @@ public class SqlUtil { if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value)) { - return StringUtils.EMPTY; + throw new BaseException("参数不符合规范,不能进行查询"); } return value; } 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-common/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java b/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java index be125f249..516db0a90 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java @@ -2,8 +2,7 @@ package com.ruoyi.common.xss; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; -import org.jsoup.Jsoup; -import org.jsoup.safety.Whitelist; +import com.ruoyi.common.utils.html.EscapeUtil; /** * XSS过滤处理 @@ -31,7 +30,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper for (int i = 0; i < length; i++) { // 防xss攻击和过滤前后空格 - escapseValues[i] = Jsoup.clean(values[i], Whitelist.relaxed()).trim(); + escapseValues[i] = EscapeUtil.clean(values[i]).trim(); } return escapseValues; } diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml index f894e8e5f..cab629cf5 100644 --- a/ruoyi-framework/pom.xml +++ b/ruoyi-framework/pom.xml @@ -5,94 +5,78 @@ ruoyi com.ruoyi - 4.0.0 + 4.5.1 4.0.0 - + ruoyi-framework - - - framework框架核心 - - + + + framework框架核心 + + - - + + org.springframework.boot spring-boot-starter-web - - 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 + com.ruoyi ruoyi-system - - - - com.github.oshi - oshi-core - - - - net.java.dev.jna - jna - - - - net.java.dev.jna - jna-platform - - + \ 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 9fa9b0afb..6b5470e8f 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 @@ -10,10 +10,10 @@ import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import com.ruoyi.common.annotation.DataScope; import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.domain.entity.SysRole; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysRole; -import com.ruoyi.system.domain.SysUser; /** * 数据过滤处理 @@ -92,7 +92,8 @@ public class DataScopeAspect * * @param joinPoint 切点 * @param user 用户 - * @param alias 别名 + * @param deptAlias 部门别名 + * @param userAlias 用户别名 */ public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias) { @@ -138,8 +139,12 @@ public class DataScopeAspect if (StringUtils.isNotBlank(sqlString.toString())) { - BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0]; - baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); + Object params = joinPoint.getArgs()[0]; + if (StringUtils.isNotNull(params) && params instanceof BaseEntity) + { + BaseEntity baseEntity = (BaseEntity) params; + baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")"); + } } } 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 4f13ddb37..f72b8051b 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 @@ -1,6 +1,6 @@ package com.ruoyi.framework.aspectj; -import java.lang.reflect.Method; +import java.util.Objects; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @@ -8,6 +8,7 @@ import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import com.ruoyi.common.annotation.DataSource; @@ -60,17 +61,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)) + DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class); + if (Objects.nonNull(dataSource)) { - return targetDataSource; - } - else - { - Method method = signature.getMethod(); - DataSource dataSource = method.getAnnotation(DataSource.class); 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 a549c06e0..b638a791f 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 @@ -12,16 +12,18 @@ 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.core.domain.entity.SysUser; import com.ruoyi.common.enums.BusinessStatus; import com.ruoyi.common.json.JSON; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.framework.manager.AsyncManager; 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; /** * 操作日志记录处理 @@ -34,6 +36,9 @@ public class LogAspect { private static final Logger log = LoggerFactory.getLogger(LogAspect.class); + /** 排除敏感属性字段 */ + public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" }; + // 配置织入点 @Pointcut("@annotation(com.ruoyi.common.annotation.Log)") public void logPointCut() @@ -45,10 +50,10 @@ public class LogAspect * * @param joinPoint 切点 */ - @AfterReturning(pointcut = "logPointCut()") - public void doAfterReturning(JoinPoint joinPoint) + @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult") + public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) { - handleLog(joinPoint, null); + handleLog(joinPoint, null, jsonResult); } /** @@ -60,10 +65,10 @@ public class LogAspect @AfterThrowing(value = "logPointCut()", throwing = "e") public void doAfterThrowing(JoinPoint joinPoint, Exception e) { - handleLog(joinPoint, e); + handleLog(joinPoint, e, null); } - protected void handleLog(final JoinPoint joinPoint, final Exception e) + protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) { try { @@ -83,6 +88,8 @@ public class LogAspect // 请求的地址 String ip = ShiroUtils.getIp(); operLog.setOperIp(ip); + // 返回参数 + operLog.setJsonResult(StringUtils.substring(JSON.marshal(jsonResult), 0, 2000)); operLog.setOperUrl(ServletUtils.getRequest().getRequestURI()); if (currentUser != null) @@ -104,6 +111,8 @@ public class LogAspect String className = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); operLog.setMethod(className + "." + methodName + "()"); + // 设置请求方式 + operLog.setRequestMethod(ServletUtils.getRequest().getMethod()); // 处理设置注解上的参数 getControllerMethodDescription(controllerLog, operLog); // 保存数据库 @@ -150,8 +159,13 @@ public class LogAspect 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)); + } } /** diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java index 4a84c5187..b6b0e88c6 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java @@ -13,7 +13,7 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy; // 表示通过aop框架暴露该代理对象,AopContext能够访问 @EnableAspectJAutoProxy(exposeProxy = true) // 指定要扫描的Mapper类的包的路径 -@MapperScan("com.ruoyi.*.mapper") +@MapperScan("com.ruoyi.**.mapper") public class ApplicationConfig { diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java index 3e4a97eff..b4c356bb0 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java @@ -20,6 +20,7 @@ import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties; import com.alibaba.druid.util.Utils; import com.ruoyi.common.enums.DataSourceType; +import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.config.properties.DruidProperties; import com.ruoyi.framework.datasource.DynamicDataSource; @@ -50,14 +51,33 @@ public class DruidConfig @Bean(name = "dynamicDataSource") @Primary - public DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource) + public DynamicDataSource dataSource(DataSource masterDataSource) { Map targetDataSources = new HashMap<>(); targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); - targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource); + setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource"); return new DynamicDataSource(masterDataSource, targetDataSources); } + /** + * 设置数据源 + * + * @param targetDataSources 备选数据源集合 + * @param sourceName 数据源名称 + * @param beanName bean名称 + */ + public void setDataSource(Map targetDataSources, String sourceName, String beanName) + { + try + { + DataSource dataSource = SpringUtils.getBean(beanName); + targetDataSources.put(sourceName, dataSource); + } + catch (Exception e) + { + } + } + /** * 去除监控页面底部的广告 */ @@ -79,6 +99,7 @@ public class DruidConfig public void init(javax.servlet.FilterConfig filterConfig) throws ServletException { } + @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException @@ -93,6 +114,7 @@ public class DruidConfig text = text.replaceAll("powered.*?shrek.wang", ""); response.getWriter().write(text); } + @Override public void destroy() { diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java new file mode 100644 index 000000000..057c9419a --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java @@ -0,0 +1,132 @@ +package com.ruoyi.framework.config; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import javax.sql.DataSource; +import org.apache.ibatis.io.VFS; +import org.apache.ibatis.session.SqlSessionFactory; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.boot.autoconfigure.SpringBootVFS; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.util.ClassUtils; +import com.ruoyi.common.utils.StringUtils; + +/** + * Mybatis支持*匹配扫描包 + * + * @author ruoyi + */ +@Configuration +public class MyBatisConfig +{ + @Autowired + private Environment env; + + static final String DEFAULT_RESOURCE_PATTERN = "**/*.class"; + + public static String setTypeAliasesPackage(String typeAliasesPackage) + { + ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver(); + MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver); + List allResult = new ArrayList(); + try + { + for (String aliasesPackage : typeAliasesPackage.split(",")) + { + List result = new ArrayList(); + aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN; + Resource[] resources = resolver.getResources(aliasesPackage); + if (resources != null && resources.length > 0) + { + MetadataReader metadataReader = null; + for (Resource resource : resources) + { + if (resource.isReadable()) + { + metadataReader = metadataReaderFactory.getMetadataReader(resource); + try + { + result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName()); + } + catch (ClassNotFoundException e) + { + e.printStackTrace(); + } + } + } + } + if (result.size() > 0) + { + HashSet hashResult = new HashSet(result); + allResult.addAll(hashResult); + } + } + if (allResult.size() > 0) + { + typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0])); + } + else + { + throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包"); + } + } + catch (IOException e) + { + e.printStackTrace(); + } + return typeAliasesPackage; + } + + public Resource[] resolveMapperLocations(String[] mapperLocations) + { + ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); + List resources = new ArrayList(); + if (mapperLocations != null) + { + for (String mapperLocation : mapperLocations) + { + try + { + Resource[] mappers = resourceResolver.getResources(mapperLocation); + resources.addAll(Arrays.asList(mappers)); + } + catch (IOException e) + { + // ignore + } + } + } + return resources.toArray(new Resource[resources.size()]); + } + + @Bean + public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception + { + String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage"); + String mapperLocations = env.getProperty("mybatis.mapperLocations"); + String configLocation = env.getProperty("mybatis.configLocation"); + typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage); + VFS.addImplClass(SpringBootVFS.class); + + final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); + sessionFactory.setDataSource(dataSource); + sessionFactory.setTypeAliasesPackage(typeAliasesPackage); + sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ","))); + sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation)); + return sessionFactory.getObject(); + } +} \ No newline at end of file diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java index a927e1a46..4a1c63104 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java @@ -7,7 +7,8 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import com.ruoyi.common.config.Global; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.constant.Constants; import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor; /** @@ -40,7 +41,7 @@ public class ResourcesConfig implements WebMvcConfigurer public void addResourceHandlers(ResourceHandlerRegistry registry) { /** 本地文件上传路径 */ - registry.addResourceHandler("/profile/**").addResourceLocations("file:" + Global.getProfile() + "/"); + registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/"); /** swagger配置 */ registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); 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 721baf37b..5fed18eec 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 @@ -21,6 +21,7 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import com.ruoyi.common.constant.Constants; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; import com.ruoyi.framework.shiro.realm.UserRealm; @@ -45,51 +46,81 @@ 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; @@ -145,6 +176,7 @@ public class ShiroConfig public UserRealm userRealm(EhCacheManager cacheManager) { UserRealm userRealm = new UserRealm(); + userRealm.setAuthorizationCacheName(Constants.SYS_AUTH_CACHE); userRealm.setCacheManager(cacheManager); return userRealm; } @@ -199,7 +231,7 @@ public class ShiroConfig * 安全管理器 */ @Bean - public SecurityManager securityManager(UserRealm userRealm, SpringSessionValidationScheduler springSessionValidationScheduler) + public SecurityManager securityManager(UserRealm userRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm. @@ -219,7 +251,6 @@ public class ShiroConfig public LogoutFilter logoutFilter() { LogoutFilter logoutFilter = new LogoutFilter(); - logoutFilter.setCacheManager(getEhCacheManager()); logoutFilter.setLoginUrl(loginUrl); return logoutFilter; } @@ -249,12 +280,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()); @@ -277,28 +309,27 @@ public class ShiroConfig /** * 自定义在线用户处理过滤器 */ - @Bean public OnlineSessionFilter onlineSessionFilter() { OnlineSessionFilter onlineSessionFilter = new OnlineSessionFilter(); onlineSessionFilter.setLoginUrl(loginUrl); + onlineSessionFilter.setOnlineSessionDAO(sessionDAO()); return onlineSessionFilter; } /** * 自定义在线用户同步过滤器 */ - @Bean public SyncOnlineSessionFilter syncOnlineSessionFilter() { SyncOnlineSessionFilter syncOnlineSessionFilter = new SyncOnlineSessionFilter(); + syncOnlineSessionFilter.setOnlineSessionDAO(sessionDAO()); return syncOnlineSessionFilter; } /** * 自定义验证码过滤器 */ - @Bean public CaptchaValidateFilter captchaValidateFilter() { CaptchaValidateFilter captchaValidateFilter = new CaptchaValidateFilter(); @@ -327,7 +358,7 @@ public class ShiroConfig { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); - cookieRememberMeManager.setCipherKey(Base64.decode("fCq+/xW488hMTCD+cmJ3aQ==")); + cookieRememberMeManager.setCipherKey(Base64.decode(cipherKey)); return cookieRememberMeManager; } 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 a84e8ac7a..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 @@ -47,7 +47,7 @@ public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter /** * 验证是否重复提交由子类实现具体的防重复提交的规则 * - * @param httpServletRequest + * @param request * @return * @throws Exception */ diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java index 5c5905fda..78a4af372 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java @@ -1,6 +1,8 @@ package com.ruoyi.framework.manager; import com.ruoyi.framework.shiro.web.session.SpringSessionValidationScheduler; +import net.sf.ehcache.CacheManager; +import org.apache.shiro.cache.ehcache.EhCacheManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -20,11 +22,15 @@ public class ShutdownManager @Autowired(required = false) private SpringSessionValidationScheduler springSessionValidationScheduler; + @Autowired(required = false) + private EhCacheManager ehCacheManager; + @PreDestroy public void destroy() { shutdownSpringSessionValidationScheduler(); shutdownAsyncManager(); + shutdownEhCacheManager(); } /** @@ -61,4 +67,21 @@ public class ShutdownManager logger.error(e.getMessage(), e); } } + + private void shutdownEhCacheManager() + { + try + { + logger.info("====关闭缓存===="); + if (ehCacheManager != null) + { + CacheManager cacheManager = ehCacheManager.getCacheManager(); + cacheManager.shutdown(); + } + } + catch (Exception e) + { + logger.error(e.getMessage(), e); + } + } } 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 719c380e4..f125664c6 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 @@ -5,11 +5,12 @@ 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.LogUtils; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.ShiroUtils; +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; -import com.ruoyi.framework.util.ShiroUtils; import com.ruoyi.system.domain.SysLogininfor; import com.ruoyi.system.domain.SysOperLog; import com.ruoyi.system.domain.SysUserOnline; @@ -80,7 +81,7 @@ public class AsyncFactory } /** - * 记录登陆信息 + * 记录登录信息 * * @param username 用户名 * @param status 状态 @@ -119,7 +120,7 @@ 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); } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/realm/UserRealm.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/realm/UserRealm.java index 258efba3f..8cda35e2d 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/realm/UserRealm.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/realm/UserRealm.java @@ -2,7 +2,6 @@ package com.ruoyi.framework.shiro.realm; import java.util.HashSet; import java.util.Set; -import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; @@ -14,21 +13,22 @@ import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.cache.Cache; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; +import org.apache.shiro.subject.SimplePrincipalCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; - +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.exception.user.CaptchaException; import com.ruoyi.common.exception.user.RoleBlockedException; import com.ruoyi.common.exception.user.UserBlockedException; import com.ruoyi.common.exception.user.UserNotExistsException; import com.ruoyi.common.exception.user.UserPasswordNotMatchException; import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.framework.shiro.service.SysLoginService; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysUser; import com.ruoyi.system.service.ISysMenuService; import com.ruoyi.system.service.ISysRoleService; @@ -133,10 +133,26 @@ public class UserRealm extends AuthorizingRealm } /** - * 清理缓存权限 + * 清理指定用户授权信息缓存 */ - public void clearCachedAuthorizationInfo() + public void clearCachedAuthorizationInfo(Object principal) { - this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals()); + SimplePrincipalCollection principals = new SimplePrincipalCollection(principal, getName()); + this.clearCachedAuthorizationInfo(principals); + } + + /** + * 清理所有用户授权信息缓存 + */ + public void clearAllCachedAuthorizationInfo() + { + Cache cache = getAuthorizationCache(); + if (cache != null) + { + for (Object key : cache.keys()) + { + cache.remove(key); + } + } } } 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 92ebe89d8..e729ff714 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 @@ -6,6 +6,7 @@ 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.core.domain.entity.SysUser; import com.ruoyi.common.enums.UserStatus; import com.ruoyi.common.exception.user.CaptchaException; import com.ruoyi.common.exception.user.UserBlockedException; @@ -15,10 +16,9 @@ import com.ruoyi.common.exception.user.UserPasswordNotMatchException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.ShiroUtils; 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; /** @@ -41,7 +41,7 @@ public class SysLoginService public SysUser login(String username, String password) { // 验证码校验 - if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) + if (ShiroConstants.CAPTCHA_ERROR.equals(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) { AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); throw new CaptchaException(); @@ -71,6 +71,7 @@ public class SysLoginService // 查询用户信息 SysUser user = userService.selectUserByLoginName(username); + /** if (user == null && maybeMobilePhoneNumber(username)) { user = userService.selectUserByPhoneNumber(username); @@ -80,6 +81,7 @@ public class SysLoginService { user = userService.selectUserByEmail(username); } + */ if (user == null) { @@ -106,6 +108,7 @@ public class SysLoginService return user; } + /** private boolean maybeEmail(String username) { if (!username.matches(UserConstants.EMAIL_PATTERN)) @@ -123,6 +126,7 @@ public class SysLoginService } return true; } + */ /** * 记录登录信息 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 96da6cde7..7eff195fa 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 @@ -10,12 +10,12 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.ShiroConstants; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.exception.user.UserPasswordNotMatchException; import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException; import com.ruoyi.common.utils.MessageUtils; import com.ruoyi.framework.manager.AsyncManager; import com.ruoyi.framework.manager.factory.AsyncFactory; -import com.ruoyi.system.domain.SysUser; /** * 登录密码方法 @@ -73,14 +73,13 @@ public class SysPasswordService return user.getPassword().equals(encryptPassword(user.getLoginName(), newPassword, user.getSalt())); } - public void clearLoginRecordCache(String username) + public void clearLoginRecordCache(String loginName) { - loginRecordCache.remove(username); + loginRecordCache.remove(loginName); } - public String encryptPassword(String username, String password, String salt) + public String encryptPassword(String loginName, String password, String salt) { - return new Md5Hash(username + password + salt).toHex().toString(); + return new Md5Hash(loginName + password + salt).toHex(); } - } 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..3959ca495 --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/service/SysRegisterService.java @@ -0,0 +1,83 @@ +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.core.domain.entity.SysUser; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.MessageUtils; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.ShiroUtils; +import com.ruoyi.framework.manager.AsyncManager; +import com.ruoyi.framework.manager.factory.AsyncFactory; +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 = "", loginName = user.getLoginName(), password = user.getPassword(); + + if (!StringUtils.isEmpty(ServletUtils.getRequest().getAttribute(ShiroConstants.CURRENT_CAPTCHA))) + { + msg = "验证码错误"; + } + else if (StringUtils.isEmpty(loginName)) + { + 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 (loginName.length() < UserConstants.USERNAME_MIN_LENGTH + || loginName.length() > UserConstants.USERNAME_MAX_LENGTH) + { + msg = "账户长度必须在2到20个字符之间"; + } + else if (UserConstants.USER_NAME_NOT_UNIQUE.equals(userService.checkLoginNameUnique(loginName))) + { + msg = "保存用户'" + loginName + "'失败,注册账号已存在"; + } + else + { + user.setPwdUpdateDate(DateUtils.getNowDate()); + user.setUserName(loginName); + 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(loginName, Constants.REGISTER, MessageUtils.message("user.register.success"))); + } + } + return msg; + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSession.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSession.java index 09b88c5ce..95d9b4c7e 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSession.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSession.java @@ -1,5 +1,7 @@ package com.ruoyi.framework.shiro.session; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; import org.apache.shiro.session.mgt.SimpleSession; import com.ruoyi.common.enums.OnlineStatus; @@ -145,4 +147,19 @@ public class OnlineSession extends SimpleSession { return super.removeAttribute(key); } + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) + .append("userId", getUserId()) + .append("loginName", getLoginName()) + .append("deptName", getDeptName()) + .append("avatar", getAvatar()) + .append("host", getHost()) + .append("browser", getBrowser()) + .append("os", getOs()) + .append("status", getStatus()) + .append("attributeChanged", isAttributeChanged()) + .toString(); + } } 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 40ff31277..bbcf1e342 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 @@ -80,12 +80,12 @@ public class OnlineSessionDAO extends EnterpriseCacheSessionDAO boolean isGuest = onlineSession.getUserId() == null || onlineSession.getUserId() == 0L; // session 数据变更了 同步 - if (isGuest == false && onlineSession.isAttributeChanged()) + if (!isGuest && onlineSession.isAttributeChanged()) { needSync = true; } - if (needSync == false) + if (!needSync) { return; } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java index e6f6896d9..bb6c0aaf2 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/session/OnlineSessionFactory.java @@ -8,7 +8,6 @@ import org.apache.shiro.web.session.mgt.WebSessionContext; import org.springframework.stereotype.Component; import com.ruoyi.common.utils.IpUtils; import com.ruoyi.common.utils.ServletUtils; - import eu.bitwalker.useragentutils.UserAgent; /** diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/util/AuthorizationUtils.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/util/AuthorizationUtils.java new file mode 100644 index 000000000..3334ec792 --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/util/AuthorizationUtils.java @@ -0,0 +1,30 @@ +package com.ruoyi.framework.shiro.util; + +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.mgt.RealmSecurityManager; +import com.ruoyi.framework.shiro.realm.UserRealm; + +/** + * 用户授权信息 + * + * @author ruoyi + */ +public class AuthorizationUtils +{ + /** + * 清理所有用户授权信息缓存 + */ + public static void clearAllCachedAuthorizationInfo() + { + getUserRealm().clearAllCachedAuthorizationInfo(); + } + + /** + * 获取自定义Realm + */ + public static UserRealm getUserRealm() + { + RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager(); + return (UserRealm) rsm.getRealms().iterator().next(); + } +} 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 f5aa96647..f8861b649 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,23 +1,20 @@ 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.core.domain.entity.SysUser; import com.ruoyi.common.utils.MessageUtils; +import com.ruoyi.common.utils.ShiroUtils; 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; /** * 退出过滤器 @@ -33,8 +30,6 @@ public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter */ private String loginUrl; - private Cache> cache; - public String getLoginUrl() { return loginUrl; @@ -61,7 +56,7 @@ public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter // 记录用户退出日志 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(); @@ -92,11 +87,4 @@ public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter } 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 743d27933..40939e91c 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 @@ -6,8 +6,8 @@ import javax.servlet.http.HttpServletRequest; import org.apache.shiro.web.filter.AccessControlFilter; import com.google.code.kaptcha.Constants; import com.ruoyi.common.constant.ShiroConstants; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.framework.util.ShiroUtils; /** * 验证码过滤器 @@ -61,6 +61,8 @@ public class CaptchaValidateFilter extends AccessControlFilter { 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/filter/kickout/KickoutSessionFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/kickout/KickoutSessionFilter.java index 2c94499e6..32789b42e 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/kickout/KickoutSessionFilter.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/kickout/KickoutSessionFilter.java @@ -19,9 +19,9 @@ import org.apache.shiro.web.util.WebUtils; import com.fasterxml.jackson.databind.ObjectMapper; import com.ruoyi.common.constant.ShiroConstants; import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.utils.ServletUtils; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysUser; +import com.ruoyi.common.utils.ShiroUtils; /** * 登录帐号控制过滤器 diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/online/OnlineSessionFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/online/OnlineSessionFilter.java index 070d91e82..bbbe6d66e 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/online/OnlineSessionFilter.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/online/OnlineSessionFilter.java @@ -7,14 +7,13 @@ import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.AccessControlFilter; import org.apache.shiro.web.util.WebUtils; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import com.ruoyi.common.constant.ShiroConstants; +import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.enums.OnlineStatus; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.framework.shiro.session.OnlineSession; import com.ruoyi.framework.shiro.session.OnlineSessionDAO; -import com.ruoyi.framework.util.ShiroUtils; -import com.ruoyi.system.domain.SysUser; /** * 自定义访问控制 @@ -29,7 +28,6 @@ public class OnlineSessionFilter extends AccessControlFilter @Value("${shiro.user.loginUrl}") private String loginUrl; - @Autowired private OnlineSessionDAO onlineSessionDAO; /** @@ -93,4 +91,9 @@ public class OnlineSessionFilter extends AccessControlFilter { WebUtils.issueRedirect(request, response, loginUrl); } + + public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO) + { + this.onlineSessionDAO = onlineSessionDAO; + } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java index e1af32d97..f8e51422c 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/filter/sync/SyncOnlineSessionFilter.java @@ -3,7 +3,6 @@ package com.ruoyi.framework.shiro.web.filter.sync; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.shiro.web.filter.PathMatchingFilter; -import org.springframework.beans.factory.annotation.Autowired; import com.ruoyi.common.constant.ShiroConstants; import com.ruoyi.framework.shiro.session.OnlineSession; import com.ruoyi.framework.shiro.session.OnlineSessionDAO; @@ -15,7 +14,6 @@ import com.ruoyi.framework.shiro.session.OnlineSessionDAO; */ public class SyncOnlineSessionFilter extends PathMatchingFilter { - @Autowired private OnlineSessionDAO onlineSessionDAO; /** @@ -33,4 +31,9 @@ public class SyncOnlineSessionFilter extends PathMatchingFilter } return true; } + + public void setOnlineSessionDAO(OnlineSessionDAO onlineSessionDAO) + { + this.onlineSessionDAO = onlineSessionDAO; + } } 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 089806733..695824243 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 @@ -103,6 +103,11 @@ public class OnlineWebSessionManager extends DefaultWebSessionManager int invalidCount = 0; int timeout = (int) this.getGlobalSessionTimeout(); + if (timeout < 0) + { + // 永不过期不进行处理 + return; + } Date expiredDate = DateUtils.addMilliseconds(new Date(), 0 - timeout); ISysUserOnlineService userOnlineService = SpringUtils.getBean(ISysUserOnlineService.class); List userOnlineList = userOnlineService.selectOnlineByExpired(expiredDate); @@ -130,6 +135,7 @@ public class OnlineWebSessionManager extends DefaultWebSessionManager } invalidCount++; needOfflineIdList.add(userOnline.getSessionId()); + userOnlineService.removeUserCache(userOnline.getLoginName(), userOnline.getSessionId()); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/SpringSessionValidationScheduler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/SpringSessionValidationScheduler.java index fcb963366..f5c9d1e6a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/SpringSessionValidationScheduler.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/shiro/web/session/SpringSessionValidationScheduler.java @@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import com.ruoyi.common.utils.Threads; @@ -39,6 +40,7 @@ public class SpringSessionValidationScheduler implements SessionValidationSchedu */ @Autowired @Qualifier("sessionManager") + @Lazy private ValidatingSessionManager sessionManager; // 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟 diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java index 26aed47db..e7312f05b 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java @@ -190,7 +190,7 @@ public class Server private void setSysFiles(OperatingSystem os) { FileSystem fileSystem = os.getFileSystem(); - OSFileStore[] fsArray = fileSystem.getFileStores(); + List fsArray = fileSystem.getFileStores(); for (OSFileStore fs : fsArray) { long free = fs.getUsableSpace(); diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/CacheService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/CacheService.java new file mode 100644 index 000000000..33d17ac46 --- /dev/null +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/CacheService.java @@ -0,0 +1,83 @@ +package com.ruoyi.framework.web.service; + +import java.util.Set; +import org.apache.commons.lang3.ArrayUtils; +import org.springframework.stereotype.Service; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.utils.CacheUtils; + +/** + * 缓存操作处理 + * + * @author ruoyi + */ +@Service +public class CacheService +{ + /** + * 获取所有缓存名称 + * + * @return 缓存列表 + */ + public String[] getCacheNames() + { + String[] cacheNames = CacheUtils.getCacheNames(); + return ArrayUtils.removeElement(cacheNames, Constants.SYS_AUTH_CACHE); + } + + /** + * 根据缓存名称获取所有键名 + * + * @param cacheName 缓存名称 + * @return 键名列表 + */ + public Set getCacheKeys(String cacheName) + { + return CacheUtils.getCache(cacheName).keys(); + } + + /** + * 根据缓存名称和键名获取内容值 + * + * @param cacheName 缓存名称 + * @param cacheKey 键名 + * @return 键值 + */ + public Object getCacheValue(String cacheName, String cacheKey) + { + return CacheUtils.get(cacheName, cacheKey); + } + + /** + * 根据名称删除缓存信息 + * + * @param cacheName 缓存名称 + */ + public void clearCacheName(String cacheName) + { + CacheUtils.removeAll(cacheName); + } + + /** + * 根据名称和键名删除缓存信息 + * + * @param cacheName 缓存名称 + * @param cacheKey 键名 + */ + public void clearCacheKey(String cacheName, String cacheKey) + { + CacheUtils.remove(cacheName, cacheKey); + } + + /** + * 清理所有缓存 + */ + public void clearAll() + { + String[] cacheNames = getCacheNames(); + for (String cacheName : cacheNames) + { + CacheUtils.removeAll(cacheName); + } + } +} 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 5ee1b3d8c..3b2d0566b 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 @@ -18,7 +18,7 @@ public class ConfigService /** * 根据键名查询参数配置信息 * - * @param configName 参数名称 + * @param configKey 参数键名 * @return 参数键值 */ public String getKey(String configKey) diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/DictService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/DictService.java index 64e7c8a0e..ced0e787e 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/DictService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/DictService.java @@ -3,8 +3,9 @@ package com.ruoyi.framework.web.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import com.ruoyi.system.domain.SysDictData; +import com.ruoyi.common.core.domain.entity.SysDictData; import com.ruoyi.system.service.ISysDictDataService; +import com.ruoyi.system.service.ISysDictTypeService; /** * RuoYi首创 html调用 thymeleaf 实现字典读取 @@ -14,6 +15,9 @@ import com.ruoyi.system.service.ISysDictDataService; @Service("dict") public class DictService { + @Autowired + private ISysDictTypeService dictTypeService; + @Autowired private ISysDictDataService dictDataService; @@ -25,7 +29,7 @@ public class DictService */ public List getType(String dictType) { - return dictDataService.selectDictDataByType(dictType); + return dictTypeService.selectDictDataByType(dictType); } /** diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java index 0123ddb1c..405e0325c 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java @@ -1,8 +1,14 @@ package com.ruoyi.framework.web.service; +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; import org.apache.shiro.SecurityUtils; +import org.apache.shiro.subject.Subject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import com.ruoyi.common.utils.security.PermissionUtils; +import com.ruoyi.common.utils.StringUtils; /** * RuoYi首创 js调用 thymeleaf 实现按钮权限可见性 @@ -12,38 +18,217 @@ import com.ruoyi.common.utils.security.PermissionUtils; @Service("permission") public class PermissionService { + private static final Logger log = LoggerFactory.getLogger(PermissionService.class); + + /** 没有权限,hidden用于前端隐藏按钮 */ + public static final String NOACCESS = "hidden"; + + private static final String ROLE_DELIMETER = ","; + + private static final String PERMISSION_DELIMETER = ","; + + /** + * 验证用户是否具备某权限,无权限返回hidden用于前端隐藏(如需返回Boolean使用isPermitted) + * + * @param permission 权限字符串 + * @return 用户是否具备某权限 + */ public String hasPermi(String permission) { - return isPermittedOperator(permission) ? "" : "hidden"; + return isPermitted(permission) ? StringUtils.EMPTY : NOACCESS; } + /** + * 验证用户是否不具备某权限,与 hasPermi逻辑相反。无权限返回hidden用于前端隐藏(如需返回Boolean使用isLacksPermitted) + * + * @param permission 权限字符串 + * @return 用户是否不具备某权限 + */ + public String lacksPermi(String permission) + { + return isLacksPermitted(permission) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否具有以下任意一个权限,无权限返回hidden用于隐藏(如需返回Boolean使用hasAnyPermissions) + * + * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表 + * @return 用户是否具有以下任意一个权限 + */ + public String hasAnyPermi(String permissions) + { + return hasAnyPermissions(permissions, PERMISSION_DELIMETER) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否具备某角色,无权限返回hidden用于隐藏(如需返回Boolean使用isRole) + * + * @param role 角色字符串 + * @return 用户是否具备某角色 + */ public String hasRole(String role) { - return hasRoleOperator(role) ? "" : "hidden"; + return isRole(role) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否不具备某角色,与hasRole逻辑相反。无权限返回hidden用于隐藏(如需返回Boolean使用isLacksRole) + * + * @param role 角色字符串 + * @return 用户是否不具备某角色 + */ + public String lacksRole(String role) + { + return isLacksRole(role) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否具有以下任意一个角色,无权限返回hidden用于隐藏(如需返回Boolean使用isAnyRoles) + * + * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 + * @return 用户是否具有以下任意一个角色 + */ + public String hasAnyRoles(String roles) + { + return isAnyRoles(roles, ROLE_DELIMETER) ? StringUtils.EMPTY : NOACCESS; + } + + /** + * 验证用户是否认证通过或已记住的用户。 + * + * @return 用户是否认证通过或已记住的用户 + */ + public boolean isUser() + { + Subject subject = SecurityUtils.getSubject(); + return subject != null && subject.getPrincipal() != null; } /** * 判断用户是否拥有某个权限 * * @param permission 权限字符串 - * @return 结果 + * @return 用户是否具备某权限 */ - private boolean isPermittedOperator(String permission) + public boolean isPermitted(String permission) { return SecurityUtils.getSubject().isPermitted(permission); } + /** + * 判断用户是否不具备某权限,与 isPermitted逻辑相反。 + * + * @param permission 权限名称 + * @return 用户是否不具备某权限 + */ + public boolean isLacksPermitted(String permission) + { + return isPermitted(permission) != true; + } + + /** + * 验证用户是否具有以下任意一个权限。 + * + * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表 + * @return 用户是否具有以下任意一个权限 + */ + public boolean hasAnyPermissions(String permissions) + { + return hasAnyPermissions(permissions, PERMISSION_DELIMETER); + } + + /** + * 验证用户是否具有以下任意一个权限。 + * + * @param permissions 以 delimeter 为分隔符的权限列表 + * @param delimeter 权限列表分隔符 + * @return 用户是否具有以下任意一个权限 + */ + public boolean hasAnyPermissions(String permissions, String delimeter) + { + Subject subject = SecurityUtils.getSubject(); + + if (subject != null) + { + if (delimeter == null || delimeter.length() == 0) + { + delimeter = PERMISSION_DELIMETER; + } + + for (String permission : permissions.split(delimeter)) + { + if (permission != null && subject.isPermitted(permission.trim()) == true) + { + return true; + } + } + } + + return false; + } + /** * 判断用户是否拥有某个角色 * * @param role 角色字符串 - * @return 结果 + * @return 用户是否具备某角色 */ - private boolean hasRoleOperator(String role) + public boolean isRole(String role) { return SecurityUtils.getSubject().hasRole(role); } + /** + * 验证用户是否不具备某角色,与 isRole逻辑相反。 + * + * @param role 角色名称 + * @return 用户是否不具备某角色 + */ + public boolean isLacksRole(String role) + { + return isRole(role) != true; + } + + /** + * 验证用户是否具有以下任意一个角色。 + * + * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 + * @return 用户是否具有以下任意一个角色 + */ + public boolean isAnyRoles(String roles) + { + return isAnyRoles(roles, ROLE_DELIMETER); + } + + /** + * 验证用户是否具有以下任意一个角色。 + * + * @param roles 以 delimeter 为分隔符的角色列表 + * @param delimeter 角色列表分隔符 + * @return 用户是否具有以下任意一个角色 + */ + public boolean isAnyRoles(String roles, String delimeter) + { + Subject subject = SecurityUtils.getSubject(); + if (subject != null) + { + if (delimeter == null || delimeter.length() == 0) + { + delimeter = ROLE_DELIMETER; + } + + for (String role : roles.split(delimeter)) + { + if (subject.hasRole(role.trim()) == true) + { + return true; + } + } + } + + return false; + } + /** * 返回用户属性值 * @@ -52,6 +237,26 @@ public class PermissionService */ public Object getPrincipalProperty(String property) { - return PermissionUtils.getPrincipalProperty(property); + Subject subject = SecurityUtils.getSubject(); + if (subject != null) + { + Object principal = subject.getPrincipal(); + try + { + BeanInfo bi = Introspector.getBeanInfo(principal.getClass()); + for (PropertyDescriptor pd : bi.getPropertyDescriptors()) + { + if (pd.getName().equals(property) == true) + { + return pd.getReadMethod().invoke(principal, (Object[]) null); + } + } + } + catch (Exception e) + { + log.error("Error reading property [{}] from principal of type [{}]", property, principal.getClass().getName()); + } + } + return null; } } diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml index d13df57f8..7c0942beb 100644 --- a/ruoyi-generator/pom.xml +++ b/ruoyi-generator/pom.xml @@ -5,24 +5,24 @@ ruoyi com.ruoyi - 4.0.0 + 4.5.1 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/config/GenConfig.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java index 49b42e7ae..1b144deb9 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java @@ -21,8 +21,8 @@ public class GenConfig /** 生成包路径 */ public static String packageName; - /** 自动去除表前缀,默认是true */ - public static String autoRemovePre; + /** 自动去除表前缀,默认是false */ + public static boolean autoRemovePre; /** 表前缀(类名不会包含表前缀) */ public static String tablePrefix; @@ -49,13 +49,13 @@ public class GenConfig GenConfig.packageName = packageName; } - public static String getAutoRemovePre() + public static boolean getAutoRemovePre() { return autoRemovePre; } @Value("${autoRemovePre}") - public void setAutoRemovePre(String autoRemovePre) + public void setAutoRemovePre(boolean autoRemovePre) { GenConfig.autoRemovePre = autoRemovePre; } 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 6e4f710dc..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,6 +1,7 @@ package com.ruoyi.generator.controller; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; @@ -15,12 +16,15 @@ 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; @@ -126,7 +130,24 @@ public class GenController extends BaseController 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"; } @@ -167,15 +188,41 @@ public class GenController extends BaseController } /** - * 生成代码 + * 生成代码(下载方式) + */ + @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 + @ResponseBody + public AjaxResult genCode(@PathVariable("tableName") String tableName) { - byte[] data = genTableService.generatorCode(tableName); - genCode(response, data); + 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(); } /** @@ -188,7 +235,7 @@ public class GenController extends BaseController 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); } 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 22c31b866..2abb94fa1 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 @@ -3,6 +3,7 @@ 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; @@ -27,11 +28,17 @@ public class GenTable extends BaseEntity @NotBlank(message = "表描述不能为空") private String tableComment; + /** 关联父表的表名 */ + private String subTableName; + + /** 本表关联父表的外键名 */ + private String subTableFkName; + /** 实体类名称(首字母大写) */ @NotBlank(message = "实体类名称不能为空") private String className; - /** 使用的模板(crud单表操作 tree树表操作) */ + /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */ private String tplCategory; /** 生成包路径 */ @@ -54,9 +61,18 @@ public class GenTable extends BaseEntity @NotBlank(message = "作者不能为空") private String functionAuthor; + /** 生成代码方式(0zip压缩包 1自定义路径) */ + private String genType; + + /** 生成路径(不填默认项目路径) */ + private String genPath; + /** 主键信息 */ private GenTableColumn pkColumn; + /** 子表信息 */ + private GenTable subTable; + /** 表列信息 */ @Valid private List columns; @@ -73,6 +89,12 @@ public class GenTable extends BaseEntity /** 树名称字段 */ private String treeName; + /** 上级菜单ID字段 */ + private String parentMenuId; + + /** 上级菜单名称字段 */ + private String parentMenuName; + public Long getTableId() { return tableId; @@ -103,6 +125,26 @@ public class GenTable extends BaseEntity this.tableComment = tableComment; } + 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; @@ -173,6 +215,26 @@ public class GenTable extends BaseEntity this.functionAuthor = functionAuthor; } + 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; @@ -183,6 +245,16 @@ public class GenTable extends BaseEntity this.pkColumn = pkColumn; } + public GenTable getSubTable() + { + return subTable; + } + + public void setSubTable(GenTable subTable) + { + this.subTable = subTable; + } + public List getColumns() { return columns; @@ -233,6 +305,36 @@ public class GenTable extends BaseEntity this.treeName = treeName; } + 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); @@ -252,4 +354,19 @@ public class GenTable extends BaseEntity { return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); } + + public boolean isSuperColumn(String javaField) + { + return isSuperColumn(this.tplCategory, javaField); + } + + 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); + } } \ 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 bb912ed48..0fe7baaaf 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 @@ -59,7 +59,7 @@ public class GenTableColumn extends BaseEntity /** 查询方式(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; /** 字典类型 */ @@ -138,6 +138,11 @@ public class GenTableColumn extends BaseEntity return javaField; } + public String getCapJavaField() + { + return StringUtils.capitalize(javaField); + } + public void setIsPk(String isPk) { this.isPk = isPk; @@ -325,7 +330,22 @@ public class GenTableColumn extends BaseEntity public static boolean isSuperColumn(String javaField) { - return StringUtils.equalsAnyIgnoreCase(javaField, "createBy", "createTime", "updateBy", "updateTime", "remark"); + return StringUtils.equalsAnyIgnoreCase(javaField, + // BaseEntity + "createBy", "createTime", "updateBy", "updateTime", "remark", + // TreeEntity + "parentName", "parentId", "orderNum", "ancestors"); + } + + public boolean isUsableColumn() + { + return isUsableColumn(javaField); + } + + public static boolean isUsableColumn(String javaField) + { + // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark"); } public String readConverterExp() 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 index 6ebe2306b..a819c741b 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java @@ -17,7 +17,7 @@ public interface GenTableColumnMapper * @return 列信息 */ public List selectDbTableColumnsByName(String tableName); - + /** * 查询业务字段列表 * @@ -42,6 +42,14 @@ public interface GenTableColumnMapper */ public int updateGenTableColumn(GenTableColumn genTableColumn); + /** + * 删除业务字段 + * + * @param genTableColumns 列数据 + * @return 结果 + */ + public int deleteGenTableColumns(List genTableColumns); + /** * 批量删除业务字段 * @@ -49,4 +57,4 @@ public interface GenTableColumnMapper * @return 结果 */ public int deleteGenTableColumnByIds(Long[] ids); -} \ No newline at end of file +} 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 index 85143e650..40314e6d9 100644 --- a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java +++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java @@ -34,6 +34,13 @@ public interface GenTableMapper */ public List selectDbTableListByNames(String[] tableNames); + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List selectGenTableAll(); + /** * 查询表ID业务信息 * 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 50e51bcda..5f5f48de0 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 @@ -35,6 +35,13 @@ public interface IGenTableService */ public List selectDbTableListByNames(String[] tableNames); + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + public List selectGenTableAll(); + /** * 查询业务信息 * @@ -76,20 +83,34 @@ public interface IGenTableService 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); /** * 修改保存参数校验 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 f7edca385..de5cc50f3 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,11 +1,13 @@ package com.ruoyi.generator.service.impl; 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; @@ -21,9 +23,11 @@ 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; @@ -81,6 +85,7 @@ public class GenTableServiceImpl implements IGenTableService * @param genTable 业务信息 * @return 数据库表集合 */ + @Override public List selectDbTableList(GenTable genTable) { return genTableMapper.selectDbTableList(genTable); @@ -92,11 +97,23 @@ public class GenTableServiceImpl implements IGenTableService * @param tableNames 表名称组 * @return 数据库表集合 */ + @Override public List selectDbTableListByNames(String[] tableNames) { return genTableMapper.selectDbTableListByNames(tableNames); } + /** + * 查询所有表信息 + * + * @return 表信息集合 + */ + @Override + public List selectGenTableAll() + { + return genTableMapper.selectGenTableAll(); + } + /** * 修改业务 * @@ -143,9 +160,9 @@ public class GenTableServiceImpl implements IGenTableService @Transactional public void importGenTable(List tableList, String operName) { - for (GenTable table : tableList) + try { - try + for (GenTable table : tableList) { String tableName = table.getTableName(); GenUtils.initTable(table, operName); @@ -161,10 +178,10 @@ public class GenTableServiceImpl implements IGenTableService } } } - catch (Exception e) - { - log.error("表名 " + table.getTableName() + " 导入失败:", e); - } + } + catch (Exception e) + { + throw new BusinessException("导入失败:" + e.getMessage()); } } @@ -174,14 +191,16 @@ public class GenTableServiceImpl implements IGenTableService * @param tableId 表编号 * @return 预览数据列表 */ + @Override public Map previewCode(Long tableId) { Map dataMap = new LinkedHashMap<>(); // 查询表信息 GenTable table = genTableMapper.selectGenTableById(tableId); - // 查询列信息 - List columns = table.getColumns(); - setPkColumn(table, columns); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); VelocityInitializer.initVelocity(); VelocityContext context = VelocityUtils.prepareContext(table); @@ -200,13 +219,13 @@ public class GenTableServiceImpl 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); @@ -214,6 +233,84 @@ public class GenTableServiceImpl implements IGenTableService 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); + } + } /** * 批量生成代码 @@ -222,7 +319,7 @@ public class GenTableServiceImpl implements IGenTableService * @return 数据 */ @Override - public byte[] generatorCode(String[] tableNames) + public byte[] downloadCode(String[] tableNames) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(outputStream); @@ -241,9 +338,10 @@ public class GenTableServiceImpl implements IGenTableService { // 查询表信息 GenTable table = genTableMapper.selectGenTableByName(tableName); - // 查询列信息 - List columns = table.getColumns(); - setPkColumn(table, columns); + // 设置主子表信息 + setSubTable(table); + // 设置主键列信息 + setPkColumn(table); VelocityInitializer.initVelocity(); @@ -263,6 +361,7 @@ public class GenTableServiceImpl implements IGenTableService 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) @@ -277,6 +376,7 @@ public class GenTableServiceImpl implements IGenTableService * * @param genTable 业务信息 */ + @Override public void validateEdit(GenTable genTable) { if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) @@ -296,17 +396,27 @@ public class GenTableServiceImpl implements IGenTableService 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 genTable 业务表信息 - * @param columns 业务字段列表 + * @param table 业务表信息 */ - public void setPkColumn(GenTable table, List columns) + public void setPkColumn(GenTable table) { - for (GenTableColumn column : columns) + for (GenTableColumn column : table.getColumns()) { if (column.isPk()) { @@ -316,7 +426,36 @@ public class GenTableServiceImpl implements IGenTableService } if (StringUtils.isNull(table.getPkColumn())) { - table.setPkColumn(columns.get(0)); + 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)); } } @@ -333,9 +472,31 @@ public class GenTableServiceImpl implements IGenTableService 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 bfbe238d8..784525129 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,6 +1,7 @@ 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; @@ -19,7 +20,7 @@ public class GenUtils */ public static void initTable(GenTable genTable, String operName) { - genTable.setClassName(StringUtils.convertToCamelCase(genTable.getTableName())); + genTable.setClassName(convertClassName(genTable.getTableName())); genTable.setPackageName(GenConfig.getPackageName()); genTable.setModuleName(getModuleName(GenConfig.getPackageName())); genTable.setBusinessName(getBusinessName(genTable.getTableName())); @@ -61,7 +62,7 @@ public class GenUtils String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ","); if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) { - column.setJavaType(GenConstants.TYPE_DOUBLE); + column.setJavaType(GenConstants.TYPE_BIGDECIMAL); } // 如果是整形 else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) @@ -110,6 +111,16 @@ public class GenUtils { 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); + } } /** @@ -152,15 +163,54 @@ public class GenUtils return businessName; } + /** + * 表名转换成Java类名 + * + * @param tableName 表名称 + * @return 类名 + */ + public static String convertClassName(String tableName) + { + boolean autoRemovePre = GenConfig.getAutoRemovePre(); + String tablePrefix = GenConfig.getTablePrefix(); + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) + { + String[] searchList = StringUtils.split(tablePrefix, ","); + 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 name 需要被替换的名字 + * @param text 需要被替换的名字 * @return 替换后的名字 */ public static String replaceText(String text) { - return text.replaceAll("(?:表|若依)", ""); + return RegExUtils.replaceAll(text, "(?:表|若依)", ""); } /** @@ -199,4 +249,20 @@ public class GenUtils return 0; } } + + /** + * 获取空数组列表 + * + * @param length 长度 + * @return 数组信息 + */ + public static String[] emptyList(int length) + { + String[] values = new String[length]; + for (int i = 0; i < length; i++) + { + values[i] = StringUtils.EMPTY; + } + return values; + } } \ No newline at end of file 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 77a54914e..78297d2be 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 @@ -22,6 +22,9 @@ public class VelocityUtils /** html空间路径 */ private static final String TEMPLATES_PATH = "main/resources/templates"; + + /** 默认上级菜单,系统工具 */ + private static final String DEFAULT_PARENT_MENU_ID = "3"; /** * 设置模板变量信息 @@ -34,11 +37,12 @@ public class VelocityUtils String businessName = genTable.getBusinessName(); String packageName = genTable.getPackageName(); String tplCategory = genTable.getTplCategory(); + String functionName = genTable.getFunctionName(); VelocityContext velocityContext = new VelocityContext(); velocityContext.put("tplCategory", genTable.getTplCategory()); velocityContext.put("tableName", genTable.getTableName()); - velocityContext.put("functionName", genTable.getFunctionName()); + velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); velocityContext.put("ClassName", genTable.getClassName()); velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); velocityContext.put("moduleName", genTable.getModuleName()); @@ -48,17 +52,30 @@ public class VelocityUtils velocityContext.put("author", genTable.getFunctionAuthor()); velocityContext.put("datetime", DateUtils.getDate()); velocityContext.put("pkColumn", genTable.getPkColumn()); - 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); + 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 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(); @@ -75,6 +92,28 @@ public class VelocityUtils { context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE)); } + 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())); } /** @@ -100,6 +139,11 @@ public class VelocityUtils 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"); @@ -130,6 +174,10 @@ public class VelocityUtils { 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); @@ -208,17 +256,24 @@ 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(); + 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"); + importList.add("com.fasterxml.jackson.annotation.JsonFormat"); } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) { @@ -238,7 +293,21 @@ public class VelocityUtils 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; } /** @@ -253,7 +322,7 @@ public class VelocityUtils { return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE)); } - return ""; + return StringUtils.EMPTY; } /** @@ -268,7 +337,7 @@ public class VelocityUtils { return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE)); } - return ""; + return StringUtils.EMPTY; } /** @@ -283,7 +352,7 @@ public class VelocityUtils { return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME)); } - return ""; + return StringUtils.EMPTY; } /** diff --git a/ruoyi-generator/src/main/resources/generator.yml b/ruoyi-generator/src/main/resources/generator.yml index 9e76f23f4..f3792cdc6 100644 --- a/ruoyi-generator/src/main/resources/generator.yml +++ b/ruoyi-generator/src/main/resources/generator.yml @@ -5,7 +5,7 @@ gen: author: ruoyi # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool packageName: com.ruoyi.system - # 自动去除表前缀,默认是true - autoRemovePre: true - # 表前缀(类名不会包含表前缀) + # 自动去除表前缀,默认是false + autoRemovePre: false + # 表前缀(生成类名不会包含表前缀,多个用逗号分隔) tablePrefix: sys_ \ No newline at end of file diff --git a/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml index acfaebcfb..cab47441a 100644 --- a/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml +++ b/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml @@ -116,5 +116,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{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 index cac87076a..a58cc4291 100644 --- a/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml +++ b/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml @@ -5,23 +5,27 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -50,17 +54,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select table_id, table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, options, create_by, create_time, update_by, update_time, remark from gen_table + 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 @@ -71,10 +75,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" AND table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'gen_%' AND table_name NOT IN (select table_name from gen_table) - AND table_name like concat('%', #{tableName}, '%') + AND lower(table_name) like lower(concat('%', #{tableName}, '%')) - AND table_comment like concat('%', #{tableComment}, '%') + AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) @@ -94,19 +98,27 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -120,6 +132,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" business_name, function_name, function_author, + gen_type, + gen_path, remark, create_by, create_time @@ -133,6 +147,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{businessName}, #{functionName}, #{functionAuthor}, + #{genType}, + #{genPath}, #{remark}, #{createBy}, sysdate() @@ -144,8 +160,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 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}, 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 @@
    - +
    +
    +
    + +
    + +
    + + +
    +
    +
    +
    +
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + +